BLOCKER: Calendar Undo uses a newer revision and overwrites later Journal edits #777

Open
opened 2026-10-02 13:10:30 +00:00 by kayg · 8 comments
Owner

Context

Round 7b data-integrity review for #427. job/calcard-series at 5f7fdb96706aca0c457a6b7851f548f7f618ac85. The Undo design is inherited; this branch also changes the source of Journal write ETags to a module cache. This finding remains in the reviewed head.

Evidence

  • apps/web/src/routes/calendar/[view]/[date]/+page.svelte:851: the editLog Undo closure captures previous fields, then calls patchEntry without the revision returned by the forward write. The move Undo at line 818 has the same pattern.
  • apps/web/src/lib/calendar/journal.ts:30: every readDay response updates the module ETag for each entry. etagFor at line 58 and patchEntry at line 67 use this module ETag.
  • The Undo step stores dates and a client closure, without a revision or durable inverse (apps/web/src/lib/calendar/edits.ts:443).

Lost-write sequence

  1. An Installation changes a Journal title from A to B; the write returns revision R2.
  2. A later API or DAV edit changes the same title from B to C; it commits revision R3.
  3. The first Installation reads the Journal day. readDay stores R3 in the module cache.
  4. The User chooses Undo for the A-to-B edit. Its closure submits title A with R3. The server accepts the current revision and overwrites C.

The server's conditional write works. The client chooses a revision newer than the operation being undone. That defeats its lost-update protection.

Validation

A local Bun check imports the exact reviewed journal.ts, with only apiFetch and listNotes stubbed. The transport fixture enforces If-Match. The check commits B at R2, installs C at R3, calls the real readDay, then calls patchEntry with the same title patch used by the Undo closure. It observes If-Match R3 and final title A. No live server or User files were changed. The Svelte closure was inspected statically, not rendered.

Expected

Undo must be bound to the result of its original mutation. Store the forward result revision, and reject an inverse if the current revision changed. Use the durable receipt adapter in #667 when Calendar adopts it. A reread must not promote an old inverse to a new revision. Keep the newer title C.

Regression test idea

Use two Installations on a disposable local server. Change A to B in the Calendar. Change B to C through the API or DAV. Refresh the first Installation's Journal read, then use its original Undo. Require a conflict and verify that C remains in the Daily note and Index. Repeat for drag/move and resize.

Severity

BLOCKER: Undo silently overwrites a later acknowledged User edit.

Duplicate check: searched all open and closed issue titles. #722 concerns live delete restoration; #346 and #385 concern editor Undo. No Calendar inverse-revision issue was found.

## Context Round 7b data-integrity review for #427. `job/calcard-series` at `5f7fdb96706aca0c457a6b7851f548f7f618ac85`. The Undo design is inherited; this branch also changes the source of Journal write ETags to a module cache. This finding remains in the reviewed head. ## Evidence - `apps/web/src/routes/calendar/[view]/[date]/+page.svelte:851`: the `editLog` Undo closure captures previous fields, then calls `patchEntry` without the revision returned by the forward write. The move Undo at line 818 has the same pattern. - `apps/web/src/lib/calendar/journal.ts:30`: every `readDay` response updates the module ETag for each entry. `etagFor` at line 58 and `patchEntry` at line 67 use this module ETag. - The Undo step stores `dates` and a client closure, without a revision or durable inverse (`apps/web/src/lib/calendar/edits.ts:443`). ## Lost-write sequence 1. An Installation changes a Journal title from A to B; the write returns revision R2. 2. A later API or DAV edit changes the same title from B to C; it commits revision R3. 3. The first Installation reads the Journal day. `readDay` stores R3 in the module cache. 4. The User chooses Undo for the A-to-B edit. Its closure submits title A with R3. The server accepts the current revision and overwrites C. The server's conditional write works. The client chooses a revision newer than the operation being undone. That defeats its lost-update protection. ## Validation A local Bun check imports the exact reviewed `journal.ts`, with only `apiFetch` and `listNotes` stubbed. The transport fixture enforces If-Match. The check commits B at R2, installs C at R3, calls the real `readDay`, then calls `patchEntry` with the same title patch used by the Undo closure. It observes If-Match R3 and final title A. No live server or User files were changed. The Svelte closure was inspected statically, not rendered. ## Expected Undo must be bound to the result of its original mutation. Store the forward result revision, and reject an inverse if the current revision changed. Use the durable receipt adapter in #667 when Calendar adopts it. A reread must not promote an old inverse to a new revision. Keep the newer title C. ## Regression test idea Use two Installations on a disposable local server. Change A to B in the Calendar. Change B to C through the API or DAV. Refresh the first Installation's Journal read, then use its original Undo. Require a conflict and verify that C remains in the Daily note and Index. Repeat for drag/move and resize. ## Severity BLOCKER: Undo silently overwrites a later acknowledged User edit. Duplicate check: searched all open and closed issue titles. #722 concerns live delete restoration; #346 and #385 concern editor Undo. No Calendar inverse-revision issue was found.
Author
Owner

Evidence line correction: UndoStep is at apps/web/src/lib/calendar/edits.ts:353, not line 443. The reviewed head and the finding are unchanged.

Evidence line correction: `UndoStep` is at `apps/web/src/lib/calendar/edits.ts:353`, not line 443. The reviewed head and the finding are unchanged.
Author
Owner

Started on job/datafix, base 2f4482ded066d9c5d9c59130377907f7fd2916c9 (job/merge-round-7a). Fetched origin and checked both origin/dev and origin/job/merge-round-7a: already up to date. The base lacks task_views.rs, the Journal ETag cache and primitives #665–#668. Those exist on the audited feature branches. Requested prerequisite integration clarification; meanwhile tracing and fixing the Calendar Undo defect present on this base. No push or deploy.

Started on `job/datafix`, base `2f4482ded066d9c5d9c59130377907f7fd2916c9` (`job/merge-round-7a`). Fetched origin and checked both origin/dev and origin/job/merge-round-7a: already up to date. The base lacks task_views.rs, the Journal ETag cache and primitives #665–#668. Those exist on the audited feature branches. Requested prerequisite integration clarification; meanwhile tracing and fixing the Calendar Undo defect present on this base. No push or deploy.
Author
Owner

Confirmed #777 on the specified base. New title/move/resize Undo tests fail on the old adapter because it fetches the latest ETag, then accepts the old inverse. The fix passes the forward response ETag into the field inverse and publishes its response only after server acceptance.

For #790, tested the same deliberate PATCH and DELETE retry regressions against the audited origin/job/calcard-series adapter. Both fail with a second 412. Both pass with the specified base's fresh stable-entry read. Retain this behavior during integration; do not restore the unbounded module ETag map.

Read the audit evidence at rev-7b-data/review-findings.md (the file is named review-findings.md, not audit-findings.md). The specified base still lacks the #731 route and #665–#668 primitives. Prerequisite branch integration remains unspecified.

Confirmed #777 on the specified base. New title/move/resize Undo tests fail on the old adapter because it fetches the latest ETag, then accepts the old inverse. The fix passes the forward response ETag into the field inverse and publishes its response only after server acceptance. For #790, tested the same deliberate PATCH and DELETE retry regressions against the audited `origin/job/calcard-series` adapter. Both fail with a second 412. Both pass with the specified base's fresh stable-entry read. Retain this behavior during integration; do not restore the unbounded module ETag map. Read the audit evidence at `rev-7b-data/review-findings.md` (the file is named review-findings.md, not audit-findings.md). The specified base still lacks the #731 route and #665–#668 primitives. Prerequisite branch integration remains unspecified.
Author
Owner

Committed the #777 revision-bound field inverse as 84af7f3cb. The Journal suite now has 10 passing tests, including #790 deliberate PATCH and DELETE retries after 412. Both #790 tests fail against the audited calcard-series adapter and pass against the specified base.

Real-browser testing also found that Composer Journal saves bypass the shared Undo registration. A follow-up now reuses editLog and sends only changed fields; production build passes and browser validation is in progress.

#731 source is absent on the specified base. A focused patch and stale replacement / Files-edit regression are being prepared against an isolated copy of the audited tasks-mode source. This does not merge the feature branch into job/datafix.

Committed the #777 revision-bound field inverse as `84af7f3cb`. The Journal suite now has 10 passing tests, including #790 deliberate PATCH and DELETE retries after 412. Both #790 tests fail against the audited calcard-series adapter and pass against the specified base. Real-browser testing also found that Composer Journal saves bypass the shared Undo registration. A follow-up now reuses `editLog` and sends only changed fields; production build passes and browser validation is in progress. #731 source is absent on the specified base. A focused patch and stale replacement / Files-edit regression are being prepared against an isolated copy of the audited tasks-mode source. This does not merge the feature branch into job/datafix.
Author
Owner

Read-only code review found two more Journal conflict paths (#777). A refused write used the success refresh order. Its range request captured a day version that was then advanced, so keepNewerCalendarLogs retained the old Logs instead of accepting current server values. The new regression fails with that order (1 failed, 13 passed), and passes with rejected refreshes advancing before the read (26 focused Calendar tests passed). The linked Note conversion also used a fresh revision without checking the retained title. It now checks that title before changing it or creating the Note. The reviewer confirmed both changes. Web check and updated production build are running. Saved Tasks views are still absent from the assigned base; their isolated source regression is still compiling dependencies after almost three hours. No unrelated feature branch was merged.

Read-only code review found two more Journal conflict paths (#777). A refused write used the success refresh order. Its range request captured a day version that was then advanced, so `keepNewerCalendarLogs` retained the old Logs instead of accepting current server values. The new regression fails with that order (1 failed, 13 passed), and passes with rejected refreshes advancing before the read (26 focused Calendar tests passed). The linked Note conversion also used a fresh revision without checking the retained title. It now checks that title before changing it or creating the Note. The reviewer confirmed both changes. Web check and updated production build are running. Saved Tasks views are still absent from the assigned base; their isolated source regression is still compiling dependencies after almost three hours. No unrelated feature branch was merged.
Author
Owner

Partial completion: Journal fixes committed; saved Tasks view fix remains an unverified candidate.

Branch job/datafix, head 4345529d69f2e4b83ba200e53f4878b6300f8532. Base 2f4482ded066d9c5d9c59130377907f7fd2916c9. Fetched and merged origin/dev and origin/job/merge-round-7a once before the final gates. No push or deploy. Issues remain open.

Built (#777, #790)
Journal Undo sends a field inverse with the forward acknowledgement revision. A later write causes 412. An accepted inverse applies the canonical response to the current Calendar model. It never restores a retained full day map. Normal PATCH and DELETE read the current stable block identity without using a retained day revision. Retained edits also check the fields they intend to change. Composer edits now use the shared write and Undo flow, including cross-day edits. Linked Note conversion checks its retained title. A rejected edit or Undo refresh accepts current server Logs. Accepted writes still protect their canonical Logs from a delayed Calendar projection.

Regression evidence: the original Undo adapter failed 3 tests; the audited #790 cache module failed the PATCH and DELETE deliberate-retry tests; the retained-field guard failed before its fix; and the rejected-refresh order failed its new test (1 failed, 13 passed). The current focused Calendar slice passed all 26 tests. No existing status assertion was weakened. A read-only reviewer confirmed the two final conflict fixes.

Files
apps/web/src/lib/calendar/journal.ts, journal.test.ts, edits.ts, edits.test.ts; apps/web/src/routes/calendar/[view]/[date]/+page.svelte; apps/web/e2e/journal-datafix.mjs; tests/adversarial/journal-revisions.mjs; bench/calendar-weekstate-609.mjs; docs/perf/2026-10-02-datafix.md. The two Python authorization files came from the authorized base merge, not this fix.

Gates and production evidence
Root cargo fmt --check exited 0 with no output. No Rust crate changed on job/datafix; crate clippy/test are not applicable to its Journal changes.

Final bun run check output:

$ node scripts/check-user-storage.mjs && node scripts/check-type-tokens.mjs && node scripts/check-motion-tokens.mjs && svelte-kit sync && svelte-check --tsconfig ./tsconfig.json
User browser caches use userStorage; only documented device/public-link exceptions remain.
Text sizes and UI shape values use shared role tokens.
UI transitions and animation options use shared motion tokens or documented exceptions.
Loading svelte-check in workspace: /home/kayg/Developer/calternal-wt/datafix/apps/web
Getting Svelte diagnostics...

svelte-check found 0 errors and 0 warnings

The full web suite before the last review fix passed:

 Test Files  154 passed (154)
      Tests  1081 passed (1081)
   Start at  16:06:32
   Duration  2341.22s (transform 35%, import 27%, environment 23%, tests 10%, setup 5%)

After the review fix, the focused slice output was:

 Test Files  2 passed (2)
      Tests  26 passed (26)
   Start at  18:36:45
   Duration  7.71s (transform 90%, import 9%, tests 1%)

The final full rerun was stopped at the time limit after two 30-second failures in unchanged WebMCP tests. It is NOT a final full-suite pass:

 ❯ |unit| src/lib/webmcp/generated.test.ts (9 tests | 2 failed) 73051ms
   × contract writes need confirmation and recheck Apps revocation 30023ms
   × a read checks access once and a write sees revocation during confirmation 30033ms
error: script "test" exited with code 130

A single isolated rerun of that unchanged file passed without assertion changes:

 Test Files  1 passed (1)
      Tests  9 passed (9)
   Start at  19:16:24
   Duration  8.66s (transform 85%, import 9%, tests 6%)

The final whole-web gate still needs a completed run on this head. The isolated result supports timing/load as the immediate failure, but does not replace the full gate.

Updated production build output:

✓ built in 33.15s
✓ built in 56ms
✓ built in 2m
> Using @sveltejs/adapter-static
  Wrote site to "build"

Real local server output, final build:

Journal datafix: original Undo returned 412; later title remains on disk and in Calendar; twelve macOS screenshots captured.

The one bounded revision API round passed earlier:

Journal revision round: stale PATCH and DELETE rejected; deliberate retries passed.

The follow-up production run skipped that API round. Screenshots use macOS platform emulation, 390/820/1440 px, light/dark. They show Calendar and the settled Composer. Claude must review visual quality.

calendar: light 390, light 820, light 1440, dark 390, dark 820, dark 1440

composer: light 390, light 820, light 1440, dark 390, dark 820, dark 1440

Saved Tasks views (#731): known gap
The assigned base and origin/dev have no saved Tasks views feature. The audited feature exists on origin/job/tasks-mode (f620390c724ee08540d38b0ba69c3d12225fc1e4). The audited Journal cache exists on origin/job/calcard-series, and shared #665–#668 primitives are also absent from the assigned base. No unrelated feature branch was merged.

A separate source copy has a candidate fix. It uses the existing Notes content ETag and match_etag, plus calternal-fs replace_if. Every saved view read/write returns its complete-source revision. PUT requires If-Match and rejects a stale configuration. The form retains its original configuration and revision across background refresh. A conflict refreshes the Index and never replays the old configuration. Closing the form clears cancelled drafts. Contract/client changes, a stale-view/Files regression, missing-precondition coverage and a derived contract check are included. One round-trip fixture now supplies the revision it read; its status assertions remain unchanged. The shared E2E harness has a minimal optional-header test hook. A saved-view profile extends the existing Tasks sampler.

Candidate patch against the Tasks feature branch. Local source: target/tmp/taskviews-validation; local patch: artifacts/datafix/issue-731-candidate.patch. This candidate is NOT on the job branch and is NOT ready to merge. Rust old-code execution did not reach the test before the product patch was prepared; the old client did fail the stale replacement regression. The candidate client passed its focused regression and its frontend suite:

 Test Files  152 passed (152)
      Tests  1020 passed (1020)
   Start at  17:09:03
   Duration  4284.66s (transform 39%, import 24%, environment 18%, tests 12%, setup 7%)

Candidate cargo fmt --check exited 0 with no output. The candidate final bun run check passed after its form cleanup change:

$ node scripts/check-user-storage.mjs && node scripts/check-type-tokens.mjs && node scripts/check-motion-tokens.mjs && svelte-kit sync && svelte-check --tsconfig ./tsconfig.json
User browser caches use userStorage; only documented device/public-link exceptions remain.
Text sizes and UI shape values use shared role tokens.
UI transitions and animation options use shared motion tokens or documented exceptions.
Loading svelte-check in workspace: /home/kayg/Developer/calternal-wt/datafix/target/tmp/taskviews-validation/apps/web
Getting Svelte diagnostics...

svelte-check found 0 errors and 0 warnings

Rust Notes and server clippy/test did not finish. The first compilation was stopped after more than three hours in dependency builds and sccache. The direct clippy attempt is time-limited; no Rust test success is claimed. Live Tasks checks and its HDD profile were not run.

The candidate still needs integration with the feature branch, Notes and server Rust gates, generated-contract verification at runtime, live Tasks concurrency checks, required Tasks screenshots and HDD measurements. The #790 regression must stay when the cached calcard-series source is integrated; the assigned base already used uncached entry reads.

Performance
The perf VM lock was busy. This is a local model-only run, load average 128.02/127.22/120.83; no HTTP/HDD qualification. Average before/after p50/p95: 4.32/11.01 → 5.25/21.9 µs; CPU 0.0306 → 0.0377 s; RSS 49.84 → 54.22 MiB; burst CPU 0.0105 → 0.0177 s. Worst (31,000 Logs): 68.66/480.37 → 116.19/290.16 µs; CPU 0.112 → 0.164 s; RSS 60.79 → 61.83 MiB; burst CPU 0.0636 → 0.1377 s. The checked day hint reduced the initial canonical-response CPU from 1.3898 to 0.164 s per 1,000 calls. docs/perf/baseline.json has no Log-inverse baseline or threshold. Its existing date-window profile measures a different operation; it is context only. The canonical response costs more CPU than the old field projection. A quiet-host release comparison remains needed.

UX gaps closed
Composer edits now register Undo, cross-day edits use the same write flow, a retained edit cannot silently replace another client's edited field, refused Undo preserves later edits, conflicts refresh current Logs, and linked Note title edits use the same retained-field guard. In the Tasks candidate, background refresh cannot silently promote a stale open form to a newer revision, and cancelled form drafts are reset.

UX gaps left
The Tasks candidate has no live production verification or screenshot set. Its source prerequisite is not integrated. HTTP/HDD performance and real Apple-client checks are not completed. Visual acceptance belongs to Claude. Normal Journal keyboard Undo was checked on the production build; this job did not repeat every existing pointer/touch action.

Decisions
Undo is conservative: any post-acknowledgement change refuses the inverse instead of rebasing a retained edit automatically. Normal retained edits check only their edited fields; unrelated fresh fields are preserved. A saved Task view uses the complete .base source ETag, so another view or extension change can conservatively require review. Reuse existing helpers and stores; do not add parallel caches for absent #665–#668 implementations. Keep missing-feature work as a candidate patch instead of merging an unrelated feature branch.

Cleanup completed: both web production builds and .svelte-kit/output directories removed. cargo clean exited 0:

Removed 6711 files, 2.2GiB total

The working tree is clean. Work stopped within the four-hour limit.

Partial completion: Journal fixes committed; saved Tasks view fix remains an unverified candidate. Branch `job/datafix`, head `4345529d69f2e4b83ba200e53f4878b6300f8532`. Base `2f4482ded066d9c5d9c59130377907f7fd2916c9`. Fetched and merged `origin/dev` and `origin/job/merge-round-7a` once before the final gates. No push or deploy. Issues remain open. **Built (#777, #790)** Journal Undo sends a field inverse with the forward acknowledgement revision. A later write causes 412. An accepted inverse applies the canonical response to the current Calendar model. It never restores a retained full day map. Normal PATCH and DELETE read the current stable block identity without using a retained day revision. Retained edits also check the fields they intend to change. Composer edits now use the shared write and Undo flow, including cross-day edits. Linked Note conversion checks its retained title. A rejected edit or Undo refresh accepts current server Logs. Accepted writes still protect their canonical Logs from a delayed Calendar projection. Regression evidence: the original Undo adapter failed 3 tests; the audited #790 cache module failed the PATCH and DELETE deliberate-retry tests; the retained-field guard failed before its fix; and the rejected-refresh order failed its new test (1 failed, 13 passed). The current focused Calendar slice passed all 26 tests. No existing status assertion was weakened. A read-only reviewer confirmed the two final conflict fixes. **Files** `apps/web/src/lib/calendar/journal.ts`, `journal.test.ts`, `edits.ts`, `edits.test.ts`; `apps/web/src/routes/calendar/[view]/[date]/+page.svelte`; `apps/web/e2e/journal-datafix.mjs`; `tests/adversarial/journal-revisions.mjs`; `bench/calendar-weekstate-609.mjs`; `docs/perf/2026-10-02-datafix.md`. The two Python authorization files came from the authorized base merge, not this fix. **Gates and production evidence** Root `cargo fmt --check` exited 0 with no output. No Rust crate changed on `job/datafix`; crate clippy/test are not applicable to its Journal changes. Final `bun run check` output: ``` $ node scripts/check-user-storage.mjs && node scripts/check-type-tokens.mjs && node scripts/check-motion-tokens.mjs && svelte-kit sync && svelte-check --tsconfig ./tsconfig.json User browser caches use userStorage; only documented device/public-link exceptions remain. Text sizes and UI shape values use shared role tokens. UI transitions and animation options use shared motion tokens or documented exceptions. Loading svelte-check in workspace: /home/kayg/Developer/calternal-wt/datafix/apps/web Getting Svelte diagnostics... svelte-check found 0 errors and 0 warnings ``` The full web suite before the last review fix passed: ``` Test Files 154 passed (154) Tests 1081 passed (1081) Start at 16:06:32 Duration 2341.22s (transform 35%, import 27%, environment 23%, tests 10%, setup 5%) ``` After the review fix, the focused slice output was: ``` Test Files 2 passed (2) Tests 26 passed (26) Start at 18:36:45 Duration 7.71s (transform 90%, import 9%, tests 1%) ``` The final full rerun was stopped at the time limit after two 30-second failures in unchanged WebMCP tests. It is NOT a final full-suite pass: ``` ❯ |unit| src/lib/webmcp/generated.test.ts (9 tests | 2 failed) 73051ms × contract writes need confirmation and recheck Apps revocation 30023ms × a read checks access once and a write sees revocation during confirmation 30033ms error: script "test" exited with code 130 ``` A single isolated rerun of that unchanged file passed without assertion changes: ``` Test Files 1 passed (1) Tests 9 passed (9) Start at 19:16:24 Duration 8.66s (transform 85%, import 9%, tests 6%) ``` The final whole-web gate still needs a completed run on this head. The isolated result supports timing/load as the immediate failure, but does not replace the full gate. Updated production build output: ``` ✓ built in 33.15s ✓ built in 56ms ✓ built in 2m > Using @sveltejs/adapter-static Wrote site to "build" ``` Real local server output, final build: ``` Journal datafix: original Undo returned 412; later title remains on disk and in Calendar; twelve macOS screenshots captured. ``` The one bounded revision API round passed earlier: ``` Journal revision round: stale PATCH and DELETE rejected; deliberate retries passed. ``` The follow-up production run skipped that API round. Screenshots use macOS platform emulation, 390/820/1440 px, light/dark. They show Calendar and the settled Composer. Claude must review visual quality. calendar: [light 390](https://git.kayg.org/attachments/63d661eb-da0f-49df-80a9-b4b817cd53b8), [light 820](https://git.kayg.org/attachments/eb3c0636-ae18-49d2-b5e9-dadbdd2cb81e), [light 1440](https://git.kayg.org/attachments/76d342fe-498e-41c8-b8a5-a4dee9045750), [dark 390](https://git.kayg.org/attachments/9bd9a879-31c8-4c1e-99d0-c3aa3ff1a248), [dark 820](https://git.kayg.org/attachments/948dfcc7-5e47-4ac9-a5c8-2cf7a6aedf4b), [dark 1440](https://git.kayg.org/attachments/59077cd5-e09f-4530-a480-fd60e7b4ca1b) composer: [light 390](https://git.kayg.org/attachments/4578f0af-dd18-4e95-8cfb-219d16214588), [light 820](https://git.kayg.org/attachments/e16706f6-b06e-46b4-a4d4-a1f00fc9c5c1), [light 1440](https://git.kayg.org/attachments/5d4bfade-c1a7-402a-9fbe-28491b9b5cb5), [dark 390](https://git.kayg.org/attachments/94d20b15-dd39-46dd-b7be-287599b5f73b), [dark 820](https://git.kayg.org/attachments/a790ee53-65ff-4664-ba59-1f661d6d256e), [dark 1440](https://git.kayg.org/attachments/0a2428e1-ef63-4956-b14b-9f02bd5f1e50) **Saved Tasks views (#731): known gap** The assigned base and `origin/dev` have no saved Tasks views feature. The audited feature exists on `origin/job/tasks-mode` (`f620390c724ee08540d38b0ba69c3d12225fc1e4`). The audited Journal cache exists on `origin/job/calcard-series`, and shared #665–#668 primitives are also absent from the assigned base. No unrelated feature branch was merged. A separate source copy has a candidate fix. It uses the existing Notes content ETag and `match_etag`, plus `calternal-fs` `replace_if`. Every saved view read/write returns its complete-source revision. PUT requires If-Match and rejects a stale configuration. The form retains its original configuration and revision across background refresh. A conflict refreshes the Index and never replays the old configuration. Closing the form clears cancelled drafts. Contract/client changes, a stale-view/Files regression, missing-precondition coverage and a derived contract check are included. One round-trip fixture now supplies the revision it read; its status assertions remain unchanged. The shared E2E harness has a minimal optional-header test hook. A saved-view profile extends the existing Tasks sampler. [Candidate patch against the Tasks feature branch](https://git.kayg.org/attachments/7df79b86-c9a6-4854-a92f-4854d084cabd). Local source: `target/tmp/taskviews-validation`; local patch: `artifacts/datafix/issue-731-candidate.patch`. This candidate is NOT on the job branch and is NOT ready to merge. Rust old-code execution did not reach the test before the product patch was prepared; the old client did fail the stale replacement regression. The candidate client passed its focused regression and its frontend suite: ``` Test Files 152 passed (152) Tests 1020 passed (1020) Start at 17:09:03 Duration 4284.66s (transform 39%, import 24%, environment 18%, tests 12%, setup 7%) ``` Candidate `cargo fmt --check` exited 0 with no output. The candidate final `bun run check` passed after its form cleanup change: ``` $ node scripts/check-user-storage.mjs && node scripts/check-type-tokens.mjs && node scripts/check-motion-tokens.mjs && svelte-kit sync && svelte-check --tsconfig ./tsconfig.json User browser caches use userStorage; only documented device/public-link exceptions remain. Text sizes and UI shape values use shared role tokens. UI transitions and animation options use shared motion tokens or documented exceptions. Loading svelte-check in workspace: /home/kayg/Developer/calternal-wt/datafix/target/tmp/taskviews-validation/apps/web Getting Svelte diagnostics... svelte-check found 0 errors and 0 warnings ``` Rust Notes and server clippy/test did not finish. The first compilation was stopped after more than three hours in dependency builds and sccache. The direct clippy attempt is time-limited; no Rust test success is claimed. Live Tasks checks and its HDD profile were not run. The candidate still needs integration with the feature branch, Notes and server Rust gates, generated-contract verification at runtime, live Tasks concurrency checks, required Tasks screenshots and HDD measurements. The #790 regression must stay when the cached calcard-series source is integrated; the assigned base already used uncached entry reads. **Performance** The perf VM lock was busy. This is a local model-only run, load average 128.02/127.22/120.83; no HTTP/HDD qualification. Average before/after p50/p95: 4.32/11.01 → 5.25/21.9 µs; CPU 0.0306 → 0.0377 s; RSS 49.84 → 54.22 MiB; burst CPU 0.0105 → 0.0177 s. Worst (31,000 Logs): 68.66/480.37 → 116.19/290.16 µs; CPU 0.112 → 0.164 s; RSS 60.79 → 61.83 MiB; burst CPU 0.0636 → 0.1377 s. The checked day hint reduced the initial canonical-response CPU from 1.3898 to 0.164 s per 1,000 calls. `docs/perf/baseline.json` has no Log-inverse baseline or threshold. Its existing date-window profile measures a different operation; it is context only. The canonical response costs more CPU than the old field projection. A quiet-host release comparison remains needed. **UX gaps closed** Composer edits now register Undo, cross-day edits use the same write flow, a retained edit cannot silently replace another client's edited field, refused Undo preserves later edits, conflicts refresh current Logs, and linked Note title edits use the same retained-field guard. In the Tasks candidate, background refresh cannot silently promote a stale open form to a newer revision, and cancelled form drafts are reset. **UX gaps left** The Tasks candidate has no live production verification or screenshot set. Its source prerequisite is not integrated. HTTP/HDD performance and real Apple-client checks are not completed. Visual acceptance belongs to Claude. Normal Journal keyboard Undo was checked on the production build; this job did not repeat every existing pointer/touch action. **Decisions** Undo is conservative: any post-acknowledgement change refuses the inverse instead of rebasing a retained edit automatically. Normal retained edits check only their edited fields; unrelated fresh fields are preserved. A saved Task view uses the complete `.base` source ETag, so another view or extension change can conservatively require review. Reuse existing helpers and stores; do not add parallel caches for absent #665–#668 implementations. Keep missing-feature work as a candidate patch instead of merging an unrelated feature branch. Cleanup completed: both web production builds and `.svelte-kit/output` directories removed. `cargo clean` exited 0: ``` Removed 6711 files, 2.2GiB total ``` The working tree is clean. Work stopped within the four-hour limit.
Author
Owner

Datafix review evidence

Review branch: job/rev2-datafix.
Review base: 440e19dce23040ac8ebaae88f0469b6535b1afcb.
Reviewed head: 4345529d6 in job/datafix.

This is a read-only review for #777. No product files change. No build,
test, server, browser, or performance command runs.

The requested three-dot diff contains other jobs from merge round 7a.
The review covers the #777 Journal adapter, Calendar write lifecycle,
retained fields, conflict refresh, and their tests. Other plugin changes
are outside this review.

The reviewed DESIGN §58 covers Agent discovery and setup. It does not
define interactive-path performance. The review uses the performance
principles and Calendar decisions in §§2, 30, 34, 38, and 46 instead.

# Datafix review evidence Review branch: `job/rev2-datafix`. Review base: `440e19dce23040ac8ebaae88f0469b6535b1afcb`. Reviewed head: `4345529d6` in `job/datafix`. This is a read-only review for #777. No product files change. No build, test, server, browser, or performance command runs. The requested three-dot diff contains other jobs from merge round 7a. The review covers the #777 Journal adapter, Calendar write lifecycle, retained fields, conflict refresh, and their tests. Other plugin changes are outside this review. The reviewed DESIGN §58 covers Agent discovery and setup. It does not define interactive-path performance. The review uses the performance principles and Calendar decisions in §§2, 30, 34, 38, and 46 instead.
Author
Owner

Independent read-only review complete. Reviewed job/datafix at
4345529d6. Review head: fbf0de949e329c7c27af3452238b60b819c24d1c
on job/rev2-datafix.

Result: changes are required.

  • P1 — #913: timed Undo changes the original zone.
    apps/web/src/routes/calendar/[view]/[date]/+page.svelte:851 and
    :901 restore retained wall times with the current timezone().
    The retained fields at :835 and :878 omit the source zone.
    A 09:00 Europe/Berlin Log resized and undone while the User zone is UTC
    becomes 09:00 UTC. The valid ETag permits that wrong inverse.
    Fix: retain and restore the original zone, including null; check
    zone when a forward patch replaces it. This defect is inherited and
    remains in the changed inverses. DESIGN §30 C12 applies.
  • P2 — #790, evidence added: open Composer retry keeps old fields.
    apps/web/src/routes/calendar/[view]/[date]/+page.svelte:1508 captures
    the original item.log; :1532 passes it to editLog on every Save.
    :892 checks those retained fields. The conflict refresh at :763
    changes Calendar data, not the open dialog's baseline. A second Save
    after title A changes elsewhere to C fails the same local guard again.
    Fix: retain the typed draft and let the explicit retry use a refreshed
    baseline. Its inverse must restore the actual value before the retry.
  • P3: no confirmed finding.

The original #777 lost-write sequence is addressed in source: move and edit
inverses capture the forward-result ETag, and patchEntry uses it without
GET. New reads cannot promote that inverse. No new server route or authority
was added in the #777 slice. The existing called routes derive the User
from the authenticated context and use User-scoped lookup. No weakened
expectation was found in the scoped Journal and edit tests.

Files built: review-datafix.md and audit-findings.md. No product code
changed. The report includes evidence, concrete fixes, regression ideas,
reuse and comment checks, and verification commands.

Gate output: none. The LIGHT job forbids build, test, server, browser, and
performance runs. git diff --check returned no output. No push, merge,
deploy, or shared build cleanup ran.

Known gaps / UX gaps left: #913 and #790. UX gaps closed: none in this review.
Runtime concurrency, authorization, drag/resize, and performance validation
remain for the merge round. From apps/web, after extending the focused
regressions for both findings:

bun run check
bunx vitest run src/lib/calendar/journal.test.ts src/lib/calendar/edits.test.ts --maxWorkers=2
node e2e/journal-datafix.mjs

These must prove the original #777 sequence, real move/resize Undo,
different source/User zones, floating Logs, zone-only conflicts, and two
Saves from the same Composer dialog. Full suites and live cross-User
matrices belong to the merge round.

Decisions: no product design choice. The LIGHT instruction overrides the
general gates and merge-before-gates workflow. The requested three-dot
diff includes other merge-round jobs; this review covers #777's slice.
At the reviewed head, DESIGN §58 is Agent discovery and setup, so the
review uses the relevant Calendar and performance principles instead.
The author's report was not used as review input.

Independent read-only review complete. Reviewed `job/datafix` at `4345529d6`. Review head: `fbf0de949e329c7c27af3452238b60b819c24d1c` on `job/rev2-datafix`. Result: changes are required. - **P1 — #913:** timed Undo changes the original zone. `apps/web/src/routes/calendar/[view]/[date]/+page.svelte:851` and `:901` restore retained wall times with the current `timezone()`. The retained fields at `:835` and `:878` omit the source zone. A 09:00 Europe/Berlin Log resized and undone while the User zone is UTC becomes 09:00 UTC. The valid ETag permits that wrong inverse. **Fix:** retain and restore the original zone, including null; check zone when a forward patch replaces it. This defect is inherited and remains in the changed inverses. DESIGN §30 C12 applies. - **P2 — #790, evidence added:** open Composer retry keeps old fields. `apps/web/src/routes/calendar/[view]/[date]/+page.svelte:1508` captures the original `item.log`; `:1532` passes it to `editLog` on every Save. `:892` checks those retained fields. The conflict refresh at `:763` changes Calendar data, not the open dialog's baseline. A second Save after title A changes elsewhere to C fails the same local guard again. **Fix:** retain the typed draft and let the explicit retry use a refreshed baseline. Its inverse must restore the actual value before the retry. - **P3:** no confirmed finding. The original #777 lost-write sequence is addressed in source: move and edit inverses capture the forward-result ETag, and `patchEntry` uses it without GET. New reads cannot promote that inverse. No new server route or authority was added in the #777 slice. The existing called routes derive the User from the authenticated context and use User-scoped lookup. No weakened expectation was found in the scoped Journal and edit tests. Files built: `review-datafix.md` and `audit-findings.md`. No product code changed. The report includes evidence, concrete fixes, regression ideas, reuse and comment checks, and verification commands. Gate output: none. The LIGHT job forbids build, test, server, browser, and performance runs. `git diff --check` returned no output. No push, merge, deploy, or shared build cleanup ran. Known gaps / UX gaps left: #913 and #790. UX gaps closed: none in this review. Runtime concurrency, authorization, drag/resize, and performance validation remain for the merge round. From `apps/web`, after extending the focused regressions for both findings: ```text bun run check bunx vitest run src/lib/calendar/journal.test.ts src/lib/calendar/edits.test.ts --maxWorkers=2 node e2e/journal-datafix.mjs ``` These must prove the original #777 sequence, real move/resize Undo, different source/User zones, floating Logs, zone-only conflicts, and two Saves from the same Composer dialog. Full suites and live cross-User matrices belong to the merge round. Decisions: no product design choice. The LIGHT instruction overrides the general gates and merge-before-gates workflow. The requested three-dot diff includes other merge-round jobs; this review covers #777's slice. At the reviewed head, DESIGN §58 is Agent discovery and setup, so the review uses the relevant Calendar and performance principles instead. The author's report was not used as review input.
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
kayg/calternal#777
No description provided.