Merge round 40: Users settings, Money register UI, reminders, Calendar and startup speed #1574

Closed
opened 2026-10-11 08:18:15 +00:00 by kayg · 50 comments
Owner

Merge round 40 on top of the merge round 39 chain (job/fix1569 0866ca3b2 = merge39 + #1566 + #1569 + origin/dev 0c712b98c).

Branches: ui-users 3343abda5 + ui-chrome4 4c23c5b80 (Settings → Users rows, menu placement in container-type ancestors, Card interactive, menu trailing detail); ui-money2 8f47550de (Money register UI, #1498 recovery, resize anchor); remtext-1568 164a4abc8 (block text in reminders, Notes migration 0039); calcold-1560 6f686af41 (cold Calendar reads, Calendar migration 0007); rec1540c c57013196 (#1540 startup SQLite contention, resumable scans); tabswitch2 555c4d8aa (bench harness only, #1233).
Not included: #1570 Money hint fix (merged after its review), #1557 Calendar layout (remeasuring).

Merge round 40 on top of the merge round 39 chain (job/fix1569 0866ca3b2 = merge39 + #1566 + #1569 + origin/dev 0c712b98c). Branches: ui-users 3343abda5 + ui-chrome4 4c23c5b80 (Settings → Users rows, menu placement in container-type ancestors, Card interactive, menu trailing detail); ui-money2 8f47550de (Money register UI, #1498 recovery, resize anchor); remtext-1568 164a4abc8 (block text in reminders, Notes migration 0039); calcold-1560 6f686af41 (cold Calendar reads, Calendar migration 0007); rec1540c c57013196 (#1540 startup SQLite contention, resumable scans); tabswitch2 555c4d8aa (bench harness only, #1233). Not included: #1570 Money hint fix (merged after its review), #1557 Calendar layout (remeasuring).
Author
Owner

Starting merge round 40 on branch job/merge40. Base SHA: 0866ca3b22. I will merge the six requested commits in order and report gate output and merge findings here.

Starting merge round 40 on branch job/merge40. Base SHA: 0866ca3b225e1d0964d80dccab14d5dc1b96b69e. I will merge the six requested commits in order and report gate output and merge findings here.
Author
Owner

The tab-switch conflict has overlapping #1233 coverage. The calcold side contains all tabswitch2 test names and exported helpers, plus four Calendar-specific tests and their fixture/read-summary helpers. Its output retains the shared Tab and Composer sample fields and adds Calendar diagnostics. I am keeping that combined version.

The tab-switch conflict has overlapping #1233 coverage. The calcold side contains all tabswitch2 test names and exported helpers, plus four Calendar-specific tests and their fixture/read-summary helpers. Its output retains the shared Tab and Composer sample fields and adds Calendar diagnostics. I am keeping that combined version.
Author
Owner

The one-time scripts/perf-lint --adopt-7c regeneration completed with perf-lint: PASS; 0 violations; 22193 scoped exceptions. It changed 132 exact scope records versus the pre-regeneration ledger: 127 io.unresolved-call, 4 io.source-parser and 1 sql.query-in-loop were added; 7 prior records were removed. The generated ratchet total rose from 22080 to 22193, which conflicts with the merge instruction to keep the lower ratchet. I am holding these generated files uncommitted while I check whether the new Notes parsing/projection paths can be resolved without increasing the ceiling.

The one-time `scripts/perf-lint --adopt-7c` regeneration completed with `perf-lint: PASS; 0 violations; 22193 scoped exceptions`. It changed 132 exact scope records versus the pre-regeneration ledger: 127 io.unresolved-call, 4 io.source-parser and 1 sql.query-in-loop were added; 7 prior records were removed. The generated ratchet total rose from 22080 to 22193, which conflicts with the merge instruction to keep the lower ratchet. I am holding these generated files uncommitted while I check whether the new Notes parsing/projection paths can be resolved without increasing the ceiling.
Author
Owner

Finding while reviewing the Notes reminder projection: index_note_projection_once awaited one note_blocks INSERT per Block inside its writer transaction. I replaced that loop with 200-row QueryBuilder batches (800 bound values, below SQLite's 999-variable limit) and added a real Index regression that spans three batches and checks the final row's plain text. This keeps the full source projection atomic while bounding statement count to ceil(blocks/200). Focused Notes gates are next.

Finding while reviewing the Notes reminder projection: `index_note_projection_once` awaited one `note_blocks` INSERT per Block inside its writer transaction. I replaced that loop with 200-row `QueryBuilder` batches (800 bound values, below SQLite's 999-variable limit) and added a real Index regression that spans three batches and checks the final row's plain text. This keeps the full source projection atomic while bounding statement count to ceil(blocks/200). Focused Notes gates are next.
kayg referenced this issue from a commit 2026-10-11 08:56:19 +00:00
kayg referenced this issue from a commit 2026-10-11 08:56:19 +00:00
kayg referenced this issue from a commit 2026-10-11 08:56:19 +00:00
kayg referenced this issue from a commit 2026-10-11 08:56:19 +00:00
kayg referenced this issue from a commit 2026-10-11 08:56:19 +00:00
kayg referenced this issue from a commit 2026-10-11 08:56:19 +00:00
Author
Owner

Merge-round finding: node --test bench/*.test.mjs exits 1 because bench/startup-1011.test.mjs and bench/tab-switch.test.mjs import bun:test; Node reports ERR_UNSUPPORTED_ESM_URL_SCHEME for bun:. The equivalent supported runner passes: bun test bench/*.test.mjs → 37 pass, 0 fail. No test assertions were changed.

Merge-round finding: `node --test bench/*.test.mjs` exits 1 because `bench/startup-1011.test.mjs` and `bench/tab-switch.test.mjs` import `bun:test`; Node reports `ERR_UNSUPPORTED_ESM_URL_SCHEME` for `bun:`. The equivalent supported runner passes: `bun test bench/*.test.mjs` → 37 pass, 0 fail. No test assertions were changed.
Author
Owner

Perf contract finding after final exact-pin regeneration: scripts/perf-lint --check reports perf-lint: INVALID: exception ratchet: io.source-parser: 6 exceptions exceed the ratchet ceiling 2; fix the new violation instead; io.unresolved-call: 16272 exceptions exceed the ratchet ceiling 16158; fix the new violation instead; total: ledger has 22198 exceptions; ratchet total is 22080.

I committed the exact merged pins in ecbefcfdd and kept contracts/perf/ratchet.json unchanged at the required lower ceilings. I did not adopt a higher ratchet. The ordinary check remains a merge blocker under the 2026-10-06 owner rule.

Perf contract finding after final exact-pin regeneration: `scripts/perf-lint --check` reports `perf-lint: INVALID: exception ratchet: io.source-parser: 6 exceptions exceed the ratchet ceiling 2; fix the new violation instead; io.unresolved-call: 16272 exceptions exceed the ratchet ceiling 16158; fix the new violation instead; total: ledger has 22198 exceptions; ratchet total is 22080`. I committed the exact merged pins in `ecbefcfdd` and kept `contracts/perf/ratchet.json` unchanged at the required lower ceilings. I did not adopt a higher ratchet. The ordinary check remains a merge blocker under the 2026-10-06 owner rule.
Author
Owner

Production comparison finding: CALTERNAL_SERVER_BIN=/mnt/hdd/targets/shared-server/4ebeba0b8/calternal-server-release bun e2e/merge39-review.mjs --auth-only stops before any visual capture because /api/v1/auth/setup/check returns 404 (early setup validity endpoint exists, expected 200). The script documents that this endpoint is added after production 4ebeba0b8, so this is a pre-existing baseline gap, not a merge-only regression. No existing expectation was changed. I will use focused Admin/Notifications probes for the surfaces the early failure skipped.

Production comparison finding: `CALTERNAL_SERVER_BIN=/mnt/hdd/targets/shared-server/4ebeba0b8/calternal-server-release bun e2e/merge39-review.mjs --auth-only` stops before any visual capture because `/api/v1/auth/setup/check` returns 404 (`early setup validity endpoint exists`, expected 200). The script documents that this endpoint is added after production 4ebeba0b8, so this is a pre-existing baseline gap, not a merge-only regression. No existing expectation was changed. I will use focused Admin/Notifications probes for the surfaces the early failure skipped.
Author
Owner

Production comparison finding: money-fidelity-1130.mjs fails on production 4ebeba0b8 before its review capture: the old SPA never exposes .import-flow combobox Account type for Card account, and Playwright times out after 30s. The unchanged test passes/continues on the merged build check later; this is classified against the requested production baseline. No assertion was altered.

Production comparison finding: `money-fidelity-1130.mjs` fails on production 4ebeba0b8 before its review capture: the old SPA never exposes `.import-flow` combobox `Account type for Card account`, and Playwright times out after 30s. The unchanged test passes/continues on the merged build check later; this is classified against the requested production baseline. No assertion was altered.
Author
Owner

Production comparison finding: money-review-capture-1140.mjs reaches the Actual import Review route on 4ebeba0b8, then fails its existing assertion because the old SPA renders 0 .import-metric cards where the #1140 review expects 7. This is a production-baseline UI difference; the expectation is unchanged. The merged-build run will determine whether there is any merge-only regression.

Production comparison finding: `money-review-capture-1140.mjs` reaches the Actual import Review route on 4ebeba0b8, then fails its existing assertion because the old SPA renders 0 `.import-metric` cards where the #1140 review expects 7. This is a production-baseline UI difference; the expectation is unchanged. The merged-build run will determine whether there is any merge-only regression.
Author
Owner

Production comparison finding: the full money.mjs flow on production 4ebeba0b8 completed its exact-Markdown transaction flow and captured the width/theme matrix, then timed out waiting for Create Budget in the default empty state. This is a pre-existing baseline UI difference; no assertion was changed. The saved capture set is under the ignored artifacts/merge40/baseline/money/ directory.

Production comparison finding: the full `money.mjs` flow on production 4ebeba0b8 completed its exact-Markdown transaction flow and captured the width/theme matrix, then timed out waiting for `Create Budget` in the default empty state. This is a pre-existing baseline UI difference; no assertion was changed. The saved capture set is under the ignored `artifacts/merge40/baseline/money/` directory.
Author
Owner

Workspace cargo test -- --test-threads=4 found a merge-only upgrade-test mismatch: the final release applies Notes 0039, but three server upgrade inventories still stopped at 0038 or counted 38/30 entries. The failures are in production_round_9_schema_upgrades_once_with_original_receipts, production_7b_schema_copy_upgrades_combined_pending_migrations, and production_7c_upgrades_content_types_once. I am updating only the migration inventories and their exact counts to include issue #1568's required 0039 receipt; no unrelated test expectation changes.

Workspace `cargo test -- --test-threads=4` found a merge-only upgrade-test mismatch: the final release applies Notes 0039, but three server upgrade inventories still stopped at 0038 or counted 38/30 entries. The failures are in `production_round_9_schema_upgrades_once_with_original_receipts`, `production_7b_schema_copy_upgrades_combined_pending_migrations`, and `production_7c_upgrades_content_types_once`. I am updating only the migration inventories and their exact counts to include issue #1568's required 0039 receipt; no unrelated test expectation changes.
Author
Owner

Production comparison finding: calendar.mjs on 4ebeba0b8 times out waiting for the Week link (getByRole('link', { name: 'Week', exact: true })). The baseline SPA predates this Calendar Week route. This is recorded as pre-existing; the merged build still needs the Calendar e2e and cold Week captures.

Production comparison finding: `calendar.mjs` on 4ebeba0b8 times out waiting for the Week link (`getByRole('link', { name: 'Week', exact: true })`). The baseline SPA predates this Calendar Week route. This is recorded as pre-existing; the merged build still needs the Calendar e2e and cold Week captures.
Author
Owner

Production comparison finding: notifications.mjs on 4ebeba0b8 registers two Users and opens the empty inbox, then times out on the newer empty-state sentence Files and folders people share with you. It exits before the reminder scenario, so the production baseline cannot exercise that scenario with this script. The merged Notifications run remains required; no assertion was changed.

Production comparison finding: `notifications.mjs` on 4ebeba0b8 registers two Users and opens the empty inbox, then times out on the newer empty-state sentence `Files and folders people share with you`. It exits before the reminder scenario, so the production baseline cannot exercise that scenario with this script. The merged Notifications run remains required; no assertion was changed.
Author
Owner

Production comparison finding: files.mjs on 4ebeba0b8 reaches the real thumbnail flow but times out waiting for the text-card thumbnail for thumbnail-cache-547.txt; the row reports mime=application/pdf and has_thumbnail=true. This is classified as a pre-existing Files baseline difference. The server log contained no CSP reports. No assertion was changed.

Production comparison finding: `files.mjs` on 4ebeba0b8 reaches the real thumbnail flow but times out waiting for the text-card thumbnail for `thumbnail-cache-547.txt`; the row reports `mime=application/pdf` and `has_thumbnail=true`. This is classified as a pre-existing Files baseline difference. The server log contained no CSP reports. No assertion was changed.
Author
Owner

Adversarial round finding: ADVERSARIAL_API_ONLY=1 tests/adversarial/run.sh reaches its API attack phases, but its MCP and Sidecar probes compare Files preferences to a two-field object. The current API includes the existing show_hidden_items field from #1153. Direct fresh-User GETs returned HTTP 200 with all three fields false on both production 4ebeba0b8 and the merge40 release. Filed as #1577; I kept the existing assertions unchanged. The same API round reported one SLOW-only appearance PUT p95 of 0.638 s against 0.500 s; other reported API probes completed without findings.

ADVERSARIAL_MONEY_ONLY=1 tests/adversarial/run.sh passed Money API and MCP attacks: cursed/oversized imports, a 40-write storm, 48 mixed create calls, cancellation and one-use tokens. XUSER_MATRIX_ONLY=1 tests/adversarial/run-split.sh passed: 227 operations replayed, 1,058 ID/missing-ID comparisons, 127 Job/Mail/quota comparisons, zero denial failures; Round 2 reported 0 findings and 0 SLOW.

Adversarial round finding: `ADVERSARIAL_API_ONLY=1 tests/adversarial/run.sh` reaches its API attack phases, but its MCP and Sidecar probes compare Files preferences to a two-field object. The current API includes the existing `show_hidden_items` field from #1153. Direct fresh-User GETs returned HTTP 200 with all three fields false on both production 4ebeba0b8 and the merge40 release. Filed as #1577; I kept the existing assertions unchanged. The same API round reported one SLOW-only appearance PUT p95 of 0.638 s against 0.500 s; other reported API probes completed without findings. `ADVERSARIAL_MONEY_ONLY=1 tests/adversarial/run.sh` passed Money API and MCP attacks: cursed/oversized imports, a 40-write storm, 48 mixed create calls, cancellation and one-use tokens. `XUSER_MATRIX_ONLY=1 tests/adversarial/run-split.sh` passed: 227 operations replayed, 1,058 ID/missing-ID comparisons, 127 Job/Mail/quota comparisons, zero denial failures; Round 2 reported 0 findings and 0 SLOW.
Author
Owner

Merge40 reproduces the existing fixture-family mismatch on both the release candidate and production 4ebeba0b8: apps/web/e2e/files.mjs waits for a text-card thumbnail for thumbnail-cache-547.txt, while the live Files row reports mime=application/pdf and has_thumbnail=true. The check times out at files.mjs:433; no server 5xx or crash occurred. This remains the pre-existing #1563 issue; I kept the assertion unchanged.

Merge40 reproduces the existing fixture-family mismatch on both the release candidate and production `4ebeba0b8`: `apps/web/e2e/files.mjs` waits for a text-card thumbnail for `thumbnail-cache-547.txt`, while the live Files row reports `mime=application/pdf` and `has_thumbnail=true`. The check times out at `files.mjs:433`; no server 5xx or crash occurred. This remains the pre-existing #1563 issue; I kept the assertion unchanged.
Author
Owner

Candidate money-fidelity-1130.mjs reaches the real import review but times out waiting for the Account type for Card account combobox at line 45. Production 4ebeba0b8 fails at the same selector. This is the existing #1558 baseline failure; I kept the assertion unchanged and captured the candidate's import form before the timeout.

Candidate `money-fidelity-1130.mjs` reaches the real import review but times out waiting for the `Account type for Card account` combobox at line 45. Production `4ebeba0b8` fails at the same selector. This is the existing #1558 baseline failure; I kept the assertion unchanged and captured the candidate's import form before the timeout.
Author
Owner

The real-server e2e apps/web/e2e/money-review-capture-1140.mjs fails on production 4ebeba0b8 and the merge40 release at its existing assertion on line 132: it expects seven .import-metric elements after import review, but sees zero. The candidate failure is the same as the production baseline and is not introduced by merge40.

Please update the capture flow to use the actual review surface and data once the import step is reached. Keep the current expectation until that behavior is reviewed; do not make the test pass by changing the count alone. All input files are disposable fixtures.

The real-server e2e `apps/web/e2e/money-review-capture-1140.mjs` fails on production `4ebeba0b8` and the merge40 release at its existing assertion on line 132: it expects seven `.import-metric` elements after import review, but sees zero. The candidate failure is the same as the production baseline and is not introduced by merge40. Please update the capture flow to use the actual review surface and data once the import step is reached. Keep the current expectation until that behavior is reviewed; do not make the test pass by changing the count alone. All input files are disposable fixtures.
Author
Owner

Merge40 reproduces #1559 exactly on the release candidate: the reversed-assignment response-order scenario passes, then money-revisions-984.mjs:100 times out waiting for getByLabel('Assigned for Food'). Production 4ebeba0b8 has the same failure. I kept the assertion and fixture unchanged; this does not block merge40 as a pre-existing e2e difference.

Merge40 reproduces #1559 exactly on the release candidate: the reversed-assignment response-order scenario passes, then `money-revisions-984.mjs:100` times out waiting for `getByLabel('Assigned for Food')`. Production `4ebeba0b8` has the same failure. I kept the assertion and fixture unchanged; this does not block merge40 as a pre-existing e2e difference.
Author
Owner

Candidate money-wizard-1140.mjs passes the acknowledged-import recovery probe, then fails the existing light/390 fixture assertion: the review summary reports 7,320 checks while the test expects at least 15,000 (money-wizard-1140.mjs:157). Production 4ebeba0b8 has the same summary assertion failure. The real import fixture is 15,000 transactions; no expectation or fixture was changed. This is a pre-existing test mismatch under #1140, not a merge40 regression.

Candidate `money-wizard-1140.mjs` passes the acknowledged-import recovery probe, then fails the existing light/390 fixture assertion: the review summary reports 7,320 checks while the test expects at least 15,000 (`money-wizard-1140.mjs:157`). Production `4ebeba0b8` has the same summary assertion failure. The real import fixture is 15,000 transactions; no expectation or fixture was changed. This is a pre-existing test mismatch under #1140, not a merge40 regression.
Author
Owner

The merge40 release reproduces #1549 in apps/web/e2e/money.mjs: after the full light/dark 390/820/1440 matrix and exact Markdown/derived-number assertions pass, it times out at line 746 waiting for Create Budget after the opening-balance preview. Production 4ebeba0b8 fails at the same step. I kept the existing expectation unchanged; this is a pre-existing baseline failure.

The merge40 release reproduces #1549 in `apps/web/e2e/money.mjs`: after the full light/dark 390/820/1440 matrix and exact Markdown/derived-number assertions pass, it times out at line 746 waiting for `Create Budget` after the opening-balance preview. Production `4ebeba0b8` fails at the same step. I kept the existing expectation unchanged; this is a pre-existing baseline failure.
Author
Owner

The merged-release full calendar.mjs e2e stops at the existing getByRole('link', { name: 'Week', exact: true }) timeout. Production 4ebeba0b8 fails at the same retired Week sidebar link; tracked by #1542. The focused calendar-week-grid-1226.mjs passed the actual merged Calendar Week view with empty/dense data at 390/820/1440 in both themes on macOS emulation. No locator or expectation was changed.

The merged-release full `calendar.mjs` e2e stops at the existing `getByRole('link', { name: 'Week', exact: true })` timeout. Production 4ebeba0b8 fails at the same retired Week sidebar link; tracked by #1542. The focused `calendar-week-grid-1226.mjs` passed the actual merged Calendar Week view with empty/dense data at 390/820/1440 in both themes on macOS emulation. No locator or expectation was changed.
Author
Owner

Merge40 reproduces #1546: notifications.mjs passes setup and invite, then line 312 times out waiting for the obsolete empty-inbox text Files and folders people share with you. Production 4ebeba0b8 has the same failure. The merged merge39-review.mjs full flow independently created the real Log reminder and captured its loaded notification at all three widths in both themes; no empty-state assertion was changed.

Merge40 reproduces #1546: `notifications.mjs` passes setup and invite, then line 312 times out waiting for the obsolete empty-inbox text `Files and folders people share with you`. Production 4ebeba0b8 has the same failure. The merged `merge39-review.mjs` full flow independently created the real Log reminder and captured its loaded notification at all three widths in both themes; no empty-state assertion was changed.
Author
Owner

NOT READY — merge round 40

Head: 9b0c0441aa81665374083ed3239cd82ad8d97275 (job/merge40). No push, deploy or merge was done. Required branch merges were applied in the requested order: 4c23c5b80, 8f47550de, 164a4abc8, 6f686af41, c57013196, 555c4d8aa. origin/dev was fetched and merged once; it was already contained.

What changed

  • Merged Settings → Users row/menu and API field errors; Money compact register, anchored resize and import Cards; block text in reminders with Notes migration 0039; Calendar range-index migration 0007 and cold reads; resumable startup reconciliation; and the tab-switch benchmark harness.
  • Batched Notes block reminder index writes in 200-row chunks (800 SQLite bind values per statement) inside the existing projection transaction. Added a regression test spanning more than two chunks.
  • Added a production-Home upgrade probe that starts Files, Notes, Money writes and Search reads during startup. Updated upgrade inventories for Notes 0039.
  • Made benchmark tests use Node's built-in test/assert APIs so the requested node --test command runs.
  • Attached 98 loaded screenshots from Chromium with macOS platform emulation at 390, 820 and 1440 px in light and dark. The zip is merge40-review.zip.

Files

Changed files relative to the branch start (0866ca3b2): 68.

Cargo.lock
apps/web/e2e/harness.mjs
apps/web/e2e/harness.test.mjs
apps/web/e2e/money-register-resize-1498.mjs
apps/web/e2e/ui-chrome4-card-states.mjs
apps/web/e2e/ui-chrome4-menu-anchor.mjs
apps/web/src/lib/components/Card.svelte.test.ts
apps/web/src/lib/components/money/MoneyImport.svelte
apps/web/src/lib/fixedContainingBlock.test.ts
apps/web/src/lib/navigation/modePreload.svelte.test.ts
apps/web/src/lib/navigation/modePreload.ts
apps/web/src/lib/notifications/InboxPanel.svelte
apps/web/src/lib/notifications/model.test.ts
apps/web/src/lib/notifications/model.ts
apps/web/src/routes/money/[budget]/accounts/[[account]]/+page.svelte
apps/web/src/routes/money/[budget]/accounts/[[account]]/register-layout.svelte.test.ts
apps/web/src/routes/money/[budget]/accounts/[[account]]/register-recovery.svelte.test.ts
apps/web/src/routes/settings/admin/UsersGroup.svelte
apps/web/src/routes/settings/admin/UsersGroup.svelte.test.ts
apps/web/src/routes/settings/admin/userCreate.test.ts
apps/web/src/routes/settings/admin/userCreate.ts
bench/cdp-input.mjs
bench/cdp-input.test.mjs
bench/notifications-read-1387-cdp.mjs
bench/reconcile-1540.py
bench/startup-1011.test.mjs
bench/tab-switch-seed.py
bench/tab-switch.mjs
bench/tab-switch.test.mjs
contracts/perf/adoption-1058.json
contracts/perf/exceptions.json
contracts/perf/ratchet.json
contracts/perf/registry.json
crates/calternal-db/src/checkpoint.rs
crates/calternal-db/src/lib.rs
crates/calternal-db/src/sqlite.rs
crates/calternal-fs/src/blob.rs
crates/calternal-fs/src/root.rs
crates/calternal-search/src/indexer.rs
crates/calternal-server/src/upgrade_tests.rs
crates/calternal-server/src/wire.rs
crates/plugins/calendar/migrations/0007_event_calendar_window.sql
crates/plugins/calendar/src/cache/store.rs
crates/plugins/calendar/src/feeds/subscriptions.rs
crates/plugins/calendar/src/items.rs
crates/plugins/calendar/src/view.rs
crates/plugins/calendar/tests/cache.rs
crates/plugins/files/src/index.rs
crates/plugins/files/src/lib.rs
crates/plugins/files/src/shares.rs
crates/plugins/files/src/uploads.rs
crates/plugins/notes/Cargo.toml
crates/plugins/notes/migrations/0039_block_reminder_text.sql
crates/plugins/notes/src/lib.rs
crates/plugins/notes/src/reminders_tests.rs
crates/plugins/notes/src/store.rs
crates/plugins/notifications/Cargo.toml
crates/plugins/notifications/src/block_reminders.rs
docs/perf/baseline.json
docs/perf/runs/tabcomp-1233-composer-baseline-2026-10-10.json
packages/ui/src/components/Card.svelte
packages/ui/src/components/menu/MenuItem.svelte
packages/ui/src/components/menu/types.ts
packages/ui/src/floating.ts
scripts/perf_guards/rules.py
scripts/perf_guards/test_rules.py
tests/adversarial/attack.py
tests/adversarial/merge40_startup.py

Gates and checks

  • cargo fmt --check — passed, exit 0, no output.
  • cargo clippy --all-targets -- -D warnings — full workspace passed before the final test-only changes. After the Notes migration inventory correction, cargo clippy -p calternal-server --all-targets -- -D warnings passed:
Compiling calternal-server v0.0.1 (/home/kayg/Developer/calternal-wt/merge40/crates/calternal-server)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 25.68s
  • Full cargo test -- --test-threads=4 initially found three upgrade inventory assertions that did not include Notes 0039 (production 7b count, round-9 migration list, and 7c migration delta). Those assertions were corrected. The server unit suite then passed 278 tests. The remaining final test failure is the deterministic performance guard:
running 1 test
test deterministic_performance_guards ... FAILED

failures:

---- deterministic_performance_guards stdout ----
thread 'deterministic_performance_guards' panicked at crates/calternal-server/tests/perf_guards.rs:19:5:
performance guard failed (exit status: 2):

perf-lint: INVALID: exception ratchet: io.source-parser: 6 exceptions exceed the ratchet ceiling 2; fix the new violation instead; io.unresolved-call: 16272 exceptions exceed the ratchet ceiling 16158; fix the new violation instead; total: ledger has 22198 exceptions; ratchet total is 22080

note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

failures:
    deterministic_performance_guards

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

error: test failed, to rerun pass `-p calternal-server --test perf_guards`
  • cd apps/web && bun run check — Svelte reports 0 errors and 0 warnings, but the command exits 1 on the same ratchet:
PASS production dependency licences: 759 locked package releases across apps/web, apps/docs and packages
perf-lint: INVALID: exception ratchet: io.source-parser: 6 exceptions exceed the ratchet ceiling 2; fix the new violation instead; io.unresolved-call: 16272 exceptions exceed the ratchet ceiling 16158; fix the new violation instead; total: ledger has 22198 exceptions; ratchet total is 22080
User browser caches use userStorage; only documented device/public-link exceptions remain.
Glass alpha, blur and backdrop-filter roles use packages/ui/src/tokens.css.
Text sizes and UI shape values use shared role tokens.
Focus policy passes: 48 focus ring rules, 133 DOM focus calls and 2 data-input writers audited.
UI transitions and animation options use shared motion tokens or documented exceptions.
Loading svelte-check in workspace: /home/kayg/Developer/calternal-wt/merge40/apps/web
Getting Svelte diagnostics...

svelte-check found 0 errors and 0 warnings
error: script "check" exited with code 1
  • cd apps/web && bun run test --maxWorkers=2: Test Files 321 passed (321); Tests 2336 passed (2336).
  • cd packages/editor && bun run test: 30 files and 529 tests passed.
  • uv run --with pytest --with-requirements scripts/perf_guards/requirements.txt -- python -m pytest scripts/perf_guards: 141 passed in 0.57s. Bare python3 -m pytest could not run because system Python has no pytest.
  • node --test bench/*.test.mjs:
1..37
# tests 37
# suites 0
# pass 37
# fail 0
# cancelled 0
# skipped 0
# todo 0
  • python3 scripts/action_registry.py --check: Action registry: 436 operations, 408 generated tools.
  • Release server build passed: Finished \release` profile [optimized] target(s) in 13m 16s`.
  • Upgrade/startup storm passed: ready=2.813s; acknowledged Files/Notes/Money=8/8/8; Search reads=16; documented 503 responses=96; Notes 0039 and Calendar 0007 applied.
  • Money adversarial checks and XUSER_MATRIX_ONLY=1 tests/adversarial/run-split.sh passed. General API audit had no non-SLOW hostile-input finding; the appearance concurrent PUT was SLOW at p95 0.638s (0.500s target). Existing exact Files preference assertions omit show_hidden_items; both production and candidate return HTTP 200 with the field. Filed #1577. No test expectation was changed.

E2E and UX evidence

  • Settings Users/admin field-error captures passed at all requested widths/themes. The Calendar Week focused capture passed at all widths/themes. The real reminder notification was captured at all widths/themes. Import Card hover, touch and keyboard checks and anchored menu checks passed.
  • Money money-create-visible-1554, money-number-review, and money-register-resize-1498 passed on the candidate; resize kept the same anchored transaction visible (top=321/410, height=34/48, scrollTop=1886/2663). The same resize passed on production 4ebeba0b8.
  • The remaining Money E2E assertions reproduced on production 4ebeba0b8: fidelity waits for an absent account-type choice (#1558); review capture expects seven absent metrics (#1578 filed); revisions waits for an absent Assigned label (#1559); wizard expects 15,000 checks where the real fixture reports 7,320 (#1140); and the full Money flow waits for Create Budget after the opening-balance preview (#1549). No expectations were changed.
  • calendar.mjs, notifications.mjs, and files.mjs also fail at their existing production-baseline assertions (#1542, #1546, #1563 respectively). The focused Calendar Week and real reminder captures passed. No assertion was changed.
  • UX gaps closed: new controls use shared UI primitives; click/touch/keyboard behavior and responsive captures were exercised. UX gap left: the requested split-row menu visual capture is absent. A synthetic imported split archive stayed at import progress step 3 and published no data, so I excluded that half-loaded screen. Existing register component tests cover split rows and their menu.

Decisions outside DESIGN

  • Notes projection chunks use 200 rows because each row binds four values; 800 parameters remain below SQLite's 999-variable limit while keeping one transaction for the projection.
  • The startup probe retries only documented readiness responses (503 with Retry-After) and fails on any other error; this preserves the documented startup contract while proving writes eventually publish.

Known gap and readiness

The exact perf pins now match all live findings. The merge must not raise contracts/perf/ratchet.json; it remains lower than the ledger because the merged Notes block-text code contributes 4 io.source-parser and 114 io.unresolved-call entries above the ceilings. Resolve that call-graph debt before merge. The screenshot archive does not include a split-row menu capture. Build output was cleaned (cargo clean removed 35,935 files / 37.5 GiB; apps/web/build and apps/web/.svelte-kit were removed).

NOT READY perf ratchet exceeds the inherited ceiling (source-parser 6/2, unresolved-call 16,272/16,158, total 22,198/22,080).

## NOT READY — merge round 40 Head: `9b0c0441aa81665374083ed3239cd82ad8d97275` (`job/merge40`). No push, deploy or merge was done. Required branch merges were applied in the requested order: `4c23c5b80`, `8f47550de`, `164a4abc8`, `6f686af41`, `c57013196`, `555c4d8aa`. `origin/dev` was fetched and merged once; it was already contained. ### What changed - Merged Settings → Users row/menu and API field errors; Money compact register, anchored resize and import Cards; block text in reminders with Notes migration 0039; Calendar range-index migration 0007 and cold reads; resumable startup reconciliation; and the tab-switch benchmark harness. - Batched Notes block reminder index writes in 200-row chunks (800 SQLite bind values per statement) inside the existing projection transaction. Added a regression test spanning more than two chunks. - Added a production-Home upgrade probe that starts Files, Notes, Money writes and Search reads during startup. Updated upgrade inventories for Notes 0039. - Made benchmark tests use Node's built-in test/assert APIs so the requested `node --test` command runs. - Attached [98 loaded screenshots](https://git.kayg.org/attachments/94257b5f-58fc-4f0a-a6e4-63b0867e25b1) from Chromium with macOS platform emulation at 390, 820 and 1440 px in light and dark. The zip is `merge40-review.zip`. ### Files Changed files relative to the branch start (`0866ca3b2`): 68. ```text Cargo.lock apps/web/e2e/harness.mjs apps/web/e2e/harness.test.mjs apps/web/e2e/money-register-resize-1498.mjs apps/web/e2e/ui-chrome4-card-states.mjs apps/web/e2e/ui-chrome4-menu-anchor.mjs apps/web/src/lib/components/Card.svelte.test.ts apps/web/src/lib/components/money/MoneyImport.svelte apps/web/src/lib/fixedContainingBlock.test.ts apps/web/src/lib/navigation/modePreload.svelte.test.ts apps/web/src/lib/navigation/modePreload.ts apps/web/src/lib/notifications/InboxPanel.svelte apps/web/src/lib/notifications/model.test.ts apps/web/src/lib/notifications/model.ts apps/web/src/routes/money/[budget]/accounts/[[account]]/+page.svelte apps/web/src/routes/money/[budget]/accounts/[[account]]/register-layout.svelte.test.ts apps/web/src/routes/money/[budget]/accounts/[[account]]/register-recovery.svelte.test.ts apps/web/src/routes/settings/admin/UsersGroup.svelte apps/web/src/routes/settings/admin/UsersGroup.svelte.test.ts apps/web/src/routes/settings/admin/userCreate.test.ts apps/web/src/routes/settings/admin/userCreate.ts bench/cdp-input.mjs bench/cdp-input.test.mjs bench/notifications-read-1387-cdp.mjs bench/reconcile-1540.py bench/startup-1011.test.mjs bench/tab-switch-seed.py bench/tab-switch.mjs bench/tab-switch.test.mjs contracts/perf/adoption-1058.json contracts/perf/exceptions.json contracts/perf/ratchet.json contracts/perf/registry.json crates/calternal-db/src/checkpoint.rs crates/calternal-db/src/lib.rs crates/calternal-db/src/sqlite.rs crates/calternal-fs/src/blob.rs crates/calternal-fs/src/root.rs crates/calternal-search/src/indexer.rs crates/calternal-server/src/upgrade_tests.rs crates/calternal-server/src/wire.rs crates/plugins/calendar/migrations/0007_event_calendar_window.sql crates/plugins/calendar/src/cache/store.rs crates/plugins/calendar/src/feeds/subscriptions.rs crates/plugins/calendar/src/items.rs crates/plugins/calendar/src/view.rs crates/plugins/calendar/tests/cache.rs crates/plugins/files/src/index.rs crates/plugins/files/src/lib.rs crates/plugins/files/src/shares.rs crates/plugins/files/src/uploads.rs crates/plugins/notes/Cargo.toml crates/plugins/notes/migrations/0039_block_reminder_text.sql crates/plugins/notes/src/lib.rs crates/plugins/notes/src/reminders_tests.rs crates/plugins/notes/src/store.rs crates/plugins/notifications/Cargo.toml crates/plugins/notifications/src/block_reminders.rs docs/perf/baseline.json docs/perf/runs/tabcomp-1233-composer-baseline-2026-10-10.json packages/ui/src/components/Card.svelte packages/ui/src/components/menu/MenuItem.svelte packages/ui/src/components/menu/types.ts packages/ui/src/floating.ts scripts/perf_guards/rules.py scripts/perf_guards/test_rules.py tests/adversarial/attack.py tests/adversarial/merge40_startup.py ``` ### Gates and checks - `cargo fmt --check` — passed, exit 0, no output. - `cargo clippy --all-targets -- -D warnings` — full workspace passed before the final test-only changes. After the Notes migration inventory correction, `cargo clippy -p calternal-server --all-targets -- -D warnings` passed: ```text Compiling calternal-server v0.0.1 (/home/kayg/Developer/calternal-wt/merge40/crates/calternal-server) Finished `dev` profile [unoptimized + debuginfo] target(s) in 25.68s ``` - Full `cargo test -- --test-threads=4` initially found three upgrade inventory assertions that did not include Notes 0039 (production 7b count, round-9 migration list, and 7c migration delta). Those assertions were corrected. The server unit suite then passed 278 tests. The remaining final test failure is the deterministic performance guard: ```text running 1 test test deterministic_performance_guards ... FAILED failures: ---- deterministic_performance_guards stdout ---- thread 'deterministic_performance_guards' panicked at crates/calternal-server/tests/perf_guards.rs:19:5: performance guard failed (exit status: 2): perf-lint: INVALID: exception ratchet: io.source-parser: 6 exceptions exceed the ratchet ceiling 2; fix the new violation instead; io.unresolved-call: 16272 exceptions exceed the ratchet ceiling 16158; fix the new violation instead; total: ledger has 22198 exceptions; ratchet total is 22080 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace failures: deterministic_performance_guards test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 3.14s error: test failed, to rerun pass `-p calternal-server --test perf_guards` ``` - `cd apps/web && bun run check` — Svelte reports 0 errors and 0 warnings, but the command exits 1 on the same ratchet: ```text PASS production dependency licences: 759 locked package releases across apps/web, apps/docs and packages perf-lint: INVALID: exception ratchet: io.source-parser: 6 exceptions exceed the ratchet ceiling 2; fix the new violation instead; io.unresolved-call: 16272 exceptions exceed the ratchet ceiling 16158; fix the new violation instead; total: ledger has 22198 exceptions; ratchet total is 22080 User browser caches use userStorage; only documented device/public-link exceptions remain. Glass alpha, blur and backdrop-filter roles use packages/ui/src/tokens.css. Text sizes and UI shape values use shared role tokens. Focus policy passes: 48 focus ring rules, 133 DOM focus calls and 2 data-input writers audited. UI transitions and animation options use shared motion tokens or documented exceptions. Loading svelte-check in workspace: /home/kayg/Developer/calternal-wt/merge40/apps/web Getting Svelte diagnostics... svelte-check found 0 errors and 0 warnings error: script "check" exited with code 1 ``` - `cd apps/web && bun run test --maxWorkers=2`: `Test Files 321 passed (321)`; `Tests 2336 passed (2336)`. - `cd packages/editor && bun run test`: 30 files and 529 tests passed. - `uv run --with pytest --with-requirements scripts/perf_guards/requirements.txt -- python -m pytest scripts/perf_guards`: `141 passed in 0.57s`. Bare `python3 -m pytest` could not run because system Python has no pytest. - `node --test bench/*.test.mjs`: ```text 1..37 # tests 37 # suites 0 # pass 37 # fail 0 # cancelled 0 # skipped 0 # todo 0 ``` - `python3 scripts/action_registry.py --check`: `Action registry: 436 operations, 408 generated tools`. - Release server build passed: `Finished \`release\` profile [optimized] target(s) in 13m 16s`. - Upgrade/startup storm passed: `ready=2.813s; acknowledged Files/Notes/Money=8/8/8; Search reads=16; documented 503 responses=96; Notes 0039 and Calendar 0007 applied`. - Money adversarial checks and `XUSER_MATRIX_ONLY=1 tests/adversarial/run-split.sh` passed. General API audit had no non-SLOW hostile-input finding; the appearance concurrent PUT was SLOW at p95 0.638s (0.500s target). Existing exact Files preference assertions omit `show_hidden_items`; both production and candidate return HTTP 200 with the field. Filed #1577. No test expectation was changed. ### E2E and UX evidence - Settings Users/admin field-error captures passed at all requested widths/themes. The Calendar Week focused capture passed at all widths/themes. The real reminder notification was captured at all widths/themes. Import Card hover, touch and keyboard checks and anchored menu checks passed. - Money `money-create-visible-1554`, `money-number-review`, and `money-register-resize-1498` passed on the candidate; resize kept the same anchored transaction visible (`top=321/410`, `height=34/48`, `scrollTop=1886/2663`). The same resize passed on production 4ebeba0b8. - The remaining Money E2E assertions reproduced on production 4ebeba0b8: fidelity waits for an absent account-type choice (#1558); review capture expects seven absent metrics (#1578 filed); revisions waits for an absent Assigned label (#1559); wizard expects 15,000 checks where the real fixture reports 7,320 (#1140); and the full Money flow waits for Create Budget after the opening-balance preview (#1549). No expectations were changed. - `calendar.mjs`, `notifications.mjs`, and `files.mjs` also fail at their existing production-baseline assertions (#1542, #1546, #1563 respectively). The focused Calendar Week and real reminder captures passed. No assertion was changed. - UX gaps closed: new controls use shared UI primitives; click/touch/keyboard behavior and responsive captures were exercised. UX gap left: the requested split-row menu visual capture is absent. A synthetic imported split archive stayed at import progress step 3 and published no data, so I excluded that half-loaded screen. Existing register component tests cover split rows and their menu. ### Decisions outside DESIGN - Notes projection chunks use 200 rows because each row binds four values; 800 parameters remain below SQLite's 999-variable limit while keeping one transaction for the projection. - The startup probe retries only documented readiness responses (`503` with `Retry-After`) and fails on any other error; this preserves the documented startup contract while proving writes eventually publish. ### Known gap and readiness The exact perf pins now match all live findings. The merge must not raise `contracts/perf/ratchet.json`; it remains lower than the ledger because the merged Notes block-text code contributes 4 `io.source-parser` and 114 `io.unresolved-call` entries above the ceilings. Resolve that call-graph debt before merge. The screenshot archive does not include a split-row menu capture. Build output was cleaned (`cargo clean` removed 35,935 files / 37.5 GiB; `apps/web/build` and `apps/web/.svelte-kit` were removed). NOT READY perf ratchet exceeds the inherited ceiling (source-parser 6/2, unresolved-call 16,272/16,158, total 22,198/22,080).
Author
Owner

Starting merge40b on branch job/merge40 at 9b0c0441aa81665374083ed3239cd82ad8d97275, with merge-round base 0866ca3b2. I am classifying each added perf-lint ledger identity against the base and supplied branch tips, then I will fix real source violations, adopt exact pins once, run the requested gates, and report the final head and verbatim gate output. No pushes, deploys, or merges beyond the required one-time origin/dev merge before final gates.

Starting merge40b on branch `job/merge40` at `9b0c0441aa81665374083ed3239cd82ad8d97275`, with merge-round base `0866ca3b2`. I am classifying each added perf-lint ledger identity against the base and supplied branch tips, then I will fix real source violations, adopt exact pins once, run the requested gates, and report the final head and verbatim gate output. No pushes, deploys, or merges beyond the required one-time `origin/dev` merge before final gates.
Author
Owner

The merged ledger has 213 exception scopes absent from base 0866ca3b2; exact source-tip comparison attributes 52 io.unresolved-call scopes to calcold-1560 and 24 (15 io.unresolved-call, 9 io.awaited-worker) to rec1540c. The remaining 137 Notes scopes split by source change: 123 are from remtext-1568 reminder-text projection reachable through open_file (119 unresolved calls and 4 source-parser calls), and 14 are from merge commit 44cf5640a (13 unresolved calls plus one sql.query-in-loop in insert_note_blocks). The 52 Calendar calls are only in-memory query construction; I will bind those exact calls to the existing bounded-query test. The 24 Files calls reach a full-file hash/type read when an HTTP lookup misses the Index; I am tracing a behavior-preserving removal. The Notes open-file path now parses and projects the reminder blocks during a read, so I am removing that route-to-index path and retaining existing indexed identity lookup. The merge-time block insert runs one SQL statement per chunk; I will replace it with one set-based insert.

There are no duplicate live (rule,file,symbol) scopes. The exact merged refresh ecbefcfdd updated stale function hashes and removed obsolete scope identities; I found no surviving duplicate identity to delete. I will recheck the complete ledger after fixes.

The merged ledger has 213 exception scopes absent from base `0866ca3b2`; exact source-tip comparison attributes 52 `io.unresolved-call` scopes to `calcold-1560` and 24 (`15 io.unresolved-call`, `9 io.awaited-worker`) to `rec1540c`. The remaining 137 Notes scopes split by source change: 123 are from `remtext-1568` reminder-text projection reachable through `open_file` (119 unresolved calls and 4 source-parser calls), and 14 are from merge commit `44cf5640a` (13 unresolved calls plus one `sql.query-in-loop` in `insert_note_blocks`). The 52 Calendar calls are only in-memory query construction; I will bind those exact calls to the existing bounded-query test. The 24 Files calls reach a full-file hash/type read when an HTTP lookup misses the Index; I am tracing a behavior-preserving removal. The Notes open-file path now parses and projects the reminder blocks during a read, so I am removing that route-to-index path and retaining existing indexed identity lookup. The merge-time block insert runs one SQL statement per chunk; I will replace it with one set-based insert. There are no duplicate live `(rule,file,symbol)` scopes. The exact merged refresh `ecbefcfdd` updated stale function hashes and removed obsolete scope identities; I found no surviving duplicate identity to delete. I will recheck the complete ledger after fixes.
Author
Owner

The latest source-guard run has 24 live new scopes, all in Files: 9 io.awaited-worker and 15 io.unresolved-call. The exact scopes are below. Each operation (entries, stat, versions) has three worker entries for hash_path_and_detect with suffixes fa24fdf426c760f9, 36ebe965c570605a, and e98aafa8b2fbb6fc. Each operation also has unresolved entries for write_records (a465b397fa19e71d, bef837c2bf10e329) and hash_path_and_detect (fa24fdf426c760f9, 36ebe965c570605a, e98aafa8b2fbb6fc). All are in crates/plugins/files/src/index.rs; operation prefixes are entries, stat, and versions.

Evidence: the cold-miss path in stat and versions calls item_id_for_http_request, which records the item, hashes its full content in spawn_blocking, and writes the Index. entries starts folder reconciliation in the background; the conservative call graph reaches the same hash/write path. Removing this behavior would omit a newly assigned item ID and content hash/MIME from cold stat results, omit version attribution until the Index catches up, and delay discovery after a stale listing. I tested replacing the HTTP fallback with Index-only lookup; it produced additional unbound read scopes and changed the cold response. These 24 are real rec1540c violations. I cannot close them without changing route behavior, so this job is NOT READY under the issue’s stop rule. I will leave the ratchet unchanged and report the final gates and these exact entries.

The latest source-guard run has 24 live new scopes, all in Files: 9 `io.awaited-worker` and 15 `io.unresolved-call`. The exact scopes are below. Each operation (`entries`, `stat`, `versions`) has three worker entries for `hash_path_and_detect` with suffixes `fa24fdf426c760f9`, `36ebe965c570605a`, and `e98aafa8b2fbb6fc`. Each operation also has unresolved entries for `write_records` (`a465b397fa19e71d`, `bef837c2bf10e329`) and `hash_path_and_detect` (`fa24fdf426c760f9`, `36ebe965c570605a`, `e98aafa8b2fbb6fc`). All are in `crates/plugins/files/src/index.rs`; operation prefixes are `entries`, `stat`, and `versions`. Evidence: the cold-miss path in `stat` and `versions` calls `item_id_for_http_request`, which records the item, hashes its full content in `spawn_blocking`, and writes the Index. `entries` starts folder reconciliation in the background; the conservative call graph reaches the same hash/write path. Removing this behavior would omit a newly assigned item ID and content hash/MIME from cold `stat` results, omit version attribution until the Index catches up, and delay discovery after a stale listing. I tested replacing the HTTP fallback with Index-only lookup; it produced additional unbound read scopes and changed the cold response. These 24 are real `rec1540c` violations. I cannot close them without changing route behavior, so this job is NOT READY under the issue’s stop rule. I will leave the ratchet unchanged and report the final gates and these exact entries.
Author
Owner

NOT READY — 24 real Files findings remain. The cold Files reads need the current ID/hash/type/version work to preserve response identity and history. Removing it changes the returned metadata. I kept that behavior intact and did not raise any ratchet ceiling.

Head: bbd4e4a8b25c56ae998927b7dc6367bfd5cb9f78 (job/merge40). The required git fetch origin && git merge origin/dev completed before final gates; origin/dev was already up to date.

Exception classification

The merged ledger had 213 new live scopes versus base, plus stale identity churn. The once-only adoption removed 143 obsolete pins tied to superseded hashes; 736 surviving exact scopes had their function hashes refreshed. There are no duplicate live (rule,file,symbol) identities now.

  • calcold-1560 branch tip (6f686af41): 52 Calendar call scopes in read_batch_query. Source review found 50 bounded in-memory query-builder calls, one in-memory row push, and one bounded Index read. I added exact pure/index-read contracts tied to the existing Calendar query-plan test; these are not unresolved IO operations.
  • remtext-1568 branch tip (164a4abc8): 123 Notes reminder projection scopes, including all 4 new io.source-parser entries. The Notes file-open route called store::index on reads. It now reads the live source and retained ID without parsing or writing projection rows; a missing projection uses the existing view frontmatter/path fallback until background indexing repairs it.
  • Merge commit 44cf5640a: 14 Notes scopes (13 unresolved calls and one SQL query-in-loop). The reminder block projection now uses one set-based INSERT ... SELECT json_each(?) statement in the existing transaction, with a fixed SQL bind count.
  • rec1540c branch tip (c57013196): 24 real Files findings remain: 9 io.awaited-worker and 15 io.unresolved-call scopes in crates/plugins/files/src/index.rs. For each of entries, stat, and versions, io.awaited-worker is at hash_path_and_detect suffixes fa24fdf426c760f9, 36ebe965c570605a, and e98aafa8b2fbb6fc. The 5 io.unresolved-call suffixes per operation are write_records:a465b397fa19e71d, write_records:bef837c2bf10e329, and those same three hash_path_and_detect suffixes. A trial that removed the HTTP cold-miss identity work changed stat/version behavior and created 48 additional live scopes, so I reverted it. This meets the issue's stop condition; changing the owning Files contract needs a separate behavior decision.

After the fixes I ran scripts/perf-lint --adopt-7c once. The ratchet is now 20,383 total, io.unresolved-call 14,500, and io.source-parser 1. Each rule is at or below the lowest supplied branch value; total is below 22,080, unresolved-call below 16,158, and source-parser below 2. No ceiling was raised. scripts/perf-lint reports zero current unpinned violations, but the 24 Files scopes above remain a behavior-preserving blocker.

Changes

  • crates/plugins/notes/src/lib.rs: remove projection rebuild from Notes file reads; test that an unindexed read does not write an Index row.
  • crates/plugins/notes/src/store.rs: replace per-chunk SQL writes with one set-based JSON expansion inside the same transaction.
  • crates/plugins/notes/src/reminders_tests.rs: cover 405 blocks across the former chunk boundary.
  • contracts/perf/registry.json: exact tested Calendar and Notes capability contracts.
  • contracts/perf/adoption-1058.json, contracts/perf/exceptions.json, contracts/perf/ratchet.json: once-only adopted pins and lowered ratchet.

Gates

  • cargo fmt --check: exit 0, no output.
  • cargo clippy -p calternal-plugin-notes --all-targets -- -D warnings: Finished dev profile [unoptimized + debuginfo] target(s) in 17.21s (exit 0).
  • cargo test -p calternal-plugin-notes: test result: ok. 332 passed; 0 failed; 5 ignored (exit 0); integration result: test result: ok. 2 passed; 0 failed.
  • cd apps/web && bun run check: PASS production dependency licences: 759 locked package releases across apps/web, apps/docs and packages; perf-lint: PASS; 0 violations; 20383 scoped exceptions; svelte-check found 0 errors and 0 warnings (exit 0).
  • cargo test -p calternal-server --test perf_guards:
    running 1 test
    test deterministic_performance_guards ... ok
    test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 33.48s (exit 0).
  • Exact requested python3 -m pytest scripts/perf_guards could not start: /home/kayg/.nix-profile/bin/python3: No module named pytest (exit 1). With pytest supplied, uv run --with pytest --with-requirements scripts/perf_guards/requirements.txt python -m pytest scripts/perf_guards passed: 141 passed in 0.49s (exit 0).
  • cargo clean: Removed 15395 files, 12.9GiB total; apps/web/build, apps/web/.svelte-kit, and target/tmp were removed.

Decisions and remaining gap

docs/DESIGN.md does not specify the fallback when a Notes read has no retained Index row. I kept the read path read-only and used the existing stable frontmatter/path ID from view until the background Indexer repairs it. It also does not specify the SQL encoding for large block projections; json_each keeps bind count fixed while the existing transaction preserves atomicity.

Known gap: the 24 Files entries listed above. Final status: NOT READY under the issue's rule. No push, deploy, merge, or issue close was performed.

NOT READY — 24 real Files findings remain. The cold Files reads need the current ID/hash/type/version work to preserve response identity and history. Removing it changes the returned metadata. I kept that behavior intact and did not raise any ratchet ceiling. Head: `bbd4e4a8b25c56ae998927b7dc6367bfd5cb9f78` (`job/merge40`). The required `git fetch origin && git merge origin/dev` completed before final gates; `origin/dev` was already up to date. ## Exception classification The merged ledger had 213 new live scopes versus base, plus stale identity churn. The once-only adoption removed 143 obsolete pins tied to superseded hashes; 736 surviving exact scopes had their function hashes refreshed. There are no duplicate live `(rule,file,symbol)` identities now. - `calcold-1560` branch tip (`6f686af41`): 52 Calendar call scopes in `read_batch_query`. Source review found 50 bounded in-memory query-builder calls, one in-memory row push, and one bounded Index read. I added exact `pure`/`index-read` contracts tied to the existing Calendar query-plan test; these are not unresolved IO operations. - `remtext-1568` branch tip (`164a4abc8`): 123 Notes reminder projection scopes, including all 4 new `io.source-parser` entries. The Notes file-open route called `store::index` on reads. It now reads the live source and retained ID without parsing or writing projection rows; a missing projection uses the existing `view` frontmatter/path fallback until background indexing repairs it. - Merge commit `44cf5640a`: 14 Notes scopes (13 unresolved calls and one SQL query-in-loop). The reminder block projection now uses one set-based `INSERT ... SELECT json_each(?)` statement in the existing transaction, with a fixed SQL bind count. - `rec1540c` branch tip (`c57013196`): 24 real Files findings remain: 9 `io.awaited-worker` and 15 `io.unresolved-call` scopes in `crates/plugins/files/src/index.rs`. For each of `entries`, `stat`, and `versions`, `io.awaited-worker` is at `hash_path_and_detect` suffixes `fa24fdf426c760f9`, `36ebe965c570605a`, and `e98aafa8b2fbb6fc`. The 5 `io.unresolved-call` suffixes per operation are `write_records:a465b397fa19e71d`, `write_records:bef837c2bf10e329`, and those same three `hash_path_and_detect` suffixes. A trial that removed the HTTP cold-miss identity work changed stat/version behavior and created 48 additional live scopes, so I reverted it. This meets the issue's stop condition; changing the owning Files contract needs a separate behavior decision. After the fixes I ran `scripts/perf-lint --adopt-7c` once. The ratchet is now 20,383 total, `io.unresolved-call` 14,500, and `io.source-parser` 1. Each rule is at or below the lowest supplied branch value; total is below 22,080, unresolved-call below 16,158, and source-parser below 2. No ceiling was raised. `scripts/perf-lint` reports zero current unpinned violations, but the 24 Files scopes above remain a behavior-preserving blocker. ## Changes - `crates/plugins/notes/src/lib.rs`: remove projection rebuild from Notes file reads; test that an unindexed read does not write an Index row. - `crates/plugins/notes/src/store.rs`: replace per-chunk SQL writes with one set-based JSON expansion inside the same transaction. - `crates/plugins/notes/src/reminders_tests.rs`: cover 405 blocks across the former chunk boundary. - `contracts/perf/registry.json`: exact tested Calendar and Notes capability contracts. - `contracts/perf/adoption-1058.json`, `contracts/perf/exceptions.json`, `contracts/perf/ratchet.json`: once-only adopted pins and lowered ratchet. ## Gates - `cargo fmt --check`: exit 0, no output. - `cargo clippy -p calternal-plugin-notes --all-targets -- -D warnings`: `Finished `dev` profile [unoptimized + debuginfo] target(s) in 17.21s` (exit 0). - `cargo test -p calternal-plugin-notes`: `test result: ok. 332 passed; 0 failed; 5 ignored` (exit 0); integration result: `test result: ok. 2 passed; 0 failed`. - `cd apps/web && bun run check`: `PASS production dependency licences: 759 locked package releases across apps/web, apps/docs and packages`; `perf-lint: PASS; 0 violations; 20383 scoped exceptions`; `svelte-check found 0 errors and 0 warnings` (exit 0). - `cargo test -p calternal-server --test perf_guards`: `running 1 test` `test deterministic_performance_guards ... ok` `test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 33.48s` (exit 0). - Exact requested `python3 -m pytest scripts/perf_guards` could not start: `/home/kayg/.nix-profile/bin/python3: No module named pytest` (exit 1). With pytest supplied, `uv run --with pytest --with-requirements scripts/perf_guards/requirements.txt python -m pytest scripts/perf_guards` passed: `141 passed in 0.49s` (exit 0). - `cargo clean`: `Removed 15395 files, 12.9GiB total`; `apps/web/build`, `apps/web/.svelte-kit`, and `target/tmp` were removed. ## Decisions and remaining gap `docs/DESIGN.md` does not specify the fallback when a Notes read has no retained Index row. I kept the read path read-only and used the existing stable frontmatter/path ID from `view` until the background Indexer repairs it. It also does not specify the SQL encoding for large block projections; `json_each` keeps bind count fixed while the existing transaction preserves atomicity. Known gap: the 24 Files entries listed above. Final status: NOT READY under the issue's rule. No push, deploy, merge, or issue close was performed.
Author
Owner

Merge round #1574: issue #1568 is complete on job/merge40.

Head SHA: 027695ae252548a02513f5cf625e6a7c6b08fe64.

Commits: b634cb109, 4409aa613, ba1dffce7, 027695ae2.

The Notes projection now removes valid Daily Log capture-zone tokens while retaining Log times. Migration 0040 resets the resumable projection cursor so existing Block text is rebuilt. Notifications split the Note name into an unbroken, ellipsized span. Tests cover escaped/unescaped markers, time/no-time lines, old-projection rebuild with unchanged Markdown, and the real notification body.

Final merged-head gates passed:

cargo fmt --check: exit 0, no output
Notes: 334 passed; 0 failed; 5 ignored, plus 2 integration tests passed
Notifications: 53 passed; 0 failed
perf-lint: PASS; 0 violations; 20383 scoped exceptions
svelte-check found 0 errors and 0 warnings
Test Files  321 passed (321)
      Tests  2337 passed (2337)

Production screenshots at 390, 820 and 1440 px in light/dark were captured with Chromium macOS platform emulation and attached to #1568. Local files remain in artifacts/merge40/owner/merge39-review/. The Notes rebuild profile recorded the first local reference in docs/perf/baseline.json (100 Notes: 2,732.492/2,822.462 ms p50/p95; 656 Notes: 19,174.86/19,240.451 ms). There was no previous Notes rebuild baseline for a before/after comparison.

contracts/perf/ratchet.json is unchanged from the starting commit. The one origin/dev fetch/merge was already up to date. Production build output was deleted, cargo clean completed, and the worktree is clean. Full report and screenshot attachments are on #1568.

Merge round #1574: issue #1568 is complete on `job/merge40`. Head SHA: `027695ae252548a02513f5cf625e6a7c6b08fe64`. Commits: `b634cb109`, `4409aa613`, `ba1dffce7`, `027695ae2`. The Notes projection now removes valid Daily Log capture-zone tokens while retaining Log times. Migration 0040 resets the resumable projection cursor so existing Block text is rebuilt. Notifications split the Note name into an unbroken, ellipsized span. Tests cover escaped/unescaped markers, time/no-time lines, old-projection rebuild with unchanged Markdown, and the real notification body. Final merged-head gates passed: ```text cargo fmt --check: exit 0, no output Notes: 334 passed; 0 failed; 5 ignored, plus 2 integration tests passed Notifications: 53 passed; 0 failed perf-lint: PASS; 0 violations; 20383 scoped exceptions svelte-check found 0 errors and 0 warnings Test Files 321 passed (321) Tests 2337 passed (2337) ``` Production screenshots at 390, 820 and 1440 px in light/dark were captured with Chromium macOS platform emulation and attached to #1568. Local files remain in `artifacts/merge40/owner/merge39-review/`. The Notes rebuild profile recorded the first local reference in `docs/perf/baseline.json` (100 Notes: 2,732.492/2,822.462 ms p50/p95; 656 Notes: 19,174.86/19,240.451 ms). There was no previous Notes rebuild baseline for a before/after comparison. `contracts/perf/ratchet.json` is unchanged from the starting commit. The one `origin/dev` fetch/merge was already up to date. Production build output was deleted, `cargo clean` completed, and the worktree is clean. Full report and screenshot attachments are on [#1568](https://git.kayg.org/kayg/calternal/issues/1568).
Author
Owner

Starting merge40 on job/merge40, base/head 027695ae252548a02513f5cf625e6a7c6b08fe64 (clean worktree). I will merge c3aadd409 (#1570) and aaaec5660 (#1575), preserve both calternal-fs intents, then run the requested merge-round gates and qualification checks.

Starting merge40 on `job/merge40`, base/head `027695ae252548a02513f5cf625e6a7c6b08fe64` (clean worktree). I will merge `c3aadd409` (#1570) and `aaaec5660` (#1575), preserve both `calternal-fs` intents, then run the requested merge-round gates and qualification checks.
Author
Owner

Gate finding: the first full workspace clippy run failed while compiling calternal-server: Frontend::get/Frontend::iter were unavailable because apps/web/build/ did not exist. The macro folder is ../../apps/web/build/ (crates/calternal-server/src/main.rs:109), and that directory was absent. I will build the web app before rerunning clippy; this is a missing generated build input, not a source edit.

Gate finding: the first full workspace clippy run failed while compiling `calternal-server`: `Frontend::get`/`Frontend::iter` were unavailable because `apps/web/build/` did not exist. The macro folder is `../../apps/web/build/` (`crates/calternal-server/src/main.rs:109`), and that directory was absent. I will build the web app before rerunning clippy; this is a missing generated build input, not a source edit.
kayg referenced this issue from a commit 2026-10-11 14:19:57 +00:00
kayg referenced this issue from a commit 2026-10-11 14:19:57 +00:00
Author
Owner

Full workspace cargo test found four calternal-server upgrade inventory failures after the round's Notes migration 0039/0040 changes: production_round_9_schema_upgrades_once_with_original_receipts, production_7b_schema_copy_upgrades_combined_pending_migrations, production_schema_copy_upgrades_once_without_reinterpreting_notes_0028, and production_7c_upgrades_content_types_once. I will update only the stale migration inventory lists/counts to include the issue's Notes migrations, keep the existing expectations otherwise, and rerun those server tests alone.

Full workspace `cargo test` found four `calternal-server` upgrade inventory failures after the round's Notes migration 0039/0040 changes: `production_round_9_schema_upgrades_once_with_original_receipts`, `production_7b_schema_copy_upgrades_combined_pending_migrations`, `production_schema_copy_upgrades_once_without_reinterpreting_notes_0028`, and `production_7c_upgrades_content_types_once`. I will update only the stale migration inventory lists/counts to include the issue's Notes migrations, keep the existing expectations otherwise, and rerun those server tests alone.
Author
Owner

Separate upgrade finding: production_schema_copy_upgrades_once_without_reinterpreting_notes_0028 still expects Notes/partial.md and Notes/kept.md plus the retained last_opened=7 value; the combined branch returned empty paths and last_opened=None for both rows (test output at upgrade_tests.rs:552). I have not changed that expectation. I am tracing whether Notes 0039/0040 alter the source rows or whether the production fixture/read path is wrong before treating this as a migration inventory update.

Separate upgrade finding: `production_schema_copy_upgrades_once_without_reinterpreting_notes_0028` still expects `Notes/partial.md` and `Notes/kept.md` plus the retained `last_opened=7` value; the combined branch returned empty paths and `last_opened=None` for both rows (test output at `upgrade_tests.rs:552`). I have not changed that expectation. I am tracing whether Notes 0039/0040 alter the source rows or whether the production fixture/read path is wrong before treating this as a migration inventory update.
Author
Owner

The first combined workspace run found four stale production-upgrade assertions after Notes migration 0040 was merged. The migration intentionally resets both Daily Log rebuild cursors while preserving their row update times; the other failures were expected pending migration counts/frontiers that still stopped at Notes 0039. I updated only those upgrade inventory and cursor expectations in crates/calternal-server/src/upgrade_tests.rs. Focused rerun: cargo test -p calternal-server --bin calternal-server wire::upgrade_tests:: — 4 passed, 0 failed. The full workspace rerun is in progress.

The first combined workspace run found four stale production-upgrade assertions after Notes migration 0040 was merged. The migration intentionally resets both Daily Log rebuild cursors while preserving their row update times; the other failures were expected pending migration counts/frontiers that still stopped at Notes 0039. I updated only those upgrade inventory and cursor expectations in `crates/calternal-server/src/upgrade_tests.rs`. Focused rerun: `cargo test -p calternal-server --bin calternal-server wire::upgrade_tests::` — 4 passed, 0 failed. The full workspace rerun is in progress.
Author
Owner

Progress update on job/merge40 at 1bd572ba0b: both requested topic branches are merged, the Notes 0040 upgrade expectation is updated and committed, and the full Rust, web, editor, perf-guard and bench-test gates pass. The local release build is complete. The production-Home startup probe is running; the money-register release profile is queued through perf-run behind the current holder. One bounded adversarial round remains.

Progress update on job/merge40 at 1bd572ba0b: both requested topic branches are merged, the Notes 0040 upgrade expectation is updated and committed, and the full Rust, web, editor, perf-guard and bench-test gates pass. The local release build is complete. The production-Home startup probe is running; the money-register release profile is queued through perf-run behind the current holder. One bounded adversarial round remains.
Author
Owner

Startup audit finding on 1bd572ba0b: the candidate upgrades the populated 4ebeba0b8 Home and completes Notes 0040, but the probe observes Money projection-table writes again on the second candidate restart. This is a real repeatability check, not a SLOW-only result. I am adding per-table counters and comparing the persisted ctime receipt across both restarts before deciding the fix.

Startup audit finding on 1bd572ba0b: the candidate upgrades the populated 4ebeba0b8 Home and completes Notes 0040, but the probe observes Money projection-table writes again on the second candidate restart. This is a real repeatability check, not a SLOW-only result. I am adding per-table counters and comparing the persisted ctime receipt across both restarts before deciding the fix.
Author
Owner

Startup audit reproduction on the final release binary and a Home written by production 4ebeba0b8 (656 Notes files, 656 Daily Log entries across 50 days): the first candidate restart reached /readyz in 5.3 s and healthz state=ok in 21.6 s. On the second restart, /readyz took 0.8 s and healthz state=ok took 16.0 s; the Daily Log rebuild completed at 136.9 s, after both signals. Money writes repeated: the second restart deleted and reinserted two register rows and two Categories, and deleted/reinserted the Budget receipt. The probe is checking source-stat and receipt stability to find why the second rebuild occurs.

Startup audit reproduction on the final release binary and a Home written by production 4ebeba0b8 (656 Notes files, 656 Daily Log entries across 50 days): the first candidate restart reached /readyz in 5.3 s and healthz state=ok in 21.6 s. On the second restart, /readyz took 0.8 s and healthz state=ok took 16.0 s; the Daily Log rebuild completed at 136.9 s, after both signals. Money writes repeated: the second restart deleted and reinserted two register rows and two Categories, and deleted/reinserted the Budget receipt. The probe is checking source-stat and receipt stability to find why the second rebuild occurs.
Author
Owner

Finding on #1574: the upgrade probe showed repeat Money projection writes after an unchanged restart. The persisted source signatures and source file stats were stable, but refresh_files_change deleted every money_register_meta row on each global Files-reconciled marker. That made the next read rebuild rows and Categories.

Commit b743887bda5f now rechecks retained source receipts for each User with bounded concurrency. Matching ctime signatures retain the published generation; changed sources use the existing repair path. The regression test counts writes to Money metadata, rows, and Categories for an unchanged global marker (zero), then changes the source and verifies the next marker rebuilds it. Focused test and Money crate clippy pass.

Finding on #1574: the upgrade probe showed repeat Money projection writes after an unchanged restart. The persisted source signatures and source file stats were stable, but `refresh_files_change` deleted every `money_register_meta` row on each global Files-reconciled marker. That made the next read rebuild rows and Categories. Commit `b743887bda5f` now rechecks retained source receipts for each User with bounded concurrency. Matching ctime signatures retain the published generation; changed sources use the existing repair path. The regression test counts writes to Money metadata, rows, and Categories for an unchanged global marker (zero), then changes the source and verifies the next marker rebuilds it. Focused test and Money crate clippy pass.
Author
Owner

Upgrade probe on a Home written by production 4ebeba0b8 passed on b743887bda5f (656 Markdown files, including 656 Daily Log entries across 50 days). Notes 0040 Daily Log rebuild finished at 26,865.3 ms on the first restart, after /readyz at 3,861.3 ms and /healthz state=ok at 20,331.1 ms. /readyz stayed below the 20 s limit. On the second restart the cursor remained complete (/readyz 449.7 ms; health ok 15,567.6 ms) and all Money metadata, row, and Category projection write counters were zero. The initial ctime receipt and Money projection were rebuilt once.

Upgrade probe on a Home written by production `4ebeba0b8` passed on `b743887bda5f` (656 Markdown files, including 656 Daily Log entries across 50 days). Notes 0040 Daily Log rebuild finished at 26,865.3 ms on the first restart, after `/readyz` at 3,861.3 ms and `/healthz state=ok` at 20,331.1 ms. `/readyz` stayed below the 20 s limit. On the second restart the cursor remained complete (`/readyz` 449.7 ms; health `ok` 15,567.6 ms) and all Money metadata, row, and Category projection write counters were zero. The initial ctime receipt and Money projection were rebuilt once.
Author
Owner

Correction to the previous startup note: the Home had 656 Markdown files total (606 Notes and 50 Daily Log files), with 656 Daily Log entries across those 50 days.

Correction to the previous startup note: the Home had 656 Markdown files total (606 Notes and 50 Daily Log files), with 656 Daily Log entries across those 50 days.
Author
Owner

Adversarial round on b743887bda5f completed within the 30-minute cap. Notes path reads, Notes Used In reads, Notifications, and Money register passed. Files copy/overwrite first stopped after its copy probes because attack2.py looked for target/debug/calternald while Cargo uses /home/kayg/build/targets/merge40c; I built calternald there and reran the incomplete Files selector with ADVERSARIAL_SYNC_BIN. That run completed its dedup recovery cases. Each completed Files run reported 0 findings and 0 SLOW findings.

XUser passed: 438 operations classified, 227 replayed, 1,058 cross-User ID comparisons, and 0 denial failures. The startup storm passed in 1.904 s with 8/8/8 acknowledged Files/Notes/Money writes, 16 Search reads, 64 documented 503 responses, and Notes 0039/0040 plus Calendar 0007 applied. No crash, 5xx, lost write, cross-User effect, or other non-SLOW finding was reported.

Adversarial round on `b743887bda5f` completed within the 30-minute cap. Notes path reads, Notes Used In reads, Notifications, and Money register passed. Files copy/overwrite first stopped after its copy probes because `attack2.py` looked for `target/debug/calternald` while Cargo uses `/home/kayg/build/targets/merge40c`; I built `calternald` there and reran the incomplete Files selector with `ADVERSARIAL_SYNC_BIN`. That run completed its dedup recovery cases. Each completed Files run reported 0 findings and 0 SLOW findings. XUser passed: 438 operations classified, 227 replayed, 1,058 cross-User ID comparisons, and 0 denial failures. The startup storm passed in 1.904 s with 8/8/8 acknowledged Files/Notes/Money writes, 16 Search reads, 64 documented 503 responses, and Notes 0039/0040 plus Calendar 0007 applied. No crash, 5xx, lost write, cross-User effect, or other non-SLOW finding was reported.
Author
Owner

READY 9d6aa985f6

What changed

  • Merged job/fix1570 (c3aadd409, #1570) and job/fs1575 (aaaec5660) with separate --no-ff merge commits. Both calternal-fs changes are retained.
  • Fixed the Money global Files reconciliation found during the merge round. It now checks persisted source receipts per User with bounded concurrency, preserves the published generation when ctime receipts are unchanged, and uses the existing repair path when a source changed. The regression test verifies unchanged scans do not rewrite rows or Categories and changed sources still rebuild.
  • Updated upgrade assertions and the startup adversarial probe for Notes migration 0040. Added the Calendar cache test module comments in a final docs-only commit.

Files

Merge-round follow-up files: crates/plugins/money/src/routes.rs, crates/plugins/money/src/register_contract_tests.rs, crates/calternal-server/src/upgrade_tests.rs, tests/adversarial/merge40_startup.py, and crates/plugins/calendar/tests/cache.rs. The two merged jobs also include their source and test files, including crates/calternal-fs/src/file_ops.rs.

Decisions not set by DESIGN.md

The global Files scan uses a concurrency limit of four for independent receipt checks. This bounds per-User I/O while avoiding serial waits over independent work. The unchanged-receipt path retains the existing published generation; a changed ctime goes through the existing repair flow.

Gates

The full workspace gates passed after the functional changes. The final commit adds only five Rust documentation lines in the Calendar cache test file; cargo fmt --check, Calendar clippy, and the Calendar cache tests passed again with that final content.

Captured command results:

cargo fmt --check
(exit 0; no output)

cargo clippy --all-targets -- -D warnings
Finished `dev` profile [unoptimized + debuginfo] target(s) in 31.27s

cargo test
126 test-result blocks; 0 failed blocks; 0 FAILED markers

cargo test -p calternal-search --test indexer overflow_recovery_answers_a_queued_integrity_check -- --exact
test result: ok. 1 passed; 0 failed; 28 filtered out; finished in 156.56s

cd apps/web && bun run check
svelte-check found 0 errors and 0 warnings

cd apps/web && bun run test --maxWorkers=2
321 files and 2,337 tests passed

cd packages/editor && bun run test
30 files and 529 tests passed

uv run --with pytest --with-requirements scripts/perf_guards/requirements.txt python -m pytest scripts/perf_guards
141 passed

node --test bench/*.test.mjs
37 passed

scripts/perf-lint --check
perf-lint: PASS; 0 violations; 20383 scoped exceptions

The full workspace Cargo test included the Search indexer suite: 29 passed, 0 failed; the known latency case also passed alone as shown above. Final Calendar check: cargo clippy -p calternal-plugin-calendar --all-targets -- -D warnings passed; cargo test -p calternal-plugin-calendar --test cache reported 2 passed, 0 failed. bun run build exited 0 (16.51s; existing ineffective dynamic-import warning). The performance ratchet remains 20383.

Release profile and startup upgrade

The release Money profile ran on perf-test-69-63 through perf-run under its shared lock. In-lock load average was 2.70 2.10 2.21. At 200k rows, published refresh serial p50/p95 was 1,397.3/9,044.4 ms (n=5); burst p50/p95 was 2,428.8/5,078.3 ms (n=4). At 50k rows, serial p50/p95 was 415.7/496.7 ms and burst p50/p95 was 803.1/1,557.0 ms. Assertions passed: 11 setter row updates, zero row insert/delete writes, and zero Category writes.

The baseline's 200k cleared-mark p50/p95 is 870.4/992.8 ms from one completed sample, so the current p95 is a follow-up signal rather than a matched before/after result. The profile JSON says qualification=local because MONEY688_QUALIFICATION=perf-vm was omitted; execution itself was on the perf VM through perf-run. I filed #1580 to repeat with corrected metadata and investigate the high serial tail. This did not block this merge qualification.

On the production-built Home copy (606 Notes and 50 Daily Log files; 656 Daily Log entries across 50 days), first restart reached /readyz in 3,861.3 ms, health state=ok in 20,331.1 ms, and completed the Notes 0040 Daily Log rebuild in 26,865.3 ms. The rebuild ran after both readiness milestones. /readyz stayed below the 20-second limit. On the second restart, /readyz took 449.7 ms, health state=ok took 15,567.6 ms, the Daily Log rebuild did no work, and Money metadata/row/Category insert-update-delete counters were all zero.

Expected cost for the global Files check is source files × one receipt fingerprint per hint, with at most four checks in flight; an unchanged source does not rebuild a row or Category.

Adversarial round

Notes path reads, Notes Used In, Notifications, Money register, Files copy/overwrite, XUser matrix, and startup probe completed. The Files selector needed a corrective rerun after its default daemon path missed the externally configured Cargo target; the rerun used ADVERSARIAL_SYNC_BIN and completed. XUser classified 438 operations, replayed 227, made 1,058 cross-User comparisons, and reported zero denial failures/findings. Startup reported ready in 1.904s and acknowledged Files/Notes/Money 8/8/8. No crashes, 5xx responses, lost writes, cross-User effects, or non-SLOW findings were found.

Gaps

The performance profile metadata typo and the 200k p95 follow-up are recorded above and tracked in #1580. No other merge-blocking findings remain. No push or deploy was performed. cargo clean removed 40,552 files / 43.0 GiB; apps/web/build, local probe output, and the job-specific perf VM staging paths were removed. The worktree is clean.

READY 9d6aa985f697cfc43080781426c9661ac0c0e1b6 ## What changed - Merged `job/fix1570` (`c3aadd409`, #1570) and `job/fs1575` (`aaaec5660`) with separate `--no-ff` merge commits. Both `calternal-fs` changes are retained. - Fixed the Money global Files reconciliation found during the merge round. It now checks persisted source receipts per User with bounded concurrency, preserves the published generation when ctime receipts are unchanged, and uses the existing repair path when a source changed. The regression test verifies unchanged scans do not rewrite rows or Categories and changed sources still rebuild. - Updated upgrade assertions and the startup adversarial probe for Notes migration 0040. Added the Calendar cache test module comments in a final docs-only commit. ## Files Merge-round follow-up files: `crates/plugins/money/src/routes.rs`, `crates/plugins/money/src/register_contract_tests.rs`, `crates/calternal-server/src/upgrade_tests.rs`, `tests/adversarial/merge40_startup.py`, and `crates/plugins/calendar/tests/cache.rs`. The two merged jobs also include their source and test files, including `crates/calternal-fs/src/file_ops.rs`. ## Decisions not set by DESIGN.md The global Files scan uses a concurrency limit of four for independent receipt checks. This bounds per-User I/O while avoiding serial waits over independent work. The unchanged-receipt path retains the existing published generation; a changed ctime goes through the existing repair flow. ## Gates The full workspace gates passed after the functional changes. The final commit adds only five Rust documentation lines in the Calendar cache test file; `cargo fmt --check`, Calendar clippy, and the Calendar cache tests passed again with that final content. Captured command results: ```text cargo fmt --check (exit 0; no output) cargo clippy --all-targets -- -D warnings Finished `dev` profile [unoptimized + debuginfo] target(s) in 31.27s cargo test 126 test-result blocks; 0 failed blocks; 0 FAILED markers cargo test -p calternal-search --test indexer overflow_recovery_answers_a_queued_integrity_check -- --exact test result: ok. 1 passed; 0 failed; 28 filtered out; finished in 156.56s cd apps/web && bun run check svelte-check found 0 errors and 0 warnings cd apps/web && bun run test --maxWorkers=2 321 files and 2,337 tests passed cd packages/editor && bun run test 30 files and 529 tests passed uv run --with pytest --with-requirements scripts/perf_guards/requirements.txt python -m pytest scripts/perf_guards 141 passed node --test bench/*.test.mjs 37 passed scripts/perf-lint --check perf-lint: PASS; 0 violations; 20383 scoped exceptions ``` The full workspace Cargo test included the Search indexer suite: 29 passed, 0 failed; the known latency case also passed alone as shown above. Final Calendar check: `cargo clippy -p calternal-plugin-calendar --all-targets -- -D warnings` passed; `cargo test -p calternal-plugin-calendar --test cache` reported 2 passed, 0 failed. `bun run build` exited 0 (16.51s; existing ineffective dynamic-import warning). The performance ratchet remains 20383. ## Release profile and startup upgrade The release Money profile ran on perf-test-69-63 through `perf-run` under its shared lock. In-lock load average was `2.70 2.10 2.21`. At 200k rows, published refresh serial p50/p95 was `1,397.3/9,044.4 ms` (n=5); burst p50/p95 was `2,428.8/5,078.3 ms` (n=4). At 50k rows, serial p50/p95 was `415.7/496.7 ms` and burst p50/p95 was `803.1/1,557.0 ms`. Assertions passed: 11 setter row updates, zero row insert/delete writes, and zero Category writes. The baseline's 200k cleared-mark p50/p95 is `870.4/992.8 ms` from one completed sample, so the current p95 is a follow-up signal rather than a matched before/after result. The profile JSON says `qualification=local` because `MONEY688_QUALIFICATION=perf-vm` was omitted; execution itself was on the perf VM through `perf-run`. I filed #1580 to repeat with corrected metadata and investigate the high serial tail. This did not block this merge qualification. On the production-built Home copy (606 Notes and 50 Daily Log files; 656 Daily Log entries across 50 days), first restart reached `/readyz` in `3,861.3 ms`, health `state=ok` in `20,331.1 ms`, and completed the Notes 0040 Daily Log rebuild in `26,865.3 ms`. The rebuild ran after both readiness milestones. `/readyz` stayed below the 20-second limit. On the second restart, `/readyz` took `449.7 ms`, health `state=ok` took `15,567.6 ms`, the Daily Log rebuild did no work, and Money metadata/row/Category insert-update-delete counters were all zero. Expected cost for the global Files check is source files × one receipt fingerprint per hint, with at most four checks in flight; an unchanged source does not rebuild a row or Category. ## Adversarial round Notes path reads, Notes Used In, Notifications, Money register, Files copy/overwrite, XUser matrix, and startup probe completed. The Files selector needed a corrective rerun after its default daemon path missed the externally configured Cargo target; the rerun used `ADVERSARIAL_SYNC_BIN` and completed. XUser classified 438 operations, replayed 227, made 1,058 cross-User comparisons, and reported zero denial failures/findings. Startup reported ready in 1.904s and acknowledged Files/Notes/Money 8/8/8. No crashes, 5xx responses, lost writes, cross-User effects, or non-SLOW findings were found. ## Gaps The performance profile metadata typo and the 200k p95 follow-up are recorded above and tracked in #1580. No other merge-blocking findings remain. No push or deploy was performed. `cargo clean` removed 40,552 files / 43.0 GiB; `apps/web/build`, local probe output, and the job-specific perf VM staging paths were removed. The worktree is clean.
Author
Owner

Independent review rev1574 starts on job/rev1574 at 9d6aa985f6. Target: b743887bda. Read-mostly: only failing defect tests will be committed. No author reports or result files read. Checks: offline source changes, invalid/unreadable folders, missing metadata, concurrent Money writes, cross-User isolation. Time box: 90 minutes.

Independent review rev1574 starts on job/rev1574 at 9d6aa985f697cfc43080781426c9661ac0c0e1b6. Target: b743887bda5f62087cd11e823520c679233f2de8. Read-mostly: only failing defect tests will be committed. No author reports or result files read. Checks: offline source changes, invalid/unreadable folders, missing metadata, concurrent Money writes, cross-User isolation. Time box: 90 minutes.
Author
Owner

Independent review finding: BLOCK. With a real unreadable Budget folder (chmod 000), global Money reconciliation returns an IO error and leaves a later valid Budget's retained metadata intact. After restoring permission, three real GET /budgets/home/accounts handler calls return HTTP 200 with stale Account balances and cleared balance instead of a fresh full source replay. The worker logs a generic error and continues, but those retained reads do not repair. Independent failing test in progress: unreadable_budget_must_not_leave_later_budget_stale. Testing the same abort across the four-User batch and completing the offline/concurrency matrix. Product code unchanged.

Independent review finding: BLOCK. With a real unreadable Budget folder (chmod 000), global Money reconciliation returns an IO error and leaves a later valid Budget's retained metadata intact. After restoring permission, three real GET /budgets/home/accounts handler calls return HTTP 200 with stale Account balances and cleared balance instead of a fresh full source replay. The worker logs a generic error and continues, but those retained reads do not repair. Independent failing test in progress: unreadable_budget_must_not_leave_later_budget_stale. Testing the same abort across the four-User batch and completing the offline/concurrency matrix. Product code unchanged.
Author
Owner

Independent review progress at 2c796d67ad0e862d9b62f5cf5f2d80d14f6e222e: committed only two intentionally failing stale-number tests; product code and old expectations unchanged. Both fail after real chmod(000) folder IO failures, with HTTP 200 Accounts returning stale balances/cleared balances and register responses omitting the offline posting, even after a successful month read. B1: later Budget for the same User. B2: fifth User outside the four-User batch, with the other three admitted Users holding normal Money write locks.

Passed exploratory checks: nine offline source/folder mutations, deleted/malformed Budget handling, new/no-meta Budgets and Users (production cold builder included), and five-User overlapping writes with exactly one acknowledged posting per User. Fresh full replay agrees with exact register rows, Account summaries and September–November reports.

Non-blocking R1: changing one User's source can rebuild another User's unchanged rows when identical source files share a Blob inode. Replacing one hardlink changes ctime on the other; bytes and inode are unchanged. All numbers remain correct. This is redundant rebuild work, not cross-User data mixing. Saved exploratory evidence in artifacts/rev1574-final-matrix.log and artifacts/rev1574-probe-source.rs. Final crate gates in progress.

Independent review progress at 2c796d67ad0e862d9b62f5cf5f2d80d14f6e222e: committed only two intentionally failing stale-number tests; product code and old expectations unchanged. Both fail after real chmod(000) folder IO failures, with HTTP 200 Accounts returning stale balances/cleared balances and register responses omitting the offline posting, even after a successful month read. B1: later Budget for the same User. B2: fifth User outside the four-User batch, with the other three admitted Users holding normal Money write locks. Passed exploratory checks: nine offline source/folder mutations, deleted/malformed Budget handling, new/no-meta Budgets and Users (production cold builder included), and five-User overlapping writes with exactly one acknowledged posting per User. Fresh full replay agrees with exact register rows, Account summaries and September–November reports. Non-blocking R1: changing one User's source can rebuild another User's unchanged rows when identical source files share a Blob inode. Replacing one hardlink changes ctime on the other; bytes and inode are unchanged. All numbers remain correct. This is redundant rebuild work, not cross-User data mixing. Saved exploratory evidence in artifacts/rev1574-final-matrix.log and artifacts/rev1574-probe-source.rs. Final crate gates in progress.
Author
Owner

BLOCK — independent Money review of b743887bd (#1574)

Head: 4f3961e57666e1b536c7436ddb5a4742f71c23c2, branch job/rev1574.
Base: 9d6aa985f697cfc43080781426c9661ac0c0e1b6.
Target: b743887bda5f62087cd11e823520c679233f2de8.
Author reports and result files were not read.

Blockers

  1. B1: one unreadable Budget leaves a later Budget serving stale numbers. Persist owner Budgets aaa in Broken and home in Home. Add a cleared synthetic expense to Home without a Files event. Inject unreadability with chmod 000 after Files has visited Broken (or after the completion marker is queued), then consume the global reconciled marker. Its per-User recheck invalidates Broken and returns its filesystem IO error before processing Home. Restore permissions. GET the Home month, its register, and its Accounts three times. These handlers stay available and return 200, but the register omits the new posting and Accounts retain old balances and cleared balances. A fresh full replay disagrees. Month reads do not repair those retained rows.
    Failing test: routes::register_contract_tests::review_1574::unreadable_budget_must_not_leave_later_budget_stale.
  2. B2: an unreadable User cancels the remaining global recheck. Persist five Users (a, b, c, d, z) with the same Budget ID home. Change z's month offline, inject unreadability of a's Budget after its Files scan, and hold the normal Money write locks for b/c/d. Deliver the global marker. a's error reaches result? and drops the buffered refresh stream before z starts. Restore permissions and release locks. z's month, register and repeated Accounts reads return 200, but register and Account numbers stay stale.
    Failing test: routes::register_contract_tests::review_1574::unreadable_user_must_not_leave_fifth_user_stale.

Files startup sends one global PluginEvent completion after a successful full scan, rather than per-file startup hints (crates/plugins/files/src/index.rs, lines 336–427). A failed Files scan sends no completion marker. These fault probes target the specified during-recheck IO failure: a folder becomes unreadable after Files has visited it or queued the marker. They do not claim that a permanently unreadable folder present before the Files scan is a new regression from this commit.

Both tests use a real calternal-fs data directory, real SQLite projection tables and production handlers. Failure messages confirm stale Account/cleared balances and missing register postings. The first cause is the early return in refresh_user_money_sources; the second is result? in the global buffer_unordered(4) loop. The worker logs an error and continues, but warm reads do not stat sources or enqueue repair for retained metadata. No product fix was made, as required by this review brief.

Reproduce both:

export CARGO_PROFILE_DEV_DEBUG=line-tables-only CARGO_INCREMENTAL=0 CARGO_BUILD_JOBS=4
export TMPDIR="$PWD/target/tmp"
cargo test -p calternal-plugin-money review_1574 -- --test-threads=2

Checks completed

  • Nine offline mutation cases pass fresh full replay: ordinary same-inode edit; same size/inode with restored mtime (old non-ctime fingerprint equality verified); source replacement by rename; month deletion; month addition; Budget Assignment edit; Account kind edit; whole Budget folder replacement; whole Budget folder rename.
  • Compare exact register postings/running balances, every Account field (including cleared balance), and September–November reports (Category Available, Ready to Assign and month rollovers). Only process-local report revision is excluded from the oracle comparison.
  • Deleted and malformed Budget folders invalidate their own projections and do not stop sibling repair.
  • A new Budget without metadata and a User without any metadata build correctly. The production cold builder is tested, as well as handler results.
  • Five Users run Money creates while reconciliation is held on a User write lock. Every acknowledgement is represented by exactly one source posting. All final projections and month reports match full replay; no deadlock is found within the 15-second bound.
  • Same Budget IDs across two Users show no mixed numbers or postings.

Non-blocking finding R1

An edit for one User can rebuild another User's unchanged Budget if source bytes share a Blob inode. Exact repro: create equal Money source files for owner/other; publish both projections; record other's month bytes, source fingerprint and register row IDs; replace only owner's month; deliver global reconciliation. Other's bytes and inode stay unchanged, but unlinking owner's hardlink changes the shared inode ctime. Other's receipt no longer matches, so its register is rebuilt and row IDs change. Both Users' numbers and postings still match a fresh full replay. This is redundant rebuild work, not a data-safety or authorization failure. It does not block under the owner rule.

The exploratory test same_ids_cross_user_keep_unchanged_projection and the full six-probe source are retained in artifacts/rev1574-probe-source.rs. The matrix output is artifacts/rev1574-final-matrix.log (three passed probes, the two stale-number failures and this harmless rebuild failure). Only the two stale-number tests are committed.

Built and files

  • crates/plugins/money/src/review_1574.rs: two failing regression tests and real-filesystem/Index/full-replay fixture helpers.
  • crates/plugins/money/src/register_contract_tests.rs: test-only module registration.
  • artifacts/rev1574-findings.md: findings appended during the review; not committed.
  • Product code, dependencies, existing expectations and lockfiles are unchanged.

Known gaps

The review uses the crate harness rather than a full deployed server process. Offline cases reopen the real data directory and persistent Index; invalidation uses the real reconciliation handler. The bounded parallel-write probe is not an exhaustive scheduler proof. Both stale-read defects remain open. No UI, performance benchmark, deployment or macOS work is part of this review.

Decisions

No product design decisions. Use a fresh MoneyIndex and full source replay as the oracle, separate from retained projection state. Classify R1 as non-blocking redundant work because all numbers remain correct. Commit only the two failing tests that expose stale numbers, as the brief requires.

Gates

Fetched origin and merged origin/dev once before final gates: Already up to date. Origin/dev was 0c712b98c.
Environment for all Cargo commands: CARGO_PROFILE_DEV_DEBUG=line-tables-only, CARGO_INCREMENTAL=0, CARGO_BUILD_JOBS=4, TMPDIR=<worktree>/target/tmp. The preset CARGO_TARGET_DIR=/home/kayg/build/targets/rev1574 was kept unchanged.

cargo fmt --check: exit 0, no output.

cargo clippy -p calternal-plugin-money --all-targets -- -D warnings: exit 0. Output verbatim:

    Checking calternal-plugin-money v0.0.1 (/home/kayg/Developer/calternal-wt/rev1574/crates/plugins/money)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 8.53s

CARGO_BUILD_JOBS=4 cargo test -p calternal-money -p calternal-plugin-money -- --test-threads=4: exit 101. All executed core Money tests passed (72 passed, one ignored). Plugin: 186 passed, two failed, three ignored. The two failures are exactly B1/B2. Full output verbatim:

   Compiling calternal-money v0.0.1 (/home/kayg/Developer/calternal-wt/rev1574/crates/calternal-money)
   Compiling calternal-plugin-money v0.0.1 (/home/kayg/Developer/calternal-wt/rev1574/crates/plugins/money)
    Finished `test` profile [unoptimized + debuginfo] target(s) in 18.92s
     Running unittests src/lib.rs (/home/kayg/build/targets/rev1574/debug/deps/calternal_money-1e2a01de24e62d5b)

running 16 tests
test codec::tests::empty_payee_is_refused_by_the_writer ... ok
test codec::tests::malformed_dated_rows_fail_instead_of_vanishing ... ok
test codec::tests::property_edit_changes_one_value ... ok
test codec::tests::round_trip_keeps_bom_crlf_and_unknown_bytes ... ok
test codec::tests::transaction_round_trip_with_punctuation_in_labels_and_payee ... ok
test edit::tests::cleared_tag_toggles_without_touching_other_tags ... ok
test edit::tests::crlf_file_keeps_crlf_on_insert ... ok
test edit::tests::unicode_payee_tag_boundaries_match_shared_vectors ... ok
test codec::tests::checked_parse_stops_after_a_bounded_line_batch ... ok
test units::tests::exact_range_is_enforced_on_parse_and_arithmetic ... ok
test units::tests::format_uses_explicit_sign_and_exact_scale ... ok
test units::tests::parse_matches_the_oracle_examples ... ok
test units::tests::scale_table_has_all_165_codes_with_unique_entries ... ok
test edit::tests::new_budget_projects_with_no_accounts ... ok
test units::independent_number_review::signed_edges_and_long_zero_padding_keep_exact_minor_units ... ok
test edit::tests::assign_inserts_updates_and_removes_rows ... ok

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

     Running tests/account_kinds.rs (/home/kayg/build/targets/rev1574/debug/deps/account_kinds-9b132658dec70242)

running 5 tests
test account_projection_rejects_legacy_and_unknown_kinds ... ok
test imported_account_kinds_project_without_losing_identity ... ok
test off_budget_balance_marker_does_not_change_budget_money ... ok
test tracking_deficit_rollover_does_not_reduce_ready_to_assign ... ok
test categorized_debit_loan_transfers_post_one_budget_leg ... ok

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

     Running tests/import.rs (/home/kayg/build/targets/rev1574/debug/deps/import-cc734ecd3c4f274b)

running 13 tests
test duplicate_source_ids_are_rejected_and_duplicate_names_are_kept ... ok
test import_keeps_same_day_source_order_for_credit_payments_and_refunds ... ok
test import_render_is_exact_and_byte_stable ... ok
test import_render_reports_progress_and_propagates_cancel ... ok
test import_stream_renderer_matches_full_rendered_files ... ok
test production_v1_metadata_upgrade_keeps_balances ... ok
test import_replay_matches_full_ledger_month_by_month ... ok
test recheck_half_minor_units_negative_zero_and_nineteen_digits ... ok
test budget_replay_stops_at_a_bounded_transaction_checkpoint ... ok
test imported_ready_to_assign_matches_independent_month_oracle ... ok
test recheck_same_day_payment_and_refund_keep_source_fifo ... ok
test random_imports_conserve_source_balances_and_markdown ... ok
test recheck_random_multicurrency_ledgers_match_all_monthly_totals ... ok

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

     Running tests/properties.rs (/home/kayg/build/targets/rev1574/debug/deps/properties-50f0dfcda0fc447c)

running 21 tests
test bill_coverage_never_clamps_the_bill ... ok
test bulkrev2::boundary_shuffle_reports_acceptance_difference ... ok
test bulkrev2::i64_extremes_are_rejected_and_safe_bound_is_exact ... ok
test bulkrev2::literal_account_sum_and_funded_card_conservation ... ok
test bulkrev2::refund_payment_calendar_choice_is_visible_next_month ... ok
test any_text_that_parses_serializes_to_the_same_bytes ... ok
test bulkrev2::split_refund_keeps_payment_overfunding_when_card_becomes_positive ... ok
test assign_then_unassign_is_the_identity ... ok
test decimal_text_round_trips_for_every_scale ... ok
test cash_ledgers_conserve_money_every_month ... ok
test fully_funded_card_spending_conserves_cash ... ok
test money_code_never_uses_floating_point ... ok
test mixed_cash_credit_deficit_rolls_only_its_cash_part ... ok
test paired_write_replay_matches_independent_calculations ... ok
test reviewed_burst_order_matches_input_order ... ok
test partial_payment_then_category_refunds_conserve_cash_across_months ... ok
test split_legs_post_exactly_the_parent ... ok
test transaction_rows_round_trip_byte_for_byte ... ok
test same_date_card_postings_are_a_function_of_the_set ... ok
test bulkrev2::funded_shuffles_conserve_real_money_every_month ... ok
test bulkrev2::same_day_shuffles_cover_splits_transfers_and_month_edges ... ok

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

     Running tests/ready_to_assign_adjustment.rs (/home/kayg/build/targets/rev1574/debug/deps/ready_to_assign_adjustment-71f95d93ae1d6a03)

running 1 test
test ready_to_assign_adjustment_changes_only_the_budget_pool ... ok

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

     Running tests/review_984.rs (/home/kayg/build/targets/rev1574/debug/deps/review_984-e1bb010954dc02d8)

running 5 tests
test review_pair_performance_profile ... ignored, performance measurements belong to the merge round on the perf VM
test review_pair_rejects_bad_months_and_amounts_without_rounding ... ok
test review_split_remainders_and_tracking_transfers_are_exact ... ok
test review_mixed_pair_matches_independent_replays ... ok
test review_large_ledger_pair_keeps_exact_totals ... ok

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

     Running tests/review_bulkrev3.rs (/home/kayg/build/targets/rev1574/debug/deps/review_bulkrev3-1a27d60055bb808c)

running 7 tests
test hidden_and_missing_categories ... ok
test legacy_payment_repair_is_idempotent_and_collision_safe ... ok
test card_opening_credit_enters_ready_to_assign_once ... ok
test unlinked_card_funded_purchase_keeps_its_payment_money ... ok
test envelope_edge_cases ... ok
test previous_witnesses_all_orders ... ok
test random_histories_conserve_money_after_every_rollover ... ok

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

     Running tests/vectors.rs (/home/kayg/build/targets/rev1574/debug/deps/vectors-04392997c28c2e72)

running 5 tests
test rust_matches_random_oracle_ledgers_without_divergences ... ok
test reviewed_r4_unlinked_card_vector_keeps_its_unfunded_amount ... ok
test reviewed_r3_vectors_assert_retired_debt_and_positive_credit ... ok
test reviewed_eleven_refund_vectors_keep_their_exact_numbers ... ok
test rust_port_matches_every_recorded_oracle_vector ... ok

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

     Running unittests src/lib.rs (/home/kayg/build/targets/rev1574/debug/deps/calternal_plugin_money-369d9e0370502d5a)

running 191 tests
test import::import_review_tests::actual_cents_conversion_never_rounds ... ok
test import::import_review_tests::actual_cc_label_requires_missing_type_confirmation ... ok
test import::import_review_tests::actual_orphan_split_children_are_rejected ... ok
test import::import_review_tests::actual_stream_memory_guard_child ... ignored, invoked as an isolated child by actual_stream_keeps_a_large_history_bounded
test import::import_review_tests::actual_transfer_legs_cannot_cross_months ... ok
test import::import_review_tests::import_control_reports_progress_and_stops_cancelled_work ... ok
test import::import_review_tests::actual_account_checks_use_raw_monthly_source_rows ... ok

running 1 test
test import::import_review_tests::ynab_transfer_pairing_handles_many_duplicate_legs ... ok
test import_fidelity_1130::independent_split_and_transfer_numbers_check ... ok
test register::tests::busy_completion_fence_is_retryable_and_keeps_intent ... ok
test register::tests::cursor_scope_and_signature_are_required ... ok
test import_fidelity_1130::actual_rows_round_trip ... ok
test import::import_review_tests::actual_stream_memory_guard_child ... ok

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

test import::import_review_tests::actual_stream_keeps_a_large_history_bounded ... ok
test register::tests::suffix_batches_never_promote_integer_balances_to_real ... ok
test register_recovery_tests::marker_wait_does_not_accept_an_empty_port_file ... ok
test register_recovery_tests::recovery_invalidates_broken_sources_without_changing_files ... ok
test register_recovery_tests::register_kill_child ... ignored, child of register_recovery_survives_sigkill_at_every_durability_point
test register::tests::pages_equal_raw_bigint_postings ... ok
test register_recovery_tests::review688_directory_source_does_not_stop_startup ... ok
test routes::durable::admission_tests::cancelled_receiver_cannot_acknowledge_a_durable_job ... ok
test projection::tests::scoped_histories_equal_full_replay has been running for over 60 seconds
test register::tests::incremental_sequences_equal_scratch_bigint has been running for over 60 seconds
test routes::durable::admission_tests::live_publication_honors_operational_queue_cancellation ... ok
test routes::durable::checkpoint_tests::progress_wait_keeps_parser_writer_release_polled ... ok
test routes::durable::money_import_undo_mutation ... ok
test routes::import_cleanup_tests::dropped_preview_worker_retains_admission_until_exit ... ok
test routes::import_cleanup_tests::idle_imports_are_reclaimed_by_expiry_cleanup ... ok
test routes::import_cleanup_tests::staged_import_files_keep_ranges_and_release_private_storage ... ok
test routes::import_staged_path_tests::staged_import_name_cannot_select_another_path_or_slot ... ok
test routes::register_contract_tests::cached_register_reads_without_source_or_projection_writes ... ok
test routes::register_contract_tests::cleared_publication_fault_does_not_replay_queued_500 ... ok
test routes::register_contract_tests::cold_register_admission_rejects_foreign_and_missing_budgets ... ok
test routes::register_contract_tests::directory_source_refuses_reads_without_server_failure ... ok
test register_recovery_tests::register_recovery_survives_sigkill_at_every_durability_point ... ok
test routes::register_contract_tests::file_scoped_edit_delete_and_cleared_keep_colliding_rows_distinct ... ok
test routes::register_contract_tests::money_transactions_pagination ... ok
test routes::register_contract_tests::money_transactions_preflight ... ok
test routes::register_contract_tests::money_admission_rejects_unowned_budgets_without_queued_work ... ok
test routes::register_contract_tests::money_transactions_projection ... ok
test routes::register_contract_tests::money_transactions_response_bounds ... ok
test routes::register_contract_tests::money_transactions_revision ... ok
test routes::register_contract_tests::queued_register_build_publishes_one_durable_generation ... ok
test routes::register_contract_tests::register_build_queue_is_bounded_and_coalesces_duplicates ... ok
test routes::register_contract_tests::register_files_events_stay_in_their_test_instance ... ok
test routes::register_contract_tests::register_filter_indexes_keep_split_membership_on_scoped_updates ... ok
test routes::register_contract_tests::register_imported_tag_heavy_writes ... ok
test routes::register_contract_tests::register_pages_stop_by_bytes_without_losing_rows ... ok
test routes::register_contract_tests::register_projection_survives_restart_and_tracks_source_revisions ... ok
test routes::register_contract_tests::register_mark_writes_touch_constant_rows_with_card_history ... ok
test routes::register_contract_tests::register_publication_reserves_writer_before_snapshot ... ok
test routes::register_contract_tests::register_repeated_tag_heavy_writes ... ok
test routes::register_contract_tests::register_tag_maximum_and_byte_paging ... ok
test routes::register_contract_tests::retained_mark_response_keeps_destination_date ... ok
test routes::register_contract_tests::review1570_same_inode_same_mtime_hint_must_refresh_numbers ... ok
test routes::register_contract_tests::register_writes_publish_before_reads ... ok
test routes::register_contract_tests::review688_category_filter_keeps_file_local_identity ... ok
test routes::register_contract_tests::review688_cleared_round_trip_restores_source_bytes ... ok
test routes::register_contract_tests::review688_file_change_invalidates_retained_numbers ... ok
test routes::register_contract_tests::review688_transfer_leg_prefix_uses_its_own_date ... ok
test routes::register_contract_tests::review688k_colliding_legs_page_and_update_independently ... ok
test routes::register_contract_tests::review688k_file_identity_upgrade_preserves_recovery ... ok
test routes::register_contract_tests::review688k_partial_marks_preserve_other_file_identities ... ok
test routes::register_contract_tests::review688rev2_failed_publication_cannot_serve_stale_numbers ... ok
test routes::register_contract_tests::review688rev2_visible_leg_collision_cannot_stop_startup ... ok
test routes::register_contract_tests::review_1574::unreadable_budget_must_not_leave_later_budget_stale ... FAILED
test routes::register_contract_tests::review688rev3_ambiguous_edit_cannot_move_another_source_row ... ok
test routes::register_contract_tests::stale_cold_builder_does_not_replace_a_newer_generation ... ok
test routes::register_contract_tests::review_1574::unreadable_user_must_not_leave_fifth_user_stale ... FAILED
test routes::register_contract_tests::stale_mark_generation_repairs_before_retry ... ok
test routes::replay_reuse_tests::assignment_retry_rebuilds_from_latest_source_bytes ... ok
test routes::replay_reuse_tests::crossings_reuse_checked_current_totals_even_with_future_months ... ok
test routes::replay_reuse_tests::crossings_cover_source_ranges_relative_to_today ... ok
test routes::review_1140::cancel_wins_before_publication_lock ... ok
test routes::review_1140::cancel_does_not_rewrite_published_result ... ok
test routes::review_1140::review1140_cancel_after_rename_before_receipt_keeps_publication ... ok
test routes::review_1140::review1140_all_formats_replay_exact_balances ... ok
test routes::review_1140::review1140_operational_cancel_before_replacement_returns_no_receipt ... ok
test routes::review_1140::review1140_discard_after_confirmation_failure_releases_admission ... ok
test routes::review_1140::review1140_staged_size_limits_fail_without_publishing ... ok
test register::tests::incremental_sequences_equal_scratch_bigint ... ok
test routes::review_1140::review1140_terminal_receipts_do_not_block_new_imports ... ok
test store::parsed_cache_tests::global_budget_and_folder_pruning_release_stale_entries ... ok
test routes::review_1140::review1140_tcp_malformed_inputs_leave_worker_usable ... ok
test store::parsed_cache_tests::parse_charge_accounts_for_line_structures ... ok
test store::parsed_cache_tests::source_receipt_versions_and_checks_both_ctime_parts ... ok
test store::parsed_cache_tests::user_cache_evicts_old_parse_entries_and_shares_hot_documents ... ok
test store::parsed_cache_tests::oversized_snapshots_share_only_while_active ... ok
test tests::a_broken_file_is_reported_not_hidden ... ok
test tests::a_new_user_sees_the_real_empty_state ... ok
test tests::a_journal_for_a_completed_move_changes_nothing ... ok
test routes::review_1140::review1140_replacement_receipt_recovery_does_not_adopt_later_edits ... ok
test tests::active_money_handle_survives_other_users_cache_pressure ... ok
test tests::actual_duplicate_names_import_by_id_without_sharing_a_payment_category ... ok
test tests::actual_export_archive_imports_exact_rows_from_private_scratch ... ok
test tests::a_read_waits_for_a_write_in_progress ... ok
test tests::a_split_row_written_by_hand_is_read_but_not_edited ... ok
test tests::api_account_numbers_equal_core_replay ... ok
test tests::assignments_retry_source_conflicts_without_losing_neighbours ... ok
test tests::backdated_create_emits_current_month_overspend_crossing ... ok
test tests::budget_flow_writes_exact_markdown_and_derives_available ... ok
test tests::bulk_write_invalid_neighbours_do_not_change_valid_rows ... ok
test tests::bulk_write_month_does_not_need_note_date_backfill ... ok
test tests::cancel_racing_confirm_has_one_consistent_outcome ... ok
test tests::cancelling_imports_leaves_no_budget_and_releases_slots ... ok
test tests::bulk_write_rejects_intermediate_overflow ... ok
test tests::card_opening_credit_route_conserves_real_budget_money ... ok
test tests::concurrent_store_edits_keep_exactly_one_winner ... ok
test tests::csv_import_keeps_progress_and_cancel_responsive ... ok
test tests::delete_transaction_emits_current_month_overspend_crossing ... ok
test tests::denied_preview_access_keeps_the_owners_pending_import ... ok
test tests::durable_import_tests::foreign_import_cancellation_matches_missing_without_changing_owner_state ... ok
test tests::durable_import_tests::generated_import_confirm_replay_and_undo_preserve_minor_units ... ok
test tests::durable_import_tests::operation_exit_child ... ignored, child of operation_recovery_survives_process_exit_at_every_phase
test tests::bulk_write_balances_equal_one_by_one has been running for over 60 seconds
test tests::card_models_ignore_arrival_batch_and_timezone has been running for over 60 seconds
test tests::durable_import_tests::operation_recovery_survives_process_exit_at_every_phase ... ok
test tests::durable_import_tests::publication_and_inverse_authority_use_full_commits ... ok
test tests::durable_import_tests::queued_import_and_undo_survive_restarts ... ok
test tests::durable_import_tests::receipt_reads_are_bounded_and_old_receipts_are_addressable ... ok
test tests::durable_import_tests::replacement_restarts_at_every_durable_phase ... ok
test tests::durable_import_tests::replay_preserves_a_live_ready_preview ... ok
test tests::durable_import_tests::running_jobs_do_not_expire_and_cancelled_jobs_do_not_restart ... ok
test tests::durable_import_tests::undo_receipt_replay_never_removes_a_restored_import ... ok
test tests::durable_import_tests::undo_refuses_a_predecessor_restored_before_the_inverse ... ok
test tests::durable_import_tests::undo_refuses_every_later_budget_edit_after_restart ... ok
test tests::durable_import_tests::undo_restarts_before_and_after_the_filesystem_inverse ... ok
test tests::failed_cross_month_move_never_counts_the_row_twice ... ok
test tests::far_month_assignment_cannot_make_the_budget_unreadable ... ok
test tests::bulk_write_balances_equal_one_by_one ... ok
test tests::gap_month_assignments_and_opening_card_debt_do_not_create_cash ... ok
test tests::historical_overspend_does_not_emit_current_month_event ... ok
test tests::hostile_inputs_are_rejected_without_writing ... ok
test tests::import_fidelity_review_requires_account_kind_and_keeps_notes ... ok
test tests::import_file_limits_match_the_money_reader ... ok
test tests::import_preview_is_owner_bound_and_confirmation_publishes_once ... ok
test tests::import_preview_reads_only_generated_staged_upload_names ... ok
test tests::inferred_opening_balance_needs_explicit_confirmation ... ok
test tests::legacy_card_payment_repair_cannot_make_its_budget_unreadable ... ok
test tests::legacy_card_payment_repair_is_editable_and_saved_category_first ... ok
test tests::memo_and_tags_split_the_payee_without_losing_text ... ok
test tests::money_is_on_for_the_instance_and_off_for_a_new_user ... ok
test tests::idle_import_receive_releases_admission_and_cancel_stops_read ... ok
test tests::month_revision_increases_after_each_assignment ... ok
test tests::move_money_keeps_ready_to_assign_and_card_gets_payment_category ... ok
test tests::multiple_assignment_rows_set_one_exact_total ... ok
test tests::other_users_and_sessions_without_data_scope_see_nothing ... ok
test tests::overflowing_category_sum_is_rejected_before_assignment_write ... ok
test tests::overflowing_cleared_subset_is_rejected_before_transaction_write ... ok
test tests::overflowing_derived_balance_is_rejected_before_the_write ... ok
test tests::overspending_reports_ynab_states ... ok
test tests::plugin_code_never_uses_floating_point ... ok
test tests::parsed_money_cache_shares_documents_and_prunes_removed_months ... ok
test tests::recheck_metadata_files_use_the_reader_size_cap ... ok
test tests::recheck_local_server_number_and_lifecycle_contract ... ok
test tests::recheck_source_checks_owner_and_opening_balance_confirmation ... ok
test tests::review_1130::review1130_cancel_after_partial_preparation ... ok
test tests::recheck_random_preview_cancellation_leaves_no_files ... ok
test tests::review_1130::review1130_legacy_home_needs_no_metadata_rewrite ... ok
test tests::review_1130::review1130_notes_are_inert ... ok
test tests::review_1130::review1130_long_imported_note_allows_amount_edit_without_loss ... ok
test tests::review_1130::review1130_reconciled_closed_balances ... ok
test tests::review_1130::review1130_split_and_closed_transfer_have_one_posting ... ok
test tests::review_1130::review1130_tcp_locks_reimport_and_cancel ... ok
test tests::review_984::review3_first_future_transaction_keeps_current_event_month ... ok
test tests::review_984::review3_future_only_edit_and_delete_keep_current_event_month ... ok
test tests::review_984::review3_outside_current_range_writes_emit_no_overspend ... ok
test tests::review_984::review_category_edit_emits_for_old_category_only ... ok
test tests::review_984::review_concurrent_assign_revisions_match_final_report ... ok
test tests::review_984::review_cross_month_refund_move_emits_current_crossing ... ok
test tests::review_984::review_file_replacement_advances_month_revision ... ok
test tests::review_984::review_exact_zero_healing_recrossing_and_delete ... ok
test tests::review_984::review_split_and_tracking_transfer_writes_are_rejected_without_events ... ok
test tests::review_984::review_user_zone_month_and_year_edges ... ok
test tests::review_984::review_source_generation_tracks_all_files_and_restoration ... ok
test tests::review_bulkrev2::four_conflicts_return_409_without_writing ... ok
test tests::same_handle_settles_a_failed_move_before_the_next_request ... ok
test tests::simultaneous_import_confirmations_have_one_winner ... ok
test tests::review_bulkrev2::two_and_five_assignment_races_match_serial_targets ... ok
test tests::source_total_mismatch_cannot_be_confirmed ... ok
test tests::slow_15mb_import_receive_completes_with_progress ... ok
test tests::transaction_identity_preview_is_atomic_and_reimport_changes_nothing ... ok
test tests::transaction_logged_event_has_the_documented_create_payload ... ok
test tests::transfer_register_view_exposes_linked_category ... ok
test tests::transfer_cleared_edits_are_per_account ... ok
test tests::wizard_background_job_recovers_preview_after_response_is_dropped ... ok
test tests::wizard_background_job_retains_safe_failure ... ok
test tests::wizard_starter_categories_validate_before_create_and_do_not_change_totals ... ok
test tests::ynab_conflicting_accounts_and_payees_are_not_silently_discarded ... ok
test tests::ynab_csv_import_keeps_exact_month_and_register_amounts ... ok
test tests::ynab_duplicate_category_ids_are_merged_only_when_identical ... ok
test tests::ynab_plan_json_import_keeps_exact_milliunits ... ok
test tests::ynab_public_demo_imports_duplicate_category_names_by_id ... ok
test tests::update_transaction_emits_current_month_overspend_crossing ... ok
test tests::card_models_ignore_arrival_batch_and_timezone ... ok
test projection::tests::scoped_histories_equal_full_replay ... ok

failures:

---- routes::register_contract_tests::review_1574::unreadable_budget_must_not_leave_later_budget_stale stdout ----

thread 'routes::register_contract_tests::review_1574::unreadable_budget_must_not_leave_later_budget_stale' (3709072) panicked at crates/plugins/money/src/review_1574.rs:109:5:
retained reads serve stale balances or rows after global reconciliation: stale Account/cleared balances=true, offline posting absent from register=true
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

---- routes::register_contract_tests::review_1574::unreadable_user_must_not_leave_fifth_user_stale stdout ----

thread 'routes::register_contract_tests::review_1574::unreadable_user_must_not_leave_fifth_user_stale' (3709488) panicked at crates/plugins/money/src/review_1574.rs:109:5:
retained reads serve stale balances or rows after global reconciliation: stale Account/cleared balances=true, offline posting absent from register=true


failures:
    routes::register_contract_tests::review_1574::unreadable_budget_must_not_leave_later_budget_stale
    routes::register_contract_tests::review_1574::unreadable_user_must_not_leave_fifth_user_stale

test result: FAILED. 186 passed; 2 failed; 3 ignored; 0 measured; 0 filtered out; finished in 1538.84s

error: test failed, to rerun pass `-p calternal-plugin-money --lib`

The combined gate stops at the intentional plugin library failures. Its later plugin integration tests and doctests do not run. For the merge round, after the product fix:

CARGO_BUILD_JOBS=4 cargo test -p calternal-money -p calternal-plugin-money --no-fail-fast -- --test-threads=4

This must pass both new stale-read tests and the deferred integration/doctest targets. The completed exploratory scenarios are in this job; they are not deferred.

Cleanup: Cargo output verbatim:

     Removed 5855 files, 2.4GiB total

Web build output is absent. Git status is clean. Only one test concern is committed, with the permission literals corrected to explicit octal in the amended head above. The new module and all touched doc comments were re-read. No pushes, deploys or issue close. Review completed within the 90-minute time box.

BLOCK

# BLOCK — independent Money review of b743887bd (#1574) Head: `4f3961e57666e1b536c7436ddb5a4742f71c23c2`, branch `job/rev1574`. Base: `9d6aa985f697cfc43080781426c9661ac0c0e1b6`. Target: `b743887bda5f62087cd11e823520c679233f2de8`. Author reports and result files were not read. ## Blockers 1. **B1: one unreadable Budget leaves a later Budget serving stale numbers.** Persist owner Budgets `aaa` in `Broken` and `home` in `Home`. Add a cleared synthetic expense to Home without a Files event. Inject unreadability with chmod 000 after Files has visited Broken (or after the completion marker is queued), then consume the global reconciled marker. Its per-User recheck invalidates Broken and returns its filesystem IO error before processing Home. Restore permissions. GET the Home month, its register, and its Accounts three times. These handlers stay available and return 200, but the register omits the new posting and Accounts retain old balances and cleared balances. A fresh full replay disagrees. Month reads do not repair those retained rows. Failing test: `routes::register_contract_tests::review_1574::unreadable_budget_must_not_leave_later_budget_stale`. 2. **B2: an unreadable User cancels the remaining global recheck.** Persist five Users (`a`, `b`, `c`, `d`, `z`) with the same Budget ID `home`. Change z's month offline, inject unreadability of a's Budget after its Files scan, and hold the normal Money write locks for b/c/d. Deliver the global marker. a's error reaches `result?` and drops the buffered refresh stream before z starts. Restore permissions and release locks. z's month, register and repeated Accounts reads return 200, but register and Account numbers stay stale. Failing test: `routes::register_contract_tests::review_1574::unreadable_user_must_not_leave_fifth_user_stale`. Files startup sends one global PluginEvent completion after a successful full scan, rather than per-file startup hints (`crates/plugins/files/src/index.rs`, lines 336–427). A failed Files scan sends no completion marker. These fault probes target the specified **during-recheck** IO failure: a folder becomes unreadable after Files has visited it or queued the marker. They do not claim that a permanently unreadable folder present before the Files scan is a new regression from this commit. Both tests use a real calternal-fs data directory, real SQLite projection tables and production handlers. Failure messages confirm stale Account/cleared balances and missing register postings. The first cause is the early return in `refresh_user_money_sources`; the second is `result?` in the global `buffer_unordered(4)` loop. The worker logs an error and continues, but warm reads do not stat sources or enqueue repair for retained metadata. No product fix was made, as required by this review brief. Reproduce both: ```sh export CARGO_PROFILE_DEV_DEBUG=line-tables-only CARGO_INCREMENTAL=0 CARGO_BUILD_JOBS=4 export TMPDIR="$PWD/target/tmp" cargo test -p calternal-plugin-money review_1574 -- --test-threads=2 ``` ## Checks completed - Nine offline mutation cases pass fresh full replay: ordinary same-inode edit; same size/inode with restored mtime (old non-ctime fingerprint equality verified); source replacement by rename; month deletion; month addition; Budget Assignment edit; Account kind edit; whole Budget folder replacement; whole Budget folder rename. - Compare exact register postings/running balances, every Account field (including cleared balance), and September–November reports (Category Available, Ready to Assign and month rollovers). Only process-local report revision is excluded from the oracle comparison. - Deleted and malformed Budget folders invalidate their own projections and do not stop sibling repair. - A new Budget without metadata and a User without any metadata build correctly. The production cold builder is tested, as well as handler results. - Five Users run Money creates while reconciliation is held on a User write lock. Every acknowledgement is represented by exactly one source posting. All final projections and month reports match full replay; no deadlock is found within the 15-second bound. - Same Budget IDs across two Users show no mixed numbers or postings. ## Non-blocking finding R1 An edit for one User can rebuild another User's unchanged Budget if source bytes share a Blob inode. Exact repro: create equal Money source files for owner/other; publish both projections; record other's month bytes, source fingerprint and register row IDs; replace only owner's month; deliver global reconciliation. Other's bytes and inode stay unchanged, but unlinking owner's hardlink changes the shared inode ctime. Other's receipt no longer matches, so its register is rebuilt and row IDs change. Both Users' numbers and postings still match a fresh full replay. This is redundant rebuild work, not a data-safety or authorization failure. It does not block under the owner rule. The exploratory test `same_ids_cross_user_keep_unchanged_projection` and the full six-probe source are retained in `artifacts/rev1574-probe-source.rs`. The matrix output is `artifacts/rev1574-final-matrix.log` (three passed probes, the two stale-number failures and this harmless rebuild failure). Only the two stale-number tests are committed. ## Built and files - `crates/plugins/money/src/review_1574.rs`: two failing regression tests and real-filesystem/Index/full-replay fixture helpers. - `crates/plugins/money/src/register_contract_tests.rs`: test-only module registration. - `artifacts/rev1574-findings.md`: findings appended during the review; not committed. - Product code, dependencies, existing expectations and lockfiles are unchanged. ## Known gaps The review uses the crate harness rather than a full deployed server process. Offline cases reopen the real data directory and persistent Index; invalidation uses the real reconciliation handler. The bounded parallel-write probe is not an exhaustive scheduler proof. Both stale-read defects remain open. No UI, performance benchmark, deployment or macOS work is part of this review. ## Decisions No product design decisions. Use a fresh MoneyIndex and full source replay as the oracle, separate from retained projection state. Classify R1 as non-blocking redundant work because all numbers remain correct. Commit only the two failing tests that expose stale numbers, as the brief requires. ## Gates Fetched origin and merged origin/dev once before final gates: `Already up to date.` Origin/dev was `0c712b98c`. Environment for all Cargo commands: `CARGO_PROFILE_DEV_DEBUG=line-tables-only`, `CARGO_INCREMENTAL=0`, `CARGO_BUILD_JOBS=4`, `TMPDIR=<worktree>/target/tmp`. The preset `CARGO_TARGET_DIR=/home/kayg/build/targets/rev1574` was kept unchanged. `cargo fmt --check`: exit 0, no output. `cargo clippy -p calternal-plugin-money --all-targets -- -D warnings`: exit 0. Output verbatim: ```text Checking calternal-plugin-money v0.0.1 (/home/kayg/Developer/calternal-wt/rev1574/crates/plugins/money) Finished `dev` profile [unoptimized + debuginfo] target(s) in 8.53s ``` `CARGO_BUILD_JOBS=4 cargo test -p calternal-money -p calternal-plugin-money -- --test-threads=4`: exit 101. All executed core Money tests passed (72 passed, one ignored). Plugin: 186 passed, two failed, three ignored. The two failures are exactly B1/B2. Full output verbatim: ```text Compiling calternal-money v0.0.1 (/home/kayg/Developer/calternal-wt/rev1574/crates/calternal-money) Compiling calternal-plugin-money v0.0.1 (/home/kayg/Developer/calternal-wt/rev1574/crates/plugins/money) Finished `test` profile [unoptimized + debuginfo] target(s) in 18.92s Running unittests src/lib.rs (/home/kayg/build/targets/rev1574/debug/deps/calternal_money-1e2a01de24e62d5b) running 16 tests test codec::tests::empty_payee_is_refused_by_the_writer ... ok test codec::tests::malformed_dated_rows_fail_instead_of_vanishing ... ok test codec::tests::property_edit_changes_one_value ... ok test codec::tests::round_trip_keeps_bom_crlf_and_unknown_bytes ... ok test codec::tests::transaction_round_trip_with_punctuation_in_labels_and_payee ... ok test edit::tests::cleared_tag_toggles_without_touching_other_tags ... ok test edit::tests::crlf_file_keeps_crlf_on_insert ... ok test edit::tests::unicode_payee_tag_boundaries_match_shared_vectors ... ok test codec::tests::checked_parse_stops_after_a_bounded_line_batch ... ok test units::tests::exact_range_is_enforced_on_parse_and_arithmetic ... ok test units::tests::format_uses_explicit_sign_and_exact_scale ... ok test units::tests::parse_matches_the_oracle_examples ... ok test units::tests::scale_table_has_all_165_codes_with_unique_entries ... ok test edit::tests::new_budget_projects_with_no_accounts ... ok test units::independent_number_review::signed_edges_and_long_zero_padding_keep_exact_minor_units ... ok test edit::tests::assign_inserts_updates_and_removes_rows ... ok test result: ok. 16 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.01s Running tests/account_kinds.rs (/home/kayg/build/targets/rev1574/debug/deps/account_kinds-9b132658dec70242) running 5 tests test account_projection_rejects_legacy_and_unknown_kinds ... ok test imported_account_kinds_project_without_losing_identity ... ok test off_budget_balance_marker_does_not_change_budget_money ... ok test tracking_deficit_rollover_does_not_reduce_ready_to_assign ... ok test categorized_debit_loan_transfers_post_one_budget_leg ... ok test result: ok. 5 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.01s Running tests/import.rs (/home/kayg/build/targets/rev1574/debug/deps/import-cc734ecd3c4f274b) running 13 tests test duplicate_source_ids_are_rejected_and_duplicate_names_are_kept ... ok test import_keeps_same_day_source_order_for_credit_payments_and_refunds ... ok test import_render_is_exact_and_byte_stable ... ok test import_render_reports_progress_and_propagates_cancel ... ok test import_stream_renderer_matches_full_rendered_files ... ok test production_v1_metadata_upgrade_keeps_balances ... ok test import_replay_matches_full_ledger_month_by_month ... ok test recheck_half_minor_units_negative_zero_and_nineteen_digits ... ok test budget_replay_stops_at_a_bounded_transaction_checkpoint ... ok test imported_ready_to_assign_matches_independent_month_oracle ... ok test recheck_same_day_payment_and_refund_keep_source_fifo ... ok test random_imports_conserve_source_balances_and_markdown ... ok test recheck_random_multicurrency_ledgers_match_all_monthly_totals ... ok test result: ok. 13 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 5.85s Running tests/properties.rs (/home/kayg/build/targets/rev1574/debug/deps/properties-50f0dfcda0fc447c) running 21 tests test bill_coverage_never_clamps_the_bill ... ok test bulkrev2::boundary_shuffle_reports_acceptance_difference ... ok test bulkrev2::i64_extremes_are_rejected_and_safe_bound_is_exact ... ok test bulkrev2::literal_account_sum_and_funded_card_conservation ... ok test bulkrev2::refund_payment_calendar_choice_is_visible_next_month ... ok test any_text_that_parses_serializes_to_the_same_bytes ... ok test bulkrev2::split_refund_keeps_payment_overfunding_when_card_becomes_positive ... ok test assign_then_unassign_is_the_identity ... ok test decimal_text_round_trips_for_every_scale ... ok test cash_ledgers_conserve_money_every_month ... ok test fully_funded_card_spending_conserves_cash ... ok test money_code_never_uses_floating_point ... ok test mixed_cash_credit_deficit_rolls_only_its_cash_part ... ok test paired_write_replay_matches_independent_calculations ... ok test reviewed_burst_order_matches_input_order ... ok test partial_payment_then_category_refunds_conserve_cash_across_months ... ok test split_legs_post_exactly_the_parent ... ok test transaction_rows_round_trip_byte_for_byte ... ok test same_date_card_postings_are_a_function_of_the_set ... ok test bulkrev2::funded_shuffles_conserve_real_money_every_month ... ok test bulkrev2::same_day_shuffles_cover_splits_transfers_and_month_edges ... ok test result: ok. 21 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 3.53s Running tests/ready_to_assign_adjustment.rs (/home/kayg/build/targets/rev1574/debug/deps/ready_to_assign_adjustment-71f95d93ae1d6a03) running 1 test test ready_to_assign_adjustment_changes_only_the_budget_pool ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.01s Running tests/review_984.rs (/home/kayg/build/targets/rev1574/debug/deps/review_984-e1bb010954dc02d8) running 5 tests test review_pair_performance_profile ... ignored, performance measurements belong to the merge round on the perf VM test review_pair_rejects_bad_months_and_amounts_without_rounding ... ok test review_split_remainders_and_tracking_transfers_are_exact ... ok test review_mixed_pair_matches_independent_replays ... ok test review_large_ledger_pair_keeps_exact_totals ... ok test result: ok. 4 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 2.08s Running tests/review_bulkrev3.rs (/home/kayg/build/targets/rev1574/debug/deps/review_bulkrev3-1a27d60055bb808c) running 7 tests test hidden_and_missing_categories ... ok test legacy_payment_repair_is_idempotent_and_collision_safe ... ok test card_opening_credit_enters_ready_to_assign_once ... ok test unlinked_card_funded_purchase_keeps_its_payment_money ... ok test envelope_edge_cases ... ok test previous_witnesses_all_orders ... ok test random_histories_conserve_money_after_every_rollover ... ok test result: ok. 7 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 4.98s Running tests/vectors.rs (/home/kayg/build/targets/rev1574/debug/deps/vectors-04392997c28c2e72) running 5 tests test rust_matches_random_oracle_ledgers_without_divergences ... ok test reviewed_r4_unlinked_card_vector_keeps_its_unfunded_amount ... ok test reviewed_r3_vectors_assert_retired_debt_and_positive_credit ... ok test reviewed_eleven_refund_vectors_keep_their_exact_numbers ... ok test rust_port_matches_every_recorded_oracle_vector ... ok test result: ok. 5 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.28s Running unittests src/lib.rs (/home/kayg/build/targets/rev1574/debug/deps/calternal_plugin_money-369d9e0370502d5a) running 191 tests test import::import_review_tests::actual_cents_conversion_never_rounds ... ok test import::import_review_tests::actual_cc_label_requires_missing_type_confirmation ... ok test import::import_review_tests::actual_orphan_split_children_are_rejected ... ok test import::import_review_tests::actual_stream_memory_guard_child ... ignored, invoked as an isolated child by actual_stream_keeps_a_large_history_bounded test import::import_review_tests::actual_transfer_legs_cannot_cross_months ... ok test import::import_review_tests::import_control_reports_progress_and_stops_cancelled_work ... ok test import::import_review_tests::actual_account_checks_use_raw_monthly_source_rows ... ok running 1 test test import::import_review_tests::ynab_transfer_pairing_handles_many_duplicate_legs ... ok test import_fidelity_1130::independent_split_and_transfer_numbers_check ... ok test register::tests::busy_completion_fence_is_retryable_and_keeps_intent ... ok test register::tests::cursor_scope_and_signature_are_required ... ok test import_fidelity_1130::actual_rows_round_trip ... ok test import::import_review_tests::actual_stream_memory_guard_child ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 190 filtered out; finished in 27.25s test import::import_review_tests::actual_stream_keeps_a_large_history_bounded ... ok test register::tests::suffix_batches_never_promote_integer_balances_to_real ... ok test register_recovery_tests::marker_wait_does_not_accept_an_empty_port_file ... ok test register_recovery_tests::recovery_invalidates_broken_sources_without_changing_files ... ok test register_recovery_tests::register_kill_child ... ignored, child of register_recovery_survives_sigkill_at_every_durability_point test register::tests::pages_equal_raw_bigint_postings ... ok test register_recovery_tests::review688_directory_source_does_not_stop_startup ... ok test routes::durable::admission_tests::cancelled_receiver_cannot_acknowledge_a_durable_job ... ok test projection::tests::scoped_histories_equal_full_replay has been running for over 60 seconds test register::tests::incremental_sequences_equal_scratch_bigint has been running for over 60 seconds test routes::durable::admission_tests::live_publication_honors_operational_queue_cancellation ... ok test routes::durable::checkpoint_tests::progress_wait_keeps_parser_writer_release_polled ... ok test routes::durable::money_import_undo_mutation ... ok test routes::import_cleanup_tests::dropped_preview_worker_retains_admission_until_exit ... ok test routes::import_cleanup_tests::idle_imports_are_reclaimed_by_expiry_cleanup ... ok test routes::import_cleanup_tests::staged_import_files_keep_ranges_and_release_private_storage ... ok test routes::import_staged_path_tests::staged_import_name_cannot_select_another_path_or_slot ... ok test routes::register_contract_tests::cached_register_reads_without_source_or_projection_writes ... ok test routes::register_contract_tests::cleared_publication_fault_does_not_replay_queued_500 ... ok test routes::register_contract_tests::cold_register_admission_rejects_foreign_and_missing_budgets ... ok test routes::register_contract_tests::directory_source_refuses_reads_without_server_failure ... ok test register_recovery_tests::register_recovery_survives_sigkill_at_every_durability_point ... ok test routes::register_contract_tests::file_scoped_edit_delete_and_cleared_keep_colliding_rows_distinct ... ok test routes::register_contract_tests::money_transactions_pagination ... ok test routes::register_contract_tests::money_transactions_preflight ... ok test routes::register_contract_tests::money_admission_rejects_unowned_budgets_without_queued_work ... ok test routes::register_contract_tests::money_transactions_projection ... ok test routes::register_contract_tests::money_transactions_response_bounds ... ok test routes::register_contract_tests::money_transactions_revision ... ok test routes::register_contract_tests::queued_register_build_publishes_one_durable_generation ... ok test routes::register_contract_tests::register_build_queue_is_bounded_and_coalesces_duplicates ... ok test routes::register_contract_tests::register_files_events_stay_in_their_test_instance ... ok test routes::register_contract_tests::register_filter_indexes_keep_split_membership_on_scoped_updates ... ok test routes::register_contract_tests::register_imported_tag_heavy_writes ... ok test routes::register_contract_tests::register_pages_stop_by_bytes_without_losing_rows ... ok test routes::register_contract_tests::register_projection_survives_restart_and_tracks_source_revisions ... ok test routes::register_contract_tests::register_mark_writes_touch_constant_rows_with_card_history ... ok test routes::register_contract_tests::register_publication_reserves_writer_before_snapshot ... ok test routes::register_contract_tests::register_repeated_tag_heavy_writes ... ok test routes::register_contract_tests::register_tag_maximum_and_byte_paging ... ok test routes::register_contract_tests::retained_mark_response_keeps_destination_date ... ok test routes::register_contract_tests::review1570_same_inode_same_mtime_hint_must_refresh_numbers ... ok test routes::register_contract_tests::register_writes_publish_before_reads ... ok test routes::register_contract_tests::review688_category_filter_keeps_file_local_identity ... ok test routes::register_contract_tests::review688_cleared_round_trip_restores_source_bytes ... ok test routes::register_contract_tests::review688_file_change_invalidates_retained_numbers ... ok test routes::register_contract_tests::review688_transfer_leg_prefix_uses_its_own_date ... ok test routes::register_contract_tests::review688k_colliding_legs_page_and_update_independently ... ok test routes::register_contract_tests::review688k_file_identity_upgrade_preserves_recovery ... ok test routes::register_contract_tests::review688k_partial_marks_preserve_other_file_identities ... ok test routes::register_contract_tests::review688rev2_failed_publication_cannot_serve_stale_numbers ... ok test routes::register_contract_tests::review688rev2_visible_leg_collision_cannot_stop_startup ... ok test routes::register_contract_tests::review_1574::unreadable_budget_must_not_leave_later_budget_stale ... FAILED test routes::register_contract_tests::review688rev3_ambiguous_edit_cannot_move_another_source_row ... ok test routes::register_contract_tests::stale_cold_builder_does_not_replace_a_newer_generation ... ok test routes::register_contract_tests::review_1574::unreadable_user_must_not_leave_fifth_user_stale ... FAILED test routes::register_contract_tests::stale_mark_generation_repairs_before_retry ... ok test routes::replay_reuse_tests::assignment_retry_rebuilds_from_latest_source_bytes ... ok test routes::replay_reuse_tests::crossings_reuse_checked_current_totals_even_with_future_months ... ok test routes::replay_reuse_tests::crossings_cover_source_ranges_relative_to_today ... ok test routes::review_1140::cancel_wins_before_publication_lock ... ok test routes::review_1140::cancel_does_not_rewrite_published_result ... ok test routes::review_1140::review1140_cancel_after_rename_before_receipt_keeps_publication ... ok test routes::review_1140::review1140_all_formats_replay_exact_balances ... ok test routes::review_1140::review1140_operational_cancel_before_replacement_returns_no_receipt ... ok test routes::review_1140::review1140_discard_after_confirmation_failure_releases_admission ... ok test routes::review_1140::review1140_staged_size_limits_fail_without_publishing ... ok test register::tests::incremental_sequences_equal_scratch_bigint ... ok test routes::review_1140::review1140_terminal_receipts_do_not_block_new_imports ... ok test store::parsed_cache_tests::global_budget_and_folder_pruning_release_stale_entries ... ok test routes::review_1140::review1140_tcp_malformed_inputs_leave_worker_usable ... ok test store::parsed_cache_tests::parse_charge_accounts_for_line_structures ... ok test store::parsed_cache_tests::source_receipt_versions_and_checks_both_ctime_parts ... ok test store::parsed_cache_tests::user_cache_evicts_old_parse_entries_and_shares_hot_documents ... ok test store::parsed_cache_tests::oversized_snapshots_share_only_while_active ... ok test tests::a_broken_file_is_reported_not_hidden ... ok test tests::a_new_user_sees_the_real_empty_state ... ok test tests::a_journal_for_a_completed_move_changes_nothing ... ok test routes::review_1140::review1140_replacement_receipt_recovery_does_not_adopt_later_edits ... ok test tests::active_money_handle_survives_other_users_cache_pressure ... ok test tests::actual_duplicate_names_import_by_id_without_sharing_a_payment_category ... ok test tests::actual_export_archive_imports_exact_rows_from_private_scratch ... ok test tests::a_read_waits_for_a_write_in_progress ... ok test tests::a_split_row_written_by_hand_is_read_but_not_edited ... ok test tests::api_account_numbers_equal_core_replay ... ok test tests::assignments_retry_source_conflicts_without_losing_neighbours ... ok test tests::backdated_create_emits_current_month_overspend_crossing ... ok test tests::budget_flow_writes_exact_markdown_and_derives_available ... ok test tests::bulk_write_invalid_neighbours_do_not_change_valid_rows ... ok test tests::bulk_write_month_does_not_need_note_date_backfill ... ok test tests::cancel_racing_confirm_has_one_consistent_outcome ... ok test tests::cancelling_imports_leaves_no_budget_and_releases_slots ... ok test tests::bulk_write_rejects_intermediate_overflow ... ok test tests::card_opening_credit_route_conserves_real_budget_money ... ok test tests::concurrent_store_edits_keep_exactly_one_winner ... ok test tests::csv_import_keeps_progress_and_cancel_responsive ... ok test tests::delete_transaction_emits_current_month_overspend_crossing ... ok test tests::denied_preview_access_keeps_the_owners_pending_import ... ok test tests::durable_import_tests::foreign_import_cancellation_matches_missing_without_changing_owner_state ... ok test tests::durable_import_tests::generated_import_confirm_replay_and_undo_preserve_minor_units ... ok test tests::durable_import_tests::operation_exit_child ... ignored, child of operation_recovery_survives_process_exit_at_every_phase test tests::bulk_write_balances_equal_one_by_one has been running for over 60 seconds test tests::card_models_ignore_arrival_batch_and_timezone has been running for over 60 seconds test tests::durable_import_tests::operation_recovery_survives_process_exit_at_every_phase ... ok test tests::durable_import_tests::publication_and_inverse_authority_use_full_commits ... ok test tests::durable_import_tests::queued_import_and_undo_survive_restarts ... ok test tests::durable_import_tests::receipt_reads_are_bounded_and_old_receipts_are_addressable ... ok test tests::durable_import_tests::replacement_restarts_at_every_durable_phase ... ok test tests::durable_import_tests::replay_preserves_a_live_ready_preview ... ok test tests::durable_import_tests::running_jobs_do_not_expire_and_cancelled_jobs_do_not_restart ... ok test tests::durable_import_tests::undo_receipt_replay_never_removes_a_restored_import ... ok test tests::durable_import_tests::undo_refuses_a_predecessor_restored_before_the_inverse ... ok test tests::durable_import_tests::undo_refuses_every_later_budget_edit_after_restart ... ok test tests::durable_import_tests::undo_restarts_before_and_after_the_filesystem_inverse ... ok test tests::failed_cross_month_move_never_counts_the_row_twice ... ok test tests::far_month_assignment_cannot_make_the_budget_unreadable ... ok test tests::bulk_write_balances_equal_one_by_one ... ok test tests::gap_month_assignments_and_opening_card_debt_do_not_create_cash ... ok test tests::historical_overspend_does_not_emit_current_month_event ... ok test tests::hostile_inputs_are_rejected_without_writing ... ok test tests::import_fidelity_review_requires_account_kind_and_keeps_notes ... ok test tests::import_file_limits_match_the_money_reader ... ok test tests::import_preview_is_owner_bound_and_confirmation_publishes_once ... ok test tests::import_preview_reads_only_generated_staged_upload_names ... ok test tests::inferred_opening_balance_needs_explicit_confirmation ... ok test tests::legacy_card_payment_repair_cannot_make_its_budget_unreadable ... ok test tests::legacy_card_payment_repair_is_editable_and_saved_category_first ... ok test tests::memo_and_tags_split_the_payee_without_losing_text ... ok test tests::money_is_on_for_the_instance_and_off_for_a_new_user ... ok test tests::idle_import_receive_releases_admission_and_cancel_stops_read ... ok test tests::month_revision_increases_after_each_assignment ... ok test tests::move_money_keeps_ready_to_assign_and_card_gets_payment_category ... ok test tests::multiple_assignment_rows_set_one_exact_total ... ok test tests::other_users_and_sessions_without_data_scope_see_nothing ... ok test tests::overflowing_category_sum_is_rejected_before_assignment_write ... ok test tests::overflowing_cleared_subset_is_rejected_before_transaction_write ... ok test tests::overflowing_derived_balance_is_rejected_before_the_write ... ok test tests::overspending_reports_ynab_states ... ok test tests::plugin_code_never_uses_floating_point ... ok test tests::parsed_money_cache_shares_documents_and_prunes_removed_months ... ok test tests::recheck_metadata_files_use_the_reader_size_cap ... ok test tests::recheck_local_server_number_and_lifecycle_contract ... ok test tests::recheck_source_checks_owner_and_opening_balance_confirmation ... ok test tests::review_1130::review1130_cancel_after_partial_preparation ... ok test tests::recheck_random_preview_cancellation_leaves_no_files ... ok test tests::review_1130::review1130_legacy_home_needs_no_metadata_rewrite ... ok test tests::review_1130::review1130_notes_are_inert ... ok test tests::review_1130::review1130_long_imported_note_allows_amount_edit_without_loss ... ok test tests::review_1130::review1130_reconciled_closed_balances ... ok test tests::review_1130::review1130_split_and_closed_transfer_have_one_posting ... ok test tests::review_1130::review1130_tcp_locks_reimport_and_cancel ... ok test tests::review_984::review3_first_future_transaction_keeps_current_event_month ... ok test tests::review_984::review3_future_only_edit_and_delete_keep_current_event_month ... ok test tests::review_984::review3_outside_current_range_writes_emit_no_overspend ... ok test tests::review_984::review_category_edit_emits_for_old_category_only ... ok test tests::review_984::review_concurrent_assign_revisions_match_final_report ... ok test tests::review_984::review_cross_month_refund_move_emits_current_crossing ... ok test tests::review_984::review_file_replacement_advances_month_revision ... ok test tests::review_984::review_exact_zero_healing_recrossing_and_delete ... ok test tests::review_984::review_split_and_tracking_transfer_writes_are_rejected_without_events ... ok test tests::review_984::review_user_zone_month_and_year_edges ... ok test tests::review_984::review_source_generation_tracks_all_files_and_restoration ... ok test tests::review_bulkrev2::four_conflicts_return_409_without_writing ... ok test tests::same_handle_settles_a_failed_move_before_the_next_request ... ok test tests::simultaneous_import_confirmations_have_one_winner ... ok test tests::review_bulkrev2::two_and_five_assignment_races_match_serial_targets ... ok test tests::source_total_mismatch_cannot_be_confirmed ... ok test tests::slow_15mb_import_receive_completes_with_progress ... ok test tests::transaction_identity_preview_is_atomic_and_reimport_changes_nothing ... ok test tests::transaction_logged_event_has_the_documented_create_payload ... ok test tests::transfer_register_view_exposes_linked_category ... ok test tests::transfer_cleared_edits_are_per_account ... ok test tests::wizard_background_job_recovers_preview_after_response_is_dropped ... ok test tests::wizard_background_job_retains_safe_failure ... ok test tests::wizard_starter_categories_validate_before_create_and_do_not_change_totals ... ok test tests::ynab_conflicting_accounts_and_payees_are_not_silently_discarded ... ok test tests::ynab_csv_import_keeps_exact_month_and_register_amounts ... ok test tests::ynab_duplicate_category_ids_are_merged_only_when_identical ... ok test tests::ynab_plan_json_import_keeps_exact_milliunits ... ok test tests::ynab_public_demo_imports_duplicate_category_names_by_id ... ok test tests::update_transaction_emits_current_month_overspend_crossing ... ok test tests::card_models_ignore_arrival_batch_and_timezone ... ok test projection::tests::scoped_histories_equal_full_replay ... ok failures: ---- routes::register_contract_tests::review_1574::unreadable_budget_must_not_leave_later_budget_stale stdout ---- thread 'routes::register_contract_tests::review_1574::unreadable_budget_must_not_leave_later_budget_stale' (3709072) panicked at crates/plugins/money/src/review_1574.rs:109:5: retained reads serve stale balances or rows after global reconciliation: stale Account/cleared balances=true, offline posting absent from register=true note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace ---- routes::register_contract_tests::review_1574::unreadable_user_must_not_leave_fifth_user_stale stdout ---- thread 'routes::register_contract_tests::review_1574::unreadable_user_must_not_leave_fifth_user_stale' (3709488) panicked at crates/plugins/money/src/review_1574.rs:109:5: retained reads serve stale balances or rows after global reconciliation: stale Account/cleared balances=true, offline posting absent from register=true failures: routes::register_contract_tests::review_1574::unreadable_budget_must_not_leave_later_budget_stale routes::register_contract_tests::review_1574::unreadable_user_must_not_leave_fifth_user_stale test result: FAILED. 186 passed; 2 failed; 3 ignored; 0 measured; 0 filtered out; finished in 1538.84s error: test failed, to rerun pass `-p calternal-plugin-money --lib` ``` The combined gate stops at the intentional plugin library failures. Its later plugin integration tests and doctests do not run. For the merge round, after the product fix: ```sh CARGO_BUILD_JOBS=4 cargo test -p calternal-money -p calternal-plugin-money --no-fail-fast -- --test-threads=4 ``` This must pass both new stale-read tests and the deferred integration/doctest targets. The completed exploratory scenarios are in this job; they are not deferred. Cleanup: Cargo output verbatim: ```text Removed 5855 files, 2.4GiB total ``` Web build output is absent. Git status is clean. Only one test concern is committed, with the permission literals corrected to explicit octal in the amended head above. The new module and all touched doc comments were re-read. No pushes, deploys or issue close. Review completed within the 90-minute time box. BLOCK
Author
Owner

Started #1574 on branch job/rev1574 at 4f3961e57666e1b536c7436ddb5a4742f71c23c2; base origin/dev merge-base is 0c712b98c164b6734d54f63485012bd1a11005b4. I have read CLAUDE.md, CONTEXT.md and DESIGN §48. I am tracing the global and scoped Files recheck paths before changing the retained-state handling.

Started #1574 on branch `job/rev1574` at `4f3961e57666e1b536c7436ddb5a4742f71c23c2`; base `origin/dev` merge-base is `0c712b98c164b6734d54f63485012bd1a11005b4`. I have read CLAUDE.md, CONTEXT.md and DESIGN §48. I am tracing the global and scoped Files recheck paths before changing the retained-state handling.
Author
Owner

Finding: both review probes map to early exits in routes.rs. refresh_user_money_sources used ? for invalidate_folder and returned on an IO error from money.load, which skipped later receipt rows after invalidating the failed Budget. The global Files reconciliation loop used result? on buffer_unordered(4), which stopped draining after the first failed User. The scoped event path shares the same receipt helper, so the receipt-loop fix covers it too. I changed these paths to log failures without source text or paths, finish remaining receipts/Users, and preserve the existing four-User concurrency bound.

Finding: both review probes map to early exits in `routes.rs`. `refresh_user_money_sources` used `?` for `invalidate_folder` and returned on an IO error from `money.load`, which skipped later receipt rows after invalidating the failed Budget. The global Files reconciliation loop used `result?` on `buffer_unordered(4)`, which stopped draining after the first failed User. The scoped event path shares the same receipt helper, so the receipt-loop fix covers it too. I changed these paths to log failures without source text or paths, finish remaining receipts/Users, and preserve the existing four-User concurrency bound.
Author
Owner

Completed #1574 on job/rev1574.

Built and committed c0f8da461efc752a08740209235619eadccf000a (fix(money): continue Files rechecks after failures). Changed crates/plugins/money/src/routes.rs only. The per-User refresh now invalidates a changed Budget before fallible reads/builds, logs a failed Budget with only User and folder identifiers, continues checking later receipts, and returns its first failure after the scope is complete. The global Files scan logs failed Users and drains its existing buffer_unordered(4) stream before returning. The scoped folder path uses the same receipt helper. Both unchanged #1574 regressions passed.

Decisions: DESIGN §48 requires Money projections to remain derived from source but does not define refresh error aggregation. A global reconciliation is a broadcast with no request to receive a partial error, so it logs failures and returns Ok after all Users finish. A scoped event keeps the existing Handler error behavior and returns the first failure only after all selected receipts finish. Work remains bounded by the existing one-stat-per-source check and four concurrent Users.

Origin check: git merge origin/dev returned Already up to date. The requested gates ran immediately before that no-op merge; no source changed in the merge. Known gaps: none found. No UI or performance behavior changed on the successful recheck path.

Gate output (verbatim result lines):

$ cargo fmt --check
(exit 0; stdout and stderr empty)

$ CARGO_BUILD_JOBS=4 cargo clippy -p calternal-plugin-money --all-targets -- -D warnings
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 1m 26s

$ CARGO_BUILD_JOBS=4 cargo test -p calternal-money -p calternal-plugin-money
    Finished `test` profile [unoptimized + debuginfo] target(s) in 1m 43s
test result: ok. 16 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.01s
test result: ok. 5 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 6.86s
test result: ok. 21 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 4.39s
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 2.37s
test result: ok. 7 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 6.73s
test result: ok. 5 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.42s
test result: ok. 188 passed; 0 failed; 3 ignored; 0 measured; 0 filtered out; finished in 1599.28s
test result: ok. 29 passed; 0 failed; 3 ignored; 0 measured; 0 filtered out; finished in 6.87s
test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 1.78s
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

$ cargo clean
     Removed 5855 files, 2.4GiB total
Completed #1574 on `job/rev1574`. Built and committed `c0f8da461efc752a08740209235619eadccf000a` (`fix(money): continue Files rechecks after failures`). Changed `crates/plugins/money/src/routes.rs` only. The per-User refresh now invalidates a changed Budget before fallible reads/builds, logs a failed Budget with only User and folder identifiers, continues checking later receipts, and returns its first failure after the scope is complete. The global Files scan logs failed Users and drains its existing `buffer_unordered(4)` stream before returning. The scoped folder path uses the same receipt helper. Both unchanged #1574 regressions passed. Decisions: DESIGN §48 requires Money projections to remain derived from source but does not define refresh error aggregation. A global reconciliation is a broadcast with no request to receive a partial error, so it logs failures and returns `Ok` after all Users finish. A scoped event keeps the existing `Handler` error behavior and returns the first failure only after all selected receipts finish. Work remains bounded by the existing one-stat-per-source check and four concurrent Users. Origin check: `git merge origin/dev` returned `Already up to date.` The requested gates ran immediately before that no-op merge; no source changed in the merge. Known gaps: none found. No UI or performance behavior changed on the successful recheck path. Gate output (verbatim result lines): ```text $ cargo fmt --check (exit 0; stdout and stderr empty) $ CARGO_BUILD_JOBS=4 cargo clippy -p calternal-plugin-money --all-targets -- -D warnings Finished `dev` profile [unoptimized + debuginfo] target(s) in 1m 26s $ CARGO_BUILD_JOBS=4 cargo test -p calternal-money -p calternal-plugin-money Finished `test` profile [unoptimized + debuginfo] target(s) in 1m 43s test result: ok. 16 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.01s test result: ok. 5 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 6.86s test result: ok. 21 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 4.39s 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 2.37s test result: ok. 7 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 6.73s test result: ok. 5 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.42s test result: ok. 188 passed; 0 failed; 3 ignored; 0 measured; 0 filtered out; finished in 1599.28s test result: ok. 29 passed; 0 failed; 3 ignored; 0 measured; 0 filtered out; finished in 6.87s test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 1.78s test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s $ cargo clean Removed 5855 files, 2.4GiB total ```
Author
Owner

Deployed to calternal.cloud in merge round 40 (build c0f8da461, 01:38 IST 2026-10-12). Health state ok, /readyz 200, served-page check passed. Pre-deploy backup taken.

Deployed to calternal.cloud in merge round 40 (build c0f8da461, 01:38 IST 2026-10-12). Health state ok, /readyz 200, served-page check passed. Pre-deploy backup taken.
kayg closed this issue 2026-10-11 20:08:48 +00:00
Commenting is not possible because the repository is archived.
No labels
No milestone
No project
No assignees
1 participant
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-v0#1574
No description provided.