Money import wizard: start, upload, live import steps, review cards, failure page #1140

Open
opened 2026-10-05 12:38:29 +00:00 by kayg · 71 comments
Owner

Owner decisions (grill, 2026-10-05). Supersedes the inline import form and #1120's overlay design (reuse #1120's metric cards inside step 4).

Today's form fails silently: "New budget name" shows the placeholder "Household" but is empty, so "Review import" stays disabled with no message. Replace the whole flow with a wizard.

Shape

  • Container: centred glass sheet over Money with a step indicator, Back / Continue at the bottom, Esc closes. Full-height sheet on phone. Deep-linkable: /money/import (+ step). Friendly motion between steps (shared spring; reduced motion respected), small nudges, plain language (ASD-STE100 at most).
  • Entry points: auto-opens when the User has no budget; Money empty state; Money ⋯ → "Import budget…"; Settings → Money. All open the same wizard.

Steps

  1. Start: "Bring your budget from" two source cards (user-facing app names live only in one UI string table; code/tests/issues use format IDs actual-zip, ynab-json, ynab-csv) or "Create a new budget" (Q10 below).
  2. Upload: one big drop zone ("Drop your export here, or choose a file"). Format auto-detected from the file; if unsure, a small "This is a …" correction. For the paired CSV format, ask for the second file after the first. Inline 3–4 step "How to export" for the chosen source + link to the full docs page (docs site issue filed separately).
  3. Importing: a vertical numbered step list, each line says what it is doing ("1 Uploading · 12 of 15 MB", "2 Reading accounts", "3 Reading 1,200 of 2,341 transactions", "4 Checking balances" …) with spinner → ✓ / ✕; expanding a line shows deeper output (counts, current account). Runs as a server-side job: the User may close the wizard; a notification arrives on completion or failure; reopening returns to the live step; a reload never loses it.
  4. Success: glassy metric cards (accounts, transactions, categories, date range, "Balances match ✓" per account); anything not imported explained in plain words; choices only when needed (closed accounts, rules/templates that will not run) with a smart default preselected; budget name prefilled from the export (never empty), editable. "Open budget"; "Undo import" stays available afterwards.
  5. Failure: a page that says why and what to do next in plain language; "Copy details" is the only technical text. Never raw errors.

Rules

  • Target is always a new budget. Re-importing the same export offers "Replace the budget you imported earlier" with confirmation and Undo. Merging is out of scope.
  • Keep every fidelity rule from #1130 and the progress/stall rules from #1121.
  • Create a new budget (Q10): same wizard; name prefilled as a real value ("Household"), currency from locale, starter categories trimmable; then opens the budget with a one-time nudge. A richer guided onboarding is a separate issue.

Evidence

e2e like a User with real export files (Actual ZIP fixture ~15 MB through the 2 MiB/s smoke proxy, YNAB JSON, YNAB CSV pair, a corrupt ZIP, a non-budget ZIP): every step, close-and-reopen mid-import, reload mid-import, failure page, Undo. Screenshots of every step at 390/820/1440, light + dark, with 4x alignment crops. Money changes need a separate break-the-numbers review before merge.

## Owner decisions (grill, 2026-10-05). Supersedes the inline import form and #1120's overlay design (reuse #1120's metric cards inside step 4). Today's form fails silently: "New budget name" shows the placeholder "Household" but is empty, so "Review import" stays disabled with no message. Replace the whole flow with a wizard. ### Shape - **Container:** centred glass sheet over Money with a step indicator, Back / Continue at the bottom, Esc closes. Full-height sheet on phone. Deep-linkable: `/money/import` (+ step). Friendly motion between steps (shared spring; reduced motion respected), small nudges, plain language (ASD-STE100 at most). - **Entry points:** auto-opens when the User has no budget; Money empty state; Money ⋯ → "Import budget…"; Settings → Money. All open the same wizard. ### Steps 1. **Start:** "Bring your budget from" two source cards (user-facing app names live only in one UI string table; code/tests/issues use format IDs `actual-zip`, `ynab-json`, `ynab-csv`) **or** "Create a new budget" (Q10 below). 2. **Upload:** one big drop zone ("Drop your export here, or choose a file"). Format auto-detected from the file; if unsure, a small "This is a …" correction. For the paired CSV format, ask for the second file after the first. Inline 3–4 step "How to export" for the chosen source + link to the full docs page (docs site issue filed separately). 3. **Importing:** a vertical numbered step list, each line says what it is doing ("1 Uploading · 12 of 15 MB", "2 Reading accounts", "3 Reading 1,200 of 2,341 transactions", "4 Checking balances" …) with spinner → ✓ / ✕; expanding a line shows deeper output (counts, current account). Runs as a **server-side job**: the User may close the wizard; a notification arrives on completion or failure; reopening returns to the live step; a reload never loses it. 4. **Success:** glassy metric cards (accounts, transactions, categories, date range, "Balances match ✓" per account); anything not imported explained in plain words; choices only when needed (closed accounts, rules/templates that will not run) with a smart default preselected; budget name prefilled from the export (never empty), editable. "Open budget"; "Undo import" stays available afterwards. 5. **Failure:** a page that says why and what to do next in plain language; "Copy details" is the only technical text. Never raw errors. ### Rules - Target is always a **new budget**. Re-importing the same export offers "Replace the budget you imported earlier" with confirmation and Undo. Merging is out of scope. - Keep every fidelity rule from #1130 and the progress/stall rules from #1121. - **Create a new budget (Q10):** same wizard; name prefilled as a real value ("Household"), currency from locale, starter categories trimmable; then opens the budget with a one-time nudge. A richer guided onboarding is a separate issue. ### Evidence e2e like a User with real export files (Actual ZIP fixture ~15 MB through the 2 MiB/s smoke proxy, YNAB JSON, YNAB CSV pair, a corrupt ZIP, a non-budget ZIP): every step, close-and-reopen mid-import, reload mid-import, failure page, Undo. Screenshots of every step at 390/820/1440, light + dark, with 4x alignment crops. Money changes need a separate break-the-numbers review before merge.
Author
Owner

Working on #1140 on job/wizard-1140, base 666356aa3518b2f44e8744532c717e7daf46cc9a. The worktree is clean and includes #1120 plus origin/dev. Reusing the shared sheet, Tus upload queue, metric cards and #1130 fidelity review. The existing parser is request-bound and the session is memory-only; server job recovery is required for reload. No new dependencies are planned.

Working on #1140 on `job/wizard-1140`, base `666356aa3518b2f44e8744532c717e7daf46cc9a`. The worktree is clean and includes #1120 plus origin/dev. Reusing the shared sheet, Tus upload queue, metric cards and #1130 fidelity review. The existing parser is request-bound and the session is memory-only; server job recovery is required for reload. No new dependencies are planned.
Author
Owner

Server slices are committed. Money crate validation passed: 97 unit tests and 27 integration tests (existing ignored tests unchanged). The shared Plugin crate passed 43 tests. Three focused wizard regressions also passed after adding account checks: response-independent preview recovery, safe failure recovery, and starter categories with zero totals. Detached results expire with the existing 30-minute preview budget. Wizard confirmation is idempotent after publication; synchronous API clients keep their single-consumption contract. A typed notification category is the only public addition in calternal-plugin.

The wizard cache tests found that the DOM test runner's Blob cannot be streamed into Node's Response; the new test now uses Node's binary Blob to model the browser transport. Production code keeps binary bytes in the existing User-scoped cache and uses the shared Tus offset, with no base64 copy.

Server slices are committed. Money crate validation passed: 97 unit tests and 27 integration tests (existing ignored tests unchanged). The shared Plugin crate passed 43 tests. Three focused wizard regressions also passed after adding account checks: response-independent preview recovery, safe failure recovery, and starter categories with zero totals. Detached results expire with the existing 30-minute preview budget. Wizard confirmation is idempotent after publication; synchronous API clients keep their single-consumption contract. A typed notification category is the only public addition in calternal-plugin. The wizard cache tests found that the DOM test runner's Blob cannot be streamed into Node's Response; the new test now uses Node's binary Blob to model the browser transport. Production code keeps binary bytes in the existing User-scoped cache and uses the shared Tus offset, with no base64 copy.
Author
Owner

The wizard UI is committed (5cc4ad2cb, followed by recovery fix 8e0f04086). The canonical route is /money/import?step=…&job=…; every entry point uses the shared session. Source drafts use the existing User-isolated cache, and reload resumes the same Tus location with HEAD before submitting the parser. A regression test covers the interval where an upload exists but no parser has been admitted. Reopening a published job preserves its success page. Copy link retains the server job UUID. Replacement and Undo check the initiating User before each deferred Files write.

Merged origin/dev once before final gates. Final Money tests: test result: ok. 97 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 60.13s and test result: ok. 27 passed; 0 failed; 3 ignored; 0 measured; 0 filtered out; finished in 11.16s. Shared Plugin: test result: ok. 43 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 5.85s. Direct Svelte check: svelte-check found 0 errors and 4 warnings in 3 files (existing unrelated warnings). bun run check stops at the same performance-ledger ratchet failure seen before this UI change; final report will quote it verbatim.

Production evidence uses the real bounded archive generator with 15 MiB of inert SQLite payload (no additional budget rows), actual Tus transfer throttled to 2 MiB/s, macOS platform emulation, all three widths and both themes. Shared-host server checks/build are still running. Per the owner's verification policy, the combined merge round owns the full e2e/adversarial matrices, perf measurements and separate break-the-numbers review.

The wizard UI is committed (`5cc4ad2cb`, followed by recovery fix `8e0f04086`). The canonical route is `/money/import?step=…&job=…`; every entry point uses the shared session. Source drafts use the existing User-isolated cache, and reload resumes the same Tus location with HEAD before submitting the parser. A regression test covers the interval where an upload exists but no parser has been admitted. Reopening a published job preserves its success page. Copy link retains the server job UUID. Replacement and Undo check the initiating User before each deferred Files write. Merged `origin/dev` once before final gates. Final Money tests: `test result: ok. 97 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 60.13s` and `test result: ok. 27 passed; 0 failed; 3 ignored; 0 measured; 0 filtered out; finished in 11.16s`. Shared Plugin: `test result: ok. 43 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 5.85s`. Direct Svelte check: `svelte-check found 0 errors and 4 warnings in 3 files` (existing unrelated warnings). `bun run check` stops at the same performance-ledger ratchet failure seen before this UI change; final report will quote it verbatim. Production evidence uses the real bounded archive generator with 15 MiB of inert SQLite payload (no additional budget rows), actual Tus transfer throttled to 2 MiB/s, macOS platform emulation, all three widths and both themes. Shared-host server checks/build are still running. Per the owner's verification policy, the combined merge round owns the full e2e/adversarial matrices, perf measurements and separate break-the-numbers review.
Author
Owner

The new money_import_job_result route needed an action-policy entry. The initial server gate failed three OpenAPI checks with money_import_job_result: declare action policy before publishing the operation. Commit 1d950349c adds the owner-bound read policy. The focused OpenAPI gate now reports:

test result: ok. 4 passed; 0 failed; 0 ignored; 0 measured; 262 filtered out; finished in 0.33s

Commit 2b52ea4d8 regenerates the OpenAPI document, action registry and client types. The canonical actual-zip input normalizes to the existing fingerprint identity, so an earlier import can still be found.

The name field now keeps an edited value across Account rechecks and reload. Parsing uses a valid seed until the export title is available; a desktop filename cannot block parsing before Review. The focused session tests report:

Test Files  1 passed (1)
Tests  13 passed (13)

Production evidence is in progress. It covers all wizard screens at 390, 820 and 1440 px, light and dark, with macOS glyphs and 4x alignment crops. Independent Money numbers review remains for the merge round.

The new `money_import_job_result` route needed an action-policy entry. The initial server gate failed three OpenAPI checks with `money_import_job_result: declare action policy before publishing the operation`. Commit 1d950349c adds the owner-bound read policy. The focused OpenAPI gate now reports: ``` test result: ok. 4 passed; 0 failed; 0 ignored; 0 measured; 262 filtered out; finished in 0.33s ``` Commit 2b52ea4d8 regenerates the OpenAPI document, action registry and client types. The canonical `actual-zip` input normalizes to the existing fingerprint identity, so an earlier import can still be found. The name field now keeps an edited value across Account rechecks and reload. Parsing uses a valid seed until the export title is available; a desktop filename cannot block parsing before Review. The focused session tests report: ``` Test Files 1 passed (1) Tests 13 passed (13) ``` Production evidence is in progress. It covers all wizard screens at 390, 820 and 1440 px, light and dark, with macOS glyphs and 4x alignment crops. Independent Money numbers review remains for the merge round.
Author
Owner

The focused replacement check found that the saved source hash was not read on re-import. The default Money codec map accepts only format, budget-id, currency and month, so the lookup did not see source-import-hash.

Commit b3b10438e adds a minimal public codec reader for selected opaque fields. The default Money key set and projection rules stay the same. The import lookup selects the identity field through that reader. The regression test confirms that the same export finds the published Budget ID and edited name.

test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 96 filtered out; finished in 12.68s

The full codec suite passed, including both oracle vector checks. Codec, Money plugin and server clippy checks passed. The final production capture run is in progress.

The full server rerun passed its functional tests:

test result: ok. 256 passed; 0 failed; 10 ignored; 0 measured; 0 filtered out; finished in 198.70s

Its integration performance guard then failed on the same ledger ratchet as the web check, tracked in #1133. The web storage guard also reports four direct sessionStorage accesses in the existing navigation status module from 67497f0d2. This job did not change that module.

The focused replacement check found that the saved source hash was not read on re-import. The default Money codec map accepts only `format`, `budget-id`, `currency` and `month`, so the lookup did not see `source-import-hash`. Commit b3b10438e adds a minimal public codec reader for selected opaque fields. The default Money key set and projection rules stay the same. The import lookup selects the identity field through that reader. The regression test confirms that the same export finds the published Budget ID and edited name. ``` test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 96 filtered out; finished in 12.68s ``` The full codec suite passed, including both oracle vector checks. Codec, Money plugin and server clippy checks passed. The final production capture run is in progress. The full server rerun passed its functional tests: ``` test result: ok. 256 passed; 0 failed; 10 ignored; 0 measured; 0 filtered out; finished in 198.70s ``` Its integration performance guard then failed on the same ledger ratchet as the web check, tracked in #1133. The web storage guard also reports four direct `sessionStorage` accesses in the existing navigation status module from 67497f0d2. This job did not change that module.
Author
Owner

Built the Money import wizard on job/wizard-1140.

Head: e1312efe11d076e21628f4a451a2966e8d875974. Base: 666356aa3. Required origin/dev merge: be176273e. No push or deploy. Work is in small commits.

Built

  • One glass sheet at /money/import, with step and job links. Money, its empty state and Settings open the same flow. The phone sheet fills the screen. Actions stay at the bottom.
  • Source cards, file detection, paired CSV upload and export steps. User-facing source names live in one UI string table.
  • Owner-bound server jobs with progress, completion notifications and result recovery. Closing or reloading the browser does not stop a submitted job.
  • Review with the #1120 metric cards, source checks, editable nonempty name and the #1130 review choices. Imports always create a new Budget.
  • Same-export replacement with confirmation and Undo. Open Budget, later Undo from the Budget menu, and plain failure details.
  • New Budget creation with a real Household value, locale currency and four removable starter categories.
  • A benchmark profile for the job admission and parse path. No performance measurements were run, as required by the latest verification policy.

The only addition to another core crate is calternal_money::codec::frontmatter_fields. It reads an explicit list of opaque fields. The existing financial key set and projection rules stay the same. The default reader omitted the saved source hash, so replacement could not find the earlier Budget. The new regression checks the published stable identity and edited name.

UX gaps closed

  • An empty placeholder no longer stops the flow without an explanation. The initial name is a real value. Whitespace gets an inline message.
  • Either CSV file can be selected first. Continue waits for the second file.
  • Reload shows the live importing view before it waits for recovery. Late cache reads cannot overwrite cancellation.
  • The sheet is centred at desktop and tablet widths and fills the phone. Every captured step checks its frame and pinned footer.
  • The creation footer submits the shared form. Status words fit the metric cards. Icons use CSS cap sizing.
  • Completion toasts no longer cover the wizard Undo action. The browser test clicks Undo while the toast is visible.
  • Retry can recover when the server has already consumed the preview token. A stale receipt cannot undo another User's Budget.

Verification

cargo fmt --check passed with no output. Clippy passed for calternal-money, calternal-plugin-money, calternal-plugin and calternal-server. Tests ran per crate, with four test threads. The full Money plugin suite ran before the final source lookup fix; that fix then passed its focused regression and the full core codec suite.

Gate output below is copied from the logs. It contains test result lines and the check failures. The server functional suite passed; the full server command failed at the existing performance ledger guard. bun run check failed on the same ledger, tracked in #1133. No existing test expectation was changed to hide either failure.

Core codec clippy:

    Finished `dev` profile [unoptimized + debuginfo] target(s) in 38.41s

Money plugin clippy:

    Finished `dev` profile [unoptimized + debuginfo] target(s) in 16.98s

Shared plugin clippy:

    Finished `dev` profile [unoptimized + debuginfo] target(s) in 2.66s

Server clippy:

    Finished `dev` profile [unoptimized + debuginfo] target(s) in 1m 09s

Money plugin tests:

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 97 filtered out; finished in 51.27s
test result: ok. 97 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 60.13s
test result: ok. 27 passed; 0 failed; 3 ignored; 0 measured; 0 filtered out; finished in 11.16s
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

Source lookup regression:

test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 96 filtered out; finished in 12.68s
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 30 filtered out; finished in 0.00s

Core Money codec tests:

test result: ok. 16 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.04s
test result: ok. 4 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.01s
test result: ok. 13 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 12.58s
test result: ok. 12 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 2.38s
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.02s
test result: ok. 4 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 4.64s
test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.63s
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

Shared plugin tests:

test result: ok. 43 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 5.85s
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

Server tests:

test result: ok. 256 passed; 0 failed; 10 ignored; 0 measured; 0 filtered out; finished in 198.70s
test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 5.84s
error: test failed, to rerun pass `-p calternal-server --test perf_guards`

Web focused tests:

 Test Files  7 passed (7)
      Tests  54 passed (54)

Final retry regression:

 Test Files  1 passed (1)
      Tests  16 passed (16)

Shared toaster tests:

 Test Files  1 passed (1)
      Tests  9 passed (9)

Svelte check:

svelte-check found 0 errors and 4 warnings in 3 files

Web check / server performance guard failure:

perf-lint: INVALID: exception ratchet: contract.blaze: 290 exceptions exceed the ratchet ceiling 289; fix the new violation instead; contract.blocked-network: 356 exceptions exceed the ratchet ceiling 355; fix the new violation instead; contract.dom-bound: 290 exceptions exceed the ratchet ceiling 289; fix the new violation instead; contract.model-bound: 290 exceptions exceed the ratchet ceiling 289; fix the new violation instead; contract.row-identity: 290 exceptions exceed the ratchet ceiling 289; fix the new violation instead; contract.snapshot: 356 exceptions exceed the ratchet ceiling 355; fix the new violation instead; coverage.profile: 356 exceptions exceed the ratchet ceiling 355; fix the new violation instead; coverage.readiness: 356 exceptions exceed the ratchet ceiling 355; fix the new violation instead; io.unresolved-call: 16191 exceptions exceed the ratchet ceiling 16190; fix the new violation instead; render.blaze-adapter: 290 exceptions exceed the ratchet ceiling 289; fix the new violation instead; render.bound: 290 exceptions exceed the ratchet ceiling 289; fix the new violation instead; render.model_byte_cap: 290 exceptions exceed the ratchet ceiling 289; fix the new violation instead; render.model_row_cap: 290 exceptions exceed the ratchet ceiling 289; fix the new violation instead; total: ledger has 21977 exceptions; ratchet total is 21964

Browser matrix, first five cases:

PASS wizard steps, reload, background reopen, Undo, create, failure: light 390
PASS wizard steps, reload, background reopen, Undo, create, failure: light 820
PASS wizard steps, reload, background reopen, Undo, create, failure: light 1440
PASS wizard steps, reload, background reopen, Undo, create, failure: dark 390
PASS wizard steps, reload, background reopen, Undo, create, failure: dark 820

Final desktop case:

PASS wizard steps, reload, background reopen, Undo, create, failure: dark 1440

Format acceptance, fresh browser:

PASS ynab-csv pair, ynab-json, replacement confirmation, Undo restoring the original, non-budget ZIP
PASS wizard production evidence: /home/kayg/Developer/calternal-wt/wizard-1140/artifacts/wizard-1140/screenshots

The storage guard reports four pre-existing direct sessionStorage calls in the navigation status module from 67497f0d2. This job did not change that file:

lib/navigation/clientRouteStatus.svelte.ts: direct sessionStorage access
lib/navigation/clientRouteStatus.svelte.ts: direct sessionStorage access
lib/navigation/clientRouteStatus.svelte.ts: direct sessionStorage access
lib/navigation/clientRouteStatus.svelte.ts: direct sessionStorage access

Glass, type, focus and motion guards passed. The production web build passed. Svelte reports four existing CSS warnings in three files.

Evidence for Claude review

The focused test uses the production web build and a real local server. It uses real export fixture files, not API response mocks. The source ZIP is 15,763,936 bytes. Chromium limits upload to 2 MiB/s. Platform emulation uses macOS. The 42 main screenshots cover seven views at 390, 820 and 1440 px, in light and dark. Four extra screenshots cover CSV, JSON and the non-budget failure. The 4x crops cover the header, footer and upload progress line.

The test checks keyboard activation, Escape, touch, close/reopen during work, reload during upload, creation, post-import Undo, corrupt ZIP failure, paired CSV, JSON, replacement confirmation and Undo restoring the original Budget identity. Screenshot review remains with Claude.

View Light 390 Light 820 Light 1440 Dark 390 Dark 820 Dark 1440
start PNG PNG PNG PNG PNG PNG
upload PNG PNG PNG PNG PNG PNG
importing PNG PNG PNG PNG PNG PNG
success-review PNG PNG PNG PNG PNG PNG
success PNG PNG PNG PNG PNG PNG
create PNG PNG PNG PNG PNG PNG
failure PNG PNG PNG PNG PNG PNG

Extra format views: csv-upload, csv-review, json-review, non-budget-failure.

4x crop archives: light 390, light 820, light 1440, dark 390, dark 820, dark 1440.

Known gaps and UX gaps left

  • Job results stay in server memory for 30 minutes. Browser close and reload work; a server restart loses an unfinished job and its result.
  • Upload recovery needs the same User's browser cache. If the cache is unavailable or evicted, the file must be selected again.
  • Wizard Undo receipts stay in this browser, with a limit of 200 receipts. Ordinary Trash remains available. These receipts do not sync across devices.
  • Replacement uses two recoverable writes: move the earlier Budget to Trash, then publish the new one. It has no durable atomic server journal.
  • Imports made before this change have no saved source fingerprint. The wizard does not guess which older Budget to replace.
  • Progress shows real stages and counts. It does not show a current-account label.
  • The full docs page is a separate issue. Export help links to the source's official guide for now.
  • The 2 MiB/s test uses Chromium network throttling. It does not prove the separately requested smoke proxy path.
  • The full Money numbers review, full browser suites and cross-device Undo review remain for the merge round. The combined branch also needs the existing ledger and navigation storage guard failures resolved.

Decisions

  • Keep the default replacement choice unchecked. A new Budget is the safe default.
  • Use the parser admission limit already in place. Keep terminal results for 30 minutes, with at most 32 terminal jobs.
  • Identify an export by its canonical format and ordered file bytes. Do not infer a match from a file name.
  • Use Housing, Groceries, Transport and Savings as the four removable starter categories. They add no transactions.
  • Use the existing Trash APIs for replacement and Undo. Record the two-write limit above.
  • Use official export help until the separate docs site page exists.
  • Use CDP throttling for focused local upload evidence. Leave smoke proxy acceptance to the merge round.

For the merge round

Run the full web suite once on the combined branch:

bun run --cwd apps/web test

With the combined release server selected through CALTERNAL_SERVER_BIN, run:

bun apps/web/e2e/money.mjs
bun apps/web/e2e/money-fidelity-1130.mjs
bun apps/web/e2e/money-wizard-1140.mjs --acceptance

The separate Money numbers reviewer must check source balances, transactions, categories, transfers, notes, closed flags and Markdown projection. The existing number assertions in the browser suites are preserved. Run the existing Money API, import review and authorization matrices from tests/adversarial/ once. Check the requested 2 MiB/s smoke proxy path, a real Apple client and the combined deploy gates.

The new profile is bench/money-wizard-1140.mjs. If performance is measured, run it on the perf VM with the shared release build, inside /root/perf.lock, and record the load average inside that lock. No performance numbers are claimed for this job.

Files

  • apps/web/e2e/money-fidelity-1130.mjs
  • apps/web/e2e/money-wizard-1140.mjs
  • apps/web/e2e/money.mjs
  • apps/web/src/lib/components/AppToaster.svelte
  • apps/web/src/lib/components/money/CreateBudgetForm.svelte
  • apps/web/src/lib/components/money/MoneyImport.svelte
  • apps/web/src/lib/components/money/MoneyImportMetrics.svelte
  • apps/web/src/lib/components/money/MoneySidebar.svelte
  • apps/web/src/lib/files/uploads.svelte.ts
  • apps/web/src/lib/money/api.ts
  • apps/web/src/lib/money/import-session.svelte.test.ts
  • apps/web/src/lib/money/import-session.svelte.ts
  • apps/web/src/lib/money/import-sources.test.ts
  • apps/web/src/lib/money/import-sources.ts
  • apps/web/src/lib/userStorage.svelte.test.ts
  • apps/web/src/lib/userStorage.ts
  • apps/web/src/routes/money/+layout.svelte
  • apps/web/src/routes/money/+page.svelte
  • apps/web/src/routes/money/[budget]/[month]/+page.svelte
  • apps/web/src/routes/money/import/+page.svelte
  • apps/web/src/routes/settings/[...path]/+page.svelte
  • bench/money-import-462.mjs
  • bench/money-import-actual-fixture.py
  • bench/money-wizard-1140.mjs
  • contracts/action-policy.json
  • contracts/actions.json
  • contracts/openapi.json
  • crates/calternal-money/src/codec.rs
  • crates/calternal-plugin/src/lib.rs
  • crates/plugins/money/src/import.rs
  • crates/plugins/money/src/routes.rs
  • crates/plugins/money/src/tests.rs
  • crates/plugins/money/src/views.rs
  • packages/api-client/src/generated.ts
Built the Money import wizard on `job/wizard-1140`. Head: `e1312efe11d076e21628f4a451a2966e8d875974`. Base: `666356aa3`. Required `origin/dev` merge: `be176273e`. No push or deploy. Work is in small commits. ## Built - One glass sheet at `/money/import`, with step and job links. Money, its empty state and Settings open the same flow. The phone sheet fills the screen. Actions stay at the bottom. - Source cards, file detection, paired CSV upload and export steps. User-facing source names live in one UI string table. - Owner-bound server jobs with progress, completion notifications and result recovery. Closing or reloading the browser does not stop a submitted job. - Review with the #1120 metric cards, source checks, editable nonempty name and the #1130 review choices. Imports always create a new Budget. - Same-export replacement with confirmation and Undo. Open Budget, later Undo from the Budget menu, and plain failure details. - New Budget creation with a real Household value, locale currency and four removable starter categories. - A benchmark profile for the job admission and parse path. No performance measurements were run, as required by the latest verification policy. The only addition to another core crate is `calternal_money::codec::frontmatter_fields`. It reads an explicit list of opaque fields. The existing financial key set and projection rules stay the same. The default reader omitted the saved source hash, so replacement could not find the earlier Budget. The new regression checks the published stable identity and edited name. ## UX gaps closed - An empty placeholder no longer stops the flow without an explanation. The initial name is a real value. Whitespace gets an inline message. - Either CSV file can be selected first. Continue waits for the second file. - Reload shows the live importing view before it waits for recovery. Late cache reads cannot overwrite cancellation. - The sheet is centred at desktop and tablet widths and fills the phone. Every captured step checks its frame and pinned footer. - The creation footer submits the shared form. Status words fit the metric cards. Icons use CSS cap sizing. - Completion toasts no longer cover the wizard Undo action. The browser test clicks Undo while the toast is visible. - Retry can recover when the server has already consumed the preview token. A stale receipt cannot undo another User's Budget. ## Verification `cargo fmt --check` passed with no output. Clippy passed for `calternal-money`, `calternal-plugin-money`, `calternal-plugin` and `calternal-server`. Tests ran per crate, with four test threads. The full Money plugin suite ran before the final source lookup fix; that fix then passed its focused regression and the full core codec suite. Gate output below is copied from the logs. It contains test result lines and the check failures. The server functional suite passed; the full server command failed at the existing performance ledger guard. `bun run check` failed on the same ledger, tracked in #1133. No existing test expectation was changed to hide either failure. Core codec clippy: ```text Finished `dev` profile [unoptimized + debuginfo] target(s) in 38.41s ``` Money plugin clippy: ```text Finished `dev` profile [unoptimized + debuginfo] target(s) in 16.98s ``` Shared plugin clippy: ```text Finished `dev` profile [unoptimized + debuginfo] target(s) in 2.66s ``` Server clippy: ```text Finished `dev` profile [unoptimized + debuginfo] target(s) in 1m 09s ``` Money plugin tests: ```text test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 97 filtered out; finished in 51.27s test result: ok. 97 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 60.13s test result: ok. 27 passed; 0 failed; 3 ignored; 0 measured; 0 filtered out; finished in 11.16s test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s ``` Source lookup regression: ```text test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 96 filtered out; finished in 12.68s test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 30 filtered out; finished in 0.00s ``` Core Money codec tests: ```text test result: ok. 16 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.04s test result: ok. 4 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.01s test result: ok. 13 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 12.58s test result: ok. 12 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 2.38s test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.02s test result: ok. 4 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 4.64s test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.63s test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s ``` Shared plugin tests: ```text test result: ok. 43 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 5.85s test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s ``` Server tests: ```text test result: ok. 256 passed; 0 failed; 10 ignored; 0 measured; 0 filtered out; finished in 198.70s test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 5.84s error: test failed, to rerun pass `-p calternal-server --test perf_guards` ``` Web focused tests: ```text Test Files 7 passed (7) Tests 54 passed (54) ``` Final retry regression: ```text Test Files 1 passed (1) Tests 16 passed (16) ``` Shared toaster tests: ```text Test Files 1 passed (1) Tests 9 passed (9) ``` Svelte check: ```text svelte-check found 0 errors and 4 warnings in 3 files ``` Web check / server performance guard failure: ```text perf-lint: INVALID: exception ratchet: contract.blaze: 290 exceptions exceed the ratchet ceiling 289; fix the new violation instead; contract.blocked-network: 356 exceptions exceed the ratchet ceiling 355; fix the new violation instead; contract.dom-bound: 290 exceptions exceed the ratchet ceiling 289; fix the new violation instead; contract.model-bound: 290 exceptions exceed the ratchet ceiling 289; fix the new violation instead; contract.row-identity: 290 exceptions exceed the ratchet ceiling 289; fix the new violation instead; contract.snapshot: 356 exceptions exceed the ratchet ceiling 355; fix the new violation instead; coverage.profile: 356 exceptions exceed the ratchet ceiling 355; fix the new violation instead; coverage.readiness: 356 exceptions exceed the ratchet ceiling 355; fix the new violation instead; io.unresolved-call: 16191 exceptions exceed the ratchet ceiling 16190; fix the new violation instead; render.blaze-adapter: 290 exceptions exceed the ratchet ceiling 289; fix the new violation instead; render.bound: 290 exceptions exceed the ratchet ceiling 289; fix the new violation instead; render.model_byte_cap: 290 exceptions exceed the ratchet ceiling 289; fix the new violation instead; render.model_row_cap: 290 exceptions exceed the ratchet ceiling 289; fix the new violation instead; total: ledger has 21977 exceptions; ratchet total is 21964 ``` Browser matrix, first five cases: ```text PASS wizard steps, reload, background reopen, Undo, create, failure: light 390 PASS wizard steps, reload, background reopen, Undo, create, failure: light 820 PASS wizard steps, reload, background reopen, Undo, create, failure: light 1440 PASS wizard steps, reload, background reopen, Undo, create, failure: dark 390 PASS wizard steps, reload, background reopen, Undo, create, failure: dark 820 ``` Final desktop case: ```text PASS wizard steps, reload, background reopen, Undo, create, failure: dark 1440 ``` Format acceptance, fresh browser: ```text PASS ynab-csv pair, ynab-json, replacement confirmation, Undo restoring the original, non-budget ZIP PASS wizard production evidence: /home/kayg/Developer/calternal-wt/wizard-1140/artifacts/wizard-1140/screenshots ``` The storage guard reports four pre-existing direct `sessionStorage` calls in the navigation status module from `67497f0d2`. This job did not change that file: ```text lib/navigation/clientRouteStatus.svelte.ts: direct sessionStorage access lib/navigation/clientRouteStatus.svelte.ts: direct sessionStorage access lib/navigation/clientRouteStatus.svelte.ts: direct sessionStorage access lib/navigation/clientRouteStatus.svelte.ts: direct sessionStorage access ``` Glass, type, focus and motion guards passed. The production web build passed. Svelte reports four existing CSS warnings in three files. ## Evidence for Claude review The focused test uses the production web build and a real local server. It uses real export fixture files, not API response mocks. The source ZIP is 15,763,936 bytes. Chromium limits upload to 2 MiB/s. Platform emulation uses macOS. The 42 main screenshots cover seven views at 390, 820 and 1440 px, in light and dark. Four extra screenshots cover CSV, JSON and the non-budget failure. The 4x crops cover the header, footer and upload progress line. The test checks keyboard activation, Escape, touch, close/reopen during work, reload during upload, creation, post-import Undo, corrupt ZIP failure, paired CSV, JSON, replacement confirmation and Undo restoring the original Budget identity. Screenshot review remains with Claude. | View | Light 390 | Light 820 | Light 1440 | Dark 390 | Dark 820 | Dark 1440 | |---|---|---|---|---|---|---| | start | [PNG](https://git.kayg.org/attachments/5d6cc4c4-392c-499b-900a-518427c5d5ea) | [PNG](https://git.kayg.org/attachments/0d7b39e3-c1f3-469b-bfaf-ed21e09f70e8) | [PNG](https://git.kayg.org/attachments/9030c807-758a-4e20-9c18-8e5506b2b5c8) | [PNG](https://git.kayg.org/attachments/15e3d1aa-cd21-47b8-bbea-e8e87a53dfcf) | [PNG](https://git.kayg.org/attachments/248ca79e-8793-44a4-82db-4b929d5c02f2) | [PNG](https://git.kayg.org/attachments/e19f6333-fc2b-4129-a73d-167bcb20ac0e) | | upload | [PNG](https://git.kayg.org/attachments/2302a8af-620a-4289-bd9e-1b4a4a8055cc) | [PNG](https://git.kayg.org/attachments/c72d1830-b6e3-4c3d-b59e-fa33f7308028) | [PNG](https://git.kayg.org/attachments/b45f510b-61b9-4c26-804b-82cc01ad7ca7) | [PNG](https://git.kayg.org/attachments/25c61b32-74bd-4eb3-b307-3a47bf1c4aa2) | [PNG](https://git.kayg.org/attachments/9a03fe5a-5fd8-4fb4-b6a3-f6c52a1ed075) | [PNG](https://git.kayg.org/attachments/ab593a4b-ddc4-49ee-8a0c-c416267f86bf) | | importing | [PNG](https://git.kayg.org/attachments/d7a86ed4-2deb-404d-8cbd-b7dde05d026a) | [PNG](https://git.kayg.org/attachments/318e4b32-d2c5-43c0-9547-a5fc94cff14a) | [PNG](https://git.kayg.org/attachments/84be54eb-5494-4c13-902f-f164528e2d5a) | [PNG](https://git.kayg.org/attachments/9847a779-f2aa-4afc-9a58-56ba7cbc23d4) | [PNG](https://git.kayg.org/attachments/8b3b08ae-69bd-4056-9652-a2c67c977c43) | [PNG](https://git.kayg.org/attachments/3f81b387-b35c-455e-a518-13e4abc1e87d) | | success-review | [PNG](https://git.kayg.org/attachments/f626e76e-8472-4834-b897-c1f76121c139) | [PNG](https://git.kayg.org/attachments/1abb6cce-fb7c-4f01-92ca-8007a5819dee) | [PNG](https://git.kayg.org/attachments/49790759-867c-477a-87a9-1668e0779f40) | [PNG](https://git.kayg.org/attachments/b71c72ca-4406-4048-a882-9380bc5c7e0f) | [PNG](https://git.kayg.org/attachments/dc40e48c-ad10-4163-a375-930834fcae7f) | [PNG](https://git.kayg.org/attachments/f54261ea-73a3-4210-a8c8-053e52d149b7) | | success | [PNG](https://git.kayg.org/attachments/09d7b19f-41cf-41bc-9ac3-1b9a8edc6aeb) | [PNG](https://git.kayg.org/attachments/a43fd349-3ad7-4b96-a8dc-a22515f0c71c) | [PNG](https://git.kayg.org/attachments/81cfa19d-50b7-4dc7-bf9f-4dd860af371e) | [PNG](https://git.kayg.org/attachments/71b7578a-f178-46e5-86a7-813d98d0a72b) | [PNG](https://git.kayg.org/attachments/9eefa4a6-7582-4271-aed5-567c44c8728b) | [PNG](https://git.kayg.org/attachments/18341ffa-8439-4b9a-8b3a-9387b96fb634) | | create | [PNG](https://git.kayg.org/attachments/63d7cd64-5e31-42ba-bfbe-344b8271d0dc) | [PNG](https://git.kayg.org/attachments/c9b0f7de-f806-4682-98bd-263a76a7e200) | [PNG](https://git.kayg.org/attachments/dc09280b-0b21-4c6a-85b3-f71b18175153) | [PNG](https://git.kayg.org/attachments/b6cc667a-ff86-4656-a60d-91f75ff951a8) | [PNG](https://git.kayg.org/attachments/d393d79d-87f5-43a4-bd42-0120debec955) | [PNG](https://git.kayg.org/attachments/8cd3722e-fdb2-4af2-a55c-f23279708b6b) | | failure | [PNG](https://git.kayg.org/attachments/216f425b-8cdb-437d-825a-951c0ab7930e) | [PNG](https://git.kayg.org/attachments/dfb35896-5f69-430d-8fd3-9370b1de668d) | [PNG](https://git.kayg.org/attachments/42a87eca-c3de-48bf-8b17-24918f120da5) | [PNG](https://git.kayg.org/attachments/e53b9c49-508f-4804-afd1-9008fc376b1c) | [PNG](https://git.kayg.org/attachments/77e5ecd9-498a-42c3-8091-35731df9ec2a) | [PNG](https://git.kayg.org/attachments/b323cbd3-72e2-49e7-bc7d-79f48789ee6d) | Extra format views: [csv-upload](https://git.kayg.org/attachments/49eaab34-425a-4566-8ef4-fb2c7a76eaad), [csv-review](https://git.kayg.org/attachments/539fb3a9-bcd2-4329-8aa8-8c8db67dd81b), [json-review](https://git.kayg.org/attachments/2fca1886-a7f6-4e84-b4e1-c0c802fd1c2f), [non-budget-failure](https://git.kayg.org/attachments/7feb01e8-b411-4a5f-be31-421a841fb812). 4x crop archives: [light 390](https://git.kayg.org/attachments/28818d2a-d0ed-4b86-bcbe-ea99d5e95e97), [light 820](https://git.kayg.org/attachments/cac0e8f3-d716-4543-ba69-f86e3b0809f1), [light 1440](https://git.kayg.org/attachments/0eb06360-1964-455c-8395-acf0a2648da6), [dark 390](https://git.kayg.org/attachments/61b8fb1c-e89e-4b80-a8ec-dcfae6d2c306), [dark 820](https://git.kayg.org/attachments/db8dbf1a-0f90-4379-ab31-fe2791080f56), [dark 1440](https://git.kayg.org/attachments/ae4397bc-a30b-4056-8ed4-6e263e300ec1). ## Known gaps and UX gaps left - Job results stay in server memory for 30 minutes. Browser close and reload work; a server restart loses an unfinished job and its result. - Upload recovery needs the same User's browser cache. If the cache is unavailable or evicted, the file must be selected again. - Wizard Undo receipts stay in this browser, with a limit of 200 receipts. Ordinary Trash remains available. These receipts do not sync across devices. - Replacement uses two recoverable writes: move the earlier Budget to Trash, then publish the new one. It has no durable atomic server journal. - Imports made before this change have no saved source fingerprint. The wizard does not guess which older Budget to replace. - Progress shows real stages and counts. It does not show a current-account label. - The full docs page is a separate issue. Export help links to the source's official guide for now. - The 2 MiB/s test uses Chromium network throttling. It does not prove the separately requested smoke proxy path. - The full Money numbers review, full browser suites and cross-device Undo review remain for the merge round. The combined branch also needs the existing ledger and navigation storage guard failures resolved. ## Decisions - Keep the default replacement choice unchecked. A new Budget is the safe default. - Use the parser admission limit already in place. Keep terminal results for 30 minutes, with at most 32 terminal jobs. - Identify an export by its canonical format and ordered file bytes. Do not infer a match from a file name. - Use Housing, Groceries, Transport and Savings as the four removable starter categories. They add no transactions. - Use the existing Trash APIs for replacement and Undo. Record the two-write limit above. - Use official export help until the separate docs site page exists. - Use CDP throttling for focused local upload evidence. Leave smoke proxy acceptance to the merge round. ## For the merge round Run the full web suite once on the combined branch: ```sh bun run --cwd apps/web test ``` With the combined release server selected through `CALTERNAL_SERVER_BIN`, run: ```sh bun apps/web/e2e/money.mjs bun apps/web/e2e/money-fidelity-1130.mjs bun apps/web/e2e/money-wizard-1140.mjs --acceptance ``` The separate Money numbers reviewer must check source balances, transactions, categories, transfers, notes, closed flags and Markdown projection. The existing number assertions in the browser suites are preserved. Run the existing Money API, import review and authorization matrices from `tests/adversarial/` once. Check the requested 2 MiB/s smoke proxy path, a real Apple client and the combined deploy gates. The new profile is `bench/money-wizard-1140.mjs`. If performance is measured, run it on the perf VM with the shared release build, inside `/root/perf.lock`, and record the load average inside that lock. No performance numbers are claimed for this job. ## Files - `apps/web/e2e/money-fidelity-1130.mjs` - `apps/web/e2e/money-wizard-1140.mjs` - `apps/web/e2e/money.mjs` - `apps/web/src/lib/components/AppToaster.svelte` - `apps/web/src/lib/components/money/CreateBudgetForm.svelte` - `apps/web/src/lib/components/money/MoneyImport.svelte` - `apps/web/src/lib/components/money/MoneyImportMetrics.svelte` - `apps/web/src/lib/components/money/MoneySidebar.svelte` - `apps/web/src/lib/files/uploads.svelte.ts` - `apps/web/src/lib/money/api.ts` - `apps/web/src/lib/money/import-session.svelte.test.ts` - `apps/web/src/lib/money/import-session.svelte.ts` - `apps/web/src/lib/money/import-sources.test.ts` - `apps/web/src/lib/money/import-sources.ts` - `apps/web/src/lib/userStorage.svelte.test.ts` - `apps/web/src/lib/userStorage.ts` - `apps/web/src/routes/money/+layout.svelte` - `apps/web/src/routes/money/+page.svelte` - `apps/web/src/routes/money/[budget]/[month]/+page.svelte` - `apps/web/src/routes/money/import/+page.svelte` - `apps/web/src/routes/settings/[...path]/+page.svelte` - `bench/money-import-462.mjs` - `bench/money-import-actual-fixture.py` - `bench/money-wizard-1140.mjs` - `contracts/action-policy.json` - `contracts/actions.json` - `contracts/openapi.json` - `crates/calternal-money/src/codec.rs` - `crates/calternal-plugin/src/lib.rs` - `crates/plugins/money/src/import.rs` - `crates/plugins/money/src/routes.rs` - `crates/plugins/money/src/tests.rs` - `crates/plugins/money/src/views.rs` - `packages/api-client/src/generated.ts`
Author
Owner

Orchestrator review of artifacts/wizard-1140/screenshots (head e1312efe1). Functionally good; the owner's ask was "incredibly user friendly, friendly pages, motion, nudges, glassy cards". Fix before merge:

Behaviour (blocking)

  1. Imports must survive a server restart (we deploy many times a night). Persist the import job in the server's job store (the existing durable jobs mechanism), resume or restart it idempotently after a restart, and keep the wizard/notification in sync. Remove the 30-minute expiry for running jobs (expire only finished, unclaimed results, e.g. after 7 days). Undo receipts are server-side (per User), not browser-scoped.

Visual (importing-dark-1440.png, success-dark-1440.png)
2. No focus rectangle around content blocks: a hard blue outline wraps "Bringing your budget over" and "Your Budget is ready" with text flush against it. Programmatic focus for announcements goes to a heading with no visible ring (tabindex=-1, focus-visible only), and content blocks get normal padding.
3. Importing step = the owner's design: a vertical numbered list of ALL steps from the start (1 Uploading, 2 Reading accounts, 3 Reading transactions, 4 Checking balances, 5 Finishing), upcoming steps dimmed, the current one with a spinner and its live detail ("208 KB of 15 MB · about 25 s left" on the same line as its progress bar), done steps with ✓; each line expands to show deeper output. Time-left sits with the progress, not under the Cancel button. Cancel is a normal secondary pill in the footer (left of "Continue in background"), not a full-width bar.
4. Success: one message, not two ("Your Budget is ready" + "Import complete / original export not changed" → one heading + one quiet line). Cards in one balanced grid (no 5 + 2 orphan row); "Balances" shows ✓ matched per account consistently with the others (value style), drop the stray progress bar under "Checks passed" or explain it. One Undo only: keep the footer "Undo import" button and drop the toast (toast rule #1142: no toast for what is already on screen); the notification (if the sheet was closed) carries the Undo instead.
5. Fill the sheet sensibly: the sheet height fits its content (no large empty area), with friendly motion between steps (shared spring, reduced-motion respected) and a small nudge where useful (e.g. "Tip: you can close this, we'll notify you").
6. Check every step with the 4x alignment rules (one left edge for all text, icons centred on the first line, equal gaps).

Merge origin/dev first (dev is fully green now: bun run check + 1827 tests). Your branch must pass both. Retake the full matrix. Commit; comment on #1140 with head SHA. Do not push. After this round, a separate Money numbers review runs before merge.

Orchestrator review of artifacts/wizard-1140/screenshots (head e1312efe1). Functionally good; the owner's ask was "incredibly user friendly, friendly pages, motion, nudges, glassy cards". Fix before merge: **Behaviour (blocking)** 1. Imports must survive a server restart (we deploy many times a night). Persist the import job in the server's job store (the existing durable `jobs` mechanism), resume or restart it idempotently after a restart, and keep the wizard/notification in sync. Remove the 30-minute expiry for running jobs (expire only finished, unclaimed results, e.g. after 7 days). Undo receipts are server-side (per User), not browser-scoped. **Visual (importing-dark-1440.png, success-dark-1440.png)** 2. No focus rectangle around content blocks: a hard blue outline wraps "Bringing your budget over" and "Your Budget is ready" with text flush against it. Programmatic focus for announcements goes to a heading with no visible ring (`tabindex=-1`, focus-visible only), and content blocks get normal padding. 3. Importing step = the owner's design: a vertical **numbered list of ALL steps from the start** (1 Uploading, 2 Reading accounts, 3 Reading transactions, 4 Checking balances, 5 Finishing), upcoming steps dimmed, the current one with a spinner and its live detail ("208 KB of 15 MB · about 25 s left" on the same line as its progress bar), done steps with ✓; each line expands to show deeper output. Time-left sits with the progress, not under the Cancel button. Cancel is a normal secondary pill in the footer (left of "Continue in background"), not a full-width bar. 4. Success: one message, not two ("Your Budget is ready" + "Import complete / original export not changed" → one heading + one quiet line). Cards in one balanced grid (no 5 + 2 orphan row); "Balances" shows ✓ matched per account consistently with the others (value style), drop the stray progress bar under "Checks passed" or explain it. One Undo only: keep the footer "Undo import" button and drop the toast (toast rule #1142: no toast for what is already on screen); the notification (if the sheet was closed) carries the Undo instead. 5. Fill the sheet sensibly: the sheet height fits its content (no large empty area), with friendly motion between steps (shared spring, reduced-motion respected) and a small nudge where useful (e.g. "Tip: you can close this, we'll notify you"). 6. Check every step with the 4x alignment rules (one left edge for all text, icons centred on the first line, equal gaps). Merge origin/dev first (dev is fully green now: `bun run check` + 1827 tests). Your branch must pass both. Retake the full matrix. Commit; comment on #1140 with head SHA. Do not push. After this round, a separate Money numbers review runs before merge.
Author
Owner

Starting wizard2-1140 on job/wizard-1140, previous head e1312efe1. Merged origin/dev first; base after merge b12690bc8a1d9d0837b5da86a836fbb744f90479. Finding: routes.rs stores detached jobs and preview plans only in process Mutex maps; cleanup expires running jobs after 30 minutes. Undo records live in browser User storage. I am replacing restart loss with durable jobs and server-owned receipts, then retaking the production screenshot matrix. No pushes or deploys.

Starting wizard2-1140 on `job/wizard-1140`, previous head `e1312efe1`. Merged origin/dev first; base after merge `b12690bc8a1d9d0837b5da86a836fbb744f90479`. Finding: routes.rs stores detached jobs and preview plans only in process Mutex maps; cleanup expires running jobs after 30 minutes. Undo records live in browser User storage. I am replacing restart loss with durable jobs and server-owned receipts, then retaking the production screenshot matrix. No pushes or deploys.
Author
Owner

UI slice committed: 922c3fab0. Production web build passed. Focused web tests: Test Files 2 passed (2) / Tests 24 passed (24). The wizard has all five numbered steps at the start, a footer Cancel action, heading announcement focus, a content-sized desktop sheet, and an eight-card summary grid. Durable source copies are needed because the browser deletes its Tus inputs after preview. Restart tests now reopen the SQLite queue and recreate route state at receipt, preview, and publication. Rust crate tests are compiling dependencies on the shared host.

UI slice committed: `922c3fab0`. Production web build passed. Focused web tests: `Test Files 2 passed (2)` / `Tests 24 passed (24)`. The wizard has all five numbered steps at the start, a footer Cancel action, heading announcement focus, a content-sized desktop sheet, and an eight-card summary grid. Durable source copies are needed because the browser deletes its Tus inputs after preview. Restart tests now reopen the SQLite queue and recreate route state at receipt, preview, and publication. Rust crate tests are compiling dependencies on the shared host.
Author
Owner

Progress: 2b9af0cd0 commits server-receipt recovery, no duplicate visible success toast, calm reconnect state, and notification Undo. Focused web regression output:

 Test Files  4 passed (4)
      Tests  41 passed (41)

The old import runner held its only acknowledged job in RAM and expired it after 30 minutes. The new implementation stores input references and outcomes in the existing jobs queue. Private source copies survive Tus cleanup. Queue replay keeps preview and Budget identities stable, and detects publication after a crash between rename and receipt commit. The real SQLite restart tests passed:

test result: ok. 99 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 91.55s
test result: ok. 27 passed; 0 failed; 3 ignored; 0 measured; 0 filtered out; finished in 22.62s

Findings closed: running imports no longer have a server or browser expiry; cancelled imports remain cancelled after restart; Undo receipts are User-specific server data; cleanup does not renew the finished-result retention clock. Final clippy and the focused cleanup regression are running. Production screenshot coverage now includes a real server restart and notification Undo at each width/theme.

Decisions: restart may repeat parsing rather than serialize the large scratch plan. Finished, unclaimed results retain private sources for seven days. Published receipts remain available. Receipt reads return a bounded recent list and can retrieve any older Budget directly by stable identity.

Progress: 2b9af0cd0 commits server-receipt recovery, no duplicate visible success toast, calm reconnect state, and notification Undo. Focused web regression output: ``` Test Files 4 passed (4) Tests 41 passed (41) ``` The old import runner held its only acknowledged job in RAM and expired it after 30 minutes. The new implementation stores input references and outcomes in the existing `jobs` queue. Private source copies survive Tus cleanup. Queue replay keeps preview and Budget identities stable, and detects publication after a crash between rename and receipt commit. The real SQLite restart tests passed: ``` test result: ok. 99 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 91.55s test result: ok. 27 passed; 0 failed; 3 ignored; 0 measured; 0 filtered out; finished in 22.62s ``` Findings closed: running imports no longer have a server or browser expiry; cancelled imports remain cancelled after restart; Undo receipts are User-specific server data; cleanup does not renew the finished-result retention clock. Final clippy and the focused cleanup regression are running. Production screenshot coverage now includes a real server restart and notification Undo at each width/theme. Decisions: restart may repeat parsing rather than serialize the large scratch plan. Finished, unclaimed results retain private sources for seven days. Published receipts remain available. Receipt reads return a bounded recent list and can retrieve any older Budget directly by stable identity.
Author
Owner

Progress: head 7ec6041bd. Changes are in atomic commits: 19446edff (durable jobs and User receipts), a01eb25e4 (lease handoff recovery), d46315372 (step disclosures and shared focus/date tokens), and 7ec6041bd (cancel wins before queue acknowledgement).

Two restart/cancel findings closed:

  • After deployment the queue may wait for its previous lease. The browser previously cancelled a quiet job after six seconds. The recovered server state now reports Resuming import; the wizard keeps polling during that handoff. The regression waits 35 seconds, then reaches Review.
  • Cancel could arrive before the durable row existed. The route now stops the live control before it reads the queue. The receiver checks cancellation before copying and after queue commit. A cancelled receiver creates zero durable jobs.

Focused web output:

 Test Files  5 passed (5)
      Tests  46 passed (46)

Money gates:

    Finished `dev` profile [unoptimized + debuginfo] target(s) in 1m 38s
test result: ok. 101 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 104.40s
test result: ok. 27 passed; 0 failed; 3 ignored; 0 measured; 0 filtered out; finished in 15.23s

cargo fmt --check exited 0 with no output. The full server build and server gates are running. Final web gates and the production screenshot matrix follow. No push or deploy.

Progress: head 7ec6041bd. Changes are in atomic commits: 19446edff (durable jobs and User receipts), a01eb25e4 (lease handoff recovery), d46315372 (step disclosures and shared focus/date tokens), and 7ec6041bd (cancel wins before queue acknowledgement). Two restart/cancel findings closed: - After deployment the queue may wait for its previous lease. The browser previously cancelled a quiet job after six seconds. The recovered server state now reports `Resuming import`; the wizard keeps polling during that handoff. The regression waits 35 seconds, then reaches Review. - Cancel could arrive before the durable row existed. The route now stops the live control before it reads the queue. The receiver checks cancellation before copying and after queue commit. A cancelled receiver creates zero durable jobs. Focused web output: ``` Test Files 5 passed (5) Tests 46 passed (46) ``` Money gates: ``` Finished `dev` profile [unoptimized + debuginfo] target(s) in 1m 38s test result: ok. 101 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 104.40s test result: ok. 27 passed; 0 failed; 3 ignored; 0 measured; 0 filtered out; finished in 15.23s ``` `cargo fmt --check` exited 0 with no output. The full server build and server gates are running. Final web gates and the production screenshot matrix follow. No push or deploy.
Author
Owner

Restart recovery uses the existing durable jobs queue. Completed receipts are per User and survive both a server restart and a fresh browser. Recent receipt reads are bounded to 100; an older Budget has a direct lookup. Active jobs have no result expiry; finished, unclaimed results expire after seven days.

Head: b4d5f55cd. The focused restart suite passed all four tests (7.46 s); the isolated reopen test passed (1.92 s). One earlier parallel run returned 503 during initial admission on the busy host; its status assertion was kept and both isolated and parallel reruns passed. Final server gates, web check/full tests, and the production screenshot matrix are running. No push or deployment.

Restart recovery uses the existing durable jobs queue. Completed receipts are per User and survive both a server restart and a fresh browser. Recent receipt reads are bounded to 100; an older Budget has a direct lookup. Active jobs have no result expiry; finished, unclaimed results expire after seven days. Head: b4d5f55cd. The focused restart suite passed all four tests (7.46 s); the isolated reopen test passed (1.92 s). One earlier parallel run returned 503 during initial admission on the busy host; its status assertion was kept and both isolated and parallel reruns passed. Final server gates, web check/full tests, and the production screenshot matrix are running. No push or deployment.
Author
Owner

A focused regression confirmed a stable-identity collision at the import job boundary: a UUID case alias of a published job was accepted as a new job (202), although both spellings derive the same stable Budget identity. The new assertion failed against the prior handler:

assertion `left == right` failed: a case alias cannot enqueue duplicate work
  left: 202
 right: 400

The fix normalizes caller UUIDs in place at upload admission, progress, result and cancellation routes. It preserves case-alias reads and prevents a second queue key. The regression also checks a fresh route state, the original receipt and cross-User isolation. Existing fixtures and assertions are unchanged. Final Money gates and the production rebuild are running.

The live screenshot walk also found that six seconds of Tus inactivity can interrupt a healthy chunk acknowledgement on this host. Commit 4529c5e9f gives only upload acknowledgement a normal 30-second request grace; the parser still uses its original six-second stall check. Both new regressions passed: a 20-second acknowledgement reaches review, and a 32-second fully idle upload pauses with its file retained for Retry.

A focused regression confirmed a stable-identity collision at the import job boundary: a UUID case alias of a published job was accepted as a new job (202), although both spellings derive the same stable Budget identity. The new assertion failed against the prior handler: ``` assertion `left == right` failed: a case alias cannot enqueue duplicate work left: 202 right: 400 ``` The fix normalizes caller UUIDs in place at upload admission, progress, result and cancellation routes. It preserves case-alias reads and prevents a second queue key. The regression also checks a fresh route state, the original receipt and cross-User isolation. Existing fixtures and assertions are unchanged. Final Money gates and the production rebuild are running. The live screenshot walk also found that six seconds of Tus inactivity can interrupt a healthy chunk acknowledgement on this host. Commit 4529c5e9f gives only upload acknowledgement a normal 30-second request grace; the parser still uses its original six-second stall check. Both new regressions passed: a 20-second acknowledgement reaches review, and a 32-second fully idle upload pauses with its file retained for Retry.
Author
Owner

Live production walkthrough found that Money completion notifications were absent from the inbox after successful publication. The existing notifications.kind CHECK allows seven kinds but omits money_import_finished. Migration 0007 rebuilds that constraint and preserves inbox rows, pending push deliveries and reminder references. origin/dev currently ends at migration 0006 (checked after git fetch). A new upgrade regression tests all three preserved authorities plus Money inbox/outbox publication. The live screenshot walkthrough now checks notification Undo with a bounded 15-second wait. No existing assertion was changed.

Live production walkthrough found that Money completion notifications were absent from the inbox after successful publication. The existing notifications.kind CHECK allows seven kinds but omits money_import_finished. Migration 0007 rebuilds that constraint and preserves inbox rows, pending push deliveries and reminder references. origin/dev currently ends at migration 0006 (checked after git fetch). A new upgrade regression tests all three preserved authorities plus Money inbox/outbox publication. The live screenshot walkthrough now checks notification Undo with a bounded 15-second wait. No existing assertion was changed.
Author
Owner

The real restart walk found a completed server job while the wizard showed a generic failure. Inspection found that bounded result reads use AbortSignal.timeout(2000), which raises DOMException TimeoutError. isAbort recognized only AbortError, so this deadline was treated as a fatal file failure. Recovery now recognizes both platform cancellation names and retries the same durable job. The new regression keeps a timed-out import alive beyond 8.5 seconds and then reaches review without cancellation. Focused wizard session output:

 Test Files  1 passed (1)
      Tests  26 passed (26)

Full web check/test and new production evidence are running. No timeout or old test expectation was raised.

The real restart walk found a completed server job while the wizard showed a generic failure. Inspection found that bounded result reads use AbortSignal.timeout(2000), which raises DOMException TimeoutError. isAbort recognized only AbortError, so this deadline was treated as a fatal file failure. Recovery now recognizes both platform cancellation names and retries the same durable job. The new regression keeps a timed-out import alive beyond 8.5 seconds and then reaches review without cancellation. Focused wizard session output: ``` Test Files 1 passed (1) Tests 26 passed (26) ``` Full web check/test and new production evidence are running. No timeout or old test expectation was raised.
Author
Owner

NOT READY FOR MERGE. Blocking #1170: the final live restart walk cancels the recovered job through the browser idle-progress watchdog. The full screenshot matrix and fresh-browser notification acceptance remain incomplete. This round stops at the job time limit with the remaining fix filed.

#1140 follow-up report

Built: durable Money import jobs, restart recovery with stable identities, per-User server Undo receipts, and the revised five-step wizard. Running jobs do not expire. Finished unclaimed previews expire after seven days. Success uses one message, a balanced metrics grid and one footer Undo. The notification schema now accepts completion events; its upgrade regression verifies publication. Live notification Undo still needs acceptance. No success toast duplicates the sheet.

Files: crates/plugins/money/src/{lib,routes,import,durable_import,durable_import_tests,tests}.rs; Money dependency and lockfile; apps/web/src/lib/components/money/{MoneyImport,MoneyImportMetrics}.svelte; Money API/session/step helpers and their tests; notification model/inbox and tests; Money route layout; generated contracts/API client; exact performance scopes; focused production walkthrough; Money benchmark profile and adversarial receipt probe. The notification migration and store upgrade test are the small required addition in the Notifications crate.

UX gaps closed: keyboard announcements no longer outline content; all five stages appear at once with expandable detail; progress and remaining time share a line; Cancel is a footer pill; sheet content fits; shared motion respects reduced motion; account balances use matched values; one on-screen Undo; server receipts survive a fresh browser; healthy Tus acknowledgements have a bounded 30-second idle grace while parser stall detection stays at six seconds. Result poll deadlines use the platform TimeoutError as retry control flow, so a slow read does not fail a durable job. Import UUID aliases share one identity and cannot admit duplicate jobs. Live review found the missing notification schema kind; migration 0007 preserves existing inbox, reminder references and deliveries.

Decisions: restart recovery reparses bounded private source copies through calternal-fs rather than serializing temporary parser files. Stable preview and Budget IDs make replay idempotent. Recent receipt reads are limited to 100, with direct stable Budget lookup for older Undo. Created receipts are retained; only finished unclaimed results expire. A recovered lease gets a Resuming import state while the existing Worker transfers ownership. No external dependency was added.

Known gaps: blocking #1170, incomplete full screenshot matrix and fresh-browser Undo acceptance. SLOW-only server deadlines are tracked in #1165 and #1169. A transient admission 503 that did not recur in isolated or subsequent Money tests is tracked in #1164. The separate Money numbers review remains required before merge. No performance measurements were run: the current verification policy reserves those for performance issues on the perf VM.

For the merge round: cargo test -p calternal-server must pass the combined branch, including the original startup/backfill and Calendar latency assertions. bun tests/adversarial/money_api.mjs and bun tests/adversarial/money_import_review.mjs must prove owner isolation, hostile-input handling and import correctness; run the combined XUser/authz matrices. cd apps/web && bun run test:e2e:money must prove all Money workflows. Full workspace gates, real Apple-client checks and deploy checks belong to that round. No push, deploy or merge was performed beyond the requested origin/dev integration.

Head: 3ffe13e318b062cadcfc2637e62900807205691f. Atomic commits are on job/wizard-1140; no push was made.

Gate output (verbatim excerpts):

cargo fmt --check

No output; exit 0.

Money clippy

    Finished `dev` profile [unoptimized + debuginfo] target(s) in 28.13s

Money tests

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 101 filtered out; finished in 96.82s
test result: ok. 101 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 96.83s
test result: ok. 27 passed; 0 failed; 3 ignored; 0 measured; 0 filtered out; finished in 29.83s
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

Notifications clippy

    Finished `dev` profile [unoptimized + debuginfo] target(s) in 15m 00s

Notifications tests

test result: ok. 34 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 5.79s
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

Server clippy

    Finished `dev` profile [unoptimized + debuginfo] target(s) in 4m 09s

Server tests (SLOW; #1169)

HTTP startup waited for an upgrade backfill: Elapsed(())
test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 265 filtered out; finished in 21.07s
test result: FAILED. 255 passed; 1 failed; 10 ignored; 0 measured; 0 filtered out; finished in 195.44s

bun run check

perf-lint: PASS; 0 violations; 22177 scoped exceptions
svelte-check found 0 errors and 4 warnings in 3 files

bun run test

Ran 136 tests in 0.202s
 0 fail
 Test Files  270 passed (270)
      Tests  1871 passed (1871)

Focused wizard tests

 Test Files  1 passed (1)
      Tests  26 passed (26)

Production build

Compressed 897 static variants; saved 21059936 bytes.

Live walkthrough

PASS acknowledged import survives a real server restart

Partial evidence only: production build with macOS emulation, light phone 390 px upload/import steps with 4× crops and the failure screen. The matrix stopped on its first case. Full width/theme evidence and notification Undo are still required. Claude remains the visual reviewer.

UX gaps left: blocking recovered-job cancellation (#1170), incomplete screenshot matrix and live notification Undo acceptance, plus the separate Money numbers review and combined merge-round verification. See the known gaps above.

**NOT READY FOR MERGE.** Blocking [#1170](https://git.kayg.org/kayg/calternal/issues/1170): the final live restart walk cancels the recovered job through the browser idle-progress watchdog. The full screenshot matrix and fresh-browser notification acceptance remain incomplete. This round stops at the job time limit with the remaining fix filed. # #1140 follow-up report Built: durable Money import jobs, restart recovery with stable identities, per-User server Undo receipts, and the revised five-step wizard. Running jobs do not expire. Finished unclaimed previews expire after seven days. Success uses one message, a balanced metrics grid and one footer Undo. The notification schema now accepts completion events; its upgrade regression verifies publication. Live notification Undo still needs acceptance. No success toast duplicates the sheet. Files: `crates/plugins/money/src/{lib,routes,import,durable_import,durable_import_tests,tests}.rs`; Money dependency and lockfile; `apps/web/src/lib/components/money/{MoneyImport,MoneyImportMetrics}.svelte`; Money API/session/step helpers and their tests; notification model/inbox and tests; Money route layout; generated contracts/API client; exact performance scopes; focused production walkthrough; Money benchmark profile and adversarial receipt probe. The notification migration and store upgrade test are the small required addition in the Notifications crate. UX gaps closed: keyboard announcements no longer outline content; all five stages appear at once with expandable detail; progress and remaining time share a line; Cancel is a footer pill; sheet content fits; shared motion respects reduced motion; account balances use matched values; one on-screen Undo; server receipts survive a fresh browser; healthy Tus acknowledgements have a bounded 30-second idle grace while parser stall detection stays at six seconds. Result poll deadlines use the platform TimeoutError as retry control flow, so a slow read does not fail a durable job. Import UUID aliases share one identity and cannot admit duplicate jobs. Live review found the missing notification schema kind; migration 0007 preserves existing inbox, reminder references and deliveries. Decisions: restart recovery reparses bounded private source copies through calternal-fs rather than serializing temporary parser files. Stable preview and Budget IDs make replay idempotent. Recent receipt reads are limited to 100, with direct stable Budget lookup for older Undo. Created receipts are retained; only finished unclaimed results expire. A recovered lease gets a Resuming import state while the existing Worker transfers ownership. No external dependency was added. Known gaps: blocking #1170, incomplete full screenshot matrix and fresh-browser Undo acceptance. SLOW-only server deadlines are tracked in #1165 and #1169. A transient admission 503 that did not recur in isolated or subsequent Money tests is tracked in #1164. The separate Money numbers review remains required before merge. No performance measurements were run: the current verification policy reserves those for performance issues on the perf VM. For the merge round: `cargo test -p calternal-server` must pass the combined branch, including the original startup/backfill and Calendar latency assertions. `bun tests/adversarial/money_api.mjs` and `bun tests/adversarial/money_import_review.mjs` must prove owner isolation, hostile-input handling and import correctness; run the combined XUser/authz matrices. `cd apps/web && bun run test:e2e:money` must prove all Money workflows. Full workspace gates, real Apple-client checks and deploy checks belong to that round. No push, deploy or merge was performed beyond the requested origin/dev integration. Head: `3ffe13e318b062cadcfc2637e62900807205691f`. Atomic commits are on `job/wizard-1140`; no push was made. Gate output (verbatim excerpts): **cargo fmt --check** No output; exit 0. **Money clippy** ```text Finished `dev` profile [unoptimized + debuginfo] target(s) in 28.13s ``` **Money tests** ```text test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 101 filtered out; finished in 96.82s test result: ok. 101 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 96.83s test result: ok. 27 passed; 0 failed; 3 ignored; 0 measured; 0 filtered out; finished in 29.83s test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s ``` **Notifications clippy** ```text Finished `dev` profile [unoptimized + debuginfo] target(s) in 15m 00s ``` **Notifications tests** ```text test result: ok. 34 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 5.79s test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s ``` **Server clippy** ```text Finished `dev` profile [unoptimized + debuginfo] target(s) in 4m 09s ``` **Server tests (SLOW; #1169)** ```text HTTP startup waited for an upgrade backfill: Elapsed(()) test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 265 filtered out; finished in 21.07s test result: FAILED. 255 passed; 1 failed; 10 ignored; 0 measured; 0 filtered out; finished in 195.44s ``` **bun run check** ```text perf-lint: PASS; 0 violations; 22177 scoped exceptions svelte-check found 0 errors and 4 warnings in 3 files ``` **bun run test** ```text Ran 136 tests in 0.202s 0 fail Test Files 270 passed (270) Tests 1871 passed (1871) ``` **Focused wizard tests** ```text Test Files 1 passed (1) Tests 26 passed (26) ``` **Production build** ```text Compressed 897 static variants; saved 21059936 bytes. ``` **Live walkthrough** ```text PASS acknowledged import survives a real server restart ``` Partial evidence only: production build with macOS emulation, light phone 390 px upload/import steps with 4× crops and the failure screen. The matrix stopped on its first case. Full width/theme evidence and notification Undo are still required. Claude remains the visual reviewer. - [failed-review.png](https://git.kayg.org/attachments/32ef8cb7-cb60-46b8-b30e-936fc33ffb90) - [partial-production-evidence.zip](https://git.kayg.org/attachments/cbd71c42-3a5a-4dd5-8d21-67b9ec4cc18f) UX gaps left: blocking recovered-job cancellation (#1170), incomplete screenshot matrix and live notification Undo acceptance, plus the separate Money numbers review and combined merge-round verification. See the known gaps above.
Author
Owner

Started wizard3-1140 on job/wizard-1140 at 3ffe13e318. Merged origin/dev once; merge head 08d99c794d. Fixing #1170, then replacing all screenshot evidence. The owner now explicitly requires that browser timeouts never cancel durable jobs; the old six-second idle-recovery test will change to assert continued polling and completion.

Started wizard3-1140 on job/wizard-1140 at 3ffe13e318b062cadcfc2637e62900807205691f. Merged origin/dev once; merge head 08d99c794d8568614676bc687832cfe46f75b14f. Fixing #1170, then replacing all screenshot evidence. The owner now explicitly requires that browser timeouts never cancel durable jobs; the old six-second idle-recovery test will change to assert continued polling and completion.
Author
Owner

Recovery fix committed as 71ab9a8f5. All 27 focused session tests pass, including lease recovery into parser work with unchanged counts beyond six seconds, missing progress, explicit Cancel and bounded upload pause without DELETE. Production web build passed. Full web check/test and server build are running. The shared server CURRENT file is absent, so this job builds its own server. Screenshot capture will clear the old set and write per-file UTC capture times.

Recovery fix committed as 71ab9a8f5. All 27 focused session tests pass, including lease recovery into parser work with unchanged counts beyond six seconds, missing progress, explicit Cancel and bounded upload pause without DELETE. Production web build passed. Full web check/test and server build are running. The shared server CURRENT file is absent, so this job builds its own server. Screenshot capture will clear the old set and write per-file UTC capture times.
Author
Owner

Current head: 29ca76fde. bun run check passed: perf-lint: PASS; 0 violations; 22177 scoped exceptions; svelte-check found 0 errors and 4 warnings in 3 files. Production web build passed: Compressed 899 static variants; saved 21062756 bytes. Full web tests and the required local server build are still running. No Rust source was changed this round. No push or deploy.

Current head: 29ca76fde. bun run check passed: perf-lint: PASS; 0 violations; 22177 scoped exceptions; svelte-check found 0 errors and 4 warnings in 3 files. Production web build passed: Compressed 899 static variants; saved 21062756 bytes. Full web tests and the required local server build are still running. No Rust source was changed this round. No push or deploy.
Author
Owner

Head 79558d51f. Both required web gates pass after the origin/dev merge. Verbatim summaries: perf-lint: PASS; 0 violations; 22177 scoped exceptions; svelte-check found 0 errors and 4 warnings in 3 files; Test Files 270 passed (270); Tests 1875 passed (1875). Production build also passed. The live restart walkthrough now asserts the original admitted job identity, ready result, wizard review and no browser job DELETE. Server compilation is still progressing; screenshot capture follows it.

Head 79558d51f. Both required web gates pass after the origin/dev merge. Verbatim summaries: perf-lint: PASS; 0 violations; 22177 scoped exceptions; svelte-check found 0 errors and 4 warnings in 3 files; Test Files 270 passed (270); Tests 1875 passed (1875). Production build also passed. The live restart walkthrough now asserts the original admitted job identity, ready result, wizard review and no browser job DELETE. Server compilation is still progressing; screenshot capture follows it.
Author
Owner

All web validation is complete and green. The server build is still advancing through calternal crates and native dependencies; no build failure has been reported. Branch remains clean at 79558d51f7. Browser captures have not started yet, so no old screenshot is being represented as current evidence.

All web validation is complete and green. The server build is still advancing through calternal crates and native dependencies; no build failure has been reported. Branch remains clean at 79558d51f7cf59b8312c7227ea3d5bf103c864b1. Browser captures have not started yet, so no old screenshot is being represented as current evidence.
Author
Owner

Server compilation has reached calternal-server and the Money, Notifications and other plugin crates. All web gates remain passed. Current committed head is 79558d51f7. The next step is the single production walkthrough with fresh macOS evidence at all widths and themes; no verification suite is being repeated.

Server compilation has reached calternal-server and the Money, Notifications and other plugin crates. All web gates remain passed. Current committed head is 79558d51f7cf59b8312c7227ea3d5bf103c864b1. The next step is the single production walkthrough with fresh macOS evidence at all widths and themes; no verification suite is being repeated.
Author
Owner

Updated head e8802d5fd. The final build includes both #1170 fixes: browser deadlines do not cancel durable jobs, and explicit Cancel uses the retained UUID after a failed read. The final production run has again passed server restart, same-ID ready result, wizard review and no watchdog DELETE. Notification publication is present. bun run check passed again with 0 errors and 4 existing warnings. Final full web tests and all six fresh capture cases are running.

Updated head e8802d5fd. The final build includes both #1170 fixes: browser deadlines do not cancel durable jobs, and explicit Cancel uses the retained UUID after a failed read. The final production run has again passed server restart, same-ID ready result, wizard review and no watchdog DELETE. Notification publication is present. bun run check passed again with 0 errors and 4 existing warnings. Final full web tests and all six fresh capture cases are running.
Author
Owner

Live phone walk found a pointer blocker: a toast covered Create budget and hover paused its timeout for the full 210-second test deadline. Root cause: AppToaster watched route-content and direct body children, but sheets mount inside the shared portal. The same dock observer now watches that portal and motion completion. A new regression failed before the fix, then passed for sheet mount, step-size change and sheet removal. Focused output: Test Files 2 passed (2); Tests 30 passed (30). This extends AppToaster’s #1140 docking addition already on this branch. Web rebuild and final gates are refreshing for the new source change.

Live phone walk found a pointer blocker: a toast covered Create budget and hover paused its timeout for the full 210-second test deadline. Root cause: AppToaster watched route-content and direct body children, but sheets mount inside the shared portal. The same dock observer now watches that portal and motion completion. A new regression failed before the fix, then passed for sheet mount, step-size change and sheet removal. Focused output: Test Files 2 passed (2); Tests 30 passed (30). This extends AppToaster’s #1140 docking addition already on this branch. Web rebuild and final gates are refreshing for the new source change.
Author
Owner

Head 0af5b9347. The watchdog fix retains the admitted job UUID across a real server restart and reaches ready review without a browser DELETE. The walkthrough found a toast covering a portaled footer; the shared toaster now observes the existing overlay layer and its regression passes (30 focused tests total). Exact observer scope hashes were refreshed without changing limits. bun run check passes: perf-lint: PASS; 0 violations; 22177 scoped exceptions and svelte-check found 0 errors and 4 warnings in 3 files. Full web suite: 269 files / 1876 tests passed, two untouched five-second component-test timeouts. Both original focused files pass unchanged (12 tests); full suite is running with one worker. Current screenshots are being replaced again after a failed Cancel in the independent corrupt-export case. Recording API status/message evidence before deciding the fix. No pushes.

Head 0af5b9347. The watchdog fix retains the admitted job UUID across a real server restart and reaches ready review without a browser DELETE. The walkthrough found a toast covering a portaled footer; the shared toaster now observes the existing overlay layer and its regression passes (30 focused tests total). Exact observer scope hashes were refreshed without changing limits. `bun run check` passes: `perf-lint: PASS; 0 violations; 22177 scoped exceptions` and `svelte-check found 0 errors and 4 warnings in 3 files`. Full web suite: 269 files / 1876 tests passed, two untouched five-second component-test timeouts. Both original focused files pass unchanged (12 tests); full suite is running with one worker. Current screenshots are being replaced again after a failed Cancel in the independent corrupt-export case. Recording API status/message evidence before deciding the fix. No pushes.
Author
Owner

Head f9684b7b7. Full web gates now pass after merging origin/dev. bun run check:

perf-lint: PASS; 0 violations; 22177 scoped exceptions
svelte-check found 0 errors and 4 warnings in 3 files

cd apps/web && bun run test --maxWorkers=1 (original deadlines/assertions):

Ran 136 tests in 0.141s
Ran 7 tests across 1 file. [1.55s]
 Test Files  271 passed (271)
      Tests  1878 passed (1878)
   Duration  759.36s (transform 28%, environment 27%, import 22%, tests 17%, setup 6%)

cargo fmt --check: exit 0; no output. Restart walkthrough passes with the admitted UUID and no browser cancellation. The current full screenshot run has passed light/390 and is continuing the five remaining cases plus format and fresh-browser Undo evidence. No screenshots are committed. No push.

Head f9684b7b7. Full web gates now pass after merging origin/dev. `bun run check`: ``` perf-lint: PASS; 0 violations; 22177 scoped exceptions svelte-check found 0 errors and 4 warnings in 3 files ``` `cd apps/web && bun run test --maxWorkers=1` (original deadlines/assertions): ``` Ran 136 tests in 0.141s Ran 7 tests across 1 file. [1.55s] Test Files 271 passed (271) Tests 1878 passed (1878) Duration 759.36s (transform 28%, environment 27%, import 22%, tests 17%, setup 6%) ``` `cargo fmt --check`: exit 0; no output. Restart walkthrough passes with the admitted UUID and no browser cancellation. The current full screenshot run has passed light/390 and is continuing the five remaining cases plus format and fresh-browser Undo evidence. No screenshots are committed. No push.
Author
Owner

Head f835d3b71. The fresh desktop success screenshot exposed transaction dates clipped at the sheet edge. Cause: .metric-value and .metric-value.compact came after .date-value and overrode date wrapping/type. The date rule now has the correct specificity and follows the generic rules. The focused suite passes 37 tests; the browser now asserts each date range fits its Card at every width/theme. Exactly three existing MoneyImportMetrics hashes were refreshed in both performance ledgers; no limits, rules or counts changed. Production build and server build-ID refresh pass. Final screenshots are being recaptured again from this source. The harmless rejected-export cleanup message is filed as #1174.

Head f835d3b71. The fresh desktop success screenshot exposed transaction dates clipped at the sheet edge. Cause: `.metric-value` and `.metric-value.compact` came after `.date-value` and overrode date wrapping/type. The date rule now has the correct specificity and follows the generic rules. The focused suite passes 37 tests; the browser now asserts each date range fits its Card at every width/theme. Exactly three existing MoneyImportMetrics hashes were refreshed in both performance ledgers; no limits, rules or counts changed. Production build and server build-ID refresh pass. Final screenshots are being recaptured again from this source. The harmless rejected-export cleanup message is filed as #1174.
Author
Owner

The final six-case production walk passed four cases and then failed dark/820 waiting for review. A read-only query of the isolated fixture queue showed the ninth import row completed, attempts=2, no created Budget, no ready preview, and error discard or confirm the pending Money import first. The browser showed failure and sent no automatic Cancel. Root cause: a repeated worker parses again even when its persisted preview still has the matching live scratch plan. Its own pending slot is rejected and the ready result is replaced by an error. The fix acknowledges an already-persisted preview only when the same User and progress UUID still own that live plan; a process restart still replays parsing because the plan is absent. New regression uses the real database and production router/worker, executes the worker again after ready, and asserts both browser result and durable preview are unchanged. Rust gates now run for calternal-plugin-money. No screenshot acceptance claim is made until the full capture round passes.

The final six-case production walk passed four cases and then failed dark/820 waiting for review. A read-only query of the isolated fixture queue showed the ninth import row `completed`, `attempts=2`, no created Budget, no ready preview, and error `discard or confirm the pending Money import first`. The browser showed failure and sent no automatic Cancel. Root cause: a repeated worker parses again even when its persisted preview still has the matching live scratch plan. Its own pending slot is rejected and the ready result is replaced by an error. The fix acknowledges an already-persisted preview only when the same User and progress UUID still own that live plan; a process restart still replays parsing because the plan is absent. New regression uses the real database and production router/worker, executes the worker again after ready, and asserts both browser result and durable preview are unchanged. Rust gates now run for calternal-plugin-money. No screenshot acceptance claim is made until the full capture round passes.
Author
Owner

Head 09dc5bd7b0. Committed the same-process replay fix with a production router/database regression. Gates:

    Finished `dev` profile [unoptimized + debuginfo] target(s) in 3m 17s
test result: ok. 102 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 63.42s
test result: ok. 27 passed; 0 failed; 3 ignored; 0 measured; 0 filtered out; finished in 8.25s
perf-lint: PASS; 0 violations; 22177 scoped exceptions
svelte-check found 0 errors and 4 warnings in 3 files

cargo fmt --check exits 0 with no output. The helper marked ignored was run in its isolated child; three integration growth profiles remain ignored as configured. The server rebuild passes. The complete six-case screenshot/format round is running again from these committed sources. No push.

Head 09dc5bd7b0ece88c806820625f1c444f06192c57. Committed the same-process replay fix with a production router/database regression. Gates: ``` Finished `dev` profile [unoptimized + debuginfo] target(s) in 3m 17s test result: ok. 102 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 63.42s test result: ok. 27 passed; 0 failed; 3 ignored; 0 measured; 0 filtered out; finished in 8.25s perf-lint: PASS; 0 violations; 22177 scoped exceptions svelte-check found 0 errors and 4 warnings in 3 files ``` `cargo fmt --check` exits 0 with no output. The helper marked ignored was run in its isolated child; three integration growth profiles remain ignored as configured. The server rebuild passes. The complete six-case screenshot/format round is running again from these committed sources. No push.
Author
Owner

#1140 / #1170 follow-up

Head: 02050bea9c6bc889f5d0c7739a3a242100676049 on job/wizard-1140. Started from 3ffe13e31; merged origin/dev once as requested (08d99c794). No push, deploy or promotion merge.

Built: the browser re-attaches to the same durable import UUID after a server restart. Optional progress can stay unchanged or disappear during lease recovery. The result endpoint decides completion and failure. Browser deadlines do not cancel server work. Explicit Cancel retains the durable identity even after a failed result clears transport state. Idle Tus uploads still pause after 30 seconds and keep the file for Retry.

A repeated server Worker now reuses its persisted ready preview when the same User and job UUID still own the live scratch plan. A restart still rebuilds a lost plan. This fixes the same-process queue replay failure found during screenshot capture.

The shared toaster now follows sheet actions in the existing portal so notifications cannot cover the footer. Transaction date ranges wrap within their Cards. The screenshot script removes stale images, records capture times, uses macOS glyphs, and asserts date overflow, content-fit frame geometry, all five initial progress steps, the footer Cancel and one success message/Undo.

Files:

  • crates/plugins/money/src/durable_import.rs
  • crates/plugins/money/src/durable_import_tests.rs
  • apps/web/src/lib/money/import-session.svelte.ts
  • apps/web/src/lib/money/import-session.svelte.test.ts
  • apps/web/src/lib/components/AppToaster.svelte
  • apps/web/src/lib/components/AppToaster.svelte.test.ts
  • apps/web/src/lib/components/money/MoneyImportMetrics.svelte
  • apps/web/e2e/money-wizard-1140.mjs
  • contracts/perf/exceptions.json
  • contracts/perf/adoption-1058.json

The performance ledgers change only exact live syntax hashes. No rule, limit, ratchet or exception count changed. No dependencies were added. Changed doc comments were read back before this report.

Gate output (verbatim):

cargo fmt --check: exit 0, no output. Per-crate Rust gates also pass for the Money Worker fix. No server route or public schema changed.

cargo clippy -p calternal-plugin-money --all-targets -- -D warnings (exit 0):

    Finished `dev` profile [unoptimized + debuginfo] target(s) in 3m 17s

cargo test -p calternal-plugin-money -- --test-threads=4 (exit 0):

test result: ok. 102 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 63.42s
test result: ok. 27 passed; 0 failed; 3 ignored; 0 measured; 0 filtered out; finished in 8.25s
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

The one unit-test helper is invoked as an isolated child and passed. Three ignored integration tests are optional growth profiles.

cd apps/web && bun run check (exit 0):

perf-lint: PASS; 0 violations; 22177 scoped exceptions
svelte-check found 0 errors and 4 warnings in 3 files

cd apps/web && bun run test --maxWorkers=1 (exit 0; original assertions and deadlines):

Ran 136 tests in 0.186s
Ran 7 tests across 1 file. [926.00ms]
 Test Files  271 passed (271)
      Tests  1878 passed (1878)
   Duration  679.18s (transform 40%, environment 20%, import 20%, tests 13%, setup 6%)

Focused Vitest (import-ui.test.ts, import-session.svelte.test.ts, AppToaster.svelte.test.ts, one worker; exit 0):

 Test Files  3 passed (3)
      Tests  37 passed (37)

Production web build (exit 0):

Compressed 899 static variants; saved 21063595 bytes.

Server build-ID refresh (exit 0):

    Finished `dev` profile [unoptimized + debuginfo] target(s) in 1m 07s

UX gaps closed: same-process queue replay no longer rejects its own ready preview; recovered parser work no longer fails after six seconds without changed counts; missing optional progress never cancels work; upload timeout never sends a job DELETE; explicit Cancel can discard a failed recovered job; portaled toasts no longer cover Create Budget; transaction dates do not clip at the Card edge. All screenshots are new production captures, with real server data created from test fixtures.

UX gaps left / known gaps: #1176 records one browser target closure during the optional phase of the long combined run. The six-case matrix passed. A separate format-only run passed every assertion; page/context/browser diagnostics are now present. No confirmed product crash or data-loss finding was identified. #1174 records a harmless temporary-copy cleanup message after a rejected ZIP. Explicit Cancel returns to Money; no Budget is created. The four web-check warnings remain in unrelated files. Visual acceptance belongs to the orchestrator. Screenshots emulate macOS; this was not a real Mac GUI run.

Decisions: no new product decision. The job instruction supersedes the former six-second idle-recovery test; its replacement proves continued polling and completion. The existing upload deadline remains 30 seconds. Browser fixture themes use the existing pre-document settings helper. The local server was built because the shared binary manifest was absent. No performance measurements run in this non-performance job under the current verification policy.

For the merge round:

  • cargo clippy --all-targets -- -D warnings and cargo test: prove the combined Rust branch.
  • bun tests/adversarial/money_api.mjs and bun tests/adversarial/money_import_review.mjs: prove hostile-input handling and import isolation.
  • Combined XUser/authz matrices: prove cross-User isolation.
  • cd apps/web && bun run test:e2e:money: prove all Money workflows on the combined build.
  • node apps/web/e2e/money-wizard-1140.mjs --acceptance: repeat the long combined round to investigate #1176 with page/context/browser diagnostics.
  • The separate Money numbers review and deployment checks remain with the orchestrator.

Verification evidence: the matrix phase passed all six cases. Its optional format phase stopped when a browser target closed (#1176). The separate --formats-only run passed CSV, JSON, replacement confirmation, server restart, Undo from a fresh browser and unrelated-ZIP rejection. It replaced all earlier format images. The 162 matrix images remain from the successful matrix phase; all product source is identical across both capture runs. No workflow assertion was removed or changed.

Format gate output (verbatim):

PASS replacement Undo from a fresh browser after server restart
PASS ynab-csv pair, ynab-json, replacement confirmation, Undo restoring the original, non-budget ZIP
PASS wizard production evidence: /home/kayg/Developer/calternal-wt/wizard-1140/artifacts/wizard-1140/screenshots; 175 current captures
Browser process exit: {"code":0,"signal":null}

Cleanup: cargo clean completed; generated web output was removed. No screenshots, videos or other review artifacts were committed.

     Removed 12398 files, 8.7GiB total

Current evidence: all 175 PNG files, manifest and gate logs; capture manifest. The times below are UTC. Captures run from 2026-10-06T04:12:39.066Z to 2026-10-06T04:25:41.329Z. macOS platform emulation applies to all captures. Header, footer and progress alignment crops are included for the orchestrator's visual review.

Screenshot file Capture time (UTC)
create-dark-1440-alignment-4x.png 2026-10-06T04:19:49.785Z
create-dark-1440-header-4x.png 2026-10-06T04:19:50.237Z
create-dark-1440.png 2026-10-06T04:19:48.305Z
create-dark-390-alignment-4x.png 2026-10-06T04:17:04.743Z
create-dark-390-header-4x.png 2026-10-06T04:17:05.059Z
create-dark-390.png 2026-10-06T04:17:04.371Z
create-dark-820-alignment-4x.png 2026-10-06T04:18:16.474Z
create-dark-820-header-4x.png 2026-10-06T04:18:16.854Z
create-dark-820.png 2026-10-06T04:18:15.966Z
create-light-1440-alignment-4x.png 2026-10-06T04:15:30.292Z
create-light-1440-header-4x.png 2026-10-06T04:15:31.028Z
create-light-1440.png 2026-10-06T04:15:29.364Z
create-light-390-alignment-4x.png 2026-10-06T04:13:36.949Z
create-light-390-header-4x.png 2026-10-06T04:13:37.289Z
create-light-390.png 2026-10-06T04:13:36.733Z
create-light-820-alignment-4x.png 2026-10-06T04:14:30.196Z
create-light-820-header-4x.png 2026-10-06T04:14:30.444Z
create-light-820.png 2026-10-06T04:14:29.620Z
csv-review-light-1440-alignment-4x.png 2026-10-06T04:24:50.305Z
csv-review-light-1440-header-4x.png 2026-10-06T04:24:51.225Z
csv-review-light-1440.png 2026-10-06T04:24:49.465Z
csv-upload-light-1440-alignment-4x.png 2026-10-06T04:24:25.566Z
csv-upload-light-1440-header-4x.png 2026-10-06T04:24:26.214Z
csv-upload-light-1440.png 2026-10-06T04:24:24.170Z
failure-dark-1440-alignment-4x.png 2026-10-06T04:19:59.693Z
failure-dark-1440-header-4x.png 2026-10-06T04:20:00.589Z
failure-dark-1440.png 2026-10-06T04:19:58.373Z
failure-dark-390-alignment-4x.png 2026-10-06T04:17:10.711Z
failure-dark-390-header-4x.png 2026-10-06T04:17:10.967Z
failure-dark-390.png 2026-10-06T04:17:10.471Z
failure-dark-820-alignment-4x.png 2026-10-06T04:18:27.474Z
failure-dark-820-header-4x.png 2026-10-06T04:18:27.970Z
failure-dark-820.png 2026-10-06T04:18:26.658Z
failure-light-1440-alignment-4x.png 2026-10-06T04:15:42.136Z
failure-light-1440-header-4x.png 2026-10-06T04:15:42.596Z
failure-light-1440.png 2026-10-06T04:15:41.356Z
failure-light-390-alignment-4x.png 2026-10-06T04:13:45.225Z
failure-light-390-header-4x.png 2026-10-06T04:13:45.473Z
failure-light-390.png 2026-10-06T04:13:44.997Z
failure-light-820-alignment-4x.png 2026-10-06T04:14:38.292Z
failure-light-820-header-4x.png 2026-10-06T04:14:38.540Z
failure-light-820.png 2026-10-06T04:14:38.028Z
importing-dark-1440-alignment-4x.png 2026-10-06T04:18:41.802Z
importing-dark-1440-header-4x.png 2026-10-06T04:18:42.230Z
importing-dark-1440-progress-4x.png 2026-10-06T04:18:42.706Z
importing-dark-1440.png 2026-10-06T04:18:41.274Z
importing-dark-390-alignment-4x.png 2026-10-06T04:15:55.812Z
importing-dark-390-header-4x.png 2026-10-06T04:15:56.076Z
importing-dark-390-progress-4x.png 2026-10-06T04:15:56.292Z
importing-dark-390.png 2026-10-06T04:15:55.504Z
importing-dark-820-alignment-4x.png 2026-10-06T04:17:28.754Z
importing-dark-820-header-4x.png 2026-10-06T04:17:29.498Z
importing-dark-820-progress-4x.png 2026-10-06T04:17:29.978Z
importing-dark-820.png 2026-10-06T04:17:28.254Z
importing-details-dark-1440-alignment-4x.png 2026-10-06T04:18:40.506Z
importing-details-dark-1440-header-4x.png 2026-10-06T04:18:40.942Z
importing-details-dark-1440.png 2026-10-06T04:18:40.062Z
importing-details-dark-390-alignment-4x.png 2026-10-06T04:15:54.840Z
importing-details-dark-390-header-4x.png 2026-10-06T04:15:55.116Z
importing-details-dark-390.png 2026-10-06T04:15:54.592Z
importing-details-dark-820-alignment-4x.png 2026-10-06T04:17:27.086Z
importing-details-dark-820-header-4x.png 2026-10-06T04:17:27.630Z
importing-details-dark-820.png 2026-10-06T04:17:26.534Z
importing-details-light-1440-alignment-4x.png 2026-10-06T04:14:49.172Z
importing-details-light-1440-header-4x.png 2026-10-06T04:14:49.652Z
importing-details-light-1440.png 2026-10-06T04:14:48.652Z
importing-details-light-390-alignment-4x.png 2026-10-06T04:12:43.762Z
importing-details-light-390-header-4x.png 2026-10-06T04:12:44.026Z
importing-details-light-390.png 2026-10-06T04:12:43.498Z
importing-details-light-820-alignment-4x.png 2026-10-06T04:13:53.613Z
importing-details-light-820-header-4x.png 2026-10-06T04:13:53.969Z
importing-details-light-820.png 2026-10-06T04:13:53.305Z
importing-light-1440-alignment-4x.png 2026-10-06T04:14:51.232Z
importing-light-1440-header-4x.png 2026-10-06T04:14:52.008Z
importing-light-1440-progress-4x.png 2026-10-06T04:14:53.660Z
importing-light-1440.png 2026-10-06T04:14:50.568Z
importing-light-390-alignment-4x.png 2026-10-06T04:12:44.594Z
importing-light-390-header-4x.png 2026-10-06T04:12:44.874Z
importing-light-390-progress-4x.png 2026-10-06T04:12:45.086Z
importing-light-390.png 2026-10-06T04:12:44.350Z
importing-light-820-alignment-4x.png 2026-10-06T04:13:54.801Z
importing-light-820-header-4x.png 2026-10-06T04:13:55.153Z
importing-light-820-progress-4x.png 2026-10-06T04:13:55.497Z
importing-light-820.png 2026-10-06T04:13:54.453Z
json-review-light-1440-alignment-4x.png 2026-10-06T04:25:08.725Z
json-review-light-1440-header-4x.png 2026-10-06T04:25:09.169Z
json-review-light-1440.png 2026-10-06T04:25:07.861Z
non-budget-failure-light-1440-alignment-4x.png 2026-10-06T04:25:41.009Z
non-budget-failure-light-1440-header-4x.png 2026-10-06T04:25:41.329Z
non-budget-failure-light-1440.png 2026-10-06T04:25:40.405Z
notification-dark-1440-alignment-4x.png 2026-10-06T04:19:41.913Z
notification-dark-1440.png 2026-10-06T04:19:40.681Z
notification-dark-390-alignment-4x.png 2026-10-06T04:16:59.615Z
notification-dark-390.png 2026-10-06T04:16:59.235Z
notification-dark-820-alignment-4x.png 2026-10-06T04:18:09.554Z
notification-dark-820.png 2026-10-06T04:18:08.978Z
notification-light-1440-alignment-4x.png 2026-10-06T04:15:24.712Z
notification-light-1440.png 2026-10-06T04:15:24.008Z
notification-light-390-alignment-4x.png 2026-10-06T04:13:33.029Z
notification-light-390.png 2026-10-06T04:13:32.821Z
notification-light-820-alignment-4x.png 2026-10-06T04:14:25.073Z
notification-light-820.png 2026-10-06T04:14:24.769Z
replacement-notification-light-1440.png 2026-10-06T04:25:26.533Z
start-dark-1440-alignment-4x.png 2026-10-06T04:18:33.130Z
start-dark-1440-header-4x.png 2026-10-06T04:18:33.690Z
start-dark-1440.png 2026-10-06T04:18:32.226Z
start-dark-390-alignment-4x.png 2026-10-06T04:15:47.476Z
start-dark-390-header-4x.png 2026-10-06T04:15:47.728Z
start-dark-390.png 2026-10-06T04:15:47.180Z
start-dark-820-alignment-4x.png 2026-10-06T04:17:15.375Z
start-dark-820-header-4x.png 2026-10-06T04:17:15.623Z
start-dark-820.png 2026-10-06T04:17:14.099Z
start-light-1440-alignment-4x.png 2026-10-06T04:14:41.948Z
start-light-1440-header-4x.png 2026-10-06T04:14:42.324Z
start-light-1440.png 2026-10-06T04:14:41.324Z
start-light-390-alignment-4x.png 2026-10-06T04:12:39.358Z
start-light-390-header-4x.png 2026-10-06T04:12:39.566Z
start-light-390.png 2026-10-06T04:12:39.066Z
start-light-820-alignment-4x.png 2026-10-06T04:13:48.273Z
start-light-820-header-4x.png 2026-10-06T04:13:48.461Z
start-light-820.png 2026-10-06T04:13:48.097Z
success-dark-1440-alignment-4x.png 2026-10-06T04:19:35.741Z
success-dark-1440-header-4x.png 2026-10-06T04:19:36.481Z
success-dark-1440.png 2026-10-06T04:19:35.081Z
success-dark-390-alignment-4x.png 2026-10-06T04:16:55.851Z
success-dark-390-header-4x.png 2026-10-06T04:16:56.227Z
success-dark-390.png 2026-10-06T04:16:55.451Z
success-dark-820-alignment-4x.png 2026-10-06T04:18:03.874Z
success-dark-820-header-4x.png 2026-10-06T04:18:04.522Z
success-dark-820.png 2026-10-06T04:18:03.434Z
success-light-1440-alignment-4x.png 2026-10-06T04:15:20.456Z
success-light-1440-header-4x.png 2026-10-06T04:15:21.072Z
success-light-1440.png 2026-10-06T04:15:19.760Z
success-light-390-alignment-4x.png 2026-10-06T04:13:30.625Z
success-light-390-header-4x.png 2026-10-06T04:13:30.813Z
success-light-390.png 2026-10-06T04:13:30.149Z
success-light-820-alignment-4x.png 2026-10-06T04:14:20.081Z
success-light-820-header-4x.png 2026-10-06T04:14:20.565Z
success-light-820.png 2026-10-06T04:14:19.725Z
success-review-dark-1440-alignment-4x.png 2026-10-06T04:19:29.557Z
success-review-dark-1440-header-4x.png 2026-10-06T04:19:30.625Z
success-review-dark-1440.png 2026-10-06T04:19:28.077Z
success-review-dark-390-alignment-4x.png 2026-10-06T04:16:52.031Z
success-review-dark-390-header-4x.png 2026-10-06T04:16:52.411Z
success-review-dark-390.png 2026-10-06T04:16:51.607Z
success-review-dark-820-alignment-4x.png 2026-10-06T04:17:53.722Z
success-review-dark-820-header-4x.png 2026-10-06T04:17:54.390Z
success-review-dark-820.png 2026-10-06T04:17:53.222Z
success-review-light-1440-alignment-4x.png 2026-10-06T04:15:15.500Z
success-review-light-1440-header-4x.png 2026-10-06T04:15:16.192Z
success-review-light-1440.png 2026-10-06T04:15:14.612Z
success-review-light-390-alignment-4x.png 2026-10-06T04:13:25.665Z
success-review-light-390-header-4x.png 2026-10-06T04:13:25.893Z
success-review-light-390.png 2026-10-06T04:13:25.401Z
success-review-light-820-alignment-4x.png 2026-10-06T04:14:16.493Z
success-review-light-820-header-4x.png 2026-10-06T04:14:17.013Z
success-review-light-820.png 2026-10-06T04:14:15.933Z
upload-dark-1440-alignment-4x.png 2026-10-06T04:18:38.274Z
upload-dark-1440-header-4x.png 2026-10-06T04:18:38.822Z
upload-dark-1440.png 2026-10-06T04:18:37.710Z
upload-dark-390-alignment-4x.png 2026-10-06T04:15:52.864Z
upload-dark-390-header-4x.png 2026-10-06T04:15:53.200Z
upload-dark-390.png 2026-10-06T04:15:52.620Z
upload-dark-820-alignment-4x.png 2026-10-06T04:17:24.455Z
upload-dark-820-header-4x.png 2026-10-06T04:17:24.695Z
upload-dark-820.png 2026-10-06T04:17:23.795Z
upload-light-1440-alignment-4x.png 2026-10-06T04:14:46.424Z
upload-light-1440-header-4x.png 2026-10-06T04:14:46.860Z
upload-light-1440.png 2026-10-06T04:14:45.996Z
upload-light-390-alignment-4x.png 2026-10-06T04:12:42.246Z
upload-light-390-header-4x.png 2026-10-06T04:12:42.414Z
upload-light-390.png 2026-10-06T04:12:42.090Z
upload-light-820-alignment-4x.png 2026-10-06T04:13:51.649Z
upload-light-820-header-4x.png 2026-10-06T04:13:51.849Z
upload-light-820.png 2026-10-06T04:13:51.489Z
# #1140 / #1170 follow-up Head: `02050bea9c6bc889f5d0c7739a3a242100676049` on `job/wizard-1140`. Started from `3ffe13e31`; merged `origin/dev` once as requested (`08d99c794`). No push, deploy or promotion merge. Built: the browser re-attaches to the same durable import UUID after a server restart. Optional progress can stay unchanged or disappear during lease recovery. The result endpoint decides completion and failure. Browser deadlines do not cancel server work. Explicit Cancel retains the durable identity even after a failed result clears transport state. Idle Tus uploads still pause after 30 seconds and keep the file for Retry. A repeated server Worker now reuses its persisted ready preview when the same User and job UUID still own the live scratch plan. A restart still rebuilds a lost plan. This fixes the same-process queue replay failure found during screenshot capture. The shared toaster now follows sheet actions in the existing portal so notifications cannot cover the footer. Transaction date ranges wrap within their Cards. The screenshot script removes stale images, records capture times, uses macOS glyphs, and asserts date overflow, content-fit frame geometry, all five initial progress steps, the footer Cancel and one success message/Undo. Files: - `crates/plugins/money/src/durable_import.rs` - `crates/plugins/money/src/durable_import_tests.rs` - `apps/web/src/lib/money/import-session.svelte.ts` - `apps/web/src/lib/money/import-session.svelte.test.ts` - `apps/web/src/lib/components/AppToaster.svelte` - `apps/web/src/lib/components/AppToaster.svelte.test.ts` - `apps/web/src/lib/components/money/MoneyImportMetrics.svelte` - `apps/web/e2e/money-wizard-1140.mjs` - `contracts/perf/exceptions.json` - `contracts/perf/adoption-1058.json` The performance ledgers change only exact live syntax hashes. No rule, limit, ratchet or exception count changed. No dependencies were added. Changed doc comments were read back before this report. Gate output (verbatim): `cargo fmt --check`: exit 0, no output. Per-crate Rust gates also pass for the Money Worker fix. No server route or public schema changed. `cargo clippy -p calternal-plugin-money --all-targets -- -D warnings` (exit 0): ``` Finished `dev` profile [unoptimized + debuginfo] target(s) in 3m 17s ``` `cargo test -p calternal-plugin-money -- --test-threads=4` (exit 0): ``` test result: ok. 102 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 63.42s test result: ok. 27 passed; 0 failed; 3 ignored; 0 measured; 0 filtered out; finished in 8.25s test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s ``` The one unit-test helper is invoked as an isolated child and passed. Three ignored integration tests are optional growth profiles. `cd apps/web && bun run check` (exit 0): ``` perf-lint: PASS; 0 violations; 22177 scoped exceptions svelte-check found 0 errors and 4 warnings in 3 files ``` `cd apps/web && bun run test --maxWorkers=1` (exit 0; original assertions and deadlines): ``` Ran 136 tests in 0.186s Ran 7 tests across 1 file. [926.00ms] Test Files 271 passed (271) Tests 1878 passed (1878) Duration 679.18s (transform 40%, environment 20%, import 20%, tests 13%, setup 6%) ``` Focused Vitest (`import-ui.test.ts`, `import-session.svelte.test.ts`, `AppToaster.svelte.test.ts`, one worker; exit 0): ``` Test Files 3 passed (3) Tests 37 passed (37) ``` Production web build (exit 0): ``` Compressed 899 static variants; saved 21063595 bytes. ``` Server build-ID refresh (exit 0): ``` Finished `dev` profile [unoptimized + debuginfo] target(s) in 1m 07s ``` UX gaps closed: same-process queue replay no longer rejects its own ready preview; recovered parser work no longer fails after six seconds without changed counts; missing optional progress never cancels work; upload timeout never sends a job DELETE; explicit Cancel can discard a failed recovered job; portaled toasts no longer cover Create Budget; transaction dates do not clip at the Card edge. All screenshots are new production captures, with real server data created from test fixtures. UX gaps left / known gaps: #1176 records one browser target closure during the optional phase of the long combined run. The six-case matrix passed. A separate format-only run passed every assertion; page/context/browser diagnostics are now present. No confirmed product crash or data-loss finding was identified. #1174 records a harmless temporary-copy cleanup message after a rejected ZIP. Explicit Cancel returns to Money; no Budget is created. The four web-check warnings remain in unrelated files. Visual acceptance belongs to the orchestrator. Screenshots emulate macOS; this was not a real Mac GUI run. Decisions: no new product decision. The job instruction supersedes the former six-second idle-recovery test; its replacement proves continued polling and completion. The existing upload deadline remains 30 seconds. Browser fixture themes use the existing pre-document settings helper. The local server was built because the shared binary manifest was absent. No performance measurements run in this non-performance job under the current verification policy. For the merge round: - `cargo clippy --all-targets -- -D warnings` and `cargo test`: prove the combined Rust branch. - `bun tests/adversarial/money_api.mjs` and `bun tests/adversarial/money_import_review.mjs`: prove hostile-input handling and import isolation. - Combined XUser/authz matrices: prove cross-User isolation. - `cd apps/web && bun run test:e2e:money`: prove all Money workflows on the combined build. - `node apps/web/e2e/money-wizard-1140.mjs --acceptance`: repeat the long combined round to investigate #1176 with page/context/browser diagnostics. - The separate Money numbers review and deployment checks remain with the orchestrator. Verification evidence: the matrix phase passed all six cases. Its optional format phase stopped when a browser target closed (#1176). The separate `--formats-only` run passed CSV, JSON, replacement confirmation, server restart, Undo from a fresh browser and unrelated-ZIP rejection. It replaced all earlier format images. The 162 matrix images remain from the successful matrix phase; all product source is identical across both capture runs. No workflow assertion was removed or changed. Format gate output (verbatim): ``` PASS replacement Undo from a fresh browser after server restart PASS ynab-csv pair, ynab-json, replacement confirmation, Undo restoring the original, non-budget ZIP PASS wizard production evidence: /home/kayg/Developer/calternal-wt/wizard-1140/artifacts/wizard-1140/screenshots; 175 current captures Browser process exit: {"code":0,"signal":null} ``` Cleanup: `cargo clean` completed; generated web output was removed. No screenshots, videos or other review artifacts were committed. ``` Removed 12398 files, 8.7GiB total ``` Current evidence: [all 175 PNG files, manifest and gate logs](https://git.kayg.org/attachments/8bf43c31-62bc-4554-a1e9-255e4ae2f1c7); [capture manifest](https://git.kayg.org/attachments/6709f869-63e4-4e2f-973b-df027f9c79de). The times below are UTC. Captures run from 2026-10-06T04:12:39.066Z to 2026-10-06T04:25:41.329Z. macOS platform emulation applies to all captures. Header, footer and progress alignment crops are included for the orchestrator's visual review. | Screenshot file | Capture time (UTC) | | --- | --- | | [create-dark-1440-alignment-4x.png](https://git.kayg.org/attachments/24f360e8-1640-4bbe-96bd-85778f827137) | 2026-10-06T04:19:49.785Z | | [create-dark-1440-header-4x.png](https://git.kayg.org/attachments/24f360e8-1640-4bbe-96bd-85778f827137) | 2026-10-06T04:19:50.237Z | | [create-dark-1440.png](https://git.kayg.org/attachments/c7cce04e-01a2-4d19-a45c-af916d0c7e52) | 2026-10-06T04:19:48.305Z | | [create-dark-390-alignment-4x.png](https://git.kayg.org/attachments/de9b8513-2693-47a1-9abf-4a425872c78d) | 2026-10-06T04:17:04.743Z | | [create-dark-390-header-4x.png](https://git.kayg.org/attachments/de9b8513-2693-47a1-9abf-4a425872c78d) | 2026-10-06T04:17:05.059Z | | [create-dark-390.png](https://git.kayg.org/attachments/09e867fc-4d4e-49e6-bf04-b04e1d3397a4) | 2026-10-06T04:17:04.371Z | | [create-dark-820-alignment-4x.png](https://git.kayg.org/attachments/7fa8d16c-cb54-48e1-965b-c8b590f84e83) | 2026-10-06T04:18:16.474Z | | [create-dark-820-header-4x.png](https://git.kayg.org/attachments/7fa8d16c-cb54-48e1-965b-c8b590f84e83) | 2026-10-06T04:18:16.854Z | | [create-dark-820.png](https://git.kayg.org/attachments/4c59a8f9-0f96-47b6-968e-ba48ce6e1e0e) | 2026-10-06T04:18:15.966Z | | [create-light-1440-alignment-4x.png](https://git.kayg.org/attachments/e6a6666c-8ba6-4a9c-86b9-7b3b24032d4c) | 2026-10-06T04:15:30.292Z | | [create-light-1440-header-4x.png](https://git.kayg.org/attachments/e6a6666c-8ba6-4a9c-86b9-7b3b24032d4c) | 2026-10-06T04:15:31.028Z | | [create-light-1440.png](https://git.kayg.org/attachments/37cb8bed-f95e-42d8-9dbe-0c03ccf49e18) | 2026-10-06T04:15:29.364Z | | [create-light-390-alignment-4x.png](https://git.kayg.org/attachments/5d06172d-0a5e-411c-bd36-c2afaac5aa09) | 2026-10-06T04:13:36.949Z | | [create-light-390-header-4x.png](https://git.kayg.org/attachments/5d06172d-0a5e-411c-bd36-c2afaac5aa09) | 2026-10-06T04:13:37.289Z | | [create-light-390.png](https://git.kayg.org/attachments/71a64fe0-9f26-4a84-b328-03d120c5c643) | 2026-10-06T04:13:36.733Z | | [create-light-820-alignment-4x.png](https://git.kayg.org/attachments/b0b5e698-ddf7-44e2-870b-f6c1b172093b) | 2026-10-06T04:14:30.196Z | | [create-light-820-header-4x.png](https://git.kayg.org/attachments/b0b5e698-ddf7-44e2-870b-f6c1b172093b) | 2026-10-06T04:14:30.444Z | | [create-light-820.png](https://git.kayg.org/attachments/9b198102-50b0-4103-8c05-6045e3b7b91e) | 2026-10-06T04:14:29.620Z | | [csv-review-light-1440-alignment-4x.png](https://git.kayg.org/attachments/e6a6666c-8ba6-4a9c-86b9-7b3b24032d4c) | 2026-10-06T04:24:50.305Z | | [csv-review-light-1440-header-4x.png](https://git.kayg.org/attachments/e6a6666c-8ba6-4a9c-86b9-7b3b24032d4c) | 2026-10-06T04:24:51.225Z | | [csv-review-light-1440.png](https://git.kayg.org/attachments/9bec4d26-361b-4122-86e3-de6e06be8366) | 2026-10-06T04:24:49.465Z | | [csv-upload-light-1440-alignment-4x.png](https://git.kayg.org/attachments/e6a6666c-8ba6-4a9c-86b9-7b3b24032d4c) | 2026-10-06T04:24:25.566Z | | [csv-upload-light-1440-header-4x.png](https://git.kayg.org/attachments/e6a6666c-8ba6-4a9c-86b9-7b3b24032d4c) | 2026-10-06T04:24:26.214Z | | [csv-upload-light-1440.png](https://git.kayg.org/attachments/a2f2fa76-14cb-4fb9-b5a9-4736866da48b) | 2026-10-06T04:24:24.170Z | | [failure-dark-1440-alignment-4x.png](https://git.kayg.org/attachments/24f360e8-1640-4bbe-96bd-85778f827137) | 2026-10-06T04:19:59.693Z | | [failure-dark-1440-header-4x.png](https://git.kayg.org/attachments/24f360e8-1640-4bbe-96bd-85778f827137) | 2026-10-06T04:20:00.589Z | | [failure-dark-1440.png](https://git.kayg.org/attachments/1ddf49d0-d25a-4358-9b9f-f97493f36448) | 2026-10-06T04:19:58.373Z | | [failure-dark-390-alignment-4x.png](https://git.kayg.org/attachments/de9b8513-2693-47a1-9abf-4a425872c78d) | 2026-10-06T04:17:10.711Z | | [failure-dark-390-header-4x.png](https://git.kayg.org/attachments/de9b8513-2693-47a1-9abf-4a425872c78d) | 2026-10-06T04:17:10.967Z | | [failure-dark-390.png](https://git.kayg.org/attachments/aed50937-1b4a-4c73-88de-55915fc0b94c) | 2026-10-06T04:17:10.471Z | | [failure-dark-820-alignment-4x.png](https://git.kayg.org/attachments/7fa8d16c-cb54-48e1-965b-c8b590f84e83) | 2026-10-06T04:18:27.474Z | | [failure-dark-820-header-4x.png](https://git.kayg.org/attachments/7fa8d16c-cb54-48e1-965b-c8b590f84e83) | 2026-10-06T04:18:27.970Z | | [failure-dark-820.png](https://git.kayg.org/attachments/3b6f3c2c-e28a-4465-a34f-eb28db8daff1) | 2026-10-06T04:18:26.658Z | | [failure-light-1440-alignment-4x.png](https://git.kayg.org/attachments/e6a6666c-8ba6-4a9c-86b9-7b3b24032d4c) | 2026-10-06T04:15:42.136Z | | [failure-light-1440-header-4x.png](https://git.kayg.org/attachments/e6a6666c-8ba6-4a9c-86b9-7b3b24032d4c) | 2026-10-06T04:15:42.596Z | | [failure-light-1440.png](https://git.kayg.org/attachments/b2e067a1-5e12-4664-8d08-891bb732b1ff) | 2026-10-06T04:15:41.356Z | | [failure-light-390-alignment-4x.png](https://git.kayg.org/attachments/5d06172d-0a5e-411c-bd36-c2afaac5aa09) | 2026-10-06T04:13:45.225Z | | [failure-light-390-header-4x.png](https://git.kayg.org/attachments/5d06172d-0a5e-411c-bd36-c2afaac5aa09) | 2026-10-06T04:13:45.473Z | | [failure-light-390.png](https://git.kayg.org/attachments/26a8e9c2-341a-45bb-8b2d-638f778b8f4b) | 2026-10-06T04:13:44.997Z | | [failure-light-820-alignment-4x.png](https://git.kayg.org/attachments/b0b5e698-ddf7-44e2-870b-f6c1b172093b) | 2026-10-06T04:14:38.292Z | | [failure-light-820-header-4x.png](https://git.kayg.org/attachments/b0b5e698-ddf7-44e2-870b-f6c1b172093b) | 2026-10-06T04:14:38.540Z | | [failure-light-820.png](https://git.kayg.org/attachments/12c68f62-02c8-4f51-81a7-b9f2eca019fd) | 2026-10-06T04:14:38.028Z | | [importing-dark-1440-alignment-4x.png](https://git.kayg.org/attachments/24f360e8-1640-4bbe-96bd-85778f827137) | 2026-10-06T04:18:41.802Z | | [importing-dark-1440-header-4x.png](https://git.kayg.org/attachments/24f360e8-1640-4bbe-96bd-85778f827137) | 2026-10-06T04:18:42.230Z | | [importing-dark-1440-progress-4x.png](https://git.kayg.org/attachments/24f360e8-1640-4bbe-96bd-85778f827137) | 2026-10-06T04:18:42.706Z | | [importing-dark-1440.png](https://git.kayg.org/attachments/8d77175b-7c29-4f41-83e6-6bedc1e0211b) | 2026-10-06T04:18:41.274Z | | [importing-dark-390-alignment-4x.png](https://git.kayg.org/attachments/de9b8513-2693-47a1-9abf-4a425872c78d) | 2026-10-06T04:15:55.812Z | | [importing-dark-390-header-4x.png](https://git.kayg.org/attachments/de9b8513-2693-47a1-9abf-4a425872c78d) | 2026-10-06T04:15:56.076Z | | [importing-dark-390-progress-4x.png](https://git.kayg.org/attachments/de9b8513-2693-47a1-9abf-4a425872c78d) | 2026-10-06T04:15:56.292Z | | [importing-dark-390.png](https://git.kayg.org/attachments/ff06d56e-5151-4d2d-9cf9-8ed286589dc9) | 2026-10-06T04:15:55.504Z | | [importing-dark-820-alignment-4x.png](https://git.kayg.org/attachments/7fa8d16c-cb54-48e1-965b-c8b590f84e83) | 2026-10-06T04:17:28.754Z | | [importing-dark-820-header-4x.png](https://git.kayg.org/attachments/7fa8d16c-cb54-48e1-965b-c8b590f84e83) | 2026-10-06T04:17:29.498Z | | [importing-dark-820-progress-4x.png](https://git.kayg.org/attachments/7fa8d16c-cb54-48e1-965b-c8b590f84e83) | 2026-10-06T04:17:29.978Z | | [importing-dark-820.png](https://git.kayg.org/attachments/a520cc69-30d9-473e-9042-fd105e6d924b) | 2026-10-06T04:17:28.254Z | | [importing-details-dark-1440-alignment-4x.png](https://git.kayg.org/attachments/24f360e8-1640-4bbe-96bd-85778f827137) | 2026-10-06T04:18:40.506Z | | [importing-details-dark-1440-header-4x.png](https://git.kayg.org/attachments/24f360e8-1640-4bbe-96bd-85778f827137) | 2026-10-06T04:18:40.942Z | | [importing-details-dark-1440.png](https://git.kayg.org/attachments/b020d939-6dc0-46df-84a4-bc85dd3aef7e) | 2026-10-06T04:18:40.062Z | | [importing-details-dark-390-alignment-4x.png](https://git.kayg.org/attachments/de9b8513-2693-47a1-9abf-4a425872c78d) | 2026-10-06T04:15:54.840Z | | [importing-details-dark-390-header-4x.png](https://git.kayg.org/attachments/de9b8513-2693-47a1-9abf-4a425872c78d) | 2026-10-06T04:15:55.116Z | | [importing-details-dark-390.png](https://git.kayg.org/attachments/d798286f-b616-4f86-8a36-568b1c8f0b1a) | 2026-10-06T04:15:54.592Z | | [importing-details-dark-820-alignment-4x.png](https://git.kayg.org/attachments/7fa8d16c-cb54-48e1-965b-c8b590f84e83) | 2026-10-06T04:17:27.086Z | | [importing-details-dark-820-header-4x.png](https://git.kayg.org/attachments/7fa8d16c-cb54-48e1-965b-c8b590f84e83) | 2026-10-06T04:17:27.630Z | | [importing-details-dark-820.png](https://git.kayg.org/attachments/3a48f7a5-4a15-428f-b002-128b2abd2568) | 2026-10-06T04:17:26.534Z | | [importing-details-light-1440-alignment-4x.png](https://git.kayg.org/attachments/e6a6666c-8ba6-4a9c-86b9-7b3b24032d4c) | 2026-10-06T04:14:49.172Z | | [importing-details-light-1440-header-4x.png](https://git.kayg.org/attachments/e6a6666c-8ba6-4a9c-86b9-7b3b24032d4c) | 2026-10-06T04:14:49.652Z | | [importing-details-light-1440.png](https://git.kayg.org/attachments/ee0bba1e-bac1-477d-885a-96df8c07f4be) | 2026-10-06T04:14:48.652Z | | [importing-details-light-390-alignment-4x.png](https://git.kayg.org/attachments/5d06172d-0a5e-411c-bd36-c2afaac5aa09) | 2026-10-06T04:12:43.762Z | | [importing-details-light-390-header-4x.png](https://git.kayg.org/attachments/5d06172d-0a5e-411c-bd36-c2afaac5aa09) | 2026-10-06T04:12:44.026Z | | [importing-details-light-390.png](https://git.kayg.org/attachments/6a138c9b-b666-4918-b755-7d0baa97b21f) | 2026-10-06T04:12:43.498Z | | [importing-details-light-820-alignment-4x.png](https://git.kayg.org/attachments/b0b5e698-ddf7-44e2-870b-f6c1b172093b) | 2026-10-06T04:13:53.613Z | | [importing-details-light-820-header-4x.png](https://git.kayg.org/attachments/b0b5e698-ddf7-44e2-870b-f6c1b172093b) | 2026-10-06T04:13:53.969Z | | [importing-details-light-820.png](https://git.kayg.org/attachments/507d34e5-ac72-44f5-acf7-ad6b4ae16b4a) | 2026-10-06T04:13:53.305Z | | [importing-light-1440-alignment-4x.png](https://git.kayg.org/attachments/e6a6666c-8ba6-4a9c-86b9-7b3b24032d4c) | 2026-10-06T04:14:51.232Z | | [importing-light-1440-header-4x.png](https://git.kayg.org/attachments/e6a6666c-8ba6-4a9c-86b9-7b3b24032d4c) | 2026-10-06T04:14:52.008Z | | [importing-light-1440-progress-4x.png](https://git.kayg.org/attachments/e6a6666c-8ba6-4a9c-86b9-7b3b24032d4c) | 2026-10-06T04:14:53.660Z | | [importing-light-1440.png](https://git.kayg.org/attachments/5eded138-1c68-4577-8ccf-3a4419534436) | 2026-10-06T04:14:50.568Z | | [importing-light-390-alignment-4x.png](https://git.kayg.org/attachments/5d06172d-0a5e-411c-bd36-c2afaac5aa09) | 2026-10-06T04:12:44.594Z | | [importing-light-390-header-4x.png](https://git.kayg.org/attachments/5d06172d-0a5e-411c-bd36-c2afaac5aa09) | 2026-10-06T04:12:44.874Z | | [importing-light-390-progress-4x.png](https://git.kayg.org/attachments/5d06172d-0a5e-411c-bd36-c2afaac5aa09) | 2026-10-06T04:12:45.086Z | | [importing-light-390.png](https://git.kayg.org/attachments/a13bf300-9dfb-4dbd-8d18-b84fb79f6c9e) | 2026-10-06T04:12:44.350Z | | [importing-light-820-alignment-4x.png](https://git.kayg.org/attachments/b0b5e698-ddf7-44e2-870b-f6c1b172093b) | 2026-10-06T04:13:54.801Z | | [importing-light-820-header-4x.png](https://git.kayg.org/attachments/b0b5e698-ddf7-44e2-870b-f6c1b172093b) | 2026-10-06T04:13:55.153Z | | [importing-light-820-progress-4x.png](https://git.kayg.org/attachments/b0b5e698-ddf7-44e2-870b-f6c1b172093b) | 2026-10-06T04:13:55.497Z | | [importing-light-820.png](https://git.kayg.org/attachments/20824456-7fb4-4032-8ccc-e8bf08672265) | 2026-10-06T04:13:54.453Z | | [json-review-light-1440-alignment-4x.png](https://git.kayg.org/attachments/e6a6666c-8ba6-4a9c-86b9-7b3b24032d4c) | 2026-10-06T04:25:08.725Z | | [json-review-light-1440-header-4x.png](https://git.kayg.org/attachments/e6a6666c-8ba6-4a9c-86b9-7b3b24032d4c) | 2026-10-06T04:25:09.169Z | | [json-review-light-1440.png](https://git.kayg.org/attachments/b6a1ab40-0f5f-4a14-a94f-bfa0df3dc67f) | 2026-10-06T04:25:07.861Z | | [non-budget-failure-light-1440-alignment-4x.png](https://git.kayg.org/attachments/e6a6666c-8ba6-4a9c-86b9-7b3b24032d4c) | 2026-10-06T04:25:41.009Z | | [non-budget-failure-light-1440-header-4x.png](https://git.kayg.org/attachments/e6a6666c-8ba6-4a9c-86b9-7b3b24032d4c) | 2026-10-06T04:25:41.329Z | | [non-budget-failure-light-1440.png](https://git.kayg.org/attachments/e4dd2a10-15e6-4de7-b962-f49a32872b6c) | 2026-10-06T04:25:40.405Z | | [notification-dark-1440-alignment-4x.png](https://git.kayg.org/attachments/24f360e8-1640-4bbe-96bd-85778f827137) | 2026-10-06T04:19:41.913Z | | [notification-dark-1440.png](https://git.kayg.org/attachments/62f651f2-b9d0-4f35-abd8-4a23eadffbe0) | 2026-10-06T04:19:40.681Z | | [notification-dark-390-alignment-4x.png](https://git.kayg.org/attachments/de9b8513-2693-47a1-9abf-4a425872c78d) | 2026-10-06T04:16:59.615Z | | [notification-dark-390.png](https://git.kayg.org/attachments/d713b01a-7e21-4e38-a1e3-a9b23da3aa74) | 2026-10-06T04:16:59.235Z | | [notification-dark-820-alignment-4x.png](https://git.kayg.org/attachments/7fa8d16c-cb54-48e1-965b-c8b590f84e83) | 2026-10-06T04:18:09.554Z | | [notification-dark-820.png](https://git.kayg.org/attachments/9225042c-4b2b-4182-b29e-7ff6a4c7e214) | 2026-10-06T04:18:08.978Z | | [notification-light-1440-alignment-4x.png](https://git.kayg.org/attachments/e6a6666c-8ba6-4a9c-86b9-7b3b24032d4c) | 2026-10-06T04:15:24.712Z | | [notification-light-1440.png](https://git.kayg.org/attachments/142a568d-b0db-4238-ba18-c44327cb030f) | 2026-10-06T04:15:24.008Z | | [notification-light-390-alignment-4x.png](https://git.kayg.org/attachments/5d06172d-0a5e-411c-bd36-c2afaac5aa09) | 2026-10-06T04:13:33.029Z | | [notification-light-390.png](https://git.kayg.org/attachments/2fd303f2-d592-4417-bb1f-ebfba1aa0087) | 2026-10-06T04:13:32.821Z | | [notification-light-820-alignment-4x.png](https://git.kayg.org/attachments/b0b5e698-ddf7-44e2-870b-f6c1b172093b) | 2026-10-06T04:14:25.073Z | | [notification-light-820.png](https://git.kayg.org/attachments/01542ec7-c112-4e9e-8f5a-4a35be101a3e) | 2026-10-06T04:14:24.769Z | | [replacement-notification-light-1440.png](https://git.kayg.org/attachments/49e730e3-d3b1-4a78-98e9-ac1444180924) | 2026-10-06T04:25:26.533Z | | [start-dark-1440-alignment-4x.png](https://git.kayg.org/attachments/24f360e8-1640-4bbe-96bd-85778f827137) | 2026-10-06T04:18:33.130Z | | [start-dark-1440-header-4x.png](https://git.kayg.org/attachments/24f360e8-1640-4bbe-96bd-85778f827137) | 2026-10-06T04:18:33.690Z | | [start-dark-1440.png](https://git.kayg.org/attachments/0c929211-92d8-4c70-a800-895316d265d6) | 2026-10-06T04:18:32.226Z | | [start-dark-390-alignment-4x.png](https://git.kayg.org/attachments/de9b8513-2693-47a1-9abf-4a425872c78d) | 2026-10-06T04:15:47.476Z | | [start-dark-390-header-4x.png](https://git.kayg.org/attachments/de9b8513-2693-47a1-9abf-4a425872c78d) | 2026-10-06T04:15:47.728Z | | [start-dark-390.png](https://git.kayg.org/attachments/f9c9c29f-83b4-4d70-a2de-6e6a743d8992) | 2026-10-06T04:15:47.180Z | | [start-dark-820-alignment-4x.png](https://git.kayg.org/attachments/7fa8d16c-cb54-48e1-965b-c8b590f84e83) | 2026-10-06T04:17:15.375Z | | [start-dark-820-header-4x.png](https://git.kayg.org/attachments/7fa8d16c-cb54-48e1-965b-c8b590f84e83) | 2026-10-06T04:17:15.623Z | | [start-dark-820.png](https://git.kayg.org/attachments/cdfd6e66-d5b7-4cb8-835a-7a23ac7cb8c5) | 2026-10-06T04:17:14.099Z | | [start-light-1440-alignment-4x.png](https://git.kayg.org/attachments/e6a6666c-8ba6-4a9c-86b9-7b3b24032d4c) | 2026-10-06T04:14:41.948Z | | [start-light-1440-header-4x.png](https://git.kayg.org/attachments/e6a6666c-8ba6-4a9c-86b9-7b3b24032d4c) | 2026-10-06T04:14:42.324Z | | [start-light-1440.png](https://git.kayg.org/attachments/e2955c28-55da-41cf-9a3e-8e3c178d4af5) | 2026-10-06T04:14:41.324Z | | [start-light-390-alignment-4x.png](https://git.kayg.org/attachments/5d06172d-0a5e-411c-bd36-c2afaac5aa09) | 2026-10-06T04:12:39.358Z | | [start-light-390-header-4x.png](https://git.kayg.org/attachments/5d06172d-0a5e-411c-bd36-c2afaac5aa09) | 2026-10-06T04:12:39.566Z | | [start-light-390.png](https://git.kayg.org/attachments/61f176ea-0ea1-4e1e-b860-8a4d9879eda9) | 2026-10-06T04:12:39.066Z | | [start-light-820-alignment-4x.png](https://git.kayg.org/attachments/b0b5e698-ddf7-44e2-870b-f6c1b172093b) | 2026-10-06T04:13:48.273Z | | [start-light-820-header-4x.png](https://git.kayg.org/attachments/b0b5e698-ddf7-44e2-870b-f6c1b172093b) | 2026-10-06T04:13:48.461Z | | [start-light-820.png](https://git.kayg.org/attachments/911839eb-8bfa-4faf-ad99-a646bd004255) | 2026-10-06T04:13:48.097Z | | [success-dark-1440-alignment-4x.png](https://git.kayg.org/attachments/24f360e8-1640-4bbe-96bd-85778f827137) | 2026-10-06T04:19:35.741Z | | [success-dark-1440-header-4x.png](https://git.kayg.org/attachments/24f360e8-1640-4bbe-96bd-85778f827137) | 2026-10-06T04:19:36.481Z | | [success-dark-1440.png](https://git.kayg.org/attachments/0f27a40a-02f1-4820-98d0-e4b77738a5de) | 2026-10-06T04:19:35.081Z | | [success-dark-390-alignment-4x.png](https://git.kayg.org/attachments/de9b8513-2693-47a1-9abf-4a425872c78d) | 2026-10-06T04:16:55.851Z | | [success-dark-390-header-4x.png](https://git.kayg.org/attachments/de9b8513-2693-47a1-9abf-4a425872c78d) | 2026-10-06T04:16:56.227Z | | [success-dark-390.png](https://git.kayg.org/attachments/3caaa5e7-5b3f-4e1d-80b6-8cd0daa216e6) | 2026-10-06T04:16:55.451Z | | [success-dark-820-alignment-4x.png](https://git.kayg.org/attachments/7fa8d16c-cb54-48e1-965b-c8b590f84e83) | 2026-10-06T04:18:03.874Z | | [success-dark-820-header-4x.png](https://git.kayg.org/attachments/7fa8d16c-cb54-48e1-965b-c8b590f84e83) | 2026-10-06T04:18:04.522Z | | [success-dark-820.png](https://git.kayg.org/attachments/7a742087-cfc8-4ca4-a538-c953184b4ddd) | 2026-10-06T04:18:03.434Z | | [success-light-1440-alignment-4x.png](https://git.kayg.org/attachments/e6a6666c-8ba6-4a9c-86b9-7b3b24032d4c) | 2026-10-06T04:15:20.456Z | | [success-light-1440-header-4x.png](https://git.kayg.org/attachments/e6a6666c-8ba6-4a9c-86b9-7b3b24032d4c) | 2026-10-06T04:15:21.072Z | | [success-light-1440.png](https://git.kayg.org/attachments/0cae4272-9b26-426b-bde8-459952e7ad7c) | 2026-10-06T04:15:19.760Z | | [success-light-390-alignment-4x.png](https://git.kayg.org/attachments/5d06172d-0a5e-411c-bd36-c2afaac5aa09) | 2026-10-06T04:13:30.625Z | | [success-light-390-header-4x.png](https://git.kayg.org/attachments/5d06172d-0a5e-411c-bd36-c2afaac5aa09) | 2026-10-06T04:13:30.813Z | | [success-light-390.png](https://git.kayg.org/attachments/7770aeda-5428-4241-a2a6-b8a9d3d6346a) | 2026-10-06T04:13:30.149Z | | [success-light-820-alignment-4x.png](https://git.kayg.org/attachments/b0b5e698-ddf7-44e2-870b-f6c1b172093b) | 2026-10-06T04:14:20.081Z | | [success-light-820-header-4x.png](https://git.kayg.org/attachments/b0b5e698-ddf7-44e2-870b-f6c1b172093b) | 2026-10-06T04:14:20.565Z | | [success-light-820.png](https://git.kayg.org/attachments/bcbf64e1-97b8-4e07-b7dd-0afa6a65f0c4) | 2026-10-06T04:14:19.725Z | | [success-review-dark-1440-alignment-4x.png](https://git.kayg.org/attachments/24f360e8-1640-4bbe-96bd-85778f827137) | 2026-10-06T04:19:29.557Z | | [success-review-dark-1440-header-4x.png](https://git.kayg.org/attachments/24f360e8-1640-4bbe-96bd-85778f827137) | 2026-10-06T04:19:30.625Z | | [success-review-dark-1440.png](https://git.kayg.org/attachments/8fcc2b7b-620f-43d1-ba34-1226eea0a459) | 2026-10-06T04:19:28.077Z | | [success-review-dark-390-alignment-4x.png](https://git.kayg.org/attachments/de9b8513-2693-47a1-9abf-4a425872c78d) | 2026-10-06T04:16:52.031Z | | [success-review-dark-390-header-4x.png](https://git.kayg.org/attachments/de9b8513-2693-47a1-9abf-4a425872c78d) | 2026-10-06T04:16:52.411Z | | [success-review-dark-390.png](https://git.kayg.org/attachments/7a54c06e-bc89-41e2-8b3a-ae9598983712) | 2026-10-06T04:16:51.607Z | | [success-review-dark-820-alignment-4x.png](https://git.kayg.org/attachments/7fa8d16c-cb54-48e1-965b-c8b590f84e83) | 2026-10-06T04:17:53.722Z | | [success-review-dark-820-header-4x.png](https://git.kayg.org/attachments/7fa8d16c-cb54-48e1-965b-c8b590f84e83) | 2026-10-06T04:17:54.390Z | | [success-review-dark-820.png](https://git.kayg.org/attachments/c6917009-705e-4798-848b-3b3e0365bf3f) | 2026-10-06T04:17:53.222Z | | [success-review-light-1440-alignment-4x.png](https://git.kayg.org/attachments/e6a6666c-8ba6-4a9c-86b9-7b3b24032d4c) | 2026-10-06T04:15:15.500Z | | [success-review-light-1440-header-4x.png](https://git.kayg.org/attachments/e6a6666c-8ba6-4a9c-86b9-7b3b24032d4c) | 2026-10-06T04:15:16.192Z | | [success-review-light-1440.png](https://git.kayg.org/attachments/df58c0c9-0217-4536-b8a1-db64f3adc2d7) | 2026-10-06T04:15:14.612Z | | [success-review-light-390-alignment-4x.png](https://git.kayg.org/attachments/5d06172d-0a5e-411c-bd36-c2afaac5aa09) | 2026-10-06T04:13:25.665Z | | [success-review-light-390-header-4x.png](https://git.kayg.org/attachments/5d06172d-0a5e-411c-bd36-c2afaac5aa09) | 2026-10-06T04:13:25.893Z | | [success-review-light-390.png](https://git.kayg.org/attachments/64192cce-dfab-4c37-aa00-4cb4762cc174) | 2026-10-06T04:13:25.401Z | | [success-review-light-820-alignment-4x.png](https://git.kayg.org/attachments/b0b5e698-ddf7-44e2-870b-f6c1b172093b) | 2026-10-06T04:14:16.493Z | | [success-review-light-820-header-4x.png](https://git.kayg.org/attachments/b0b5e698-ddf7-44e2-870b-f6c1b172093b) | 2026-10-06T04:14:17.013Z | | [success-review-light-820.png](https://git.kayg.org/attachments/9d9f3f96-d60b-4626-aa1b-94772abb59d2) | 2026-10-06T04:14:15.933Z | | [upload-dark-1440-alignment-4x.png](https://git.kayg.org/attachments/24f360e8-1640-4bbe-96bd-85778f827137) | 2026-10-06T04:18:38.274Z | | [upload-dark-1440-header-4x.png](https://git.kayg.org/attachments/24f360e8-1640-4bbe-96bd-85778f827137) | 2026-10-06T04:18:38.822Z | | [upload-dark-1440.png](https://git.kayg.org/attachments/8b489fd8-9f90-485b-ad11-dc057887f0b2) | 2026-10-06T04:18:37.710Z | | [upload-dark-390-alignment-4x.png](https://git.kayg.org/attachments/de9b8513-2693-47a1-9abf-4a425872c78d) | 2026-10-06T04:15:52.864Z | | [upload-dark-390-header-4x.png](https://git.kayg.org/attachments/de9b8513-2693-47a1-9abf-4a425872c78d) | 2026-10-06T04:15:53.200Z | | [upload-dark-390.png](https://git.kayg.org/attachments/8004bb49-518b-481a-a820-16726c4e4b0f) | 2026-10-06T04:15:52.620Z | | [upload-dark-820-alignment-4x.png](https://git.kayg.org/attachments/7fa8d16c-cb54-48e1-965b-c8b590f84e83) | 2026-10-06T04:17:24.455Z | | [upload-dark-820-header-4x.png](https://git.kayg.org/attachments/7fa8d16c-cb54-48e1-965b-c8b590f84e83) | 2026-10-06T04:17:24.695Z | | [upload-dark-820.png](https://git.kayg.org/attachments/718ab21d-4745-4b93-b235-b26c3c411ce3) | 2026-10-06T04:17:23.795Z | | [upload-light-1440-alignment-4x.png](https://git.kayg.org/attachments/e6a6666c-8ba6-4a9c-86b9-7b3b24032d4c) | 2026-10-06T04:14:46.424Z | | [upload-light-1440-header-4x.png](https://git.kayg.org/attachments/e6a6666c-8ba6-4a9c-86b9-7b3b24032d4c) | 2026-10-06T04:14:46.860Z | | [upload-light-1440.png](https://git.kayg.org/attachments/c1ae60da-2655-4366-ba15-a01b279b8c4d) | 2026-10-06T04:14:45.996Z | | [upload-light-390-alignment-4x.png](https://git.kayg.org/attachments/5d06172d-0a5e-411c-bd36-c2afaac5aa09) | 2026-10-06T04:12:42.246Z | | [upload-light-390-header-4x.png](https://git.kayg.org/attachments/5d06172d-0a5e-411c-bd36-c2afaac5aa09) | 2026-10-06T04:12:42.414Z | | [upload-light-390.png](https://git.kayg.org/attachments/6554aec4-2ad9-4f92-8c1d-32deada001d6) | 2026-10-06T04:12:42.090Z | | [upload-light-820-alignment-4x.png](https://git.kayg.org/attachments/b0b5e698-ddf7-44e2-870b-f6c1b172093b) | 2026-10-06T04:13:51.649Z | | [upload-light-820-header-4x.png](https://git.kayg.org/attachments/b0b5e698-ddf7-44e2-870b-f6c1b172093b) | 2026-10-06T04:13:51.849Z | | [upload-light-820.png](https://git.kayg.org/attachments/0cf16a62-14f5-4d37-9223-3ecf823b08dd) | 2026-10-06T04:13:51.489Z |
Author
Owner

Independent review started on job/wizard-1140, head 02050bea9c6bc889f5d0c7739a3a242100676049. I will check source balance evidence, durable queue replay, cancellation, replacement Undo, User isolation and malformed input. Findings and regressions go in review-1140.md. No push or deploy.

Independent review started on `job/wizard-1140`, head `02050bea9c6bc889f5d0c7739a3a242100676049`. I will check source balance evidence, durable queue replay, cancellation, replacement Undo, User isolation and malformed input. Findings and regressions go in `review-1140.md`. No push or deploy.
Author
Owner

Independent review findings at 02050bea9:

  • confirm_import removes its pending preview before it takes the Budget write lock. publish_import does not check cancellation while it writes files or before rename. I added a deterministic regression which holds that lock and cancels after preview consumption.
  • cancel_import_job replaces a published in-memory result with Import cancelled. No Budget was created. even though the Budget exists. A regression requires its published result to remain unchanged.
  • undoImport calls Files Trash after listBudgets; it does not compare the Budget files with the publication receipt. Later User edits can therefore be removed without a refusal or merge.
  • Replacement uses two browser requests: Files Trash, then Money confirm. No server replacement intent owns the gap between those requests. A different Installation cannot recover the old receipt if the browser stops before confirm.

I will fix the cancellation defects separately. The replacement and conditional Undo gaps remain merge blockers until their server-owned transaction design is supplied. Evidence is recorded in review-1140.md.

Independent review findings at `02050bea9`: - `confirm_import` removes its pending preview before it takes the Budget write lock. `publish_import` does not check cancellation while it writes files or before rename. I added a deterministic regression which holds that lock and cancels after preview consumption. - `cancel_import_job` replaces a published in-memory result with `Import cancelled. No Budget was created.` even though the Budget exists. A regression requires its published result to remain unchanged. - `undoImport` calls Files Trash after `listBudgets`; it does not compare the Budget files with the publication receipt. Later User edits can therefore be removed without a refusal or merge. - Replacement uses two browser requests: Files Trash, then Money confirm. No server replacement intent owns the gap between those requests. A different Installation cannot recover the old receipt if the browser stops before confirm. I will fix the cancellation defects separately. The replacement and conditional Undo gaps remain merge blockers until their server-owned transaction design is supplied. Evidence is recorded in `review-1140.md`.
Author
Owner

Committed cancellation fixes as 89a57d00d78b7491a05285b9cd91a574b2519a13.

Both new regressions failed on the starting code. Cancellation before publication returned 201 and created a Budget. Cancellation after publication returned a failure with a created Budget ID. Both now pass. Publication shares the cancellation token, checks each file and checks the token immediately before the synchronous rename. Cancel after rename preserves success. Preview and job cancellation use the same handler. Synchronous previews keep their token after normal request completion.

The new check_cancelled checkpoint omits the parser deadline because time spent reviewing is not execution time. This is the only new decision in this fix.

Money Clippy:

    Finished `dev` profile [unoptimized + debuginfo] target(s) in 8.36s

Money tests:

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 104 filtered out; finished in 34.06s
test result: ok. 104 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 49.84s
test result: ok. 27 passed; 0 failed; 3 ignored; 0 measured; 0 filtered out; finished in 10.92s
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

No existing test expectation was changed. Independent format/input checks are next. Merge blockers are tracked in #1177 and #1178.

Committed cancellation fixes as `89a57d00d78b7491a05285b9cd91a574b2519a13`. Both new regressions failed on the starting code. Cancellation before publication returned 201 and created a Budget. Cancellation after publication returned a failure with a created Budget ID. Both now pass. Publication shares the cancellation token, checks each file and checks the token immediately before the synchronous rename. Cancel after rename preserves success. Preview and job cancellation use the same handler. Synchronous previews keep their token after normal request completion. The new `check_cancelled` checkpoint omits the parser deadline because time spent reviewing is not execution time. This is the only new decision in this fix. Money Clippy: ```text Finished `dev` profile [unoptimized + debuginfo] target(s) in 8.36s ``` Money tests: ```text test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 104 filtered out; finished in 34.06s test result: ok. 104 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 49.84s test result: ok. 27 passed; 0 failed; 3 ignored; 0 measured; 0 filtered out; finished in 10.92s test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s ``` No existing test expectation was changed. Independent format/input checks are next. Merge blockers are tracked in #1177 and #1178.
Author
Owner

Independent review update: cancellation now reconciles a complete Budget after rename when its receipt finalization has not completed. The regression keeps the replacement Trash receipt and the same published identity. Discard after a target-name conflict releases durable admission without changing the existing missing-preview status. Eight independent review regressions cover these boundaries, totals for all three adapters, ordinary User isolation, malformed local HTTP uploads, staged limits and terminal-cache eviction.

Server gate findings were filed as #1184: two unchanged upgrade tests omit Notifications 0007 (actual migration total 144, expected 143). Shared Admin visibility/control is filed as #1183. Replacement durability (#1178) and Undo after later edits (#1177) remain blockers. Final exact pins and gates are running; no push or merge was performed.

Independent review update: cancellation now reconciles a complete Budget after rename when its receipt finalization has not completed. The regression keeps the replacement Trash receipt and the same published identity. Discard after a target-name conflict releases durable admission without changing the existing missing-preview status. Eight independent review regressions cover these boundaries, totals for all three adapters, ordinary User isolation, malformed local HTTP uploads, staged limits and terminal-cache eviction. Server gate findings were filed as #1184: two unchanged upgrade tests omit Notifications 0007 (actual migration total 144, expected 143). Shared Admin visibility/control is filed as #1183. Replacement durability (#1178) and Undo after later edits (#1177) remain blockers. Final exact pins and gates are running; no push or merge was performed.
Author
Owner

SAFE TO MERGE: no. Head 96ec6f04203a10cefcf9c1f97e66335761d2a416 (code head be41fb067).

Built: shared publication cancellation checkpoints; correct published outcomes after cancellation or receipt-finalization failure; bounded durable terminal read-cache admission; discard admission after a failed confirmation; eight independent review regressions. Account totals use raw source sums for Actual ZIP, YNAB JSON and the YNAB CSV pair. Transfer legs, closed Accounts where exported, unchanged transaction arrays after replay, UTF-8 BOM/CRLF, ordinary User isolation, malformed local HTTP files and staged upload limits are checked.

Files: crates/plugins/money/src/{routes,import,durable_import,review_1140,tests}.rs; contracts/perf/{registry,exceptions,adoption-1058}.json; review-1140.md. Exact performance pins and typed pure-call bindings changed; no scope, limit or ratchet was raised.

Known gaps: #1177 Undo silently removes later edits; #1178 replacement/Undo lack durable server intent across separate requests; #1183 shared Admin job visibility and controls need an explicit Role policy; #1184 protected server upgrade tests omit Notifications 0007. The review limits, UX gaps, decisions, merge-round commands and verbatim gate summaries follow. No existing test assertion changed. No push or deploy. Cargo cleanup removed 12.0 GiB and web build output was deleted.

Independent Money import review (#1140)

Reviewed starting head: 02050bea9c6bc889f5d0c7739a3a242100676049.
Branch: job/wizard-1140. No push or deploy.

Findings

  • Publication consumes a preview before it obtains the Budget write lock. It has no cancellation checkpoint during file writes or before the folder rename. A Cancel can return 204 while that confirmation still creates a Budget. A deterministic lock test is added in review_1140.rs.
  • Cancel after publication changes the in-memory result to failure, although the durable result and Budget still exist. A regression test requires the published result to stay unchanged.
  • Import Undo uses the shared Files Trash action without an import revision check. A later User edit is not checked before removal. This needs a server-owned conditional inverse. Filed as #1177.
  • Replacement first trashes the old Budget in the browser, then sends confirmation. A crash between those requests has no server-owned replacement intent. The browser stores the receipt, but a different Installation cannot recover it before confirmation records it. Filed as #1178.

Verification

Both publication regressions failed on the starting code. The lock test returned
201 after cancellation. The published result test returned state: failed with
a created Budget identity. After the fix, both focused regressions pass.

The fix carries cancellation into publication, checks each file and the final
rename, and serializes terminal cancellation with the Budget write lock. It keeps
a completed publication successful. Synchronous previews keep their control token
after the parser request returns. User review time does not consume the parser
execution deadline.

The final verdict is SAFE TO MERGE: no. Replacement durability (#1178) and
Undo after later edits (#1177) still need server changes. The additional
Admin policy gap (#1183) and protected upgrade failures (#1184) also need
an orchestrator decision.

Independent checks added

  • review1140_all_formats_replay_exact_balances: raw source sums are the
    oracle for each Account in actual-zip, ynab-json and ynab-csv. It checks
    closed Accounts where the source has that field, both transfer legs, split
    totals, UTF-8 BOM and CRLF CSV, restart from a ready preview, and recovery
    after publication before the receipt commit. Confirmation still returns the
    same identity, and only one Budget exists.
  • The same test checks denied progress, result, Cancel and confirm requests
    from another User. Existing durable tests cover private receipt reads after
    restart and older receipt lookup.
  • review1140_tcp_malformed_inputs_leave_worker_usable: one local TCP round
    rejects a corrupt ZIP, a ZIP with no database, malformed JSON and invalid
    CSV encodings. Each failure has fixed plain text, leaves no Budget and
    releases admission. The same Worker then accepts a valid export.
  • review1140_staged_size_limits_fail_without_publishing: streamed test files
    check the JSON adapter cap and the aggregate upload cap. The Worker does not
    publish a Budget. Test data uses the worktree TMPDIR.
  • The eight review tests cover terminal-cache admission, unchanged transaction arrays after receipt recovery, cancellation after rename before receipt finalization, and admission after a failed confirmation. No existing test expectation was changed.
  • The #1170 browser session tests pass: 29 tests. Their unchanged-count
    recovery case completes without the old six-second cancellation.

Limits of the review

The queue tests use real SQLite and restart route state. They do not kill a
server process during every individual write. Publication-before-receipt
recovery is tested by removing only the saved receipt after the folder rename.
The TCP tests use the production Money router with test-only authenticated
Users. They do not replace full-server authentication tests. Archive byte and
expanded database limits were inspected; this round does not execute a large
compression bomb. Notification drafts take the owner User from the queue row;
no independent notification delivery fault test was added.

The original branch has browser evidence for replacement confirmation and Undo
from another Installation. It does not cover later edits or the gap between
Trash and confirmation. The two filed blockers remain open.

Terminal job admission finding

The receiver counts every in-memory job toward a limit of 32. Successful and
failed outcomes are retained even when no preview is pending. Thus terminal
records can block later imports on the whole Instance. The fix evicts the oldest
terminal read-cache records, but keeps receiving, parsing and ready previews.
The durable queue restores evicted results through User-bound lookups. The same
helper bounds restart hydration and Worker insertion. A test seeds 32 safe
terminal records, admits a valid import and reads an evicted failure again.

The performance guard has exact tested bindings for the helper's HashMap,
String, Option and Instant operations. These calls have no file or provider IO.
The existing Money pins have 44 hash updates. Exception scopes, limits, owners,
expiry dates and ratchet values are unchanged. No guard rule was changed.

Privileged job visibility

Money routes pass ordinary cross-User tests. Shared Admin job list and detail
routes read summaries without a User filter. Shared Admin queue controls can
retry or resume the money.import kind. They expose job IDs, state and counts,
not export bytes, preview data or receipts. This conflicts with the review's
unqualified isolation rule and needs a reviewed Role exception or a restriction.
No shared Admin behavior was changed in this Money review. Filed as #1183.

Finalization and failed-confirmation findings

A receipt write can fail after the complete Budget folder is renamed. Cancel
now checks for that stable Budget identity under the write lock and settles the
existing receipt. It keeps the replacement Trash identity and reports the
published outcome. Restart hydration gives a complete Budget priority over a
stale cancellation error. A test removes the saved publication result, retains
the replacement receipt, and cancels in the same process. The Budget and receipt
remain intact.

A name conflict consumes the scratch preview before publication. Discard now
clears the durable preview through the shared cancellation path, so the next
import can start. Its existing missing-preview 404 status stays unchanged. A
regression test checks the conflict, discard and subsequent admission.

Server gate findings

Two protected upgrade tests expect Notifications migrations only through 0006,
but the wizard branch adds 0007. The actual migration list has notifications 7;
the actual total is 144 instead of 143. The expectations remain unchanged under
the owner rule. Filed as #1184 for the orchestrator's decision. The separate
process test also times out waiting 15 seconds for startup on this shared host.
This is a SLOW-only result; the two schema mismatches are not SLOW.

Decisions

  • User review time does not use the parser execution deadline. Publication
    checks cancellation without that deadline.
  • Evict only terminal read-cache entries, ordered by expiry. Retain active
    receive, parse and ready controls. Restore evicted results from the queue.
  • The complete renamed Budget is the publication authority. Receipt recovery
    keeps its stable identity and replacement receipt.
  • Keep the missing-preview 404 contract after failed confirmation. Clear its
    owner-bound durable admission as part of that discard attempt.

UX gaps closed

Cancel cannot acknowledge an unpublished import and then let it publish. A
published import keeps its success result. Completed job records cannot block
new imports. Discard after a failed confirmation releases admission.

UX gaps left

Undo does not check later edits. Replacement and Undo each span separate
requests without durable server intent. These are #1177 and #1178. No UI code
changed in this review; the original branch owns the existing screenshot set.

Scope and merge-round work

This review added focused reliability verification. It ran its local TCP
malformed-input round and its restart regressions. Full adversarial matrices,
full browser e2e, deployment and Apple-client interop remain merge-round work.
Do not substitute the focused tests for those combined-branch checks. The
blocking replacement and Undo work must land before that round can approve.

No dependency version was changed. No performance timing was run: this issue is
a correctness review. Exact performance-guard pins were refreshed without
changing exception scopes, limits, owners, expiry dates or ratchet values.

For the merge round, after the blocking fixes:

  • cargo test -p calternal-server -- --test-threads=4: prove the reviewed
    Notifications upgrade contract and all shared server tests.
  • cd apps/web && bun e2e/money-wizard-1140.mjs: prove the full wizard flow
    and its platform, width and theme evidence on the combined branch.
  • bash tests/adversarial/run-split.sh: prove the combined server's
    authorization, cross-User and malformed-input matrices.

Final gates (verbatim summary lines)

The full Money suite preceded the final Clippy expression correction. The
eight focused review tests then passed on code head be41fb067. The origin/dev
merge was already up to date. Rust gates used four build jobs and four test
threads. Web tests used two Workers.

cargo fmt --check

Exit 0; no output.

cargo clippy -p calternal-plugin-money --all-targets -- -D warnings

    Finished `dev` profile [unoptimized + debuginfo] target(s) in 2m 31s

cargo test -p calternal-plugin-money -- --test-threads=4

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 110 filtered out; finished in 65.05s
test result: ok. 110 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 91.33s
test result: ok. 27 passed; 0 failed; 3 ignored; 0 measured; 0 filtered out; finished in 14.88s
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

cargo test -p calternal-plugin-money review_1140 -- --test-threads=4

test result: ok. 8 passed; 0 failed; 0 ignored; 0 measured; 103 filtered out; finished in 9.48s
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 30 filtered out; finished in 0.00s

cargo clippy -p calternal-server --all-targets -- -D warnings

    Finished `dev` profile [unoptimized + debuginfo] target(s) in 1m 04s

cargo test -p calternal-server -- --test-threads=4

test result: FAILED. 253 passed; 3 failed; 10 ignored; 0 measured; 0 filtered out; finished in 74.17s

cargo test -p calternal-server --test perf_guards -- --test-threads=4

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 91.74s

cd apps/web && bun run check

perf-lint: PASS; 0 violations; 22177 scoped exceptions
svelte-check found 0 errors and 4 warnings in 3 files

cd apps/web && bun run test -- --maxWorkers=2

 Test Files  271 passed (271)
      Tests  1878 passed (1878)

Full logs stay in artifacts/wizardrev-1140/. The full server failure is
253 passed, three failed and ten ignored: two schema expectations (#1184) and
one SLOW-only startup timeout. Existing assertions remain unchanged.

Cleanup: Cargo removed 17,939 files, 12.0 GiB. Web production output was deleted.
No push, deploy or branch merge into dev was performed.

SAFE TO MERGE: **no**. Head `96ec6f04203a10cefcf9c1f97e66335761d2a416` (code head `be41fb067`). Built: shared publication cancellation checkpoints; correct published outcomes after cancellation or receipt-finalization failure; bounded durable terminal read-cache admission; discard admission after a failed confirmation; eight independent review regressions. Account totals use raw source sums for Actual ZIP, YNAB JSON and the YNAB CSV pair. Transfer legs, closed Accounts where exported, unchanged transaction arrays after replay, UTF-8 BOM/CRLF, ordinary User isolation, malformed local HTTP files and staged upload limits are checked. Files: `crates/plugins/money/src/{routes,import,durable_import,review_1140,tests}.rs`; `contracts/perf/{registry,exceptions,adoption-1058}.json`; `review-1140.md`. Exact performance pins and typed pure-call bindings changed; no scope, limit or ratchet was raised. Known gaps: #1177 Undo silently removes later edits; #1178 replacement/Undo lack durable server intent across separate requests; #1183 shared Admin job visibility and controls need an explicit Role policy; #1184 protected server upgrade tests omit Notifications 0007. The review limits, UX gaps, decisions, merge-round commands and verbatim gate summaries follow. No existing test assertion changed. No push or deploy. Cargo cleanup removed 12.0 GiB and web build output was deleted. # Independent Money import review (#1140) Reviewed starting head: `02050bea9c6bc889f5d0c7739a3a242100676049`. Branch: `job/wizard-1140`. No push or deploy. ## Findings - Publication consumes a preview before it obtains the Budget write lock. It has no cancellation checkpoint during file writes or before the folder rename. A Cancel can return 204 while that confirmation still creates a Budget. A deterministic lock test is added in `review_1140.rs`. - Cancel after publication changes the in-memory result to failure, although the durable result and Budget still exist. A regression test requires the published result to stay unchanged. - Import Undo uses the shared Files Trash action without an import revision check. A later User edit is not checked before removal. This needs a server-owned conditional inverse. Filed as #1177. - Replacement first trashes the old Budget in the browser, then sends confirmation. A crash between those requests has no server-owned replacement intent. The browser stores the receipt, but a different Installation cannot recover it before confirmation records it. Filed as #1178. ## Verification Both publication regressions failed on the starting code. The lock test returned 201 after cancellation. The published result test returned `state: failed` with a created Budget identity. After the fix, both focused regressions pass. The fix carries cancellation into publication, checks each file and the final rename, and serializes terminal cancellation with the Budget write lock. It keeps a completed publication successful. Synchronous previews keep their control token after the parser request returns. User review time does not consume the parser execution deadline. The final verdict is SAFE TO MERGE: **no**. Replacement durability (#1178) and Undo after later edits (#1177) still need server changes. The additional Admin policy gap (#1183) and protected upgrade failures (#1184) also need an orchestrator decision. ## Independent checks added - `review1140_all_formats_replay_exact_balances`: raw source sums are the oracle for each Account in `actual-zip`, `ynab-json` and `ynab-csv`. It checks closed Accounts where the source has that field, both transfer legs, split totals, UTF-8 BOM and CRLF CSV, restart from a ready preview, and recovery after publication before the receipt commit. Confirmation still returns the same identity, and only one Budget exists. - The same test checks denied progress, result, Cancel and confirm requests from another User. Existing durable tests cover private receipt reads after restart and older receipt lookup. - `review1140_tcp_malformed_inputs_leave_worker_usable`: one local TCP round rejects a corrupt ZIP, a ZIP with no database, malformed JSON and invalid CSV encodings. Each failure has fixed plain text, leaves no Budget and releases admission. The same Worker then accepts a valid export. - `review1140_staged_size_limits_fail_without_publishing`: streamed test files check the JSON adapter cap and the aggregate upload cap. The Worker does not publish a Budget. Test data uses the worktree TMPDIR. - The eight review tests cover terminal-cache admission, unchanged transaction arrays after receipt recovery, cancellation after rename before receipt finalization, and admission after a failed confirmation. No existing test expectation was changed. - The #1170 browser session tests pass: 29 tests. Their unchanged-count recovery case completes without the old six-second cancellation. ## Limits of the review The queue tests use real SQLite and restart route state. They do not kill a server process during every individual write. Publication-before-receipt recovery is tested by removing only the saved receipt after the folder rename. The TCP tests use the production Money router with test-only authenticated Users. They do not replace full-server authentication tests. Archive byte and expanded database limits were inspected; this round does not execute a large compression bomb. Notification drafts take the owner User from the queue row; no independent notification delivery fault test was added. The original branch has browser evidence for replacement confirmation and Undo from another Installation. It does not cover later edits or the gap between Trash and confirmation. The two filed blockers remain open. ## Terminal job admission finding The receiver counts every in-memory job toward a limit of 32. Successful and failed outcomes are retained even when no preview is pending. Thus terminal records can block later imports on the whole Instance. The fix evicts the oldest terminal read-cache records, but keeps receiving, parsing and ready previews. The durable queue restores evicted results through User-bound lookups. The same helper bounds restart hydration and Worker insertion. A test seeds 32 safe terminal records, admits a valid import and reads an evicted failure again. The performance guard has exact tested bindings for the helper's HashMap, String, Option and Instant operations. These calls have no file or provider IO. The existing Money pins have 44 hash updates. Exception scopes, limits, owners, expiry dates and ratchet values are unchanged. No guard rule was changed. ## Privileged job visibility Money routes pass ordinary cross-User tests. Shared Admin job list and detail routes read summaries without a User filter. Shared Admin queue controls can retry or resume the `money.import` kind. They expose job IDs, state and counts, not export bytes, preview data or receipts. This conflicts with the review's unqualified isolation rule and needs a reviewed Role exception or a restriction. No shared Admin behavior was changed in this Money review. Filed as #1183. ## Finalization and failed-confirmation findings A receipt write can fail after the complete Budget folder is renamed. Cancel now checks for that stable Budget identity under the write lock and settles the existing receipt. It keeps the replacement Trash identity and reports the published outcome. Restart hydration gives a complete Budget priority over a stale cancellation error. A test removes the saved publication result, retains the replacement receipt, and cancels in the same process. The Budget and receipt remain intact. A name conflict consumes the scratch preview before publication. Discard now clears the durable preview through the shared cancellation path, so the next import can start. Its existing missing-preview 404 status stays unchanged. A regression test checks the conflict, discard and subsequent admission. ## Server gate findings Two protected upgrade tests expect Notifications migrations only through 0006, but the wizard branch adds 0007. The actual migration list has notifications 7; the actual total is 144 instead of 143. The expectations remain unchanged under the owner rule. Filed as #1184 for the orchestrator's decision. The separate process test also times out waiting 15 seconds for startup on this shared host. This is a SLOW-only result; the two schema mismatches are not SLOW. ## Decisions - User review time does not use the parser execution deadline. Publication checks cancellation without that deadline. - Evict only terminal read-cache entries, ordered by expiry. Retain active receive, parse and ready controls. Restore evicted results from the queue. - The complete renamed Budget is the publication authority. Receipt recovery keeps its stable identity and replacement receipt. - Keep the missing-preview 404 contract after failed confirmation. Clear its owner-bound durable admission as part of that discard attempt. ## UX gaps closed Cancel cannot acknowledge an unpublished import and then let it publish. A published import keeps its success result. Completed job records cannot block new imports. Discard after a failed confirmation releases admission. ## UX gaps left Undo does not check later edits. Replacement and Undo each span separate requests without durable server intent. These are #1177 and #1178. No UI code changed in this review; the original branch owns the existing screenshot set. ## Scope and merge-round work This review added focused reliability verification. It ran its local TCP malformed-input round and its restart regressions. Full adversarial matrices, full browser e2e, deployment and Apple-client interop remain merge-round work. Do not substitute the focused tests for those combined-branch checks. The blocking replacement and Undo work must land before that round can approve. No dependency version was changed. No performance timing was run: this issue is a correctness review. Exact performance-guard pins were refreshed without changing exception scopes, limits, owners, expiry dates or ratchet values. For the merge round, after the blocking fixes: - `cargo test -p calternal-server -- --test-threads=4`: prove the reviewed Notifications upgrade contract and all shared server tests. - `cd apps/web && bun e2e/money-wizard-1140.mjs`: prove the full wizard flow and its platform, width and theme evidence on the combined branch. - `bash tests/adversarial/run-split.sh`: prove the combined server's authorization, cross-User and malformed-input matrices. ## Final gates (verbatim summary lines) The full Money suite preceded the final Clippy expression correction. The eight focused review tests then passed on code head `be41fb067`. The origin/dev merge was already up to date. Rust gates used four build jobs and four test threads. Web tests used two Workers. `cargo fmt --check` ```text Exit 0; no output. ``` `cargo clippy -p calternal-plugin-money --all-targets -- -D warnings` ```text Finished `dev` profile [unoptimized + debuginfo] target(s) in 2m 31s ``` `cargo test -p calternal-plugin-money -- --test-threads=4` ```text test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 110 filtered out; finished in 65.05s test result: ok. 110 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 91.33s test result: ok. 27 passed; 0 failed; 3 ignored; 0 measured; 0 filtered out; finished in 14.88s test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s ``` `cargo test -p calternal-plugin-money review_1140 -- --test-threads=4` ```text test result: ok. 8 passed; 0 failed; 0 ignored; 0 measured; 103 filtered out; finished in 9.48s test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 30 filtered out; finished in 0.00s ``` `cargo clippy -p calternal-server --all-targets -- -D warnings` ```text Finished `dev` profile [unoptimized + debuginfo] target(s) in 1m 04s ``` `cargo test -p calternal-server -- --test-threads=4` ```text test result: FAILED. 253 passed; 3 failed; 10 ignored; 0 measured; 0 filtered out; finished in 74.17s ``` `cargo test -p calternal-server --test perf_guards -- --test-threads=4` ```text test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 91.74s ``` `cd apps/web && bun run check` ```text perf-lint: PASS; 0 violations; 22177 scoped exceptions svelte-check found 0 errors and 4 warnings in 3 files ``` `cd apps/web && bun run test -- --maxWorkers=2` ```text Test Files 271 passed (271) Tests 1878 passed (1878) ``` Full logs stay in `artifacts/wizardrev-1140/`. The full server failure is 253 passed, three failed and ten ignored: two schema expectations (#1184) and one SLOW-only startup timeout. Existing assertions remain unchanged. Cleanup: Cargo removed 17,939 files, 12.0 GiB. Web production output was deleted. No push, deploy or branch merge into dev was performed.
Author
Owner

Started wizard4-1140 on job/wizard-1140 at 96ec6f0420. Read the contract, DESIGN section 48 and review-1140.md. Implementing the four owner-decided blockers in separate commits; no push or deploy.

Started wizard4-1140 on job/wizard-1140 at 96ec6f04203a10cefcf9c1f97e66335761d2a416. Read the contract, DESIGN section 48 and review-1140.md. Implementing the four owner-decided blockers in separate commits; no push or deploy.
Author
Owner

Replacement finding #1178 is committed at 1b021fde38. Restart/cancellation tests cover intent, Trash, rename and receipt finalization with a reopened Index and fresh Installation. The browser no longer trashes or restores the replaced Budget. Added replay-safe shared filesystem inverse infrastructure for #1177; implementing the conditional Undo route next.

Replacement finding #1178 is committed at 1b021fde3828f9b7a8c8048f97d4449b129e405c. Restart/cancellation tests cover intent, Trash, rename and receipt finalization with a reopened Index and fresh Installation. The browser no longer trashes or restores the replaced Budget. Added replay-safe shared filesystem inverse infrastructure for #1177; implementing the conditional Undo route next.
Author
Owner

Implemented #1177 in b825bae753ad72d0f9054ae8615376c0acffcb8e. Undo is a User-bound server mutation. It compares exact published file names and BLAKE3 hashes under the Root writer lock before committing any inverse intent. Folder rename, transaction edit, new month, unknown line, unknown file and filename changes refuse with the required plain text and leave files and receipt unchanged. The browser never falls back to Files Trash/restore.

#1178 focused recovery evidence also covers abrupt child process exit at phases 1–6, cancellation before publication, byte-exact predecessor restoration and harmless consumed-receipt replay after manual restoration.

test result: ok. 9 passed; 0 failed; 1 ignored; 0 measured; 107 filtered out; finished in 34.43s
Test Files  2 passed (2)
     Tests  37 passed (37)
test result: ok. 96 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 19.51s

The ignored process entry is invoked explicitly by the passing parent test. Other filesystem integration targets passed. Money and filesystem Clippy passed. Final combined gates and visual evidence remain in progress. Legacy receipts without trusted publication hashes cannot enable Undo by hashing edited files retroactively.

Implemented #1177 in `b825bae753ad72d0f9054ae8615376c0acffcb8e`. Undo is a User-bound server mutation. It compares exact published file names and BLAKE3 hashes under the Root writer lock before committing any inverse intent. Folder rename, transaction edit, new month, unknown line, unknown file and filename changes refuse with the required plain text and leave files and receipt unchanged. The browser never falls back to Files Trash/restore. #1178 focused recovery evidence also covers abrupt child process exit at phases 1–6, cancellation before publication, byte-exact predecessor restoration and harmless consumed-receipt replay after manual restoration. ``` test result: ok. 9 passed; 0 failed; 1 ignored; 0 measured; 107 filtered out; finished in 34.43s Test Files 2 passed (2) Tests 37 passed (37) test result: ok. 96 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 19.51s ``` The ignored process entry is invoked explicitly by the passing parent test. Other filesystem integration targets passed. Money and filesystem Clippy passed. Final combined gates and visual evidence remain in progress. Legacy receipts without trusted publication hashes cannot enable Undo by hashing edited files retroactively.
Author
Owner

#1184 committed in 87a9599c08bf491ddd3b7de043713a92d0345436: Notifications 0007 is included in both production upgrade fixtures. The pending frontier and total counts each gain exactly one receipt. All preservation, checksum/timestamp and idempotent replay assertions remain intact; the commit body explains the authorized expectation changes.

Focused gate:

test result: ok. 5 passed; 0 failed; 0 ignored; 0 measured; 262 filtered out; finished in 6.80s

No migration number, migration SQL or deployed receipt changed. Final server Clippy and full crate tests remain in progress.

#1184 committed in `87a9599c08bf491ddd3b7de043713a92d0345436`: Notifications 0007 is included in both production upgrade fixtures. The pending frontier and total counts each gain exactly one receipt. All preservation, checksum/timestamp and idempotent replay assertions remain intact; the commit body explains the authorized expectation changes. Focused gate: ``` test result: ok. 5 passed; 0 failed; 0 ignored; 0 measured; 262 filtered out; finished in 6.80s ``` No migration number, migration SQL or deployed receipt changed. Final server Clippy and full crate tests remain in progress.
Author
Owner

#1183 committed in 7cb7c2c4805c779baed1692f32b2fa4490507bce. DESIGN §48 records the owner-approved exception: an Admin can retry/cancel another User's Money work, with content-free operational views only. List and detail clear progress text/counts and replace raw errors with a fixed class. One bounded scalar query supplies source bytes; neither view deserializes a Money result or receipt.

The live-app fixture uses an actual Admin and a second User. It verifies private Budget/file/result/receipt markers are absent, counts are null, results are 404, receipts are empty, and retry/cancel work without changing private payload fields.

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 266 filtered out; finished in 11.13s
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 17m 57s

The ignored fixture is also invoked by the enabled live-app process wrapper in the full crate gate. Full server tests and production screenshot evidence remain in progress.

#1183 committed in `7cb7c2c4805c779baed1692f32b2fa4490507bce`. DESIGN §48 records the owner-approved exception: an Admin can retry/cancel another User's Money work, with content-free operational views only. List and detail clear progress text/counts and replace raw errors with a fixed class. One bounded scalar query supplies source bytes; neither view deserializes a Money result or receipt. The live-app fixture uses an actual Admin and a second User. It verifies private Budget/file/result/receipt markers are absent, counts are null, results are 404, receipts are empty, and retry/cancel work without changing private payload fields. ``` test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 266 filtered out; finished in 11.13s Finished `dev` profile [unoptimized + debuginfo] target(s) in 17m 57s ``` The ignored fixture is also invoked by the enabled live-app process wrapper in the full crate gate. Full server tests and production screenshot evidence remain in progress.
Author
Owner

Finding at head 6a6e51773: the ordinary SQLite writer uses WAL/NORMAL. Non-rebuildable publication and inverse authority must be committed with the existing WAL/FULL authority pool before any filesystem mutation. Publication intent/finalization, inverse intent/consumption and cancellation/abandonment now use that pool; parser/progress writes remain ordinary. DESIGN §2 records this narrow exception. The production-route regression verifies FULL=2, ordinary=1, two authority commits per publication and inverse, and no authority write on consumed replay. Real process-exit/reopen tests pass at all six phases, as do byte-preserving edit refusals and restored-predecessor collision refusal.

Money gate output:

test result: ok. 118 passed; 0 failed; 2 ignored; 0 measured; 0 filtered out; finished in 97.08s
Finding at head 6a6e51773: the ordinary SQLite writer uses WAL/NORMAL. Non-rebuildable publication and inverse authority must be committed with the existing WAL/FULL authority pool before any filesystem mutation. Publication intent/finalization, inverse intent/consumption and cancellation/abandonment now use that pool; parser/progress writes remain ordinary. DESIGN §2 records this narrow exception. The production-route regression verifies FULL=2, ordinary=1, two authority commits per publication and inverse, and no authority write on consumed replay. Real process-exit/reopen tests pass at all six phases, as do byte-preserving edit refusals and restored-predecessor collision refusal. Money gate output: ``` test result: ok. 118 passed; 0 failed; 2 ignored; 0 measured; 0 filtered out; finished in 97.08s ```
Author
Owner

Finding and fix at head 48b973914: Admin cancellation is a queue operation. Pending cancellation changes state to cancelled; leased cancellation sets cancellation_requested. Neither sets the live browser import control. Publication now reads both owner-bound forms at its final checkpoint, before the source moves. A real-route regression interrupts at intent and Trash, cancels through JobQueue without a RAM signal, resumes the same live operation, and compares the restored original file names and hashes.

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 120 filtered out; finished in 5.08s

Money Clippy and complete tests pass:

    Finished `dev` profile [unoptimized + debuginfo] target(s) in 11.95s
test result: ok. 119 passed; 0 failed; 2 ignored; 0 measured; 0 filtered out; finished in 128.57s
test result: ok. 27 passed; 0 failed; 3 ignored; 0 measured; 0 filtered out; finished in 12.66s

All six production macOS-emulated screenshot cases pass at 390, 820 and 1440 px in light and dark (36 captures). Final web and server gates are in progress.

Finding and fix at head 48b973914: Admin cancellation is a queue operation. Pending cancellation changes state to cancelled; leased cancellation sets cancellation_requested. Neither sets the live browser import control. Publication now reads both owner-bound forms at its final checkpoint, before the source moves. A real-route regression interrupts at intent and Trash, cancels through JobQueue without a RAM signal, resumes the same live operation, and compares the restored original file names and hashes. ``` test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 120 filtered out; finished in 5.08s ``` Money Clippy and complete tests pass: ``` Finished `dev` profile [unoptimized + debuginfo] target(s) in 11.95s test result: ok. 119 passed; 0 failed; 2 ignored; 0 measured; 0 filtered out; finished in 128.57s test result: ok. 27 passed; 0 failed; 3 ignored; 0 measured; 0 filtered out; finished in 12.66s ``` All six production macOS-emulated screenshot cases pass at 390, 820 and 1440 px in light and dark (36 captures). Final web and server gates are in progress.
Author
Owner

Finding and fix at head abd4812a0: a shared queue cancellation can restore the original Budget without setting the browser RAM control. Settlement previously returned only success/failure of the filesystem work, so confirmation could then construct a false creation receipt. Settlement now explicitly returns publication versus safe abandonment; confirmation returns cancellation for abandonment. The existing real-operation regression also checks that cancelled settlement reports no created Budget. No prior test expectation changed.

Final Money output:

    Finished `dev` profile [unoptimized + debuginfo] target(s) in 39.36s
test result: ok. 119 passed; 0 failed; 2 ignored; 0 measured; 0 filtered out; finished in 156.47s
test result: ok. 27 passed; 0 failed; 3 ignored; 0 measured; 0 filtered out; finished in 8.90s

Web check passes with zero errors, and full web tests passed all 271 files / 1883 tests. Final server tests are running.

Finding and fix at head abd4812a0: a shared queue cancellation can restore the original Budget without setting the browser RAM control. Settlement previously returned only success/failure of the filesystem work, so confirmation could then construct a false creation receipt. Settlement now explicitly returns publication versus safe abandonment; confirmation returns cancellation for abandonment. The existing real-operation regression also checks that cancelled settlement reports no created Budget. No prior test expectation changed. Final Money output: ``` Finished `dev` profile [unoptimized + debuginfo] target(s) in 39.36s test result: ok. 119 passed; 0 failed; 2 ignored; 0 measured; 0 filtered out; finished in 156.47s test result: ok. 27 passed; 0 failed; 3 ignored; 0 measured; 0 filtered out; finished in 8.90s ``` Web check passes with zero errors, and full web tests passed all 271 files / 1883 tests. Final server tests are running.
Author
Owner

All four review findings are implemented in ten atomic commits. The branch is not fully green: the server suite has an unresolved startup deadline failure, tracked in #1192. Do not mark this report READY FOR MERGE.

Branch: job/wizard-1140. Head: abd4812a0a6a59a48e68f1aabeae2aafed31cbe0. The one origin/dev merge check returned Already up to date. No push, deploy, promotion or merge into dev was performed.

Built

  • #1177: an owner-bound server Undo endpoint compares exact published names and BLAKE3 hashes under the shared writer lock. Any edit or rename refuses with the owner's exact plain-text copy. Refusal changes no file or receipt. A matching import goes to Trash and its predecessor is restored in one journal. The receipt is single-use, including restart, replay and late parser completion.
  • #1178: the server owns replacement staging, durable intent, old-budget Trash, publication and finalization. FULL commits precede source mutations. Restart and real process-exit tests cover all four publication phases and both inverse phases. Cancellation restores the original exact bytes before publication. Admin queue cancellation checks both pending cancellation state and leased cancellation flags; abandonment cannot produce a false creation receipt.
  • #1183: Admin Money job lists/details expose content-free operational fields. They hide names, amounts, item counts, raw errors, results and receipts. Retry/cancel remains available. The production route test uses an Admin and a second User. DESIGN §48 records the isolation exception.
  • #1184: both production upgrade fixtures now include Notifications 0007. Original receipt timestamps/checksums, retained data and repeat-upgrade assertions remain.
  • Contracts, generated API types, classifications and exact performance proofs are refreshed. No guard was weakened; scoped exceptions fell from 22177 to 22149. The existing benchmark now covers publication, replacement and both inverses.

UX gaps closed

Edited imports retain their Budget and Undo receipt after refusal. Unchanged Undo works with touch and keyboard. Open Budget navigates. Replacement uses the server operation. Session changes fence writes. Admin views carry no Budget content. Six macOS-emulated production cases cover 390, 820 and 1440 px, light and dark; 36 screenshots are attached. Action alignment crops were checked. Visual quality review remains with the orchestrator.

UX gaps left / known gaps

Legacy receipts without trusted published hashes refuse Undo. There is no separate one-click redo toast after Undo; Files never restores the replacement from the browser. The full server gate remains failed at the unchanged 15-second startup deadline. An isolated fresh-process retry also failed; a load-only cause is not established. #1192 has both outputs. The focused Admin regression, all five upgrade tests and the remaining server integration checks pass.

Decisions

Use the existing FULL authority pool for the small, non-rebuildable import intents and inverse receipts; parsing/progress stays NORMAL. DESIGN §2 records this narrow exception. Legacy receipts fail closed; do not manufacture trusted hashes from possibly edited files. Reuse the existing queue and filesystem journal with deterministic private Trash names, including rename-once replay when restoration reuses the source path.

Gate output (verbatim excerpts)

cargo fmt --check passed with exit 0 and no output. git diff --check passed.

Per-crate Clippy (--all-targets -- -D warnings), in order: calternal-fs, calternal-plugin-money, calternal-server:

    Finished `dev` profile [unoptimized + debuginfo] target(s) in 3m 31s
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 39.36s
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 41.59s

cargo test -p calternal-fs:

test result: ok. 96 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 19.51s
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.10s
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.55s
test result: ok. 48 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 9.29s
test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.05s
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

cargo test -p calternal-plugin-money -- --test-threads=4:

test result: ok. 119 passed; 0 failed; 2 ignored; 0 measured; 0 filtered out; finished in 156.47s
test result: ok. 27 passed; 0 failed; 3 ignored; 0 measured; 0 filtered out; finished in 8.90s

cd apps/web && bun run check; bun run test --maxWorkers=2:

perf-lint: PASS; 0 violations; 22149 scoped exceptions
svelte-check found 0 errors and 4 warnings in 3 files
 Test Files  271 passed (271)
      Tests  1883 passed (1883)

cargo test -p calternal-server -- --test-threads=4 — failed:

HTTP startup waited for an upgrade backfill: Elapsed(())
test result: FAILED. 255 passed; 1 failed; 11 ignored; 0 measured; 0 filtered out; finished in 102.92s

Unchanged isolated startup retry — failed:

test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 266 filtered out; finished in 97.22s

Focused wire::tests::admin_money_jobs_are_content_free -- --ignored --exact --test-threads=1:

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 266 filtered out; finished in 20.85s

cargo test -p calternal-server --test perf_guards --test private_index_permissions -- --test-threads=4:

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 45.79s
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.85s

python3 -m unittest discover -s tests/adversarial -p test_xuser_classification.py:

Ran 16 tests in 0.421s

OK

For the merge round

  • Resolve #1192 and run cargo test -p calternal-server -- --test-threads=4; prove HTTP startup does not wait for a locked upgrade backfill. Keep the current expectation.
  • Run tests/adversarial/run.sh; prove the combined authorization, cross-User and hostile-input matrices. This job ran focused real-route regressions and offline classifications, not the full matrices.
  • After the combined production build, run CALTERNAL_E2E_ASSET_OVERRIDE=1 bun apps/web/e2e/money-wizard-1140.mjs --acceptance with CALTERNAL_SERVER_BIN set to that build; prove the full format/restart/replacement acceptance round.
  • Staging/o2 and real macOS interoperability remain merge-round work under the verification policy. The requested second independent numbers review remains outstanding.
  • This is a correctness job. No performance run was made under the current policy. When measured on the perf VM, use flock /root/perf.lock bash -c 'uptime; bun bench/money-wizard-1140.mjs' with the combined shared release binary in CALTERNAL_SERVER_BIN; record p50/p95, CPU/RSS and the burst beside docs/perf/baseline.json.

Screenshot attachments

Files

  • apps/web/e2e/money-wizard-1140.mjs
  • apps/web/src/lib/money/api.test.ts
  • apps/web/src/lib/money/api.ts
  • apps/web/src/lib/money/import-session.svelte.test.ts
  • apps/web/src/lib/money/import-session.svelte.ts
  • bench/money-wizard-1140.mjs
  • contracts/action-policy.json
  • contracts/actions.json
  • contracts/openapi.json
  • contracts/perf/adoption-1058.json
  • contracts/perf/exceptions.json
  • contracts/perf/ratchet.json
  • contracts/perf/registry.json
  • crates/calternal-fs/src/journal.rs
  • crates/calternal-fs/src/trash.rs
  • crates/calternal-server/src/upgrade_tests.rs
  • crates/calternal-server/src/wire.rs
  • crates/plugins/money/src/durable_import.rs
  • crates/plugins/money/src/durable_import_tests.rs
  • crates/plugins/money/src/routes.rs
  • crates/plugins/money/src/tests.rs
  • docs/DESIGN.md
  • packages/api-client/src/generated.ts
  • tests/adversarial/test_xuser_classification.py
  • tests/adversarial/xuser_matrix.py

Cleanup

Cargo clean completed:

Removed 18614 files, 13.6GiB total

Web build output, .svelte-kit and the job's generated test temporary directory were removed. Review artifacts remain ignored and attached to #1140. The worktree is clean.

All four review findings are implemented in ten atomic commits. The branch is **not fully green**: the server suite has an unresolved startup deadline failure, tracked in [#1192](https://git.kayg.org/kayg/calternal/issues/1192). Do not mark this report READY FOR MERGE. Branch: `job/wizard-1140`. Head: `abd4812a0a6a59a48e68f1aabeae2aafed31cbe0`. The one origin/dev merge check returned `Already up to date.` No push, deploy, promotion or merge into dev was performed. **Built** - #1177: an owner-bound server Undo endpoint compares exact published names and BLAKE3 hashes under the shared writer lock. Any edit or rename refuses with the owner's exact plain-text copy. Refusal changes no file or receipt. A matching import goes to Trash and its predecessor is restored in one journal. The receipt is single-use, including restart, replay and late parser completion. - #1178: the server owns replacement staging, durable intent, old-budget Trash, publication and finalization. FULL commits precede source mutations. Restart and real process-exit tests cover all four publication phases and both inverse phases. Cancellation restores the original exact bytes before publication. Admin queue cancellation checks both pending cancellation state and leased cancellation flags; abandonment cannot produce a false creation receipt. - #1183: Admin Money job lists/details expose content-free operational fields. They hide names, amounts, item counts, raw errors, results and receipts. Retry/cancel remains available. The production route test uses an Admin and a second User. DESIGN §48 records the isolation exception. - #1184: both production upgrade fixtures now include Notifications 0007. Original receipt timestamps/checksums, retained data and repeat-upgrade assertions remain. - Contracts, generated API types, classifications and exact performance proofs are refreshed. No guard was weakened; scoped exceptions fell from 22177 to 22149. The existing benchmark now covers publication, replacement and both inverses. **UX gaps closed** Edited imports retain their Budget and Undo receipt after refusal. Unchanged Undo works with touch and keyboard. Open Budget navigates. Replacement uses the server operation. Session changes fence writes. Admin views carry no Budget content. Six macOS-emulated production cases cover 390, 820 and 1440 px, light and dark; 36 screenshots are attached. Action alignment crops were checked. Visual quality review remains with the orchestrator. **UX gaps left / known gaps** Legacy receipts without trusted published hashes refuse Undo. There is no separate one-click redo toast after Undo; Files never restores the replacement from the browser. The full server gate remains failed at the unchanged 15-second startup deadline. An isolated fresh-process retry also failed; a load-only cause is not established. #1192 has both outputs. The focused Admin regression, all five upgrade tests and the remaining server integration checks pass. **Decisions** Use the existing FULL authority pool for the small, non-rebuildable import intents and inverse receipts; parsing/progress stays NORMAL. DESIGN §2 records this narrow exception. Legacy receipts fail closed; do not manufacture trusted hashes from possibly edited files. Reuse the existing queue and filesystem journal with deterministic private Trash names, including rename-once replay when restoration reuses the source path. **Gate output (verbatim excerpts)** `cargo fmt --check` passed with exit 0 and no output. `git diff --check` passed. Per-crate Clippy (`--all-targets -- -D warnings`), in order: calternal-fs, calternal-plugin-money, calternal-server: ``` Finished `dev` profile [unoptimized + debuginfo] target(s) in 3m 31s Finished `dev` profile [unoptimized + debuginfo] target(s) in 39.36s Finished `dev` profile [unoptimized + debuginfo] target(s) in 41.59s ``` `cargo test -p calternal-fs`: ``` test result: ok. 96 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 19.51s test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.10s test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.55s test result: ok. 48 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 9.29s test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.05s test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s ``` `cargo test -p calternal-plugin-money -- --test-threads=4`: ``` test result: ok. 119 passed; 0 failed; 2 ignored; 0 measured; 0 filtered out; finished in 156.47s test result: ok. 27 passed; 0 failed; 3 ignored; 0 measured; 0 filtered out; finished in 8.90s ``` `cd apps/web && bun run check`; `bun run test --maxWorkers=2`: ``` perf-lint: PASS; 0 violations; 22149 scoped exceptions svelte-check found 0 errors and 4 warnings in 3 files Test Files 271 passed (271) Tests 1883 passed (1883) ``` `cargo test -p calternal-server -- --test-threads=4` — failed: ``` HTTP startup waited for an upgrade backfill: Elapsed(()) test result: FAILED. 255 passed; 1 failed; 11 ignored; 0 measured; 0 filtered out; finished in 102.92s ``` Unchanged isolated startup retry — failed: ``` test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 266 filtered out; finished in 97.22s ``` Focused `wire::tests::admin_money_jobs_are_content_free -- --ignored --exact --test-threads=1`: ``` test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 266 filtered out; finished in 20.85s ``` `cargo test -p calternal-server --test perf_guards --test private_index_permissions -- --test-threads=4`: ``` test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 45.79s test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.85s ``` `python3 -m unittest discover -s tests/adversarial -p test_xuser_classification.py`: ``` Ran 16 tests in 0.421s OK ``` **For the merge round** - Resolve #1192 and run `cargo test -p calternal-server -- --test-threads=4`; prove HTTP startup does not wait for a locked upgrade backfill. Keep the current expectation. - Run `tests/adversarial/run.sh`; prove the combined authorization, cross-User and hostile-input matrices. This job ran focused real-route regressions and offline classifications, not the full matrices. - After the combined production build, run `CALTERNAL_E2E_ASSET_OVERRIDE=1 bun apps/web/e2e/money-wizard-1140.mjs --acceptance` with `CALTERNAL_SERVER_BIN` set to that build; prove the full format/restart/replacement acceptance round. - Staging/o2 and real macOS interoperability remain merge-round work under the verification policy. The requested second independent numbers review remains outstanding. - This is a correctness job. No performance run was made under the current policy. When measured on the perf VM, use `flock /root/perf.lock bash -c 'uptime; bun bench/money-wizard-1140.mjs'` with the combined shared release binary in `CALTERNAL_SERVER_BIN`; record p50/p95, CPU/RSS and the burst beside `docs/perf/baseline.json`. **Screenshot attachments** - [inverse-light-390.zip](https://git.kayg.org/attachments/a4c8756e-074e-43c6-9acc-c73895de3c11) - [inverse-light-820.zip](https://git.kayg.org/attachments/ff6328bc-300f-4a11-83e5-0cf1202dba20) - [inverse-light-1440.zip](https://git.kayg.org/attachments/101b5cff-9b7f-4413-bb82-b8307a8015b8) - [inverse-dark-390.zip](https://git.kayg.org/attachments/656922c3-178e-483a-9b03-480519eae66e) - [inverse-dark-820.zip](https://git.kayg.org/attachments/df3ca33d-8c5e-466c-995c-993fa7279985) - [inverse-dark-1440.zip](https://git.kayg.org/attachments/d921a64b-afe4-4a8f-b3c4-336de453dd13) **Files** - `apps/web/e2e/money-wizard-1140.mjs` - `apps/web/src/lib/money/api.test.ts` - `apps/web/src/lib/money/api.ts` - `apps/web/src/lib/money/import-session.svelte.test.ts` - `apps/web/src/lib/money/import-session.svelte.ts` - `bench/money-wizard-1140.mjs` - `contracts/action-policy.json` - `contracts/actions.json` - `contracts/openapi.json` - `contracts/perf/adoption-1058.json` - `contracts/perf/exceptions.json` - `contracts/perf/ratchet.json` - `contracts/perf/registry.json` - `crates/calternal-fs/src/journal.rs` - `crates/calternal-fs/src/trash.rs` - `crates/calternal-server/src/upgrade_tests.rs` - `crates/calternal-server/src/wire.rs` - `crates/plugins/money/src/durable_import.rs` - `crates/plugins/money/src/durable_import_tests.rs` - `crates/plugins/money/src/routes.rs` - `crates/plugins/money/src/tests.rs` - `docs/DESIGN.md` - `packages/api-client/src/generated.ts` - `tests/adversarial/test_xuser_classification.py` - `tests/adversarial/xuser_matrix.py` **Cleanup** Cargo clean completed: ``` Removed 18614 files, 13.6GiB total ``` Web build output, .svelte-kit and the job's generated test temporary directory were removed. Review artifacts remain ignored and attached to #1140. The worktree is clean.
Author
Owner

Second review started on job/wizard-1140, head abd4812a0a6a59a48e68f1aabeae2aafed31cbe0, base d0061ec3df127d81c86729d07d899b0bf2b6de91. Scope: #1178 replacement recovery, #1177 conditional Undo, #1184 upgrade fixtures, #1183 operational Admin controls and their import interactions. I will add independent defensive regressions, run focused tests and required gates, and report SAFE TO MERGE yes/no. No push or deploy.

Second review started on `job/wizard-1140`, head `abd4812a0a6a59a48e68f1aabeae2aafed31cbe0`, base `d0061ec3df127d81c86729d07d899b0bf2b6de91`. Scope: #1178 replacement recovery, #1177 conditional Undo, #1184 upgrade fixtures, #1183 operational Admin controls and their import interactions. I will add independent defensive regressions, run focused tests and required gates, and report SAFE TO MERGE yes/no. No push or deploy.
Author
Owner

Second-review finding: merging origin/dev exposed duplicate Notifications migration 0007 (0007_web_toasts.sql on dev, 0007_money_import.sql on this branch). The two SQL files also rebuild the same inbox with different columns and kind checks. Keeping either version would reject the other producer or lose toast action labels. Fix: retain deployed web toast 0007 byte-for-byte; move Money completion to 0008 and preserve the full 0007 schema, long titles, action labels, push deliveries and reminder references. #1184 upgrade frontiers now include both receipts; original preservation/idempotence assertions remain. Added an exact-row upgrade regression with a 1000-character toast title and action label. No dependency changed.

Second-review finding: merging origin/dev exposed duplicate Notifications migration 0007 (`0007_web_toasts.sql` on dev, `0007_money_import.sql` on this branch). The two SQL files also rebuild the same inbox with different columns and kind checks. Keeping either version would reject the other producer or lose toast action labels. Fix: retain deployed web toast 0007 byte-for-byte; move Money completion to 0008 and preserve the full 0007 schema, long titles, action labels, push deliveries and reminder references. #1184 upgrade frontiers now include both receipts; original preservation/idempotence assertions remain. Added an exact-row upgrade regression with a 1000-character toast title and action label. No dependency changed.
Author
Owner

Started #1140 on job/wizchoices-1140, based on the running numbers-review head abd4812a0a6a59a48e68f1aabeae2aafed31cbe0. I am working only in the import review/choices UI and its tests. I read CLAUDE.md, CONTEXT.md, DESIGN §§34, 48 and 59, and the issue owner decisions. I will reuse @calternal/ui components and capture the requested macOS screenshots from the real app build.

Started #1140 on `job/wizchoices-1140`, based on the running numbers-review head `abd4812a0a6a59a48e68f1aabeae2aafed31cbe0`. I am working only in the import review/choices UI and its tests. I read `CLAUDE.md`, `CONTEXT.md`, DESIGN §§34, 48 and 59, and the issue owner decisions. I will reuse `@calternal/ui` components and capture the requested macOS screenshots from the real app build.
Author
Owner

Finding for the review UI: ImportPreview.account_kind_questions contains only account ID/name pairs, so the web client has no per-account open/closed state to display. The import route accepts only cash and card overrides (crates/plugins/money/src/import.rs), while DESIGN §48 makes Tracking source-authoritative and maps loans to Tracking. This UI-only slice will show truthful Cash/Credit card choices and will not infer or fabricate open/closed badges or send unsupported kind values.

Finding for the review UI: `ImportPreview.account_kind_questions` contains only account ID/name pairs, so the web client has no per-account open/closed state to display. The import route accepts only `cash` and `card` overrides (`crates/plugins/money/src/import.rs`), while DESIGN §48 makes Tracking source-authoritative and maps loans to Tracking. This UI-only slice will show truthful Cash/Credit card choices and will not infer or fabricate open/closed badges or send unsupported kind values.
Author
Owner

Web integration evidence after origin/dev 5301e020859c1d61b4a7f812a5049a64241203e8: check passes (perf-lint: PASS; 0 violations; 22404 scoped exceptions; svelte-check found 0 errors and 2 warnings in 2 files). Full tests fail only the toast-policy source audit:

 Test Files  1 failed | 278 passed (279)
      Tests  1 failed | 1959 passed (1960)

Filed #1196 with the five exact import call sites and the existing exact Undo-refusal options assertion. No existing test expectation or guard was weakened. The branch cannot receive SAFE TO MERGE while this gate fails. Offline cross-User classification checks pass: Ran 17 tests in 0.335s / OK.

Web integration evidence after origin/dev `5301e020859c1d61b4a7f812a5049a64241203e8`: check passes (`perf-lint: PASS; 0 violations; 22404 scoped exceptions`; `svelte-check found 0 errors and 2 warnings in 2 files`). Full tests fail only the toast-policy source audit: ```text Test Files 1 failed | 278 passed (279) Tests 1 failed | 1959 passed (1960) ``` Filed #1196 with the five exact import call sites and the existing exact Undo-refusal options assertion. No existing test expectation or guard was weakened. The branch cannot receive SAFE TO MERGE while this gate fails. Offline cross-User classification checks pass: `Ran 17 tests in 0.335s` / `OK`.
Author
Owner

Defensive second-review regression found a same-Installation outcome mismatch after Admin cancellation wins before replacement publication. The real queue accepted CancellationRequested; confirmation returned a client error and the predecessor bytes remained exact, but the owner result route returned ready from RAM instead of failed. Before-fix focused result:

assertion `left == right` failed
  left: String("ready")
 right: "failed"
test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 122 filtered out; finished in 43.57s

Fix: the authority UPDATE now returns the existing progress identity, and a shared owner-bound terminal cache helper applies the committed outcome to the Installation cache. Undo uses the same helper. This adds no query and no filesystem IO; expected extra work is one HashMap lookup and one fixed-string allocation per terminal outcome. Focused after-fix result:

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 122 filtered out; finished in 33.97s

The full Money gate is being rerun after this change. No existing expectation was changed.

Defensive second-review regression found a same-Installation outcome mismatch after Admin cancellation wins before replacement publication. The real queue accepted `CancellationRequested`; confirmation returned a client error and the predecessor bytes remained exact, but the owner result route returned `ready` from RAM instead of `failed`. Before-fix focused result: ```text assertion `left == right` failed left: String("ready") right: "failed" test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 122 filtered out; finished in 43.57s ``` Fix: the authority UPDATE now returns the existing progress identity, and a shared owner-bound terminal cache helper applies the committed outcome to the Installation cache. Undo uses the same helper. This adds no query and no filesystem IO; expected extra work is one HashMap lookup and one fixed-string allocation per terminal outcome. Focused after-fix result: ```text test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 122 filtered out; finished in 33.97s ``` The full Money gate is being rerun after this change. No existing expectation was changed.
Author
Owner

Merge finding: origin/dev adds Notifications migration 0007 for web toasts, while this wizard branch already had Notifications 0007 for Money import completion. Both rebuild notifications with different kind constraints. I retained both as versions 7 and 8, and updated the later rebuild to preserve web_toast, action_label, and the longer toast title bound. The upgrade ledger now checks both receipts. This is a merge-only migration renumbering to keep both branches' behavior and unique per-plugin versions.

Merge finding: `origin/dev` adds Notifications migration 0007 for web toasts, while this wizard branch already had Notifications 0007 for Money import completion. Both rebuild `notifications` with different kind constraints. I retained both as versions 7 and 8, and updated the later rebuild to preserve `web_toast`, `action_label`, and the longer toast title bound. The upgrade ledger now checks both receipts. This is a merge-only migration renumbering to keep both branches' behavior and unique per-plugin versions.
Author
Owner

Runtime evidence for #1196: apps/web/src/lib/stores/toasts.svelte.ts:165 returns without showing or persisting a toast when opts.policy === 'drop' || (!opts.action && !opts.backgroundResult). The five unclassified import calls therefore disappear in the merged app. In particular, the #1177 server refusal reaches undoImport, but its toast has neither field, so the User does not see why Undo is unavailable. This is a visible interaction defect as well as a failed audit. Keep the existing exact refusal assertion unchanged under the owner rule; the follow-up must explicitly reconcile it with the reviewed toast policy. #1140 cannot be SAFE TO MERGE until that work is done.

Runtime evidence for #1196: `apps/web/src/lib/stores/toasts.svelte.ts:165` returns without showing or persisting a toast when `opts.policy === 'drop' || (!opts.action && !opts.backgroundResult)`. The five unclassified import calls therefore disappear in the merged app. In particular, the #1177 server refusal reaches `undoImport`, but its toast has neither field, so the User does not see why Undo is unavailable. This is a visible interaction defect as well as a failed audit. Keep the existing exact refusal assertion unchanged under the owner rule; the follow-up must explicitly reconcile it with the reviewed toast policy. #1140 cannot be SAFE TO MERGE until that work is done.
Author
Owner

Perf-contract merge finding: the merged UI/source changed exact tracked scopes from both origin/dev and the wizard branch. I refreshed the exact live snapshot with the repository's scripts/perf-lint --adopt-7c command. Its guard passed: Adopted 7035 exact #1058 sites; ordinary future ratchet remains active and perf-lint: PASS; 0 violations; 22404 scoped exceptions. No guard rule was changed.

Perf-contract merge finding: the merged UI/source changed exact tracked scopes from both `origin/dev` and the wizard branch. I refreshed the exact live snapshot with the repository's `scripts/perf-lint --adopt-7c` command. Its guard passed: `Adopted 7035 exact #1058 sites; ordinary future ratchet remains active` and `perf-lint: PASS; 0 violations; 22404 scoped exceptions`. No guard rule was changed.
Author
Owner

Web verification found one inherited failure after merging origin/dev: apps/web/src/lib/stores/toast-policy.test.ts rejects five unclassified Money toasts (3 in MoneyImport.svelte, 2 in import-session.svelte.ts's Undo handler). Full run: 278 files / 1,960 tests, with 278 files and 1,959 tests passing. The two import-session.svelte.ts sites are in Undo code, outside this job's explicit ownership, so I will not change them here. I am recording the gate result and will finish the owned review UI work and screenshots.

Web verification found one inherited failure after merging `origin/dev`: `apps/web/src/lib/stores/toast-policy.test.ts` rejects five unclassified Money toasts (3 in `MoneyImport.svelte`, 2 in `import-session.svelte.ts`'s Undo handler). Full run: 278 files / 1,960 tests, with 278 files and 1,959 tests passing. The two `import-session.svelte.ts` sites are in Undo code, outside this job's explicit ownership, so I will not change them here. I am recording the gate result and will finish the owned review UI work and screenshots.
Author
Owner

Second review complete. SAFE TO MERGE: no. Final head: 0e95a20971930bf876710a08d5c403b8abe757c5. Tested code head: 6f380260b0af3a89c2cdeb639b0b686c18d40779; the final commit adds only the report. Worktree is clean.

Second review of #1140

SAFE TO MERGE: no. Follow-up #1196 blocks the web gate and hides the Undo refusal message.

Scope and revisions

This review covers only #1178 server-owned replacement and crash recovery, #1177 conditional Undo, #1184 protected upgrade fixtures, and #1183 content-free Admin job controls. It checks their interaction with the import. It does not repeat the unrelated first review.

Start: abd4812a0a6a59a48e68f1aabeae2aafed31cbe0 on job/wizard-1140. One required fetch and merge used origin/dev at 5301e020859c1d61b4a7f812a5049a64241203e8. Tested code head: 6f380260b0af3a89c2cdeb639b0b686c18d40779. The final issue comment records the report commit head.

Defensive cases and findings

  • Replacement crash recovery (#1178): the existing replacement_restarts_at_every_durable_phase and abrupt-exit tests pass. The conditional filesystem inverse tests pass. New review1140_replacement_receipt_recovery_does_not_adopt_later_edits covers receipt recovery at phases 3 and 4. It edits the published Budget before restart, refuses Undo twice with 409, checks the exact edited file set and unchanged receipt, and restores the predecessor to check its exact original file set.
  • Edit then Undo (#1177): undo_refuses_every_later_budget_edit_after_restart, predecessor-restore refusal, receipt replay, and before/after inverse restart tests pass. The new receipt-recovery case also passes. The backend preserves later edits. The merged shared toast policy suppresses the UI refusal message; see #1196 below.
  • Cancel before publication (#1178/#1183): new review1140_operational_cancel_before_replacement_returns_no_receipt holds the Money publication lock, accepts cancellation through the shared queue without a browser RAM signal, then runs the real confirmation route. It checks no creation receipt, the exact predecessor, one Budget, no replacement Trash, and a failed result. Before the fix, the final result was incorrectly ready in the owning Installation cache. Commit 6f380260b mirrors the committed terminal result into that owner-bound cache. The focused case and full Money suite pass.
  • Admin and second User (#1183): the existing live-app test now uses three real User sessions: owner, Admin and ordinary viewer. Admin operational controls remain content-free. The viewer gets 403 from Admin routes. Both non-owners get 404 from private Money result/detail routes, and the viewer's own list excludes the job. The isolated live-app group runs this otherwise ignored test and passes.
  • Upgrade (#1184): the required dev merge exposed a real migration collision. Deployed Notifications 0007 is the web-toast migration. Commit 95db5124c keeps it byte-for-byte and moves Money completion to 0008. A new upgrade test keeps the exact deployed toast row, long title, action label and read state through two migrations, then inserts typed Money completion. The protected server upgrade tests pass. Only migration frontiers/counts changed; historical receipt preservation and replay assertions remain.

Blocking follow-up #1196

bun run test -- --maxWorkers=2 fails only src/lib/stores/toast-policy.test.ts. Five Money toast calls lack an action, a named background result, or an explicit drop decision. They cover the new-Budget nudge, Copy details success/failure, and Undo success/failure.

This also changes runtime behavior: toasts.svelte.ts returns without showing or saving a toast when it has neither an action nor backgroundResult. The #1177 Undo refusal message therefore disappears after the merge. The focused Undo test mocks the toast boundary and does not detect this suppression.

The existing refusal regression asserts the exact unclassified toast options. The owner rule forbids changing that expectation to make a gate pass without explicit behavior authorization. This review keeps that assertion and the shared policy intact. #1196 records the evidence and the required reconciliation. The branch must pass both web gates before it is safe to merge.

Changes and files

  • crates/plugins/money/src/durable_import.rs: committed cancellation result cache update; shared helper also serves the existing Undo cache update.
  • crates/plugins/money/src/review_1140.rs: two defensive regression cases.
  • crates/calternal-server/src/wire.rs: authenticated second-User privacy coverage.
  • crates/plugins/notifications/migrations/0008_money_import.sql and src/store.rs: Money migration after deployed web toasts; exact-row upgrade regression. Remove obsolete 0007_money_import.sql; retain dev's 0007_web_toasts.sql.
  • crates/calternal-server/src/upgrade_tests.rs: exact protected migration frontier for both migrations.
  • Merge resolution: Notifications InboxPanel.svelte, inbox.svelte.test.ts, model.ts; XUser classification test documentation; generated contracts/actions.json; exact perf registry, exception, adoption and ratchet records. Preserve dev web-toast handling and branch Money Undo handling together. Do not weaken perf rules or increase exception scopes.
  • review-1140-second.md: this review record.

Atomic commits: 95db5124c (dev merge and migration reconciliation), 1408475a1 (authenticated privacy case), 6f380260b (terminal cache fix and regression cases).

UX gaps closed

Cancellation now shows the same failed result in the owning Installation as in the durable job. Backend Undo refuses after edits, including edits before receipt recovery. Admin job controls disclose no Money content to the Admin or a second User.

UX gaps left

#1196: classify Money toast calls and preserve visible Undo refusal under the shared toast policy. This review adds no visual controls. Existing Notifications Inbox controls are reused during merge resolution. No new CSS, icons, layout, or primitive variants were added. Screenshots of the complete import remain part of the UI/merge review.

Decisions and cost

Use Notifications 0008 because the single fetched dev revision already owns 0007. Drain the one-row UPDATE RETURNING statement before updating RAM so statement completion and sync errors are observed. Use the existing owner-bound read cache helper for cancellation and Undo. In the new receipt test, complete normal source-copy cleanup before comparing the durable authority payload; receipt and byte-preservation assertions remain exact.

These are implementation choices. No open product decision was implemented. The cache fix adds one owner-bound HashMap lookup and one fixed-string allocation to the existing terminal authority UPDATE. It adds no query or filesystem operation. Work is constant per cancelled import. No performance measurement was run: this is a correctness review, and the latest verification policy limits perf measurements to performance issues.

Gates

Commands used CARGO_PROFILE_DEV_DEBUG=line-tables-only, CARGO_INCREMENTAL=0, CARGO_BUILD_JOBS=4, and worktree target/tmp as TMPDIR. The preset CARGO_TARGET_DIR was retained. Crates ran separately. cargo fmt --check passed with no output. The following summary output is verbatim; full logs remain under artifacts/wizardrev2-1140/.

cargo clippy -p calternal-plugin-money --all-targets -- -D warnings

    Finished `dev` profile [unoptimized + debuginfo] target(s) in 12.52s

cargo test -p calternal-plugin-money

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 122 filtered out; finished in 48.02s
test result: ok. 121 passed; 0 failed; 2 ignored; 0 measured; 0 filtered out; finished in 101.41s
test result: ok. 27 passed; 0 failed; 3 ignored; 0 measured; 0 filtered out; finished in 7.45s
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

cargo clippy -p calternal-plugin-notifications --all-targets -- -D warnings

    Finished `dev` profile [unoptimized + debuginfo] target(s) in 9m 04s

cargo test -p calternal-plugin-notifications

test result: ok. 39 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 2.21s
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

cargo clippy -p calternal-fs --all-targets -- -D warnings

    Finished `dev` profile [unoptimized + debuginfo] target(s) in 44.42s

cargo test -p calternal-fs

test result: ok. 97 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 28.48s
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.18s
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.86s
test result: ok. 52 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 15.36s
test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.05s
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

cargo clippy -p calternal-server --all-targets -- -D warnings

    Finished `dev` profile [unoptimized + debuginfo] target(s) in 3m 49s

cargo test -p calternal-server

test result: ok. 263 passed; 0 failed; 11 ignored; 0 measured; 0 filtered out; finished in 186.39s
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 43.84s
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.58s

cd apps/web && bun run check

perf-lint: PASS; 0 violations; 22404 scoped exceptions
svelte-check found 0 errors and 2 warnings in 2 files

cd apps/web && bun run test -- --maxWorkers=2

 Test Files  1 failed | 278 passed (279)
      Tests  1 failed | 1959 passed (1960)

The focused XUser classification test also passed: 17 tests, OK. All requested defensive scenarios ran. No requested scenario is deferred.

Initial setup/test failures are retained in artifacts: server clippy first lacked generated production assets and passed after a real web build; the new upgrade fixture first used a retention-expired timestamp and now uses a live timestamp; the new receipt snapshot first raced normal source-copy cleanup and now drains that cleanup before the snapshot. Existing assertions were not relaxed. The cancellation ready/failed failure was a code defect and has its regression fix.

Known limits and merge-round work

Checkpoint tests exercise abrupt process exits and Root/Index restart, not physical power loss. No UI screenshots, full browser e2e, deployment, or Mac interop ran in this backend second review. Per the verification policy, the combined merge round must run:

  • cd apps/web && bun run check and bun run test -- --maxWorkers=2 after #1196 is resolved. Prove the shared policy and exact Undo refusal regression agree.
  • cd apps/web && bun e2e/money-wizard-1140.mjs. Prove production wizard flows and edited-Budget Undo refusal. Capture macOS rendering at 390, 820 and 1440 px in light and dark; extend the harness if it does not cover those cases.
  • bash tests/adversarial/run-split.sh. Prove combined authorization, XUser and robustness matrices against the merged server.

Cleanup completed: cargo clean removed 15.5 GiB. Generated web build, renderer build, Svelte output and copied Excalidraw fonts were deleted. No artifacts were committed. No push, deploy, issue close, or merge into dev was performed.

Second review complete. SAFE TO MERGE: **no**. Final head: `0e95a20971930bf876710a08d5c403b8abe757c5`. Tested code head: `6f380260b0af3a89c2cdeb639b0b686c18d40779`; the final commit adds only the report. Worktree is clean. # Second review of #1140 SAFE TO MERGE: **no**. Follow-up #1196 blocks the web gate and hides the Undo refusal message. ## Scope and revisions This review covers only #1178 server-owned replacement and crash recovery, #1177 conditional Undo, #1184 protected upgrade fixtures, and #1183 content-free Admin job controls. It checks their interaction with the import. It does not repeat the unrelated first review. Start: `abd4812a0a6a59a48e68f1aabeae2aafed31cbe0` on `job/wizard-1140`. One required fetch and merge used `origin/dev` at `5301e020859c1d61b4a7f812a5049a64241203e8`. Tested code head: `6f380260b0af3a89c2cdeb639b0b686c18d40779`. The final issue comment records the report commit head. ## Defensive cases and findings - **Replacement crash recovery (#1178):** the existing `replacement_restarts_at_every_durable_phase` and abrupt-exit tests pass. The conditional filesystem inverse tests pass. New `review1140_replacement_receipt_recovery_does_not_adopt_later_edits` covers receipt recovery at phases 3 and 4. It edits the published Budget before restart, refuses Undo twice with 409, checks the exact edited file set and unchanged receipt, and restores the predecessor to check its exact original file set. - **Edit then Undo (#1177):** `undo_refuses_every_later_budget_edit_after_restart`, predecessor-restore refusal, receipt replay, and before/after inverse restart tests pass. The new receipt-recovery case also passes. The backend preserves later edits. The merged shared toast policy suppresses the UI refusal message; see #1196 below. - **Cancel before publication (#1178/#1183):** new `review1140_operational_cancel_before_replacement_returns_no_receipt` holds the Money publication lock, accepts cancellation through the shared queue without a browser RAM signal, then runs the real confirmation route. It checks no creation receipt, the exact predecessor, one Budget, no replacement Trash, and a failed result. Before the fix, the final result was incorrectly `ready` in the owning Installation cache. Commit `6f380260b` mirrors the committed terminal result into that owner-bound cache. The focused case and full Money suite pass. - **Admin and second User (#1183):** the existing live-app test now uses three real User sessions: owner, Admin and ordinary viewer. Admin operational controls remain content-free. The viewer gets 403 from Admin routes. Both non-owners get 404 from private Money result/detail routes, and the viewer's own list excludes the job. The isolated live-app group runs this otherwise ignored test and passes. - **Upgrade (#1184):** the required dev merge exposed a real migration collision. Deployed Notifications 0007 is the web-toast migration. Commit `95db5124c` keeps it byte-for-byte and moves Money completion to 0008. A new upgrade test keeps the exact deployed toast row, long title, action label and read state through two migrations, then inserts typed Money completion. The protected server upgrade tests pass. Only migration frontiers/counts changed; historical receipt preservation and replay assertions remain. ## Blocking follow-up #1196 `bun run test -- --maxWorkers=2` fails only `src/lib/stores/toast-policy.test.ts`. Five Money toast calls lack an action, a named background result, or an explicit drop decision. They cover the new-Budget nudge, Copy details success/failure, and Undo success/failure. This also changes runtime behavior: `toasts.svelte.ts` returns without showing or saving a toast when it has neither an action nor `backgroundResult`. The #1177 Undo refusal message therefore disappears after the merge. The focused Undo test mocks the toast boundary and does not detect this suppression. The existing refusal regression asserts the exact unclassified toast options. The owner rule forbids changing that expectation to make a gate pass without explicit behavior authorization. This review keeps that assertion and the shared policy intact. #1196 records the evidence and the required reconciliation. The branch must pass both web gates before it is safe to merge. ## Changes and files - `crates/plugins/money/src/durable_import.rs`: committed cancellation result cache update; shared helper also serves the existing Undo cache update. - `crates/plugins/money/src/review_1140.rs`: two defensive regression cases. - `crates/calternal-server/src/wire.rs`: authenticated second-User privacy coverage. - `crates/plugins/notifications/migrations/0008_money_import.sql` and `src/store.rs`: Money migration after deployed web toasts; exact-row upgrade regression. Remove obsolete `0007_money_import.sql`; retain dev's `0007_web_toasts.sql`. - `crates/calternal-server/src/upgrade_tests.rs`: exact protected migration frontier for both migrations. - Merge resolution: Notifications `InboxPanel.svelte`, `inbox.svelte.test.ts`, `model.ts`; XUser classification test documentation; generated `contracts/actions.json`; exact perf registry, exception, adoption and ratchet records. Preserve dev web-toast handling and branch Money Undo handling together. Do not weaken perf rules or increase exception scopes. - `review-1140-second.md`: this review record. Atomic commits: `95db5124c` (dev merge and migration reconciliation), `1408475a1` (authenticated privacy case), `6f380260b` (terminal cache fix and regression cases). ## UX gaps closed Cancellation now shows the same failed result in the owning Installation as in the durable job. Backend Undo refuses after edits, including edits before receipt recovery. Admin job controls disclose no Money content to the Admin or a second User. ## UX gaps left #1196: classify Money toast calls and preserve visible Undo refusal under the shared toast policy. This review adds no visual controls. Existing Notifications Inbox controls are reused during merge resolution. No new CSS, icons, layout, or primitive variants were added. Screenshots of the complete import remain part of the UI/merge review. ## Decisions and cost Use Notifications 0008 because the single fetched dev revision already owns 0007. Drain the one-row UPDATE RETURNING statement before updating RAM so statement completion and sync errors are observed. Use the existing owner-bound read cache helper for cancellation and Undo. In the new receipt test, complete normal source-copy cleanup before comparing the durable authority payload; receipt and byte-preservation assertions remain exact. These are implementation choices. No open product decision was implemented. The cache fix adds one owner-bound HashMap lookup and one fixed-string allocation to the existing terminal authority UPDATE. It adds no query or filesystem operation. Work is constant per cancelled import. No performance measurement was run: this is a correctness review, and the latest verification policy limits perf measurements to performance issues. ## Gates Commands used `CARGO_PROFILE_DEV_DEBUG=line-tables-only`, `CARGO_INCREMENTAL=0`, `CARGO_BUILD_JOBS=4`, and worktree `target/tmp` as TMPDIR. The preset CARGO_TARGET_DIR was retained. Crates ran separately. `cargo fmt --check` passed with no output. The following summary output is verbatim; full logs remain under `artifacts/wizardrev2-1140/`. `cargo clippy -p calternal-plugin-money --all-targets -- -D warnings` ```text Finished `dev` profile [unoptimized + debuginfo] target(s) in 12.52s ``` `cargo test -p calternal-plugin-money` ```text test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 122 filtered out; finished in 48.02s test result: ok. 121 passed; 0 failed; 2 ignored; 0 measured; 0 filtered out; finished in 101.41s test result: ok. 27 passed; 0 failed; 3 ignored; 0 measured; 0 filtered out; finished in 7.45s test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s ``` `cargo clippy -p calternal-plugin-notifications --all-targets -- -D warnings` ```text Finished `dev` profile [unoptimized + debuginfo] target(s) in 9m 04s ``` `cargo test -p calternal-plugin-notifications` ```text test result: ok. 39 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 2.21s test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s ``` `cargo clippy -p calternal-fs --all-targets -- -D warnings` ```text Finished `dev` profile [unoptimized + debuginfo] target(s) in 44.42s ``` `cargo test -p calternal-fs` ```text test result: ok. 97 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 28.48s test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.18s test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.86s test result: ok. 52 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 15.36s test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.05s test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s ``` `cargo clippy -p calternal-server --all-targets -- -D warnings` ```text Finished `dev` profile [unoptimized + debuginfo] target(s) in 3m 49s ``` `cargo test -p calternal-server` ```text test result: ok. 263 passed; 0 failed; 11 ignored; 0 measured; 0 filtered out; finished in 186.39s test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 43.84s test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.58s ``` `cd apps/web && bun run check` ```text perf-lint: PASS; 0 violations; 22404 scoped exceptions svelte-check found 0 errors and 2 warnings in 2 files ``` `cd apps/web && bun run test -- --maxWorkers=2` ```text Test Files 1 failed | 278 passed (279) Tests 1 failed | 1959 passed (1960) ``` The focused XUser classification test also passed: 17 tests, OK. All requested defensive scenarios ran. No requested scenario is deferred. Initial setup/test failures are retained in artifacts: server clippy first lacked generated production assets and passed after a real web build; the new upgrade fixture first used a retention-expired timestamp and now uses a live timestamp; the new receipt snapshot first raced normal source-copy cleanup and now drains that cleanup before the snapshot. Existing assertions were not relaxed. The cancellation ready/failed failure was a code defect and has its regression fix. ## Known limits and merge-round work Checkpoint tests exercise abrupt process exits and Root/Index restart, not physical power loss. No UI screenshots, full browser e2e, deployment, or Mac interop ran in this backend second review. Per the verification policy, the combined merge round must run: - `cd apps/web && bun run check` and `bun run test -- --maxWorkers=2` after #1196 is resolved. Prove the shared policy and exact Undo refusal regression agree. - `cd apps/web && bun e2e/money-wizard-1140.mjs`. Prove production wizard flows and edited-Budget Undo refusal. Capture macOS rendering at 390, 820 and 1440 px in light and dark; extend the harness if it does not cover those cases. - `bash tests/adversarial/run-split.sh`. Prove combined authorization, XUser and robustness matrices against the merged server. Cleanup completed: cargo clean removed 15.5 GiB. Generated web build, renderer build, Svelte output and copied Excalidraw fonts were deleted. No artifacts were committed. No push, deploy, issue close, or merge into dev was performed.
Author
Owner

Implemented #1196 at 689e3760af6819f9e462c3646327654a391a78a0 on job/wizard-1140. The worktree is clean. No push or deploy.

Status: CODE AND REQUIRED GATES PASS. PRODUCTION REGRESSION AND SCREENSHOT MATRIX ARE STILL PENDING. Do not treat the failed setup runs as passing evidence.

Built:

  • Extend the ported shared StatusPill with an inline variant. Keep its empty atomic polite live region mounted before an action. Show a decorative check or alert icon with the complete result text.
  • Show Money import Undo refusals and successful results in the wizard or the initiating notification row. Keep the exact server refusal and the receipt after later edits. Keep successful results visible until the User closes the sheet; do not navigate a notification away before its result can be read.
  • Guard repeated Undo activation. Disable a notification Undo after success. A notification read-state failure cannot replace a confirmed Undo result. Clear row feedback on session end and bound it to 200 results.
  • Show Copy details success and failure inline. Keep the one-time new-Budget nudge with a real Add account action and a stable link. The toast policy and its allow-list are unchanged.
  • Commit a focused real-server regression for edited Budget data, aria-live feedback, Undo results, Copy details, and Add account. It covers phone (390), tablet (820), desktop (1440), light and dark, macOS platform emulation, keyboard/touch, and 4x status crops.
  • Refresh only existing exact syntax hashes in the performance contracts. No rule, limit, exception count or ratchet was raised.

Commits:

  • a59f577de feat(ui): add inline live feedback to StatusPill for action results
  • 3911516a7 fix(money): keep import Undo outcomes visible inline without toasts
  • 689e3760a test(money): cover inline import feedback on all review widths and themes

Files:

  • apps/web/e2e/money-wizard-1140.mjs
  • apps/web/src/lib/components/StatusPill.svelte.test.ts
  • apps/web/src/lib/components/money/MoneyImport.svelte
  • apps/web/src/lib/money/import-session.svelte.test.ts
  • apps/web/src/lib/money/import-session.svelte.ts
  • apps/web/src/lib/notifications/InboxPanel.svelte
  • contracts/perf/adoption-1058.json
  • contracts/perf/exceptions.json
  • contracts/perf/registry.json
  • packages/ui/README.md
  • packages/ui/src/components/StatusPill.svelte

Shared controls: StatusPill owns status paint, icons and live announcements. Pill owns Undo, Copy details, Open Budget and Close. The existing OverlaySurface owns the wizard sheet. The shared toast renderer owns the nudge and its Pill action. No feature-local primitive restyling was added.

Validation:

  • git fetch origin && git merge origin/dev: Already up to date. Base dev SHA: 5301e020859c1d61b4a7f812a5049a64241203e8.
  • cargo fmt --check: exit 0, no output.
  • bun run check: exit 0. Verbatim summary:
perf-lint: PASS; 0 violations; 22404 scoped exceptions
svelte-check found 0 errors and 2 warnings in 2 files
  • bun run test -- --maxWorkers=2: exit 0. Verbatim summary:
 Test Files  280 passed (280)
      Tests  1963 passed (1963)
  • Focused Vitest (StatusPill, import session and unchanged toast-policy audit): exit 0. The two later-added cases also pass. Verbatim summary:
 Test Files  3 passed (3)
      Tests  37 passed (37)
  • cargo clippy -p calternal-money --all-targets -- -D warnings: exit 0.
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 1m 53s
  • cargo test -p calternal-money: exit 0.
test result: ok. 16 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.04s
test result: ok. 4 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.05s
test result: ok. 13 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 12.79s
test result: ok. 12 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 1.96s
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.03s
test result: ok. 4 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 3.40s
test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.68s
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
  • cargo clippy -p calternal-plugin-money --all-targets -- -D warnings: exit 0.
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 22m 15s
  • cargo test -p calternal-plugin-money: exit 0. Includes the Undo mutation route and refusal after every later Budget edit and server restart.
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 122 filtered out; finished in 54.10s
test result: ok. 121 passed; 0 failed; 2 ignored; 0 measured; 0 filtered out; finished in 79.34s
test result: ok. 27 passed; 0 failed; 3 ignored; 0 measured; 0 filtered out; finished in 10.59s
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
  • Production web build at the head commit: exit 0. node --check apps/web/e2e/money-wizard-1140.mjs: exit 0.

UX gaps closed: suppressed refusals; invisible Undo success; navigation that hid notification success; repeated Undo activation; read-state errors that overwrote Undo success; silent Copy details feedback; a nudge with no action.

Known gaps / UX gaps left: the matching branch server build did not yet finish. The focused production regression and the six macOS width/theme screenshot cases must still run. No passing visual evidence or visual approval is claimed. The first browser attempt used the prebuilt embedded frontend because the asset override was omitted. The second used this worktree's assets with a dev backend that lacked this branch's unmerged wizard changes. Both failures are retained in the evidence logs. The web check reports two existing CSS warnings in AttachmentDeck and AgendaList. Existing ignored Rust cases remain unchanged: isolated child entry points and performance profiles.

Decisions: keep Undo success visible until Close; keep notification results in their row without automatic navigation; make the one-time new-Budget nudge actionable with Add account. Inline results are local feedback and are cleared when the session ends. No new backend decision or dependency was added.

Expected work: the same two dependent Undo requests as before; one status line per displayed result; local receipt/result updates bounded to 200 entries. No additional server IO, query, Home scan, per-row observer or runtime alignment measurement. Performance measurements were not run because this is not a performance issue, per the current verification policy.

For the merge round (use this branch's server, not the shared dev binary):

export CARGO_PROFILE_DEV_DEBUG=line-tables-only CARGO_INCREMENTAL=0 CARGO_BUILD_JOBS=4 TMPDIR="$PWD/target/tmp"
cargo build -p calternal-server
cd apps/web
bun run build
CALTERNAL_E2E_ASSET_OVERRIDE=1 CALTERNAL_SERVER_BIN="$CARGO_TARGET_DIR/debug/calternal-server" TMPDIR="$PWD/../../target/tmp" bun e2e/money-wizard-1140.mjs --undo-feedback-only

This must prove that editing after import produces the exact visible, announced Undo refusal and leaves the Budget unchanged; it must capture all six macOS width/theme cases. Attach the screenshots for the orchestrator's visual review. Full e2e, adversarial matrices, release, staging and Mac interop stay with the merge round under the verification policy.

Cleanup: cargo clean ran after stopping the incomplete server build. Web build output and the copied diagnostic server were removed. Verbatim cleanup output:

     Removed 11610 files, 5.4GiB total

Evidence: verbatim gate logs and failed/incomplete runtime setup logs. No passing screenshot matrix is included.

Implemented #1196 at `689e3760af6819f9e462c3646327654a391a78a0` on `job/wizard-1140`. The worktree is clean. No push or deploy. Status: CODE AND REQUIRED GATES PASS. PRODUCTION REGRESSION AND SCREENSHOT MATRIX ARE STILL PENDING. Do not treat the failed setup runs as passing evidence. Built: - Extend the ported shared `StatusPill` with an inline variant. Keep its empty atomic polite live region mounted before an action. Show a decorative check or alert icon with the complete result text. - Show Money import Undo refusals and successful results in the wizard or the initiating notification row. Keep the exact server refusal and the receipt after later edits. Keep successful results visible until the User closes the sheet; do not navigate a notification away before its result can be read. - Guard repeated Undo activation. Disable a notification Undo after success. A notification read-state failure cannot replace a confirmed Undo result. Clear row feedback on session end and bound it to 200 results. - Show Copy details success and failure inline. Keep the one-time new-Budget nudge with a real Add account action and a stable link. The toast policy and its allow-list are unchanged. - Commit a focused real-server regression for edited Budget data, aria-live feedback, Undo results, Copy details, and Add account. It covers phone (390), tablet (820), desktop (1440), light and dark, macOS platform emulation, keyboard/touch, and 4x status crops. - Refresh only existing exact syntax hashes in the performance contracts. No rule, limit, exception count or ratchet was raised. Commits: - `a59f577de` feat(ui): add inline live feedback to StatusPill for action results - `3911516a7` fix(money): keep import Undo outcomes visible inline without toasts - `689e3760a` test(money): cover inline import feedback on all review widths and themes Files: - `apps/web/e2e/money-wizard-1140.mjs` - `apps/web/src/lib/components/StatusPill.svelte.test.ts` - `apps/web/src/lib/components/money/MoneyImport.svelte` - `apps/web/src/lib/money/import-session.svelte.test.ts` - `apps/web/src/lib/money/import-session.svelte.ts` - `apps/web/src/lib/notifications/InboxPanel.svelte` - `contracts/perf/adoption-1058.json` - `contracts/perf/exceptions.json` - `contracts/perf/registry.json` - `packages/ui/README.md` - `packages/ui/src/components/StatusPill.svelte` Shared controls: StatusPill owns status paint, icons and live announcements. Pill owns Undo, Copy details, Open Budget and Close. The existing OverlaySurface owns the wizard sheet. The shared toast renderer owns the nudge and its Pill action. No feature-local primitive restyling was added. Validation: - `git fetch origin && git merge origin/dev`: `Already up to date.` Base dev SHA: `5301e020859c1d61b4a7f812a5049a64241203e8`. - `cargo fmt --check`: exit 0, no output. - `bun run check`: exit 0. Verbatim summary: ```text perf-lint: PASS; 0 violations; 22404 scoped exceptions svelte-check found 0 errors and 2 warnings in 2 files ``` - `bun run test -- --maxWorkers=2`: exit 0. Verbatim summary: ```text Test Files 280 passed (280) Tests 1963 passed (1963) ``` - Focused Vitest (`StatusPill`, import session and unchanged toast-policy audit): exit 0. The two later-added cases also pass. Verbatim summary: ```text Test Files 3 passed (3) Tests 37 passed (37) ``` - `cargo clippy -p calternal-money --all-targets -- -D warnings`: exit 0. ```text Finished `dev` profile [unoptimized + debuginfo] target(s) in 1m 53s ``` - `cargo test -p calternal-money`: exit 0. ```text test result: ok. 16 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.04s test result: ok. 4 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.05s test result: ok. 13 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 12.79s test result: ok. 12 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 1.96s test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.03s test result: ok. 4 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 3.40s test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.68s test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s ``` - `cargo clippy -p calternal-plugin-money --all-targets -- -D warnings`: exit 0. ```text Finished `dev` profile [unoptimized + debuginfo] target(s) in 22m 15s ``` - `cargo test -p calternal-plugin-money`: exit 0. Includes the Undo mutation route and refusal after every later Budget edit and server restart. ```text test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 122 filtered out; finished in 54.10s test result: ok. 121 passed; 0 failed; 2 ignored; 0 measured; 0 filtered out; finished in 79.34s test result: ok. 27 passed; 0 failed; 3 ignored; 0 measured; 0 filtered out; finished in 10.59s test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s ``` - Production web build at the head commit: exit 0. `node --check apps/web/e2e/money-wizard-1140.mjs`: exit 0. UX gaps closed: suppressed refusals; invisible Undo success; navigation that hid notification success; repeated Undo activation; read-state errors that overwrote Undo success; silent Copy details feedback; a nudge with no action. Known gaps / UX gaps left: the matching branch server build did not yet finish. The focused production regression and the six macOS width/theme screenshot cases must still run. No passing visual evidence or visual approval is claimed. The first browser attempt used the prebuilt embedded frontend because the asset override was omitted. The second used this worktree's assets with a dev backend that lacked this branch's unmerged wizard changes. Both failures are retained in the evidence logs. The web check reports two existing CSS warnings in AttachmentDeck and AgendaList. Existing ignored Rust cases remain unchanged: isolated child entry points and performance profiles. Decisions: keep Undo success visible until Close; keep notification results in their row without automatic navigation; make the one-time new-Budget nudge actionable with Add account. Inline results are local feedback and are cleared when the session ends. No new backend decision or dependency was added. Expected work: the same two dependent Undo requests as before; one status line per displayed result; local receipt/result updates bounded to 200 entries. No additional server IO, query, Home scan, per-row observer or runtime alignment measurement. Performance measurements were not run because this is not a performance issue, per the current verification policy. For the merge round (use this branch's server, not the shared dev binary): ```sh export CARGO_PROFILE_DEV_DEBUG=line-tables-only CARGO_INCREMENTAL=0 CARGO_BUILD_JOBS=4 TMPDIR="$PWD/target/tmp" cargo build -p calternal-server cd apps/web bun run build CALTERNAL_E2E_ASSET_OVERRIDE=1 CALTERNAL_SERVER_BIN="$CARGO_TARGET_DIR/debug/calternal-server" TMPDIR="$PWD/../../target/tmp" bun e2e/money-wizard-1140.mjs --undo-feedback-only ``` This must prove that editing after import produces the exact visible, announced Undo refusal and leaves the Budget unchanged; it must capture all six macOS width/theme cases. Attach the screenshots for the orchestrator's visual review. Full e2e, adversarial matrices, release, staging and Mac interop stay with the merge round under the verification policy. Cleanup: `cargo clean` ran after stopping the incomplete server build. Web build output and the copied diagnostic server were removed. Verbatim cleanup output: ```text Removed 11610 files, 5.4GiB total ``` Evidence: [verbatim gate logs and failed/incomplete runtime setup logs](https://git.kayg.org/attachments/619ae214-72cd-4eca-ae96-97006f5e8abf). No passing screenshot matrix is included.
Author
Owner

Finding for #1140: the production Actual ZIP path admitted a durable import, but the page remained on Reading for 600,000 ms and never reached Review. No Money API error response or browser crash appeared; the local server was still running. An earlier no-padding run also remained on Reading for 210,000 ms. I did not change importer/server code because this job owns only review/choices UI.

I completed the requested production screenshots with an E2E-only ready-job fixture: real production web build and local server, real registration/authentication, real theme API, and a fixture preview with 54 Accounts, four type questions, 15,284 transactions, and 52,860 passing checks. It produced 18 macOS screenshots across 390/820/1440 in light and dark, and verifies keyboard and bulk type choices. The fixture is test-only and does not measure parser throughput. The actual large import path remains unverified on this host.

Finding for #1140: the production Actual ZIP path admitted a durable import, but the page remained on Reading for 600,000 ms and never reached Review. No Money API error response or browser crash appeared; the local server was still running. An earlier no-padding run also remained on Reading for 210,000 ms. I did not change importer/server code because this job owns only review/choices UI. I completed the requested production screenshots with an E2E-only ready-job fixture: real production web build and local server, real registration/authentication, real theme API, and a fixture preview with 54 Accounts, four type questions, 15,284 transactions, and 52,860 passing checks. It produced 18 macOS screenshots across 390/820/1440 in light and dark, and verifies keyboard and bulk type choices. The fixture is test-only and does not measure parser throughput. The actual large import path remains unverified on this host.
Author
Owner

Finished #1140 on job/wizchoices-1140.

Head: 6fdc2410a12ce8aaf861e1e45961e919784dbae1
Commits: 95ef54f6e review choices; 2a87b65d3 merged origin/dev; 4486f2a93 production screenshot fixture; 6fdc2410a clipboard feedback and exact perf pin refresh.

Built

  • Account review is a clean Card row list with the shared Select picker. Credit, CC and Card names receive a selected Credit card suggestion. “Set all remaining to…” fills untouched rows. The shared Pill primary action says “Import budget” and stays disabled while any type is unset, with the reason beside it.
  • Checks show one All 52,860 checks passed status and five expandable value-over-label Cards. Difference rows use shared Card elements and grouped numbers. The source copy says “Your export file is not changed.”
  • Copy details now reports its result inline for screen readers. Creating a new budget navigates to the budget without a redundant toast.
  • Review rendering cost is O(question Accounts + 5 check groups); it does not scan transaction rows.

Files

apps/web/src/lib/components/money/MoneyImport.svelte, MoneyImportMetrics.svelte, MoneyImportDifferences.svelte, apps/web/e2e/money-wizard-1140.mjs, apps/web/e2e/money-review-capture-1140.mjs, bench/money-import-actual-fixture.py, contracts/perf/adoption-1058.json, contracts/perf/exceptions.json.

UX gaps closed

The review has aligned type rows, name-based defaults, a bulk choice, a disabled-state reason, concise grouped differences, one passing-check summary, expandable details, and keyboard-tested picker/bulk actions. Shared visible controls: Card for rows, metrics and differences; Select for type menus; Pill for wizard actions.

UX gaps left and known gaps

  • The current Money preview contract exposes only Cash and Credit card account types. Loan, Investment and Tracking are not offered because this UI cannot submit those kinds to the server.
  • The preview does not include per-question open/closed state, so the rows do not show an invented badge.
  • The real 54-account Actual import was admitted, then stayed on Reading for 600,000 ms with no Money API error or browser crash. The test-only ready preview allowed production UI review, but large-parser completion is unverified on this host.
  • The 18 current macOS captures are in artifacts/wizard-1140/review-screenshots/ and are not committed. I could not attach them: fj exposes issue comments but no attachment command, and direct API auth was not available without exposing credentials.
  • Full bun run test had 1 failing test out of 279 (1,959/1,960 assertions). After removing this UI's three unclassified toast calls, the focused toast-policy test reports only two remaining calls in import-session.svelte.ts Undo code, which is outside this job. I left that code and test expectations unchanged.

Decisions

  • Keep the UI aligned with the existing Cash/Card server contract.
  • Omit open/closed badges because the preview has no per-account state.
  • The screenshot-only fixture uses 54 Accounts, four type questions (three suggested), 15,284 transactions and 52,860 checks. It is test-only; it does not ship in the app.
  • The origin merge took migration number 0007, so the existing Money migration was renumbered to 0008 before gates.

Verification output

cargo fmt --check: exit 0 (no output)
cargo clippy -p calternal-plugin-notifications --all-targets -- -D warnings: exit 0
cargo test -p calternal-plugin-notifications: 38 passed, 0 failed
cargo clippy -p calternal-server --all-targets -- -D warnings: exit 0
cargo test -p calternal-server: 263 passed, 0 failed, 11 ignored; perf_guards 1 passed; private_index_permissions 1 passed
perf-lint: PASS; 0 violations; 22404 scoped exceptions
svelte-check found 0 errors and 2 warnings in 2 files
bun run check: exit 0

The two Svelte warnings are existing empty focus CSS rules in packages/ui/src/components/calendar/AttachmentDeck.svelte and AgendaList.svelte.

FAIL  |unit| src/lib/stores/toast-policy.test.ts > toast policy > requires an action, a named background result, or an explicit no-toast decision
src/lib/money/import-session.svelte.ts:726: { label: 'Import undone.' }
src/lib/money/import-session.svelte.ts:730: { label: failure instanceof MoneyImportApiError && failure.status === 409 ? failure.message : 'The import could not be undone. Try again.', kind: 'alert' }
Test Files  1 failed (1)
Tests  1 failed (1)

The production review capture passed for light/dark at 390, 820 and 1440 on macOS. Local fixture readiness measured p50 5,837 ms and p95 7,691 ms (browser/auth/API start through review assertions). The production web build completed with: Compressed 917 static variants; saved 21228227 bytes. After verification, cargo clean reported: Removed 19545 files, 15.7GiB total; apps/web/build was removed.

Finished #1140 on `job/wizchoices-1140`. Head: `6fdc2410a12ce8aaf861e1e45961e919784dbae1` Commits: `95ef54f6e` review choices; `2a87b65d3` merged `origin/dev`; `4486f2a93` production screenshot fixture; `6fdc2410a` clipboard feedback and exact perf pin refresh. ## Built - Account review is a clean Card row list with the shared `Select` picker. Credit, CC and Card names receive a selected Credit card suggestion. “Set all remaining to…” fills untouched rows. The shared `Pill` primary action says “Import budget” and stays disabled while any type is unset, with the reason beside it. - Checks show one `All 52,860 checks passed` status and five expandable value-over-label Cards. Difference rows use shared `Card` elements and grouped numbers. The source copy says “Your export file is not changed.” - Copy details now reports its result inline for screen readers. Creating a new budget navigates to the budget without a redundant toast. - Review rendering cost is O(question Accounts + 5 check groups); it does not scan transaction rows. ## Files `apps/web/src/lib/components/money/MoneyImport.svelte`, `MoneyImportMetrics.svelte`, `MoneyImportDifferences.svelte`, `apps/web/e2e/money-wizard-1140.mjs`, `apps/web/e2e/money-review-capture-1140.mjs`, `bench/money-import-actual-fixture.py`, `contracts/perf/adoption-1058.json`, `contracts/perf/exceptions.json`. ## UX gaps closed The review has aligned type rows, name-based defaults, a bulk choice, a disabled-state reason, concise grouped differences, one passing-check summary, expandable details, and keyboard-tested picker/bulk actions. Shared visible controls: `Card` for rows, metrics and differences; `Select` for type menus; `Pill` for wizard actions. ## UX gaps left and known gaps - The current Money preview contract exposes only Cash and Credit card account types. Loan, Investment and Tracking are not offered because this UI cannot submit those kinds to the server. - The preview does not include per-question open/closed state, so the rows do not show an invented badge. - The real 54-account Actual import was admitted, then stayed on Reading for 600,000 ms with no Money API error or browser crash. The test-only ready preview allowed production UI review, but large-parser completion is unverified on this host. - The 18 current macOS captures are in `artifacts/wizard-1140/review-screenshots/` and are not committed. I could not attach them: `fj` exposes issue comments but no attachment command, and direct API auth was not available without exposing credentials. - Full `bun run test` had 1 failing test out of 279 (1,959/1,960 assertions). After removing this UI's three unclassified toast calls, the focused toast-policy test reports only two remaining calls in `import-session.svelte.ts` Undo code, which is outside this job. I left that code and test expectations unchanged. ## Decisions - Keep the UI aligned with the existing Cash/Card server contract. - Omit open/closed badges because the preview has no per-account state. - The screenshot-only fixture uses 54 Accounts, four type questions (three suggested), 15,284 transactions and 52,860 checks. It is test-only; it does not ship in the app. - The origin merge took migration number 0007, so the existing Money migration was renumbered to 0008 before gates. ## Verification output ```text cargo fmt --check: exit 0 (no output) cargo clippy -p calternal-plugin-notifications --all-targets -- -D warnings: exit 0 cargo test -p calternal-plugin-notifications: 38 passed, 0 failed cargo clippy -p calternal-server --all-targets -- -D warnings: exit 0 cargo test -p calternal-server: 263 passed, 0 failed, 11 ignored; perf_guards 1 passed; private_index_permissions 1 passed perf-lint: PASS; 0 violations; 22404 scoped exceptions svelte-check found 0 errors and 2 warnings in 2 files bun run check: exit 0 ``` The two Svelte warnings are existing empty focus CSS rules in `packages/ui/src/components/calendar/AttachmentDeck.svelte` and `AgendaList.svelte`. ```text FAIL |unit| src/lib/stores/toast-policy.test.ts > toast policy > requires an action, a named background result, or an explicit no-toast decision src/lib/money/import-session.svelte.ts:726: { label: 'Import undone.' } src/lib/money/import-session.svelte.ts:730: { label: failure instanceof MoneyImportApiError && failure.status === 409 ? failure.message : 'The import could not be undone. Try again.', kind: 'alert' } Test Files 1 failed (1) Tests 1 failed (1) ``` The production review capture passed for light/dark at 390, 820 and 1440 on macOS. Local fixture readiness measured p50 5,837 ms and p95 7,691 ms (browser/auth/API start through review assertions). The production web build completed with: `Compressed 917 static variants; saved 21228227 bytes.` After verification, `cargo clean` reported: `Removed 19545 files, 15.7GiB total`; `apps/web/build` was removed.
Author
Owner

Started merge30j on job/merge30, base 90a7a5efb. Merge job/wizard-1140, then job/wizchoices-1140; preserve all migrations and assertions, regenerate action contracts, reconcile exact performance pins, and run the requested web and per-crate Rust gates. No push or deploy.

Started merge30j on `job/merge30`, base `90a7a5efb`. Merge `job/wizard-1140`, then `job/wizchoices-1140`; preserve all migrations and assertions, regenerate action contracts, reconcile exact performance pins, and run the requested web and per-crate Rust gates. No push or deploy.
Author
Owner

Merged wizard as 72b6f0554, then review choices as 0ffeac9c3. origin/dev is already an ancestor after the required fetch and merge.

Upgrade reconciliation retains Auth 16, Files 26/27/28, Search 5, Notes 34/35 and Notifications 7/8. Both wizard branches implement the same Notifications 0008 feature; retained the wizard SQL with explicit column lists and child-table preservation. Expected additions are 17 from the round-9 fixture and 9 from the production 7c fixture. Every existing preservation assertion is retained.

UI reconciliation retains #1196 inline StatusPill feedback for Copy details and Undo, the working Add account nudge, live persisted-notice actions, and the incoming Account choices and review cards. Regenerated actions from the merged OpenAPI contract; 421 operations, 398 generated tools. Final gates are running; no completion claim yet.

Merged wizard as `72b6f0554`, then review choices as `0ffeac9c3`. `origin/dev` is already an ancestor after the required fetch and merge. Upgrade reconciliation retains Auth 16, Files 26/27/28, Search 5, Notes 34/35 and Notifications 7/8. Both wizard branches implement the same Notifications 0008 feature; retained the wizard SQL with explicit column lists and child-table preservation. Expected additions are 17 from the round-9 fixture and 9 from the production 7c fixture. Every existing preservation assertion is retained. UI reconciliation retains #1196 inline StatusPill feedback for Copy details and Undo, the working Add account nudge, live persisted-notice actions, and the incoming Account choices and review cards. Regenerated actions from the merged OpenAPI contract; 421 operations, 398 generated tools. Final gates are running; no completion claim yet.
Author
Owner

Exact performance reconciliation now passes: Exact live reconciliation: 22615 pins; 7750 exact #1058 sites; 0 violations.

The combined registry held multiple records for the same stable identity from different branch revisions. Reconciled each inventory against parsed live source, retained declared contracts, and removed stale/duplicate records. Inventoried the new /money/import view with the shared User-storage session-clearing contract; no unmeasured budget or behavior proof was claimed. Reused the existing #1058 adoption and ratchet validators. No guard source, rule, measured baseline, expiry or broad waiver changed.

Clean bun install --frozen-lockfile passed (911 packages). Formatting passed with no output. Production web build passed. Full web tests and the required Rust gates are still running; refreshed full web check is running.

Exact performance reconciliation now passes: `Exact live reconciliation: 22615 pins; 7750 exact #1058 sites; 0 violations`. The combined registry held multiple records for the same stable identity from different branch revisions. Reconciled each inventory against parsed live source, retained declared contracts, and removed stale/duplicate records. Inventoried the new `/money/import` view with the shared User-storage session-clearing contract; no unmeasured budget or behavior proof was claimed. Reused the existing #1058 adoption and ratchet validators. No guard source, rule, measured baseline, expiry or broad waiver changed. Clean `bun install --frozen-lockfile` passed (911 packages). Formatting passed with no output. Production web build passed. Full web tests and the required Rust gates are still running; refreshed full web check is running.
Author
Owner

Web gates pass on merge30j (current head beefb2ad8; the last commit changes only a Rust test wrapper). Verbatim summaries:

bun install --frozen-lockfile after removing installed node_modules directories:

bun install v1.4.2 (744846f84)

911 packages installed [5.69s]

cd apps/web && bun run check:

perf-lint: PASS; 0 violations; 22615 scoped exceptions
svelte-check found 0 errors and 2 warnings in 2 files

The warnings are empty focus CSS rules in shared Calendar AttachmentDeck and AgendaList.

cd apps/web && bun run test --maxWorkers=2:

Ran 136 tests in 0.064s
OK
 Test Files  282 passed (282)
      Tests  1978 passed (1978)
   Duration  590.05s (transform 34%, environment 23%, import 21%, tests 16%, setup 5%)

Additional registry checks found two contract/recipe coverage mismatches and were filed as #1203. No test expectation was weakened. Rust gates and real-server verification are not complete yet.

Web gates pass on merge30j (current head beefb2ad8; the last commit changes only a Rust test wrapper). Verbatim summaries: `bun install --frozen-lockfile` after removing installed node_modules directories: ```text bun install v1.4.2 (744846f84) 911 packages installed [5.69s] ``` `cd apps/web && bun run check`: ```text perf-lint: PASS; 0 violations; 22615 scoped exceptions svelte-check found 0 errors and 2 warnings in 2 files ``` The warnings are empty focus CSS rules in shared Calendar AttachmentDeck and AgendaList. `cd apps/web && bun run test --maxWorkers=2`: ```text Ran 136 tests in 0.064s OK Test Files 282 passed (282) Tests 1978 passed (1978) Duration 590.05s (transform 34%, environment 23%, import 21%, tests 16%, setup 5%) ``` Additional registry checks found two contract/recipe coverage mismatches and were filed as #1203. No test expectation was weakened. Rust gates and real-server verification are not complete yet.
Author
Owner

Adversarial preflight found a merge integration gap: the new post-bind /healthz contract uses startup_healthz, which had no authorization-matrix classification. The handler and its source docs define this as public, content-free startup phase metadata (#1161).

Fixed in b6df96c0b with one exact method/path/operation triple. Added a regression first; it failed on the missing policy. The regression also refuses another method, path or operation ID, so this is not a prefix waiver. Existing expectations are unchanged.

Verbatim verification:

Ran 16 tests in 1.741s

OK
Ran 17 tests in 0.368s

OK
Cross-User classification gate: 423 operations classified
Generated entry point classification: 1194 tools classified
Admin coverage: 52 reviewed operations; contract and Rust guards agree

Rust gates remain in progress.

Adversarial preflight found a merge integration gap: the new post-bind `/healthz` contract uses `startup_healthz`, which had no authorization-matrix classification. The handler and its source docs define this as public, content-free startup phase metadata (#1161). Fixed in `b6df96c0b` with one exact method/path/operation triple. Added a regression first; it failed on the missing policy. The regression also refuses another method, path or operation ID, so this is not a prefix waiver. Existing expectations are unchanged. Verbatim verification: ```text Ran 16 tests in 1.741s OK Ran 17 tests in 0.368s OK Cross-User classification gate: 423 operations classified Generated entry point classification: 1194 tools classified Admin coverage: 52 reviewed operations; contract and Rust guards agree ``` Rust gates remain in progress.
Author
Owner

Progress at 2026-10-06 13:52 UTC: head b6df96c0b37308788b1800946d249fffaf94cf4f; working tree is clean. Both requested branches and fetched origin/dev are included.

Web check and all 1978 web tests pass. Exact perf pins and classification regressions pass. The first server clippy invocation is still progressing through the shared compiler service (now at tokenizers/Tantivy dependencies), with no reported compiler failure. CARGO_BUILD_JOBS remains 4, incremental output is off, the preset target is unchanged, and no uncommitted work is being held during compilation.

The requested per-crate Rust tests and real-server Money/browser round remain pending. No push or deploy.

Progress at 2026-10-06 13:52 UTC: head `b6df96c0b37308788b1800946d249fffaf94cf4f`; working tree is clean. Both requested branches and fetched origin/dev are included. Web check and all 1978 web tests pass. Exact perf pins and classification regressions pass. The first server clippy invocation is still progressing through the shared compiler service (now at tokenizers/Tantivy dependencies), with no reported compiler failure. CARGO_BUILD_JOBS remains 4, incremental output is off, the preset target is unchanged, and no uncommitted work is being held during compilation. The requested per-crate Rust tests and real-server Money/browser round remain pending. No push or deploy.
Author
Owner

Head 56f44bf81d6aa7aa57dad7bf6b2787cc916fca1c; worktree is clean. Server clippy passed:

    Finished `dev` profile [unoptimized + debuginfo] target(s) in 88m 02s

The sequential Rust gate runner is now compiling cargo test -p calternal-server -- --test-threads=4. It has not returned a test result yet. Both requested merges and the exact performance-pin reconciliation are committed. Full web check and 1,978 Vitest tests passed. No push or deploy.

Head `56f44bf81d6aa7aa57dad7bf6b2787cc916fca1c`; worktree is clean. Server clippy passed: ```text Finished `dev` profile [unoptimized + debuginfo] target(s) in 88m 02s ``` The sequential Rust gate runner is now compiling `cargo test -p calternal-server -- --test-threads=4`. It has not returned a test result yet. Both requested merges and the exact performance-pin reconciliation are committed. Full web check and 1,978 Vitest tests passed. No push or deploy.
Author
Owner

Real-server acceptance found a Money import stall at head 56f44bf81. The 15,000-transaction Actual fixture timed out at Review after 210 seconds, both with restart (390 px) and without restart (820 px). The screen remained on Finishing, 1 of 1 steps. Synthetic queue metadata showed four attempts, last_error = Budget import lease ended., and no persisted preview.

The controlled Money handler awaited progress writes inside its timer branch. That stopped polling the parser while it could own the same single writer. The shared Worker already prevents this cycle (#1042). A focused regression using a real one-connection SQLite pool reproduced the starvation:

test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 123 filtered out; finished in 2.60s

The fix keeps parser completion polled while the progress monitor waits, using the existing Worker pattern. Focused verification and fresh affected Rust gates are running. Earlier server gate failures were free-space-reserve refusals; the retry produced 265 passed, 0 failed plus both integration checks passing. No assertion or production reserve changed.

Real-server acceptance found a Money import stall at head `56f44bf81`. The 15,000-transaction Actual fixture timed out at Review after 210 seconds, both with restart (390 px) and without restart (820 px). The screen remained on Finishing, 1 of 1 steps. Synthetic queue metadata showed four attempts, `last_error = Budget import lease ended.`, and no persisted preview. The controlled Money handler awaited progress writes inside its timer branch. That stopped polling the parser while it could own the same single writer. The shared Worker already prevents this cycle (#1042). A focused regression using a real one-connection SQLite pool reproduced the starvation: ```text test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 123 filtered out; finished in 2.60s ``` The fix keeps parser completion polled while the progress monitor waits, using the existing Worker pattern. Focused verification and fresh affected Rust gates are running. Earlier server gate failures were free-space-reserve refusals; the retry produced 265 passed, 0 failed plus both integration checks passing. No assertion or production reserve changed.
Author
Owner

Committed the writer starvation fix as 5dfa3c016. Focused regression changed from a two-second timeout to passing in 0.09 seconds. Money gates passed:

    Finished `dev` profile [unoptimized + debuginfo] target(s) in 51.36s
test result: ok. 122 passed; 0 failed; 2 ignored; 0 measured; 0 filtered out; finished in 75.73s
test result: ok. 27 passed; 0 failed; 3 ignored; 0 measured; 0 filtered out; finished in 5.25s

Production review fixture screenshots: 390, 820 and 1440 px, Light and Dark, macOS platform. These test-only ready-preview fixtures prove the rendered review controls, not real parser acceptance. Capture profile: p50 2688 ms, p95 3518 ms on this shared local host. The full real-import acceptance now uses the rebuilt fixed server. Server clippy passed again; server tests are running. Exact perf reconciliation remains 22615 live pins and zero violations; no rule or ratchet changed for the fix.

Committed the writer starvation fix as `5dfa3c016`. Focused regression changed from a two-second timeout to passing in 0.09 seconds. Money gates passed: ```text Finished `dev` profile [unoptimized + debuginfo] target(s) in 51.36s test result: ok. 122 passed; 0 failed; 2 ignored; 0 measured; 0 filtered out; finished in 75.73s test result: ok. 27 passed; 0 failed; 3 ignored; 0 measured; 0 filtered out; finished in 5.25s ``` [Production review fixture screenshots](https://git.kayg.org/attachments/a1d7cd3d-c55d-4182-92f1-ee047cee32cf): 390, 820 and 1440 px, Light and Dark, macOS platform. These test-only ready-preview fixtures prove the rendered review controls, not real parser acceptance. Capture profile: p50 2688 ms, p95 3518 ms on this shared local host. The full real-import acceptance now uses the rebuilt fixed server. Server clippy passed again; server tests are running. Exact perf reconciliation remains 22615 live pins and zero violations; no rule or ratchet changed for the fix.
Author
Owner

The fixed real-server restart case reached Review. Its unchanged expectation exposed a second defect: the 54-Account fixture requests four ambiguous Account questions, but only three appeared. Actual metadata was absent for Everyday CC; the parser asked only about names containing credit or card and silently treated this Account as Cash.

Added a standalone-word CC confirmation rule, with explicit source types and existing User choices taking priority. CSV inference is unchanged. The new regression failed before the change, then passed; existing acceptance expectations and fixtures remain unchanged. Full Money gates passed: 123 unit tests, 27 import-review tests, zero failures. Fresh server gates are running. Review scans only untyped, unselected labels (O(total label bytes)); all typed Accounts return before the scan. No new dependency, layout measurement or database work.

The fixed real-server restart case reached Review. Its unchanged expectation exposed a second defect: the 54-Account fixture requests four ambiguous Account questions, but only three appeared. Actual metadata was absent for `Everyday CC`; the parser asked only about names containing `credit` or `card` and silently treated this Account as Cash. Added a standalone-word CC confirmation rule, with explicit source types and existing User choices taking priority. CSV inference is unchanged. The new regression failed before the change, then passed; existing acceptance expectations and fixtures remain unchanged. Full Money gates passed: 123 unit tests, 27 import-review tests, zero failures. Fresh server gates are running. Review scans only untyped, unselected labels (O(total label bytes)); all typed Accounts return before the scan. No new dependency, layout measurement or database work.
Author
Owner

Found in merge30j (#1140), production head cc1aae60a. The real Actual fixture reaches Review after the writer and CC fixes, with four Account questions and four selected Card suggestions. The unchanged acceptance assertion then fails:

Synthetic review summary: All 7,320 checks passed
AssertionError: the review summary shows at least 15,000 real checks

The fixture has 54 Accounts, two Categories, 120 months and 15,000 transactions. Its checks are 54 × 120 Account balances, 2 × 120 × 3 Category checks, and 120 Ready-to-assign checks: 7,320. Transaction count is not the check count. This reproduced on both 390 px with restart and 820 px without restart. The expectation totalCheckCount >= 15000 and source fixtures remain unchanged, per the owner rule.

The test also selected the bulk picker as an Account picker after the review-step merge. Narrowing only those three selectors to .account-kind-row-card .select-trigger makes all four existing Card-label assertions pass. No assertion changed. A count-only diagnostic log supplies the evidence above.

The orchestrator must decide whether the threshold should use the actual source-check formula or the fixture should contain more Categories. Do not alter financial checks or inflate the displayed count. This blocks completing the monolithic acceptance script beyond Review; the required web/Rust gates pass and independent format/Undo checks are being run.

Found in merge30j (#1140), production head `cc1aae60a`. The real Actual fixture reaches Review after the writer and CC fixes, with four Account questions and four selected Card suggestions. The unchanged acceptance assertion then fails: ```text Synthetic review summary: All 7,320 checks passed AssertionError: the review summary shows at least 15,000 real checks ``` The fixture has 54 Accounts, two Categories, 120 months and 15,000 transactions. Its checks are 54 × 120 Account balances, 2 × 120 × 3 Category checks, and 120 Ready-to-assign checks: 7,320. Transaction count is not the check count. This reproduced on both 390 px with restart and 820 px without restart. The expectation `totalCheckCount >= 15000` and source fixtures remain unchanged, per the owner rule. The test also selected the bulk picker as an Account picker after the review-step merge. Narrowing only those three selectors to `.account-kind-row-card .select-trigger` makes all four existing Card-label assertions pass. No assertion changed. A count-only diagnostic log supplies the evidence above. The orchestrator must decide whether the threshold should use the actual source-check formula or the fixture should contain more Categories. Do not alter financial checks or inflate the displayed count. This blocks completing the monolithic acceptance script beyond Review; the required web/Rust gates pass and independent format/Undo checks are being run.
Author
Owner

Found during merge30j (#1140), head ff53d7b8b. Run the real production check cd apps/web && bun e2e/money-wizard-1140.mjs --inverse-only with the current server and macOS emulation. Phone Light completes refusal, successful Undo and Admin captures. Tablet Light completes the refused Undo, preserving the edited Budget and its receipt.

Reopening /money/import then pressing Enter on the second .source-choice leaves the view at source; the file input never appears. The existing setInputFiles assertion times out after 90 seconds at line 477. There is no reported browser exception. Both first-import selection and phone re-import worked in the same run. The failure screenshot is retained in artifacts/wizard-1140/failed-review.png.

Do not assume a parser or Undo failure: both imports and the refusal before this source-selection step worked. Check whether startup/recovery resets the chosen step or the test dispatches Enter before client event wiring is ready. Keep the existing interaction and assertions. This is a UI/test readiness gap, not evidence of data loss or an authorization hole.

Found during merge30j (#1140), head `ff53d7b8b`. Run the real production check `cd apps/web && bun e2e/money-wizard-1140.mjs --inverse-only` with the current server and macOS emulation. Phone Light completes refusal, successful Undo and Admin captures. Tablet Light completes the refused Undo, preserving the edited Budget and its receipt. Reopening `/money/import` then pressing Enter on the second `.source-choice` leaves the view at `source`; the file input never appears. The existing `setInputFiles` assertion times out after 90 seconds at line 477. There is no reported browser exception. Both first-import selection and phone re-import worked in the same run. The failure screenshot is retained in `artifacts/wizard-1140/failed-review.png`. Do not assume a parser or Undo failure: both imports and the refusal before this source-selection step worked. Check whether startup/recovery resets the chosen step or the test dispatches Enter before client event wiring is ready. Keep the existing interaction and assertions. This is a UI/test readiness gap, not evidence of data loss or an authorization hole.
Author
Owner

Found by merge30j (#1140), head ff53d7b8b, production shell e2e with macOS platform emulation. Owner setup, passkey/recovery handoff, Daily note Log entry, Note read and CSP checks passed. The mode-tray viewport then failed to settle at 1440 px after a pointer switch to Ask:

viewport=1440; visible=[Files,Photos,Mail,Ask]; selected=Ask
scrollLeft=106; trackWidth=274; clientWidth=274; scrollWidth=380
selectedAnimations=[]
Ask left=753 right=835

assertTrayViewport fails at apps/web/e2e/shell.mjs:736, called by testTabBar:797. The source mode-tray component is unchanged by the Money merge. No expectation was changed and the full shell test was run once. Check selected-tab visibility and tray scroll bounds on the real production app; retain pointer/keyboard motion. This is a shell layout/verification gap, not evidence of data loss or an authorization hole.

Found by merge30j (#1140), head `ff53d7b8b`, production shell e2e with macOS platform emulation. Owner setup, passkey/recovery handoff, Daily note Log entry, Note read and CSP checks passed. The mode-tray viewport then failed to settle at 1440 px after a pointer switch to Ask: ```text viewport=1440; visible=[Files,Photos,Mail,Ask]; selected=Ask scrollLeft=106; trackWidth=274; clientWidth=274; scrollWidth=380 selectedAnimations=[] Ask left=753 right=835 ``` `assertTrayViewport` fails at `apps/web/e2e/shell.mjs:736`, called by `testTabBar:797`. The source mode-tray component is unchanged by the Money merge. No expectation was changed and the full shell test was run once. Check selected-tab visibility and tray scroll bounds on the real production app; retain pointer/keyboard motion. This is a shell layout/verification gap, not evidence of data loss or an authorization hole.
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#1140
No description provided.