Journal: sync retry after 503 duplicates paragraphs #1295

Closed
opened 2026-10-07 01:24:18 +00:00 by kayg · 81 comments
Owner

Tracks the Daily note sync collision found in #1202 at round 31 head 139d4378e. Source paragraphs appeared twice after conditional sync upload races and Index-busy responses. Investigate publication ordering and safe retry semantics with a deterministic regression. Work branch job/journaldup; base 3601719b80.

Tracks the Daily note sync collision found in #1202 at round 31 head 139d4378e. Source paragraphs appeared twice after conditional sync upload races and Index-busy responses. Investigate publication ordering and safe retry semantics with a deterministic regression. Work branch job/journaldup; base 3601719b80a39f712daf07b37879b22929dfffa0.
Author
Owner

Confirmed ff53d7b8b contains the same complete_install -> ensure_recorded_install_matches late-412 path as round 31. This is an existing production bug, not introduced by round 31. Files holds the namespace lock but not the shared Notes writer during installation; a Log edit can land after upload rename and before validation. Added deterministic route regressions for that window and real SQLite BUSY after rename; compiling them before the repair. Existing tus upload IDs already provide durable retry identities. The CLI preserves the ID, but does not finalize a received-full upload on resume; checking this recovery gap too.

Confirmed ff53d7b8b contains the same complete_install -> ensure_recorded_install_matches late-412 path as round 31. This is an existing production bug, not introduced by round 31. Files holds the namespace lock but not the shared Notes writer during installation; a Log edit can land after upload rename and before validation. Added deterministic route regressions for that window and real SQLite BUSY after rename; compiling them before the repair. Existing tus upload IDs already provide durable retry identities. The CLI preserves the ID, but does not finalize a received-full upload on resume; checking this recovery gap too.
Author
Owner

Committed browser recovery slice 97d363927: plain Files uploads now resume finalization with the same tus URL after 503. Focused Vitest: Tests 16 passed (16), including the new assertion that retry PATCH sends zero bytes. Svelte diagnostics: svelte-check found 0 errors and 1 warning in 1 file. Whole web check currently reports the changed upload-handler performance pin; that pin will be refreshed with the backend repair without weakening its rule or limit. origin/dev fetched and merged once (Already up to date). Rust regressions still compiling the fresh per-job target.

Committed browser recovery slice 97d363927: plain Files uploads now resume finalization with the same tus URL after 503. Focused Vitest: Tests 16 passed (16), including the new assertion that retry PATCH sends zero bytes. Svelte diagnostics: svelte-check found 0 errors and 1 warning in 1 file. Whole web check currently reports the changed upload-handler performance pin; that pin will be refreshed with the backend repair without weakening its rule or limit. origin/dev fetched and merged once (Already up to date). Rust regressions still compiling the fresh per-job target.
Author
Owner

Deterministic original-code regression now reproduces the late 412: journal_upload_excludes_notes_writer_until_publication fails with left: 412, right: 204 after the paragraph landed. The other three regressions pass: stale preconditions never install; busy admission leaves source untouched; real SQLite BUSY after rename retains the tus ID and publication-only retry preserves the inode. Thus 503 can follow a source write, but the demonstrated duplicate cause is the late 412 followed by read-and-append retry. Repair adds the existing namespace -> Notes guard and captures the response item ID before retry-key cleanup, removing a possible late Index refresh failure.

Deterministic original-code regression now reproduces the late 412: journal_upload_excludes_notes_writer_until_publication fails with left: 412, right: 204 after the paragraph landed. The other three regressions pass: stale preconditions never install; busy admission leaves source untouched; real SQLite BUSY after rename retains the tus ID and publication-only retry preserves the inode. Thus 503 can follow a source write, but the demonstrated duplicate cause is the late 412 followed by read-and-append retry. Repair adds the existing namespace -> Notes guard and captures the response item ID before retry-key cleanup, removing a possible late Index refresh failure.
Author
Owner

The repaired route passes all four deterministic regressions: test result: ok. 4 passed; 0 failed; 0 ignored; 0 measured; 264 filtered out; finished in 6.32s. Note formats use the existing Notes path validator and writer guard; binary uploads do not hold that guard. Empty final PATCH now returns tus version and offset as well as the stable item ID. Refreshed exactly one existing performance syntax pin; added 0 exceptions and raised 0 limits. Serial per-crate Rust gates and complete web check/test are running.

The repaired route passes all four deterministic regressions: test result: ok. 4 passed; 0 failed; 0 ignored; 0 measured; 264 filtered out; finished in 6.32s. Note formats use the existing Notes path validator and writer guard; binary uploads do not hold that guard. Empty final PATCH now returns tus version and offset as well as the stable item ID. Refreshed exactly one existing performance syntax pin; added 0 exceptions and raised 0 limits. Serial per-crate Rust gates and complete web check/test are running.
Author
Owner

Saved backend repair as atomic commit 30720c462 after four focused regressions passed and cargo fmt --check passed. Browser slice is 97d363927. Final per-crate clippy/test is still running serially; bun run check now exits 0 with svelte-check found 0 errors and 1 warning in 1 file, and full bun run test is running with --maxWorkers=2. No claim of final gate completion yet.

Saved backend repair as atomic commit 30720c462 after four focused regressions passed and cargo fmt --check passed. Browser slice is 97d363927. Final per-crate clippy/test is still running serially; bun run check now exits 0 with svelte-check found 0 errors and 1 warning in 1 file, and full bun run test is running with --maxWorkers=2. No claim of final gate completion yet.
Author
Owner

Recovery inspection found a second gap: resume_installed_intent rejects a changed installed hash with 500, even when a legitimate Notes edit followed the applied upload and its 503. Added a regression for 503 -> later Log edit -> same-ID empty PATCH, which must preserve both edits and the later inode. A failure-only server witness now seals the applied path/hash in private staging under the writer guard; normal successful uploads add no witness fsync. Recovery can publish the current Note without replaying the older bytes. Retry staging remains until the durable row retires; garbage cleanup cannot turn an acknowledged mutation into a keyless 5xx. Notes clippy passed; crate tests continue.

Recovery inspection found a second gap: resume_installed_intent rejects a changed installed hash with 500, even when a legitimate Notes edit followed the applied upload and its 503. Added a regression for 503 -> later Log edit -> same-ID empty PATCH, which must preserve both edits and the later inode. A failure-only server witness now seals the applied path/hash in private staging under the writer guard; normal successful uploads add no witness fsync. Recovery can publish the current Note without replaying the older bytes. Retry staging remains until the durable row retires; garbage cleanup cannot turn an acknowledged mutation into a keyless 5xx. Notes clippy passed; crate tests continue.
Author
Owner

Resuming journaldup2 on job/journaldup at 30720c462 (base 3601719b8). Read all six previous comments and reviewed the six unfinished files. Completing the failure-only publication witness and same-ID sync recovery, then running deterministic regressions, per-crate gates and one local release-server Journal sync reliability check. No push or deployment.

Resuming journaldup2 on job/journaldup at 30720c462 (base 3601719b8). Read all six previous comments and reviewed the six unfinished files. Completing the failure-only publication witness and same-ID sync recovery, then running deterministic regressions, per-crate gates and one local release-server Journal sync reliability check. No push or deployment.
Author
Owner

Recovery review: ff53d7b8b also rejects an installed intent when actual_hash differs from install_hash, so the 503 -> later Note edit -> same-ID retry gap exists in production too. The new regression takes a real BEGIN IMMEDIATE on the authority connection at the existing post-rename hook; it verifies applied source bytes and a retained upload row before the later Log edit, then checks retry and startup recovery preserve the later inode. Healthy uploads add no witness fsync. A failed Note publication writes one bounded private staging witness. Sync now checks a live tus ID even if destination bytes already match; a full received offset still requires publication.

Recovery review: ff53d7b8b also rejects an installed intent when actual_hash differs from install_hash, so the 503 -> later Note edit -> same-ID retry gap exists in production too. The new regression takes a real BEGIN IMMEDIATE on the authority connection at the existing post-rename hook; it verifies applied source bytes and a retained upload row before the later Log edit, then checks retry and startup recovery preserve the later inode. Healthy uploads add no witness fsync. A failed Note publication writes one bounded private staging witness. Sync now checks a live tus ID even if destination bytes already match; a full received offset still requires publication.
Author
Owner

Web suite passed (bun run test --maxWorkers=2): Test Files 287 passed (287); Tests 2036 passed (2036). Saved the retry-test documentation in fce4af17b. The pre-fix regression is compiling against job/merge31 uploads.rs with the new test fixture; the repaired source is saved separately and will be restored before final gates. Source review also hardened recovery so an IO error cannot be mistaken for a later deletion and retire its applied witness.

Web suite passed (bun run test --maxWorkers=2): Test Files 287 passed (287); Tests 2036 passed (2036). Saved the retry-test documentation in fce4af17b. The pre-fix regression is compiling against job/merge31 uploads.rs with the new test fixture; the repaired source is saved separately and will be restored before final gates. Source review also hardened recovery so an IO error cannot be mistaken for a later deletion and retire its applied witness.
Author
Owner

Deterministic before-fix result: with the exact job/merge31 uploads.rs blob (3b03951050), journal_upload_retry_keeps_later_note_edits failed after real SQLite BUSY following rename, verified installed source bytes, and a later Log edit. Same-ID empty PATCH returned left: 500, right: 204. test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 268 filtered out; finished in 0.87s. No production instrumentation was added; the post-rename race hook already exists on job/merge31. ff53d7b8b has the same hash-rejection path. Repaired source restored; focused verification running.

Deterministic before-fix result: with the exact job/merge31 uploads.rs blob (3b03951050684f2d3c0ab0d9b14c70d5f5a57264), journal_upload_retry_keeps_later_note_edits failed after real SQLite BUSY following rename, verified installed source bytes, and a later Log edit. Same-ID empty PATCH returned left: 500, right: 204. test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 268 filtered out; finished in 0.87s. No production instrumentation was added; the post-rename race hook already exists on job/merge31. ff53d7b8b has the same hash-rejection path. Repaired source restored; focused verification running.
Author
Owner

Committed server recovery slice after focused verification. Repaired result: test result: ok. 5 passed; 0 failed; 0 ignored; 0 measured; 264 filtered out; finished in 2.86s. This includes the same deterministic test that failed on merge31 with 500, and startup recovery after the later edit. cargo fmt --check passed (no output); perf-lint: PASS; 0 violations; 22548 scoped exceptions. No performance pin or limit changed. Healthy uploads add no durable witness write; failed Note publication does. Same-ID sync-client tests are compiling next.

Committed server recovery slice after focused verification. Repaired result: test result: ok. 5 passed; 0 failed; 0 ignored; 0 measured; 264 filtered out; finished in 2.86s. This includes the same deterministic test that failed on merge31 with 500, and startup recovery after the later edit. cargo fmt --check passed (no output); perf-lint: PASS; 0 violations; 22548 scoped exceptions. No performance pin or limit changed. Healthy uploads add no durable witness write; failed Note publication does. Same-ID sync-client tests are compiling next.
Author
Owner

Focused sync transport verification passed: test result: ok. 7 passed; 0 failed; 0 ignored; 0 measured; 58 filtered out; finished in 0.44s. Coverage includes 503 before bytes commit, 503 after final receipt, a dropped final response, missing/inconsistent HEAD bounds, matching source with pending publication, and bounded expired-upload restarts. Committing this slice and fetching/merging origin/dev once before final gates. The probe change is saved as 92551fad6; its syntax check passed and the real local release-server run remains ahead.

Focused sync transport verification passed: test result: ok. 7 passed; 0 failed; 0 ignored; 0 measured; 58 filtered out; finished in 0.44s. Coverage includes 503 before bytes commit, 503 after final receipt, a dropped final response, missing/inconsistent HEAD bounds, matching source with pending publication, and bounded expired-upload restarts. Committing this slice and fetching/merging origin/dev once before final gates. The probe change is saved as 92551fad6; its syntax check passed and the real local release-server run remains ahead.
Author
Owner

Atomic transport slice is 8d9cb2d95a. Required final git fetch origin && git merge origin/dev completed: Already up to date. Final serial per-crate fmt/clippy/tests and web check/test are running on this head. Server repair is 4fc9cdf47; no dependency or schema change was needed.

Atomic transport slice is 8d9cb2d95a397bfa5ef1c420db10aeff8d8fcd94. Required final git fetch origin && git merge origin/dev completed: Already up to date. Final serial per-crate fmt/clippy/tests and web check/test are running on this head. Server repair is 4fc9cdf47; no dependency or schema change was needed.
Author
Owner

Dropped-response coverage now includes server request cancellation at the existing post-rename hook, not only a scripted client transport reset. Finalization moves its existing upload guard into one server task; the task retains namespace and Notes writers through publication or failure-witness sealing. Admission remains cancellable and each upload ID owns at most one finalization task. test result: ok. 6 passed; 0 failed; 0 ignored; 0 measured; 264 filtered out; finished in 5.80s. Concurrent retry waits for retirement and returns 404; source bytes and inode stay unchanged. Refreshed exactly one existing patch:mutation syntax hash, added 0 exceptions and changed 0 limits. The affected Files gates and web check are being refreshed for this slice.

Dropped-response coverage now includes server request cancellation at the existing post-rename hook, not only a scripted client transport reset. Finalization moves its existing upload guard into one server task; the task retains namespace and Notes writers through publication or failure-witness sealing. Admission remains cancellable and each upload ID owns at most one finalization task. test result: ok. 6 passed; 0 failed; 0 ignored; 0 measured; 264 filtered out; finished in 5.80s. Concurrent retry waits for retirement and returns 404; source bytes and inode stay unchanged. Refreshed exactly one existing patch:mutation syntax hash, added 0 exceptions and changed 0 limits. The affected Files gates and web check are being refreshed for this slice.
Author
Owner

Head is 1a4b5232ac. Completed sync and Notes gates: sync clippy -D warnings passed; test result: ok. 65 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 2.09s. Daemon: 2 passed. Notes clippy -D warnings passed; test result: ok. 314 passed; 0 failed; 4 ignored; 0 measured; 0 filtered out; finished in 415.01s. Apple replay: 2 passed. Final web check exits 0 with svelte-check found 0 errors and 1 warning in 1 file. Web suite: Test Files 287 passed (287); Tests 2036 passed (2036). The six focused Files regressions pass; refreshing its full gate after the cancellation slice, then building this exact head as the local release server for one Journal sync reliability check.

Head is 1a4b5232ac3951460b54a1cc46170b2b7bffde55. Completed sync and Notes gates: sync clippy -D warnings passed; test result: ok. 65 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 2.09s. Daemon: 2 passed. Notes clippy -D warnings passed; test result: ok. 314 passed; 0 failed; 4 ignored; 0 measured; 0 filtered out; finished in 415.01s. Apple replay: 2 passed. Final web check exits 0 with svelte-check found 0 errors and 1 warning in 1 file. Web suite: Test Files 287 passed (287); Tests 2036 passed (2036). The six focused Files regressions pass; refreshing its full gate after the cancellation slice, then building this exact head as the local release server for one Journal sync reliability check.
Author
Owner

Final Files gate exposed an existing cleanup-harness defect in internal_temp_paths_never_enter_index_during_atomic_write_reconcile_storm: on its five-minute timeout, cleanup joined watcher inside the worker loop and then awaited the same JoinHandle again. Tokio panicked with JoinHandle polled after completion, masking the real timeout. Removing only the duplicate watcher join; keeping all 1,000 writes, four scans, the five-minute deadline and every assertion unchanged. Focused storm verification is running once, then the complete Files gate will be refreshed. The six Journal regressions passed in the failed suite. No claim of all final gates passing yet.

Final Files gate exposed an existing cleanup-harness defect in internal_temp_paths_never_enter_index_during_atomic_write_reconcile_storm: on its five-minute timeout, cleanup joined watcher inside the worker loop and then awaited the same JoinHandle again. Tokio panicked with JoinHandle polled after completion, masking the real timeout. Removing only the duplicate watcher join; keeping all 1,000 writes, four scans, the five-minute deadline and every assertion unchanged. Focused storm verification is running once, then the complete Files gate will be refreshed. The six Journal regressions passed in the failed suite. No claim of all final gates passing yet.
Author
Owner

Committed 5adc81b4ea: storm cleanup joins the watcher once, preserving the actual failure cause. Its focused test passed: test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 269 filtered out; finished in 186.12s. Workload, deadline and assertions are unchanged. Refreshed Files clippy with -D warnings passed; full Files tests are running, followed by the required local release build and one Journal sync reliability check. All six Journal regression cases have passed in this full run.

Committed 5adc81b4ead11c29738a602415a8456484d4b830: storm cleanup joins the watcher once, preserving the actual failure cause. Its focused test passed: `test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 269 filtered out; finished in 186.12s`. Workload, deadline and assertions are unchanged. Refreshed Files clippy with -D warnings passed; full Files tests are running, followed by the required local release build and one Journal sync reliability check. All six Journal regression cases have passed in this full run.
Author
Owner

Head 5adc81b4ea. All required gates now pass after the one origin/dev merge. Files storm cleanup fixes only the double join; the full suite passes with its original deadline and workload. Local release server is compiling for the required one-run Journal sync reliability check. Verbatim final test/check summaries:

calternal-sync
test result: ok. 65 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 2.09s
test result: ok. 2 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
calternal-plugin-files
test result: ok. 266 passed; 0 failed; 4 ignored; 0 measured; 0 filtered out; finished in 212.32s
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
calternal-plugin-notes
test result: ok. 314 passed; 0 failed; 4 ignored; 0 measured; 0 filtered out; finished in 415.01s
test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 1.04s
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
perf-lint: PASS; 0 violations; 22548 scoped exceptions
svelte-check found 0 errors and 1 warning in 1 file
 Test Files  287 passed (287)
      Tests  2036 passed (2036)
Head 5adc81b4ead11c29738a602415a8456484d4b830. All required gates now pass after the one origin/dev merge. Files storm cleanup fixes only the double join; the full suite passes with its original deadline and workload. Local release server is compiling for the required one-run Journal sync reliability check. Verbatim final test/check summaries: ```text calternal-sync test result: ok. 65 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 2.09s test result: ok. 2 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 calternal-plugin-files test result: ok. 266 passed; 0 failed; 4 ignored; 0 measured; 0 filtered out; finished in 212.32s test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s calternal-plugin-notes test result: ok. 314 passed; 0 failed; 4 ignored; 0 measured; 0 filtered out; finished in 415.01s test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 1.04s test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s perf-lint: PASS; 0 violations; 22548 scoped exceptions svelte-check found 0 errors and 1 warning in 1 file Test Files 287 passed (287) Tests 2036 passed (2036) ```
Author
Owner

Head remains 5adc81b4ea; working tree is clean and required gates pass. The fresh local release build has compiled its dependencies and plugins. The final calternal-server Rust compiler process is still active, with no compile errors. The required one-run Journal sync reliability check is queued with a 20-minute limit. No probe has been run yet; final report and target/web-output cleanup follow it.

Head remains 5adc81b4ead11c29738a602415a8456484d4b830; working tree is clean and required gates pass. The fresh local release build has compiled its dependencies and plugins. The final calternal-server Rust compiler process is still active, with no compile errors. The required one-run Journal sync reliability check is queued with a 20-minute limit. No probe has been run yet; final report and target/web-output cleanup follow it.
Author
Owner

#1295 — Daily note sync retry publication

Built: browser and daemon upload retries keep the durable tus ID after an ambiguous final PATCH. Files finalization keeps the namespace and Notes writer through publication, even when the HTTP request is dropped. Applied-upload proof survives an Index-busy failure, later Log edits and startup recovery. Retry publishes the current revision and does not reinstall the old snapshot. Staging cleanup follows upload-row retirement.

Files: apps/web/src/lib/files/uploads.svelte.ts and uploads.svelte.test.ts; crates/calternal-sync/src/remote.rs and transfer.rs; crates/plugins/files/src/lib.rs and uploads.rs; crates/plugins/notes/src/lib.rs; contracts/perf/exceptions.json; tests/adversarial/attack2.py, xuser_matrix.py, test_xuser_classification.py and run.sh.

Regression evidence: journal_upload_retry_keeps_later_note_edits forces a real SQLite writer reservation after the source rename, confirms the initial 503 applied bytes, edits the Note, and retries the same tus ID. Exact job/merge31 uploads.rs fails with 500 instead of 204. Production ff53d7b8b4 has the same late-precondition and hash-mismatch recovery paths, so it has the same bug. New tests also cover startup recovery, writer exclusion and dropped-request/concurrent-retry ownership. No existing test expectations, workloads or deadlines were changed. A storm-test cleanup defect was fixed: timeout cleanup previously joined the watcher twice and masked the timeout with a panic.

UX gaps closed: full-offset browser retries finalize the original upload; later Log edits remain intact; dropped requests keep writer ownership until publication ends. Existing UploadQueue is reused; no new visible controls or styles.

Decisions: use a bounded server-only staging witness on publication failure, with no new schema or dependency and no extra healthy-path fsync. Move only finalization into an owned server task; admission stays cancellable and each upload ID owns at most one such task. Retain conservative recovery when a legacy intent has no applied proof. Refresh only the exact existing performance source pin, without widening a rule.

Minimal public addition: Notes reexports its existing note_path validator so Files selects the same supported Note paths for writer coordination. No new parsing rule was added.

Expected cost: existing O(bytes) staging/hash work per upload, O(1) finalization task and metadata per admitted ID; failure-only small witness write. No per-request Home scan. No benchmark was run because the verification policy reserves performance measurements for performance issues.

Known gaps: existing duplicate paragraphs are not rewritten automatically, to avoid removing User content. Legacy unsealed ambiguous intents remain conservative. Notes has four existing ignored optional tests; Files has four existing ignored optional tests. Web check reports one existing empty CSS rule warning in AttachmentDeck.svelte. No new UI surface requires screenshots.

For the merge round: cargo fmt --check, cargo clippy --all-targets -- -D warnings, and cargo test -- --test-threads=4 must verify the combined branch. cd apps/web && bun run test:e2e:notes must check Note and Log flows on that build. tests/adversarial/run.sh must check the combined API, cross-User and authorization matrices. This job runs its own required Journal sync reliability check on its local release server.

Head SHA: 777730599b

Gates (verbatim summary output; all commands exited 0):

cargo fmt --check: no output.

cargo clippy -p calternal-sync --all-targets -- -D warnings:

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

cargo test -p calternal-sync -- --test-threads=4:

test result: ok. 65 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 2.09s
test result: ok. 2 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 clippy -p calternal-plugin-files --all-targets -- -D warnings:

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

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

test result: ok. 266 passed; 0 failed; 4 ignored; 0 measured; 0 filtered out; finished in 212.32s
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

cargo clippy -p calternal-plugin-notes --all-targets -- -D warnings:

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

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

test result: ok. 314 passed; 0 failed; 4 ignored; 0 measured; 0 filtered out; finished in 415.01s
test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 1.04s
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

cd apps/web && bun run check:

perf-lint: PASS; 0 violations; 22548 scoped exceptions
svelte-check found 0 errors and 1 warning in 1 file

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

 Test Files  287 passed (287)
      Tests  2036 passed (2036)
   Duration  311.07s (environment 28%, transform 26%, import 23%, tests 17%, setup 5%)

Runner prerequisite: the first invocation stopped before starting a server because the fail-closed inventory lacked existing feature flag and Notifications mark-unread IDs. Added their resource classes and two regression cases. The Admin and fresh sign-in rules are unchanged. No existing test expectation changed.

The release binary was built from 5adc81b4ea; the following commits only add Python classifications/tests and shell runner diagnostics. Rust and web product code are unchanged.

Additional offline gates (verbatim):

Ran 19 tests in 0.410s
OK
Cross-User classification gate: 429 operations classified
Generated entry point classification: 1206 tools classified
Admin coverage: 53 reviewed operations; contract and Rust guards agree

Release build (verbatim):

    Finished `release` profile [optimized] target(s) in 82m 23s

The SSD fixture had 14 GiB available on a 591 GiB filesystem. Log creates correctly returned the storage-reserve 507, so no Daily note existed for inspection. Moved this job's lexical target/tmp to its HDD scratch directory, with 177 GiB available; the production reserve stayed enabled. HDD startup then exceeded the runner's default 60 s budget. Added an optional 1..600 half-second polling budget (default stays 120) and content-free startup diagnostics. This run selected 360 polls. Readiness still requires HTTP 200; API request deadlines and expectations are unchanged. bash -n tests/adversarial/run.sh exited 0 with no output.

Journal sync reliability check (local release server; summary lines only):

journalrace: 2021-03-14: 6 seeds, 40 creates answered 201, 0 timed out (0 of them landed), 3 uploads, 46 entries
server alive at end: True
==== ROUND 2 FINDINGS 7
==== ROUND 2 SLOW 1

The runner exited 1. All seven FINDINGS are labelled SLOW: sync clients had no response within 30 s. The separate SLOW footer counts one latency sample. There were no non-SLOW findings, duplicate paragraphs, duplicate entry IDs, lost acknowledged creates or damaged lines. All 46 Log entries were present; three sync uploads completed. Seven uploads exceeded the client deadline, so their eventual completion is not proven by this check. Per the busy-host policy, no repeat round was run after that SLOW-only result.

UX gaps left: prior duplicates need a separate repair action. Legacy unsealed install intents are still rejected when their current hash differs from the recorded upload hash; they need review and can prevent startup recovery. No older build can supply the new failure witness retroactively. This job prevents new retry duplicates and preserves later edits.

Legacy follow-up filed: #1325, Legacy Note upload intents with later edits cannot recover after restart.

Cleanup complete: cargo clean output (verbatim):

     Removed 25604 files, 14.7GiB total

Removed /mnt/hdd/targets/journaldup, apps/web/build and apps/web/.svelte-kit; restored an empty normal target/tmp directory. No server remains running. Working tree is clean. No push or deploy was done.

# #1295 — Daily note sync retry publication Built: browser and daemon upload retries keep the durable tus ID after an ambiguous final PATCH. Files finalization keeps the namespace and Notes writer through publication, even when the HTTP request is dropped. Applied-upload proof survives an Index-busy failure, later Log edits and startup recovery. Retry publishes the current revision and does not reinstall the old snapshot. Staging cleanup follows upload-row retirement. Files: apps/web/src/lib/files/uploads.svelte.ts and uploads.svelte.test.ts; crates/calternal-sync/src/remote.rs and transfer.rs; crates/plugins/files/src/lib.rs and uploads.rs; crates/plugins/notes/src/lib.rs; contracts/perf/exceptions.json; tests/adversarial/attack2.py, xuser_matrix.py, test_xuser_classification.py and run.sh. Regression evidence: journal_upload_retry_keeps_later_note_edits forces a real SQLite writer reservation after the source rename, confirms the initial 503 applied bytes, edits the Note, and retries the same tus ID. Exact job/merge31 uploads.rs fails with 500 instead of 204. Production ff53d7b8b4da5a21f862d57dcc3496f8c019f647 has the same late-precondition and hash-mismatch recovery paths, so it has the same bug. New tests also cover startup recovery, writer exclusion and dropped-request/concurrent-retry ownership. No existing test expectations, workloads or deadlines were changed. A storm-test cleanup defect was fixed: timeout cleanup previously joined the watcher twice and masked the timeout with a panic. UX gaps closed: full-offset browser retries finalize the original upload; later Log edits remain intact; dropped requests keep writer ownership until publication ends. Existing UploadQueue is reused; no new visible controls or styles. Decisions: use a bounded server-only staging witness on publication failure, with no new schema or dependency and no extra healthy-path fsync. Move only finalization into an owned server task; admission stays cancellable and each upload ID owns at most one such task. Retain conservative recovery when a legacy intent has no applied proof. Refresh only the exact existing performance source pin, without widening a rule. Minimal public addition: Notes reexports its existing `note_path` validator so Files selects the same supported Note paths for writer coordination. No new parsing rule was added. Expected cost: existing O(bytes) staging/hash work per upload, O(1) finalization task and metadata per admitted ID; failure-only small witness write. No per-request Home scan. No benchmark was run because the verification policy reserves performance measurements for performance issues. Known gaps: existing duplicate paragraphs are not rewritten automatically, to avoid removing User content. Legacy unsealed ambiguous intents remain conservative. Notes has four existing ignored optional tests; Files has four existing ignored optional tests. Web check reports one existing empty CSS rule warning in AttachmentDeck.svelte. No new UI surface requires screenshots. For the merge round: `cargo fmt --check`, `cargo clippy --all-targets -- -D warnings`, and `cargo test -- --test-threads=4` must verify the combined branch. `cd apps/web && bun run test:e2e:notes` must check Note and Log flows on that build. `tests/adversarial/run.sh` must check the combined API, cross-User and authorization matrices. This job runs its own required Journal sync reliability check on its local release server. Head SHA: 777730599b7752c1195530c35d962e1df077fa36 Gates (verbatim summary output; all commands exited 0): `cargo fmt --check`: no output. `cargo clippy -p calternal-sync --all-targets -- -D warnings`: ```text Finished `dev` profile [unoptimized + debuginfo] target(s) in 3m 24s ``` `cargo test -p calternal-sync -- --test-threads=4`: ```text test result: ok. 65 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 2.09s test result: ok. 2 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 clippy -p calternal-plugin-files --all-targets -- -D warnings`: ```text Finished `dev` profile [unoptimized + debuginfo] target(s) in 44.56s ``` `cargo test -p calternal-plugin-files -- --test-threads=4`: ```text test result: ok. 266 passed; 0 failed; 4 ignored; 0 measured; 0 filtered out; finished in 212.32s test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s ``` `cargo clippy -p calternal-plugin-notes --all-targets -- -D warnings`: ```text Finished `dev` profile [unoptimized + debuginfo] target(s) in 1m 35s ``` `cargo test -p calternal-plugin-notes -- --test-threads=4`: ```text test result: ok. 314 passed; 0 failed; 4 ignored; 0 measured; 0 filtered out; finished in 415.01s test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 1.04s test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s ``` `cd apps/web && bun run check`: ```text perf-lint: PASS; 0 violations; 22548 scoped exceptions svelte-check found 0 errors and 1 warning in 1 file ``` `cd apps/web && bun run test --maxWorkers=2`: ```text Test Files 287 passed (287) Tests 2036 passed (2036) Duration 311.07s (environment 28%, transform 26%, import 23%, tests 17%, setup 5%) ``` Runner prerequisite: the first invocation stopped before starting a server because the fail-closed inventory lacked existing feature flag and Notifications mark-unread IDs. Added their resource classes and two regression cases. The Admin and fresh sign-in rules are unchanged. No existing test expectation changed. The release binary was built from 5adc81b4ead11c29738a602415a8456484d4b830; the following commits only add Python classifications/tests and shell runner diagnostics. Rust and web product code are unchanged. Additional offline gates (verbatim): ```text Ran 19 tests in 0.410s OK Cross-User classification gate: 429 operations classified Generated entry point classification: 1206 tools classified Admin coverage: 53 reviewed operations; contract and Rust guards agree ``` Release build (verbatim): ```text Finished `release` profile [optimized] target(s) in 82m 23s ``` The SSD fixture had 14 GiB available on a 591 GiB filesystem. Log creates correctly returned the storage-reserve 507, so no Daily note existed for inspection. Moved this job's lexical `target/tmp` to its HDD scratch directory, with 177 GiB available; the production reserve stayed enabled. HDD startup then exceeded the runner's default 60 s budget. Added an optional 1..600 half-second polling budget (default stays 120) and content-free startup diagnostics. This run selected 360 polls. Readiness still requires HTTP 200; API request deadlines and expectations are unchanged. `bash -n tests/adversarial/run.sh` exited 0 with no output. Journal sync reliability check (local release server; summary lines only): ```text journalrace: 2021-03-14: 6 seeds, 40 creates answered 201, 0 timed out (0 of them landed), 3 uploads, 46 entries server alive at end: True ==== ROUND 2 FINDINGS 7 ==== ROUND 2 SLOW 1 ``` The runner exited 1. All seven FINDINGS are labelled SLOW: sync clients had no response within 30 s. The separate SLOW footer counts one latency sample. There were no non-SLOW findings, duplicate paragraphs, duplicate entry IDs, lost acknowledged creates or damaged lines. All 46 Log entries were present; three sync uploads completed. Seven uploads exceeded the client deadline, so their eventual completion is not proven by this check. Per the busy-host policy, no repeat round was run after that SLOW-only result. UX gaps left: prior duplicates need a separate repair action. Legacy unsealed install intents are still rejected when their current hash differs from the recorded upload hash; they need review and can prevent startup recovery. No older build can supply the new failure witness retroactively. This job prevents new retry duplicates and preserves later edits. Legacy follow-up filed: [#1325](https://git.kayg.org/kayg/calternal/issues/1325), Legacy Note upload intents with later edits cannot recover after restart. Cleanup complete: `cargo clean` output (verbatim): ```text Removed 25604 files, 14.7GiB total ``` Removed `/mnt/hdd/targets/journaldup`, `apps/web/build` and `apps/web/.svelte-kit`; restored an empty normal `target/tmp` directory. No server remains running. Working tree is clean. No push or deploy was done.
Author
Owner

jdrev read-only review started. Branch job/journaldup; HEAD 777730599b; base 3601719b80. Checking durable tus identity, crash recovery, writer guard lifetime and User isolation. Tracked files and refs remain unchanged.

jdrev read-only review started. Branch job/journaldup; HEAD 777730599b7752c1195530c35d962e1df077fa36; base 3601719b80a39f712daf07b37879b22929dfffa0. Checking durable tus identity, crash recovery, writer guard lifetime and User isolation. Tracked files and refs remain unchanged.
Author
Owner

jdrev findings — reviewed head 777730599b

F1 — P1 — Lost successful final PATCH creates a new upload identity

  • Files: apps/web/src/lib/files/uploads.svelte.ts:414–424; crates/plugins/files/src/uploads.rs:2193 (terminal DELETE).
  • Scenario: server commits a final PATCH, deletes its upload row, and the response is dropped. Browser task records no destination. Resume sees HEAD 404, clears location, POSTs a new upload, and sends the same bytes again. Default rename installs a second Note; replace can capture the later destination revision and overwrite a later Log edit with the old client File.
  • Evidence: untracked jdrev-upload.svelte.test.ts reproduces POST u1 / PATCH u1 (lost response) / HEAD u1 404 / POST u2 / PATCH u2. All 17 tests passed, including the observation regression; existing tests were copied unchanged. Server side is being verified separately.
  • Suggested regression: complete and commit the real final PATCH, drop only its response, append a Log edit, then resume from the original tus URL. Assert no second POST, no second Note, and preservation of the later Log line. Retain a completed upload receipt bound to actor and destination, with a bounded retention policy, so completed and expired uploads are distinguishable.

F2 — P2 — Seven historical timeouts have no retained completion evidence

  • Files: tests/adversarial/attack2.py:4388–4440; tests/adversarial/run.sh:108 (disposable fixture).
  • Scenario: sync_upload returns the same ('timeout', line) tuple for a timed-out GET, POST, or PATCH. It drops the tus location and request stage. The final check only rejects multiple occurrences of a timed-out paragraph, not zero occurrences. Thus 'seven timed-out uploads' need not mean seven admitted uploads, and zero copies can pass.
  • Evidence: prior report explicitly states completion was unverified and records cleanup of the server/build/fixture. No per-upload IDs or retained Index rows were saved. This cohort cannot be classified as eventually completed or stuck from the surviving evidence.
  • Suggested test: save stage, upload ID, full offset, and terminal result without credentials; after stopping new jobs, inspect each admitted ID and retry the same ID until a bounded terminal result (204/412/404 with completion proof). Distinguish pre-admission timeout from unfinished finalization. Preserve the fixture until every operation is classified.
  • Sync-side source evidence for F1: crates/calternal-sync/src/remote.rs:849 propagates HEAD 404 as UploadExpired; transfer.rs:158–162 automatically creates a new ID for that error. Its original If-Match stops a destructive replacement, but the same-ID contract still fails and may generate a spurious conflict copy. An observation probe through RemoteClient is queued.
# jdrev findings — reviewed head 777730599b7752c1195530c35d962e1df077fa36 ## F1 — P1 — Lost successful final PATCH creates a new upload identity - Files: apps/web/src/lib/files/uploads.svelte.ts:414–424; crates/plugins/files/src/uploads.rs:2193 (terminal DELETE). - Scenario: server commits a final PATCH, deletes its upload row, and the response is dropped. Browser task records no destination. Resume sees HEAD 404, clears `location`, POSTs a new upload, and sends the same bytes again. Default `rename` installs a second Note; `replace` can capture the later destination revision and overwrite a later Log edit with the old client File. - Evidence: untracked jdrev-upload.svelte.test.ts reproduces POST u1 / PATCH u1 (lost response) / HEAD u1 404 / POST u2 / PATCH u2. All 17 tests passed, including the observation regression; existing tests were copied unchanged. Server side is being verified separately. - Suggested regression: complete and commit the real final PATCH, drop only its response, append a Log edit, then resume from the original tus URL. Assert no second POST, no second Note, and preservation of the later Log line. Retain a completed upload receipt bound to actor and destination, with a bounded retention policy, so completed and expired uploads are distinguishable. ## F2 — P2 — Seven historical timeouts have no retained completion evidence - Files: tests/adversarial/attack2.py:4388–4440; tests/adversarial/run.sh:108 (disposable fixture). - Scenario: `sync_upload` returns the same ('timeout', line) tuple for a timed-out GET, POST, or PATCH. It drops the tus location and request stage. The final check only rejects multiple occurrences of a timed-out paragraph, not zero occurrences. Thus 'seven timed-out uploads' need not mean seven admitted uploads, and zero copies can pass. - Evidence: prior report explicitly states completion was unverified and records cleanup of the server/build/fixture. No per-upload IDs or retained Index rows were saved. This cohort cannot be classified as eventually completed or stuck from the surviving evidence. - Suggested test: save stage, upload ID, full offset, and terminal result without credentials; after stopping new jobs, inspect each admitted ID and retry the same ID until a bounded terminal result (204/412/404 with completion proof). Distinguish pre-admission timeout from unfinished finalization. Preserve the fixture until every operation is classified. - Sync-side source evidence for F1: crates/calternal-sync/src/remote.rs:849 propagates HEAD 404 as `UploadExpired`; transfer.rs:158–162 automatically creates a new ID for that error. Its original If-Match stops a destructive replacement, but the same-ID contract still fails and may generate a spurious conflict copy. An observation probe through `RemoteClient` is queued.
Author
Owner

jdrev findings — reviewed head 777730599b

F1 — P1 — Lost successful final PATCH creates a new upload identity

  • Files: apps/web/src/lib/files/uploads.svelte.ts:414–424; crates/plugins/files/src/uploads.rs:2193 (terminal DELETE).
  • Scenario: server commits a final PATCH, deletes its upload row, and the response is dropped. Browser task records no destination. Resume sees HEAD 404, clears location, POSTs a new upload, and sends the same bytes again. Default rename installs a second Note; replace can capture the later destination revision and overwrite a later Log edit with the old client File.
  • Evidence: untracked jdrev-upload.svelte.test.ts reproduces POST u1 / PATCH u1 (lost response) / HEAD u1 404 / POST u2 / PATCH u2. All 17 tests passed, including the observation regression; existing tests were copied unchanged. Server side is being verified separately.
  • Suggested regression: complete and commit the real final PATCH, drop only its response, append a Log edit, then resume from the original tus URL. Assert no second POST, no second Note, and preservation of the later Log line. Retain a completed upload receipt bound to actor and destination, with a bounded retention policy, so completed and expired uploads are distinguishable.

F2 — P2 — Seven historical timeouts have no retained completion evidence

  • Files: tests/adversarial/attack2.py:4388–4440; tests/adversarial/run.sh:108 (disposable fixture).
  • Scenario: sync_upload returns the same ('timeout', line) tuple for a timed-out GET, POST, or PATCH. It drops the tus location and request stage. The final check only rejects multiple occurrences of a timed-out paragraph, not zero occurrences. Thus 'seven timed-out uploads' need not mean seven admitted uploads, and zero copies can pass.
  • Evidence: prior report explicitly states completion was unverified and records cleanup of the server/build/fixture. No per-upload IDs or retained Index rows were saved. This cohort cannot be classified as eventually completed or stuck from the surviving evidence.
  • Suggested test: save stage, upload ID, full offset, and terminal result without credentials; after stopping new jobs, inspect each admitted ID and retry the same ID until a bounded terminal result (204/412/404 with completion proof). Distinguish pre-admission timeout from unfinished finalization. Preserve the fixture until every operation is classified.
  • Sync-side source evidence for F1: crates/calternal-sync/src/remote.rs:849 propagates HEAD 404 as UploadExpired; transfer.rs:158–162 automatically creates a new ID for that error. Its original If-Match stops a destructive replacement, but the same-ID contract still fails and may generate a spurious conflict copy. An observation probe through RemoteClient is queued.

F3 — P1 — Crash recovery can race new Log edits before HTTP recovery runs

  • Files: crates/plugins/files/src/uploads.rs:451 and :2305; crates/calternal-server/src/wire.rs:1783, :2045 and :5852.
  • Scenario: even the new binary can be killed after source rename and before complete_install handles an error and writes the failure witness. On restart only reservations are restored before serving. recover_installs runs later, behind Search and Notes backfill. A Log edit in that interval changes the hash of the unsealed installed Note. Recovery returns unexpected content; PATCH retry returns 500. This is a new-binary crash path, not only legacy state from #1325.
  • Evidence: pre-serving startup calls restore_upload_reservations, not recover_installs; /readyz checks only a SELECT and system directory writability. Background Files reconciliation logs errors and continues. The unsealed/later-edit fixture is queued in the public Files integration test. The optional startup polling budget does not protect this boundary.
  • Suggested test: kill the new server immediately after rename without a sealed witness; restart, create/edit a Log entry before background Files reconciliation, and retry the persisted tus ID. Assert successful publication or a safe terminal receipt, no 500 and no skipped recovery. Recover these source-write intents before accepting Notes writes, or durably seal application at the source publication boundary.
# jdrev findings — reviewed head 777730599b7752c1195530c35d962e1df077fa36 ## F1 — P1 — Lost successful final PATCH creates a new upload identity - Files: apps/web/src/lib/files/uploads.svelte.ts:414–424; crates/plugins/files/src/uploads.rs:2193 (terminal DELETE). - Scenario: server commits a final PATCH, deletes its upload row, and the response is dropped. Browser task records no destination. Resume sees HEAD 404, clears `location`, POSTs a new upload, and sends the same bytes again. Default `rename` installs a second Note; `replace` can capture the later destination revision and overwrite a later Log edit with the old client File. - Evidence: untracked jdrev-upload.svelte.test.ts reproduces POST u1 / PATCH u1 (lost response) / HEAD u1 404 / POST u2 / PATCH u2. All 17 tests passed, including the observation regression; existing tests were copied unchanged. Server side is being verified separately. - Suggested regression: complete and commit the real final PATCH, drop only its response, append a Log edit, then resume from the original tus URL. Assert no second POST, no second Note, and preservation of the later Log line. Retain a completed upload receipt bound to actor and destination, with a bounded retention policy, so completed and expired uploads are distinguishable. ## F2 — P2 — Seven historical timeouts have no retained completion evidence - Files: tests/adversarial/attack2.py:4388–4440; tests/adversarial/run.sh:108 (disposable fixture). - Scenario: `sync_upload` returns the same ('timeout', line) tuple for a timed-out GET, POST, or PATCH. It drops the tus location and request stage. The final check only rejects multiple occurrences of a timed-out paragraph, not zero occurrences. Thus 'seven timed-out uploads' need not mean seven admitted uploads, and zero copies can pass. - Evidence: prior report explicitly states completion was unverified and records cleanup of the server/build/fixture. No per-upload IDs or retained Index rows were saved. This cohort cannot be classified as eventually completed or stuck from the surviving evidence. - Suggested test: save stage, upload ID, full offset, and terminal result without credentials; after stopping new jobs, inspect each admitted ID and retry the same ID until a bounded terminal result (204/412/404 with completion proof). Distinguish pre-admission timeout from unfinished finalization. Preserve the fixture until every operation is classified. - Sync-side source evidence for F1: crates/calternal-sync/src/remote.rs:849 propagates HEAD 404 as `UploadExpired`; transfer.rs:158–162 automatically creates a new ID for that error. Its original If-Match stops a destructive replacement, but the same-ID contract still fails and may generate a spurious conflict copy. An observation probe through `RemoteClient` is queued. ## F3 — P1 — Crash recovery can race new Log edits before HTTP recovery runs - Files: crates/plugins/files/src/uploads.rs:451 and :2305; crates/calternal-server/src/wire.rs:1783, :2045 and :5852. - Scenario: even the new binary can be killed after source rename and before `complete_install` handles an error and writes the failure witness. On restart only reservations are restored before serving. `recover_installs` runs later, behind Search and Notes backfill. A Log edit in that interval changes the hash of the unsealed installed Note. Recovery returns `unexpected content`; PATCH retry returns 500. This is a new-binary crash path, not only legacy state from #1325. - Evidence: pre-serving startup calls `restore_upload_reservations`, not `recover_installs`; `/readyz` checks only a SELECT and system directory writability. Background Files reconciliation logs errors and continues. The unsealed/later-edit fixture is queued in the public Files integration test. The optional startup polling budget does not protect this boundary. - Suggested test: kill the new server immediately after rename without a sealed witness; restart, create/edit a Log entry before background Files reconciliation, and retry the persisted tus ID. Assert successful publication or a safe terminal receipt, no 500 and no skipped recovery. Recover these source-write intents before accepting Notes writes, or durably seal application at the source publication boundary.
Author
Owner

jdrev findings — reviewed head 777730599b

F1 — P1 — Lost successful final PATCH creates a new upload identity

  • Files: apps/web/src/lib/files/uploads.svelte.ts:414–424; crates/plugins/files/src/uploads.rs:2193 (terminal DELETE).
  • Scenario: server commits a final PATCH, deletes its upload row, and the response is dropped. Browser task records no destination. Resume sees HEAD 404, clears location, POSTs a new upload, and sends the same bytes again. Default rename installs a second Note; replace can capture the later destination revision and overwrite a later Log edit with the old client File.
  • Evidence: untracked jdrev-upload.svelte.test.ts reproduces POST u1 / PATCH u1 (lost response) / HEAD u1 404 / POST u2 / PATCH u2. All 17 tests passed, including the observation regression; existing tests were copied unchanged. Server side is being verified separately.
  • Suggested regression: complete and commit the real final PATCH, drop only its response, append a Log edit, then resume from the original tus URL. Assert no second POST, no second Note, and preservation of the later Log line. Retain a completed upload receipt bound to actor and destination, with a bounded retention policy, so completed and expired uploads are distinguishable.

F2 — P2 — Seven historical timeouts have no retained completion evidence

  • Files: tests/adversarial/attack2.py:4388–4440; tests/adversarial/run.sh:108 (disposable fixture).
  • Scenario: sync_upload returns the same ('timeout', line) tuple for a timed-out GET, POST, or PATCH. It drops the tus location and request stage. The final check only rejects multiple occurrences of a timed-out paragraph, not zero occurrences. Thus 'seven timed-out uploads' need not mean seven admitted uploads, and zero copies can pass.
  • Evidence: prior report explicitly states completion was unverified and records cleanup of the server/build/fixture. No per-upload IDs or retained Index rows were saved. This cohort cannot be classified as eventually completed or stuck from the surviving evidence.
  • Suggested test: save stage, upload ID, full offset, and terminal result without credentials; after stopping new jobs, inspect each admitted ID and retry the same ID until a bounded terminal result (204/412/404 with completion proof). Distinguish pre-admission timeout from unfinished finalization. Preserve the fixture until every operation is classified.
  • Sync-side source evidence for F1: crates/calternal-sync/src/remote.rs:849 propagates HEAD 404 as UploadExpired; transfer.rs:158–162 automatically creates a new ID for that error. Its original If-Match stops a destructive replacement, but the same-ID contract still fails and may generate a spurious conflict copy. An observation probe through RemoteClient is queued.

F3 — P1 — Crash recovery can race new Log edits before HTTP recovery runs

  • Files: crates/plugins/files/src/uploads.rs:451 and :2305; crates/calternal-server/src/wire.rs:1783, :2045 and :5852.
  • Scenario: even the new binary can be killed after source rename and before complete_install handles an error and writes the failure witness. On restart only reservations are restored before serving. recover_installs runs later, behind Search and Notes backfill. A Log edit in that interval changes the hash of the unsealed installed Note. Recovery returns unexpected content; PATCH retry returns 500. This is a new-binary crash path, not only legacy state from #1325.
  • Evidence: pre-serving startup calls restore_upload_reservations, not recover_installs; /readyz checks only a SELECT and system directory writability. Background Files reconciliation logs errors and continues. The unsealed/later-edit fixture is queued in the public Files integration test. The optional startup polling budget does not protect this boundary.
  • Suggested test: kill the new server immediately after rename without a sealed witness; restart, create/edit a Log entry before background Files reconciliation, and retry the persisted tus ID. Assert successful publication or a safe terminal receipt, no 500 and no skipped recovery. Recover these source-write intents before accepting Notes writes, or durably seal application at the source publication boundary.

F4 — P2 — Active detached publication has no lease-enforced guard deadline

  • Files: crates/plugins/files/src/uploads.rs:1521–1532, :1710–1717 and :2364.
  • Scenario: a finalizer takes the Instance namespace mutex, then waits for a Notes writer. Dropping the request leaves it running. Expiring the upload row does not cancel it: cleanup waits on the same upload mutex. A stuck underlying writer/IO can therefore retain the namespace indefinitely. Ordinary abandoned partial uploads do have the documented 15-minute idle and 24-hour maximum lifetime; that is not a deadline for an active detached publisher.
  • Evidence: observation test abandoned_finalizer_wait_is_not_bounded_by_upload_expiry passed. It holds the Notes writer, aborts the request, expires the row, observes both cleanup and a namespace waiter blocked, then releases the Notes writer and observes publication release the namespace. No ordinary-operation permanent leak was demonstrated; this finding is lack of an enforced bound, not a claim that every slow upload is stuck.
  • Suggested test: block a finalizer before source IO and after durable rename, advance a fake clock through both lease limits, and assert a defined recovery handoff releases writer ownership safely without cancelling an active blocking rename or losing its witness. Do not fix this by putting an unsafe timeout around filesystem publication.

Additional independent evidence

  • F1: the real production Files router accepted a new replacement upload after a lost success and a later edit. The test observed the current Note lose ^later, while the server acknowledged the new PATCH with 204. Historical Versions were not checked; this is current-source overwrite, not a claim of irreversible deletion from Versions.
  • F3: the actual Journal route returned 201 for a Log create over a new-binary unsealed crash intent. Files recovery then returned unexpected content, and PATCH on the original ID returned 500. The acknowledged Log bytes were retained, but the intent remained unresumable. This reproduces the new-binary startup window through real Plugin handlers; no process kill was used.
  • Cross-User HEAD/PATCH/DELETE returned 404; same-ID simultaneous PATCH produced 204/404 and one file. Cross-Note retargeting via PATCH metadata cannot change the stored destination, but the extra metadata is ignored with 204 rather than explicitly refused.
  • The first default-rename server observation used an incomplete test fixture (it omitted the browser's Upload-Conflict-Policy: rename header), so the server's default fail policy returned 412. The untracked fixture was corrected to send the real browser header. Existing repository tests and expectations were not changed. The initial failed log is retained.
# jdrev findings — reviewed head 777730599b7752c1195530c35d962e1df077fa36 ## F1 — P1 — Lost successful final PATCH creates a new upload identity - Files: apps/web/src/lib/files/uploads.svelte.ts:414–424; crates/plugins/files/src/uploads.rs:2193 (terminal DELETE). - Scenario: server commits a final PATCH, deletes its upload row, and the response is dropped. Browser task records no destination. Resume sees HEAD 404, clears `location`, POSTs a new upload, and sends the same bytes again. Default `rename` installs a second Note; `replace` can capture the later destination revision and overwrite a later Log edit with the old client File. - Evidence: untracked jdrev-upload.svelte.test.ts reproduces POST u1 / PATCH u1 (lost response) / HEAD u1 404 / POST u2 / PATCH u2. All 17 tests passed, including the observation regression; existing tests were copied unchanged. Server side is being verified separately. - Suggested regression: complete and commit the real final PATCH, drop only its response, append a Log edit, then resume from the original tus URL. Assert no second POST, no second Note, and preservation of the later Log line. Retain a completed upload receipt bound to actor and destination, with a bounded retention policy, so completed and expired uploads are distinguishable. ## F2 — P2 — Seven historical timeouts have no retained completion evidence - Files: tests/adversarial/attack2.py:4388–4440; tests/adversarial/run.sh:108 (disposable fixture). - Scenario: `sync_upload` returns the same ('timeout', line) tuple for a timed-out GET, POST, or PATCH. It drops the tus location and request stage. The final check only rejects multiple occurrences of a timed-out paragraph, not zero occurrences. Thus 'seven timed-out uploads' need not mean seven admitted uploads, and zero copies can pass. - Evidence: prior report explicitly states completion was unverified and records cleanup of the server/build/fixture. No per-upload IDs or retained Index rows were saved. This cohort cannot be classified as eventually completed or stuck from the surviving evidence. - Suggested test: save stage, upload ID, full offset, and terminal result without credentials; after stopping new jobs, inspect each admitted ID and retry the same ID until a bounded terminal result (204/412/404 with completion proof). Distinguish pre-admission timeout from unfinished finalization. Preserve the fixture until every operation is classified. - Sync-side source evidence for F1: crates/calternal-sync/src/remote.rs:849 propagates HEAD 404 as `UploadExpired`; transfer.rs:158–162 automatically creates a new ID for that error. Its original If-Match stops a destructive replacement, but the same-ID contract still fails and may generate a spurious conflict copy. An observation probe through `RemoteClient` is queued. ## F3 — P1 — Crash recovery can race new Log edits before HTTP recovery runs - Files: crates/plugins/files/src/uploads.rs:451 and :2305; crates/calternal-server/src/wire.rs:1783, :2045 and :5852. - Scenario: even the new binary can be killed after source rename and before `complete_install` handles an error and writes the failure witness. On restart only reservations are restored before serving. `recover_installs` runs later, behind Search and Notes backfill. A Log edit in that interval changes the hash of the unsealed installed Note. Recovery returns `unexpected content`; PATCH retry returns 500. This is a new-binary crash path, not only legacy state from #1325. - Evidence: pre-serving startup calls `restore_upload_reservations`, not `recover_installs`; `/readyz` checks only a SELECT and system directory writability. Background Files reconciliation logs errors and continues. The unsealed/later-edit fixture is queued in the public Files integration test. The optional startup polling budget does not protect this boundary. - Suggested test: kill the new server immediately after rename without a sealed witness; restart, create/edit a Log entry before background Files reconciliation, and retry the persisted tus ID. Assert successful publication or a safe terminal receipt, no 500 and no skipped recovery. Recover these source-write intents before accepting Notes writes, or durably seal application at the source publication boundary. ## F4 — P2 — Active detached publication has no lease-enforced guard deadline - Files: crates/plugins/files/src/uploads.rs:1521–1532, :1710–1717 and :2364. - Scenario: a finalizer takes the Instance namespace mutex, then waits for a Notes writer. Dropping the request leaves it running. Expiring the upload row does not cancel it: cleanup waits on the same upload mutex. A stuck underlying writer/IO can therefore retain the namespace indefinitely. Ordinary abandoned partial uploads do have the documented 15-minute idle and 24-hour maximum lifetime; that is not a deadline for an active detached publisher. - Evidence: observation test `abandoned_finalizer_wait_is_not_bounded_by_upload_expiry` passed. It holds the Notes writer, aborts the request, expires the row, observes both cleanup and a namespace waiter blocked, then releases the Notes writer and observes publication release the namespace. No ordinary-operation permanent leak was demonstrated; this finding is lack of an enforced bound, not a claim that every slow upload is stuck. - Suggested test: block a finalizer before source IO and after durable rename, advance a fake clock through both lease limits, and assert a defined recovery handoff releases writer ownership safely without cancelling an active blocking rename or losing its witness. Do not fix this by putting an unsafe timeout around filesystem publication. ### Additional independent evidence - F1: the real production Files router accepted a new replacement upload after a lost success and a later edit. The test observed the current Note lose `^later`, while the server acknowledged the new PATCH with 204. Historical Versions were not checked; this is current-source overwrite, not a claim of irreversible deletion from Versions. - F3: the actual Journal route returned 201 for a Log create over a new-binary unsealed crash intent. Files recovery then returned `unexpected content`, and PATCH on the original ID returned 500. The acknowledged Log bytes were retained, but the intent remained unresumable. This reproduces the new-binary startup window through real Plugin handlers; no process kill was used. - Cross-User HEAD/PATCH/DELETE returned 404; same-ID simultaneous PATCH produced 204/404 and one file. Cross-Note retargeting via PATCH metadata cannot change the stored destination, but the extra metadata is ignored with 204 rather than explicitly refused. - The first default-rename server observation used an incomplete test fixture (it omitted the browser's `Upload-Conflict-Policy: rename` header), so the server's default fail policy returned 412. The untracked fixture was corrected to send the real browser header. Existing repository tests and expectations were not changed. The initial failed log is retained.
Author
Owner

jdrev findings — reviewed head 777730599b

F1 — P1 — Lost successful final PATCH creates a new upload identity

  • Files: apps/web/src/lib/files/uploads.svelte.ts:414–424; crates/plugins/files/src/uploads.rs:2193 (terminal DELETE).
  • Scenario: server commits a final PATCH, deletes its upload row, and the response is dropped. Browser task records no destination. Resume sees HEAD 404, clears location, POSTs a new upload, and sends the same bytes again. Default rename installs a second Note; replace can capture the later destination revision and overwrite a later Log edit with the old client File.
  • Evidence: untracked jdrev-upload.svelte.test.ts reproduces POST u1 / PATCH u1 (lost response) / HEAD u1 404 / POST u2 / PATCH u2. All 17 tests passed, including the observation regression; existing tests were copied unchanged. Server side is being verified separately.
  • Suggested regression: complete and commit the real final PATCH, drop only its response, append a Log edit, then resume from the original tus URL. Assert no second POST, no second Note, and preservation of the later Log line. Retain a completed upload receipt bound to actor and destination, with a bounded retention policy, so completed and expired uploads are distinguishable.

F2 — P2 — Seven historical timeouts have no retained completion evidence

  • Files: tests/adversarial/attack2.py:4388–4440; tests/adversarial/run.sh:108 (disposable fixture).
  • Scenario: sync_upload returns the same ('timeout', line) tuple for a timed-out GET, POST, or PATCH. It drops the tus location and request stage. The final check only rejects multiple occurrences of a timed-out paragraph, not zero occurrences. Thus 'seven timed-out uploads' need not mean seven admitted uploads, and zero copies can pass.
  • Evidence: prior report explicitly states completion was unverified and records cleanup of the server/build/fixture. No per-upload IDs or retained Index rows were saved. This cohort cannot be classified as eventually completed or stuck from the surviving evidence.
  • Suggested test: save stage, upload ID, full offset, and terminal result without credentials; after stopping new jobs, inspect each admitted ID and retry the same ID until a bounded terminal result (204/412/404 with completion proof). Distinguish pre-admission timeout from unfinished finalization. Preserve the fixture until every operation is classified.
  • Sync-side source evidence for F1: crates/calternal-sync/src/remote.rs:849 propagates HEAD 404 as UploadExpired; transfer.rs:158–162 automatically creates a new ID for that error. Its original If-Match stops a destructive replacement, but the same-ID contract still fails and may generate a spurious conflict copy. An observation probe through RemoteClient is queued.

F3 — P1 — Crash recovery can race new Log edits before HTTP recovery runs

  • Files: crates/plugins/files/src/uploads.rs:451 and :2305; crates/calternal-server/src/wire.rs:1783, :2045 and :5852.
  • Scenario: even the new binary can be killed after source rename and before complete_install handles an error and writes the failure witness. On restart only reservations are restored before serving. recover_installs runs later, behind Search and Notes backfill. A Log edit in that interval changes the hash of the unsealed installed Note. Recovery returns unexpected content; PATCH retry returns 500. This is a new-binary crash path, not only legacy state from #1325.
  • Evidence: pre-serving startup calls restore_upload_reservations, not recover_installs; /readyz checks only a SELECT and system directory writability. Background Files reconciliation logs errors and continues. The unsealed/later-edit fixture is queued in the public Files integration test. The optional startup polling budget does not protect this boundary.
  • Suggested test: kill the new server immediately after rename without a sealed witness; restart, create/edit a Log entry before background Files reconciliation, and retry the persisted tus ID. Assert successful publication or a safe terminal receipt, no 500 and no skipped recovery. Recover these source-write intents before accepting Notes writes, or durably seal application at the source publication boundary.

F4 — P2 — Active detached publication has no lease-enforced guard deadline

  • Files: crates/plugins/files/src/uploads.rs:1521–1532, :1710–1717 and :2364.
  • Scenario: a finalizer takes the Instance namespace mutex, then waits for a Notes writer. Dropping the request leaves it running. Expiring the upload row does not cancel it: cleanup waits on the same upload mutex. A stuck underlying writer/IO can therefore retain the namespace indefinitely. Ordinary abandoned partial uploads do have the documented 15-minute idle and 24-hour maximum lifetime; that is not a deadline for an active detached publisher.
  • Evidence: observation test abandoned_finalizer_wait_is_not_bounded_by_upload_expiry passed. It holds the Notes writer, aborts the request, expires the row, observes both cleanup and a namespace waiter blocked, then releases the Notes writer and observes publication release the namespace. No ordinary-operation permanent leak was demonstrated; this finding is lack of an enforced bound, not a claim that every slow upload is stuck.
  • Suggested test: block a finalizer before source IO and after durable rename, advance a fake clock through both lease limits, and assert a defined recovery handoff releases writer ownership safely without cancelling an active blocking rename or losing its witness. Do not fix this by putting an unsafe timeout around filesystem publication.

Additional independent evidence

  • F1: the real production Files router accepted a new replacement upload after a lost success and a later edit. The test observed the current Note lose ^later, while the server acknowledged the new PATCH with 204. Historical Versions were not checked; this is current-source overwrite, not a claim of irreversible deletion from Versions.
  • F3: the actual Journal route returned 201 for a Log create over a new-binary unsealed crash intent. Files recovery then returned unexpected content, and PATCH on the original ID returned 500. The acknowledged Log bytes were retained, but the intent remained unresumable. This reproduces the new-binary startup window through real Plugin handlers; no process kill was used.
  • Cross-User HEAD/PATCH/DELETE returned 404; same-ID simultaneous PATCH produced 204/404 and one file. Cross-Note retargeting via PATCH metadata cannot change the stored destination, but the extra metadata is ignored with 204 rather than explicitly refused.
  • The first default-rename server observation used an incomplete test fixture (it omitted the browser's Upload-Conflict-Policy: rename header), so the server's default fail policy returned 412. The untracked fixture was corrected to send the real browser header. Existing repository tests and expectations were not changed. The initial failed log is retained.

Probe completion

The corrected production-router observation suite passed all 7 cases. It reproduced both F1 variants (two Notes with the same original Log line, and a replacement that removes a later Log line from current bytes), F3 (Journal 201 followed by recovery failure and same-ID PATCH 500), and F4 (expiry does not release an active detached publisher's guard). The sealed-witness restart path preserved the later edit. Cross-User routes and simultaneous same-ID requests passed the isolation assertions. Retarget metadata was ignored, preserving the original Note destination.

The sync observation test passed: a dropped PATCH followed by HEAD 404 is classified as UploadExpired, which send_snapshot treats as a restart trigger. The original If-Match protects daemon bytes from destructive replay, but this does not satisfy the required same-ID retry contract.

The original seven timeouts remain unverified. This is an evidence limit, not proof that they completed or were permanently stuck. No new run can establish the terminal status of a deleted fixture's unidentified requests.

Untracked test sources were saved under artifacts/ and removed from the source tree after testing. No tracked source, test expectation, lockfile, branch ref or commit was changed. The reviewed head is unchanged. No merge/fetch was performed because this is the specifically requested read-only review of that exact head.

# jdrev findings — reviewed head 777730599b7752c1195530c35d962e1df077fa36 ## F1 — P1 — Lost successful final PATCH creates a new upload identity - Files: apps/web/src/lib/files/uploads.svelte.ts:414–424; crates/plugins/files/src/uploads.rs:2193 (terminal DELETE). - Scenario: server commits a final PATCH, deletes its upload row, and the response is dropped. Browser task records no destination. Resume sees HEAD 404, clears `location`, POSTs a new upload, and sends the same bytes again. Default `rename` installs a second Note; `replace` can capture the later destination revision and overwrite a later Log edit with the old client File. - Evidence: untracked jdrev-upload.svelte.test.ts reproduces POST u1 / PATCH u1 (lost response) / HEAD u1 404 / POST u2 / PATCH u2. All 17 tests passed, including the observation regression; existing tests were copied unchanged. Server side is being verified separately. - Suggested regression: complete and commit the real final PATCH, drop only its response, append a Log edit, then resume from the original tus URL. Assert no second POST, no second Note, and preservation of the later Log line. Retain a completed upload receipt bound to actor and destination, with a bounded retention policy, so completed and expired uploads are distinguishable. ## F2 — P2 — Seven historical timeouts have no retained completion evidence - Files: tests/adversarial/attack2.py:4388–4440; tests/adversarial/run.sh:108 (disposable fixture). - Scenario: `sync_upload` returns the same ('timeout', line) tuple for a timed-out GET, POST, or PATCH. It drops the tus location and request stage. The final check only rejects multiple occurrences of a timed-out paragraph, not zero occurrences. Thus 'seven timed-out uploads' need not mean seven admitted uploads, and zero copies can pass. - Evidence: prior report explicitly states completion was unverified and records cleanup of the server/build/fixture. No per-upload IDs or retained Index rows were saved. This cohort cannot be classified as eventually completed or stuck from the surviving evidence. - Suggested test: save stage, upload ID, full offset, and terminal result without credentials; after stopping new jobs, inspect each admitted ID and retry the same ID until a bounded terminal result (204/412/404 with completion proof). Distinguish pre-admission timeout from unfinished finalization. Preserve the fixture until every operation is classified. - Sync-side source evidence for F1: crates/calternal-sync/src/remote.rs:849 propagates HEAD 404 as `UploadExpired`; transfer.rs:158–162 automatically creates a new ID for that error. Its original If-Match stops a destructive replacement, but the same-ID contract still fails and may generate a spurious conflict copy. An observation probe through `RemoteClient` is queued. ## F3 — P1 — Crash recovery can race new Log edits before HTTP recovery runs - Files: crates/plugins/files/src/uploads.rs:451 and :2305; crates/calternal-server/src/wire.rs:1783, :2045 and :5852. - Scenario: even the new binary can be killed after source rename and before `complete_install` handles an error and writes the failure witness. On restart only reservations are restored before serving. `recover_installs` runs later, behind Search and Notes backfill. A Log edit in that interval changes the hash of the unsealed installed Note. Recovery returns `unexpected content`; PATCH retry returns 500. This is a new-binary crash path, not only legacy state from #1325. - Evidence: pre-serving startup calls `restore_upload_reservations`, not `recover_installs`; `/readyz` checks only a SELECT and system directory writability. Background Files reconciliation logs errors and continues. The unsealed/later-edit fixture is queued in the public Files integration test. The optional startup polling budget does not protect this boundary. - Suggested test: kill the new server immediately after rename without a sealed witness; restart, create/edit a Log entry before background Files reconciliation, and retry the persisted tus ID. Assert successful publication or a safe terminal receipt, no 500 and no skipped recovery. Recover these source-write intents before accepting Notes writes, or durably seal application at the source publication boundary. ## F4 — P2 — Active detached publication has no lease-enforced guard deadline - Files: crates/plugins/files/src/uploads.rs:1521–1532, :1710–1717 and :2364. - Scenario: a finalizer takes the Instance namespace mutex, then waits for a Notes writer. Dropping the request leaves it running. Expiring the upload row does not cancel it: cleanup waits on the same upload mutex. A stuck underlying writer/IO can therefore retain the namespace indefinitely. Ordinary abandoned partial uploads do have the documented 15-minute idle and 24-hour maximum lifetime; that is not a deadline for an active detached publisher. - Evidence: observation test `abandoned_finalizer_wait_is_not_bounded_by_upload_expiry` passed. It holds the Notes writer, aborts the request, expires the row, observes both cleanup and a namespace waiter blocked, then releases the Notes writer and observes publication release the namespace. No ordinary-operation permanent leak was demonstrated; this finding is lack of an enforced bound, not a claim that every slow upload is stuck. - Suggested test: block a finalizer before source IO and after durable rename, advance a fake clock through both lease limits, and assert a defined recovery handoff releases writer ownership safely without cancelling an active blocking rename or losing its witness. Do not fix this by putting an unsafe timeout around filesystem publication. ### Additional independent evidence - F1: the real production Files router accepted a new replacement upload after a lost success and a later edit. The test observed the current Note lose `^later`, while the server acknowledged the new PATCH with 204. Historical Versions were not checked; this is current-source overwrite, not a claim of irreversible deletion from Versions. - F3: the actual Journal route returned 201 for a Log create over a new-binary unsealed crash intent. Files recovery then returned `unexpected content`, and PATCH on the original ID returned 500. The acknowledged Log bytes were retained, but the intent remained unresumable. This reproduces the new-binary startup window through real Plugin handlers; no process kill was used. - Cross-User HEAD/PATCH/DELETE returned 404; same-ID simultaneous PATCH produced 204/404 and one file. Cross-Note retargeting via PATCH metadata cannot change the stored destination, but the extra metadata is ignored with 204 rather than explicitly refused. - The first default-rename server observation used an incomplete test fixture (it omitted the browser's `Upload-Conflict-Policy: rename` header), so the server's default fail policy returned 412. The untracked fixture was corrected to send the real browser header. Existing repository tests and expectations were not changed. The initial failed log is retained. ### Probe completion The corrected production-router observation suite passed all 7 cases. It reproduced both F1 variants (two Notes with the same original Log line, and a replacement that removes a later Log line from current bytes), F3 (Journal 201 followed by recovery failure and same-ID PATCH 500), and F4 (expiry does not release an active detached publisher's guard). The sealed-witness restart path preserved the later edit. Cross-User routes and simultaneous same-ID requests passed the isolation assertions. Retarget metadata was ignored, preserving the original Note destination. The sync observation test passed: a dropped PATCH followed by HEAD 404 is classified as `UploadExpired`, which `send_snapshot` treats as a restart trigger. The original If-Match protects daemon bytes from destructive replay, but this does not satisfy the required same-ID retry contract. The original seven timeouts remain unverified. This is an evidence limit, not proof that they completed or were permanently stuck. No new run can establish the terminal status of a deleted fixture's unidentified requests. Untracked test sources were saved under artifacts/ and removed from the source tree after testing. No tracked source, test expectation, lockfile, branch ref or commit was changed. The reviewed head is unchanged. No merge/fetch was performed because this is the specifically requested read-only review of that exact head.
Author
Owner

jdrev findings — reviewed head 777730599b

F1 — P1 — Lost successful final PATCH creates a new upload identity

  • Files: apps/web/src/lib/files/uploads.svelte.ts:414–424; crates/plugins/files/src/uploads.rs:2193 (terminal DELETE).
  • Scenario: server commits a final PATCH, deletes its upload row, and the response is dropped. Browser task records no destination. Resume sees HEAD 404, clears location, POSTs a new upload, and sends the same bytes again. Default rename installs a second Note; replace can capture the later destination revision and overwrite a later Log edit with the old client File.
  • Evidence: untracked jdrev-upload.svelte.test.ts reproduces POST u1 / PATCH u1 (lost response) / HEAD u1 404 / POST u2 / PATCH u2. All 17 tests passed, including the observation regression; existing tests were copied unchanged. Server side is being verified separately.
  • Suggested regression: complete and commit the real final PATCH, drop only its response, append a Log edit, then resume from the original tus URL. Assert no second POST, no second Note, and preservation of the later Log line. Retain a completed upload receipt bound to actor and destination, with a bounded retention policy, so completed and expired uploads are distinguishable.

F2 — P2 — Seven historical timeouts have no retained completion evidence

  • Files: tests/adversarial/attack2.py:4388–4440; tests/adversarial/run.sh:108 (disposable fixture).
  • Scenario: sync_upload returns the same ('timeout', line) tuple for a timed-out GET, POST, or PATCH. It drops the tus location and request stage. The final check only rejects multiple occurrences of a timed-out paragraph, not zero occurrences. Thus 'seven timed-out uploads' need not mean seven admitted uploads, and zero copies can pass.
  • Evidence: prior report explicitly states completion was unverified and records cleanup of the server/build/fixture. No per-upload IDs or retained Index rows were saved. This cohort cannot be classified as eventually completed or stuck from the surviving evidence.
  • Suggested test: save stage, upload ID, full offset, and terminal result without credentials; after stopping new jobs, inspect each admitted ID and retry the same ID until a bounded terminal result (204/412/404 with completion proof). Distinguish pre-admission timeout from unfinished finalization. Preserve the fixture until every operation is classified.
  • Sync-side source evidence for F1: crates/calternal-sync/src/remote.rs:849 propagates HEAD 404 as UploadExpired; transfer.rs:158–162 automatically creates a new ID for that error. Its original If-Match stops a destructive replacement, but the same-ID contract still fails and may generate a spurious conflict copy. An observation probe through RemoteClient is queued.

F3 — P1 — Crash recovery can race new Log edits before HTTP recovery runs

  • Files: crates/plugins/files/src/uploads.rs:451 and :2305; crates/calternal-server/src/wire.rs:1783, :2045 and :5852.
  • Scenario: even the new binary can be killed after source rename and before complete_install handles an error and writes the failure witness. On restart only reservations are restored before serving. recover_installs runs later, behind Search and Notes backfill. A Log edit in that interval changes the hash of the unsealed installed Note. Recovery returns unexpected content; PATCH retry returns 500. This is a new-binary crash path, not only legacy state from #1325.
  • Evidence: pre-serving startup calls restore_upload_reservations, not recover_installs; /readyz checks only a SELECT and system directory writability. Background Files reconciliation logs errors and continues. The unsealed/later-edit fixture is queued in the public Files integration test. The optional startup polling budget does not protect this boundary.
  • Suggested test: kill the new server immediately after rename without a sealed witness; restart, create/edit a Log entry before background Files reconciliation, and retry the persisted tus ID. Assert successful publication or a safe terminal receipt, no 500 and no skipped recovery. Recover these source-write intents before accepting Notes writes, or durably seal application at the source publication boundary.

F4 — P2 — Active detached publication has no lease-enforced guard deadline

  • Files: crates/plugins/files/src/uploads.rs:1521–1532, :1710–1717 and :2364.
  • Scenario: a finalizer takes the Instance namespace mutex, then waits for a Notes writer. Dropping the request leaves it running. Expiring the upload row does not cancel it: cleanup waits on the same upload mutex. A stuck underlying writer/IO can therefore retain the namespace indefinitely. Ordinary abandoned partial uploads do have the documented 15-minute idle and 24-hour maximum lifetime; that is not a deadline for an active detached publisher.
  • Evidence: observation test abandoned_finalizer_wait_is_not_bounded_by_upload_expiry passed. It holds the Notes writer, aborts the request, expires the row, observes both cleanup and a namespace waiter blocked, then releases the Notes writer and observes publication release the namespace. No ordinary-operation permanent leak was demonstrated; this finding is lack of an enforced bound, not a claim that every slow upload is stuck.
  • Suggested test: block a finalizer before source IO and after durable rename, advance a fake clock through both lease limits, and assert a defined recovery handoff releases writer ownership safely without cancelling an active blocking rename or losing its witness. Do not fix this by putting an unsafe timeout around filesystem publication.

Additional independent evidence

  • F1: the real production Files router accepted a new replacement upload after a lost success and a later edit. The test observed the current Note lose ^later, while the server acknowledged the new PATCH with 204. Historical Versions were not checked; this is current-source overwrite, not a claim of irreversible deletion from Versions.
  • F3: the actual Journal route returned 201 for a Log create over a new-binary unsealed crash intent. Files recovery then returned unexpected content, and PATCH on the original ID returned 500. The acknowledged Log bytes were retained, but the intent remained unresumable. This reproduces the new-binary startup window through real Plugin handlers; no process kill was used.
  • Cross-User HEAD/PATCH/DELETE returned 404; same-ID simultaneous PATCH produced 204/404 and one file. Cross-Note retargeting via PATCH metadata cannot change the stored destination, but the extra metadata is ignored with 204 rather than explicitly refused.
  • The first default-rename server observation used an incomplete test fixture (it omitted the browser's Upload-Conflict-Policy: rename header), so the server's default fail policy returned 412. The untracked fixture was corrected to send the real browser header. Existing repository tests and expectations were not changed. The initial failed log is retained.

Probe completion

The corrected production-router observation suite passed all 7 cases. It reproduced both F1 variants (two Notes with the same original Log line, and a replacement that removes a later Log line from current bytes), F3 (Journal 201 followed by recovery failure and same-ID PATCH 500), and F4 (expiry does not release an active detached publisher's guard). The sealed-witness restart path preserved the later edit. Cross-User routes and simultaneous same-ID requests passed the isolation assertions. Retarget metadata was ignored, preserving the original Note destination.

The sync observation test passed: a dropped PATCH followed by HEAD 404 is classified as UploadExpired, which send_snapshot treats as a restart trigger. The original If-Match protects daemon bytes from destructive replay, but this does not satisfy the required same-ID retry contract.

The original seven timeouts remain unverified. This is an evidence limit, not proof that they completed or were permanently stuck. No new run can establish the terminal status of a deleted fixture's unidentified requests.

Untracked test sources were saved under artifacts/ and removed from the source tree after testing. No tracked source, test expectation, lockfile, branch ref or commit was changed. The reviewed head is unchanged. No merge/fetch was performed because this is the specifically requested read-only review of that exact head.

F5 — P2 — Cross-Note retarget request is ignored, not refused

  • File: crates/plugins/files/src/uploads.rs:1374 (PATCH parses offset and loads the original destination, but does not check retargeting metadata).
  • Scenario: create an upload for Note A, then PATCH that ID with Upload-Metadata naming Note B. The response is 204 and the bytes go to Note A. Note B is untouched, so this is not a cross-User authorization hole or a demonstrated cross-Note destination change. It does not meet the brief's explicit requirement to refuse reuse across Notes.
  • Evidence: patch_metadata_cannot_retarget_the_upload_to_another_note passed as an observation test: it asserted the current 204 response and absence of Note B.
  • Suggested test: reuse Note A's upload ID with a conflicting destination binding, require a client error, and assert neither Note changes. Document and validate the caller's destination binding when resuming a saved tus URL, so a mismatched File cannot be applied to the original Note unnoticed.
# jdrev findings — reviewed head 777730599b7752c1195530c35d962e1df077fa36 ## F1 — P1 — Lost successful final PATCH creates a new upload identity - Files: apps/web/src/lib/files/uploads.svelte.ts:414–424; crates/plugins/files/src/uploads.rs:2193 (terminal DELETE). - Scenario: server commits a final PATCH, deletes its upload row, and the response is dropped. Browser task records no destination. Resume sees HEAD 404, clears `location`, POSTs a new upload, and sends the same bytes again. Default `rename` installs a second Note; `replace` can capture the later destination revision and overwrite a later Log edit with the old client File. - Evidence: untracked jdrev-upload.svelte.test.ts reproduces POST u1 / PATCH u1 (lost response) / HEAD u1 404 / POST u2 / PATCH u2. All 17 tests passed, including the observation regression; existing tests were copied unchanged. Server side is being verified separately. - Suggested regression: complete and commit the real final PATCH, drop only its response, append a Log edit, then resume from the original tus URL. Assert no second POST, no second Note, and preservation of the later Log line. Retain a completed upload receipt bound to actor and destination, with a bounded retention policy, so completed and expired uploads are distinguishable. ## F2 — P2 — Seven historical timeouts have no retained completion evidence - Files: tests/adversarial/attack2.py:4388–4440; tests/adversarial/run.sh:108 (disposable fixture). - Scenario: `sync_upload` returns the same ('timeout', line) tuple for a timed-out GET, POST, or PATCH. It drops the tus location and request stage. The final check only rejects multiple occurrences of a timed-out paragraph, not zero occurrences. Thus 'seven timed-out uploads' need not mean seven admitted uploads, and zero copies can pass. - Evidence: prior report explicitly states completion was unverified and records cleanup of the server/build/fixture. No per-upload IDs or retained Index rows were saved. This cohort cannot be classified as eventually completed or stuck from the surviving evidence. - Suggested test: save stage, upload ID, full offset, and terminal result without credentials; after stopping new jobs, inspect each admitted ID and retry the same ID until a bounded terminal result (204/412/404 with completion proof). Distinguish pre-admission timeout from unfinished finalization. Preserve the fixture until every operation is classified. - Sync-side source evidence for F1: crates/calternal-sync/src/remote.rs:849 propagates HEAD 404 as `UploadExpired`; transfer.rs:158–162 automatically creates a new ID for that error. Its original If-Match stops a destructive replacement, but the same-ID contract still fails and may generate a spurious conflict copy. An observation probe through `RemoteClient` is queued. ## F3 — P1 — Crash recovery can race new Log edits before HTTP recovery runs - Files: crates/plugins/files/src/uploads.rs:451 and :2305; crates/calternal-server/src/wire.rs:1783, :2045 and :5852. - Scenario: even the new binary can be killed after source rename and before `complete_install` handles an error and writes the failure witness. On restart only reservations are restored before serving. `recover_installs` runs later, behind Search and Notes backfill. A Log edit in that interval changes the hash of the unsealed installed Note. Recovery returns `unexpected content`; PATCH retry returns 500. This is a new-binary crash path, not only legacy state from #1325. - Evidence: pre-serving startup calls `restore_upload_reservations`, not `recover_installs`; `/readyz` checks only a SELECT and system directory writability. Background Files reconciliation logs errors and continues. The unsealed/later-edit fixture is queued in the public Files integration test. The optional startup polling budget does not protect this boundary. - Suggested test: kill the new server immediately after rename without a sealed witness; restart, create/edit a Log entry before background Files reconciliation, and retry the persisted tus ID. Assert successful publication or a safe terminal receipt, no 500 and no skipped recovery. Recover these source-write intents before accepting Notes writes, or durably seal application at the source publication boundary. ## F4 — P2 — Active detached publication has no lease-enforced guard deadline - Files: crates/plugins/files/src/uploads.rs:1521–1532, :1710–1717 and :2364. - Scenario: a finalizer takes the Instance namespace mutex, then waits for a Notes writer. Dropping the request leaves it running. Expiring the upload row does not cancel it: cleanup waits on the same upload mutex. A stuck underlying writer/IO can therefore retain the namespace indefinitely. Ordinary abandoned partial uploads do have the documented 15-minute idle and 24-hour maximum lifetime; that is not a deadline for an active detached publisher. - Evidence: observation test `abandoned_finalizer_wait_is_not_bounded_by_upload_expiry` passed. It holds the Notes writer, aborts the request, expires the row, observes both cleanup and a namespace waiter blocked, then releases the Notes writer and observes publication release the namespace. No ordinary-operation permanent leak was demonstrated; this finding is lack of an enforced bound, not a claim that every slow upload is stuck. - Suggested test: block a finalizer before source IO and after durable rename, advance a fake clock through both lease limits, and assert a defined recovery handoff releases writer ownership safely without cancelling an active blocking rename or losing its witness. Do not fix this by putting an unsafe timeout around filesystem publication. ### Additional independent evidence - F1: the real production Files router accepted a new replacement upload after a lost success and a later edit. The test observed the current Note lose `^later`, while the server acknowledged the new PATCH with 204. Historical Versions were not checked; this is current-source overwrite, not a claim of irreversible deletion from Versions. - F3: the actual Journal route returned 201 for a Log create over a new-binary unsealed crash intent. Files recovery then returned `unexpected content`, and PATCH on the original ID returned 500. The acknowledged Log bytes were retained, but the intent remained unresumable. This reproduces the new-binary startup window through real Plugin handlers; no process kill was used. - Cross-User HEAD/PATCH/DELETE returned 404; same-ID simultaneous PATCH produced 204/404 and one file. Cross-Note retargeting via PATCH metadata cannot change the stored destination, but the extra metadata is ignored with 204 rather than explicitly refused. - The first default-rename server observation used an incomplete test fixture (it omitted the browser's `Upload-Conflict-Policy: rename` header), so the server's default fail policy returned 412. The untracked fixture was corrected to send the real browser header. Existing repository tests and expectations were not changed. The initial failed log is retained. ### Probe completion The corrected production-router observation suite passed all 7 cases. It reproduced both F1 variants (two Notes with the same original Log line, and a replacement that removes a later Log line from current bytes), F3 (Journal 201 followed by recovery failure and same-ID PATCH 500), and F4 (expiry does not release an active detached publisher's guard). The sealed-witness restart path preserved the later edit. Cross-User routes and simultaneous same-ID requests passed the isolation assertions. Retarget metadata was ignored, preserving the original Note destination. The sync observation test passed: a dropped PATCH followed by HEAD 404 is classified as `UploadExpired`, which `send_snapshot` treats as a restart trigger. The original If-Match protects daemon bytes from destructive replay, but this does not satisfy the required same-ID retry contract. The original seven timeouts remain unverified. This is an evidence limit, not proof that they completed or were permanently stuck. No new run can establish the terminal status of a deleted fixture's unidentified requests. Untracked test sources were saved under artifacts/ and removed from the source tree after testing. No tracked source, test expectation, lockfile, branch ref or commit was changed. The reviewed head is unchanged. No merge/fetch was performed because this is the specifically requested read-only review of that exact head. ## F5 — P2 — Cross-Note retarget request is ignored, not refused - File: crates/plugins/files/src/uploads.rs:1374 (PATCH parses offset and loads the original destination, but does not check retargeting metadata). - Scenario: create an upload for Note A, then PATCH that ID with Upload-Metadata naming Note B. The response is 204 and the bytes go to Note A. Note B is untouched, so this is not a cross-User authorization hole or a demonstrated cross-Note destination change. It does not meet the brief's explicit requirement to refuse reuse across Notes. - Evidence: `patch_metadata_cannot_retarget_the_upload_to_another_note` passed as an observation test: it asserted the current 204 response and absence of Note B. - Suggested test: reuse Note A's upload ID with a conflicting destination binding, require a client error, and assert neither Note changes. Document and validate the caller's destination binding when resuming a saved tus URL, so a mismatched File cannot be applied to the original Note unnoticed.
Author
Owner

jdrev read-only defensive review of job/journaldup, issue #1295 and the #1202 retry contract.

Head: 777730599b. Base: 3601719b80. The branch and tracked files are unchanged. No edits to tracked files, commits, pushes, merges, or deploys were made.

Built: temporary, untracked observation probes through the production Files and Notes Plugin routers, the public sync transport, the browser upload queue, and the runner's startup loop. Probe sources and logs are retained in artifacts/. Passing observation probes reproduce the listed bugs; they do not mean the contract is safe.

Blocking findings:

  • F1, P1 — apps/web/src/lib/files/uploads.svelte.ts:414; crates/plugins/files/src/uploads.rs:2193; crates/calternal-sync/src/remote.rs:849 and transfer.rs:158. A successful final PATCH deletes the retry row before sending its response. If that response is dropped, HEAD returns 404. Browser resume creates another ID: the real Files router produced two indexed Notes with the same Log line under rename, and a new replacement removed a later Log line from the current Note. The sync transport also classifies this dropped-success HEAD 404 as UploadExpired; send_snapshot restarts the ID. Its original If-Match limits destructive daemon replay, but the same-ID contract still fails. Add a bounded, actor- and Note-bound completed receipt and a lost-success regression.
  • F3, P1 — crates/plugins/files/src/uploads.rs:451 and :2305; crates/calternal-server/src/wire.rs:1783, :2045, :5852. A new-binary crash after rename can leave an unsealed intent. Only reservations are restored before HTTP; Files recovery runs later, after Notes backfills and Search. The actual Journal handler acknowledged a create with 201 over a modelled crash intent; recovery then returned unexpected content and the original-ID retry returned 500. The acknowledged bytes survived, but publication stayed stuck. This extends the legacy concern in #1325 to a current-binary crash/startup window. Recover source-write intents before accepting conflicting writes, or seal application durably at publication.

Follow-ups:

  • F2, P2 — tests/adversarial/attack2.py:4388. The seven historical timeouts cannot be classified as complete or stuck. GET, POST and PATCH timeouts share one result shape; IDs/stages were not retained, and the fixture was deleted. Three uploads were reported complete. Preserve stage/ID/terminal proof and classify each admitted upload before fixture cleanup.
  • F4, P2 — crates/plugins/files/src/uploads.rs:1521, :1710, :2364. An active detached finalizer has no lease-enforced guard deadline. With the Notes writer held, request cancellation and row expiry left the Instance namespace and cleanup blocked until that writer was released. Partial abandoned uploads have the normal 15-minute/24-hour expiry; this is not a bound on active finalization. No normal-operation permanent leak was demonstrated. Test a safe recovery handoff rather than cancelling an active rename.
  • F5, P2 — crates/plugins/files/src/uploads.rs:1374. Conflicting PATCH destination metadata receives 204 and is ignored. The original Note is used and the other Note is untouched, but the brief's explicit refusal requirement is unmet. Validate a conflicting resume destination binding and test that neither Note changes.
  • F6, P2 — tests/adversarial/run.sh:280 and :289. Startup override bounds polls, not elapsed time: curl has no timeout. One slow mocked readiness call outlived an external 1-second deadline with a one-poll budget. Add per-probe timeouts and a total deadline. Defaults remain 120 polls; invalid overrides are refused and final readiness is still required. Readiness does not certify Files recovery completion; recovery failures are logged and startup continues.

Passing areas: all six existing Journal upload regressions passed, including writer ownership across request cancellation, same-ID busy retry, stale precondition refusal and sealed-witness preservation of a later edit. Cross-User HEAD/PATCH/DELETE returned 404. Simultaneous same-ID PATCH returned 204/404 and installed one file. Sealed-witness recovery kept later source bytes. All ordinary idle/lifetime expiry tests passed.

Files: artifacts/jdrev-findings.md; jdrev-rust-probes.rs; jdrev-sync-probes.rs; jdrev-upload.svelte.test.ts; jdrev-startup-budget.sh; jdrev-startup-stall.sh; and the jdrev-*.log evidence files. Temporary test files in source directories were removed after execution.

Gate output (verbatim result lines):

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

cargo test -p calternal-sync -- --test-threads=4:

test result: ok. 65 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 4.37s
test result: ok. 2 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 test -p calternal-plugin-files --lib -- --test-threads=4:

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

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

test result: ok. 314 passed; 0 failed; 4 ignored; 0 measured; 0 filtered out; finished in 457.47s
test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 3.43s
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

Focused Files observation probes:

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

Focused sync observation probe:

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

cd apps/web && bunx vitest run src/lib/files/jdrev-upload.svelte.test.ts --maxWorkers=2:

 Test Files  1 passed (1)
      Tests  17 passed (17)

Startup shell checks:

PASS default: 120 polls; final readiness fails; health diagnostics run
PASS override: 360 polls; final readiness still fails
PASS ready response: exits the loop and verifies readiness again
PASS invalid budgets: refused
PASS observation: one startup poll remained blocked past the external 1-second deadline

Known gaps: no production fixes under this read-only brief. The original seven timeouts remain unverified. Crash testing used durable-row/source fixtures and real Plugin handlers, not an actual process kill or full two-daemon campaign. Historical Versions were not checked in the current-source overwrite probe; this report does not claim irreversible deletion from Versions. Full server startup, clippy, full web checks, e2e and release builds were not run by this source review.

Review runner notes: one initial observation fixture omitted the browser's rename header and got 412; only that new untracked fixture was corrected. Existing expectations were unchanged. The first sync test shell wrapper used a reserved zsh variable after Cargo completed; the wrapper was corrected and the final sync command exited 0. Initial logs are retained.

Decisions: no product design choices. Preserve the supplied exact head instead of applying the generic merge/commit workflow, because this brief explicitly requires a read-only review. No new dependency or user-visible operation was added. UX gaps closed: none; UX gaps left: F1's duplicated/replaced current Note and incomplete retry confirmation.

Cleanup (verbatim):

Removed 8907 files, 8.9GiB total

Web build output was removed. The worktree is clean and the head is unchanged.

BLOCK

jdrev read-only defensive review of job/journaldup, issue #1295 and the #1202 retry contract. Head: 777730599b7752c1195530c35d962e1df077fa36. Base: 3601719b80a39f712daf07b37879b22929dfffa0. The branch and tracked files are unchanged. No edits to tracked files, commits, pushes, merges, or deploys were made. Built: temporary, untracked observation probes through the production Files and Notes Plugin routers, the public sync transport, the browser upload queue, and the runner's startup loop. Probe sources and logs are retained in artifacts/. Passing observation probes reproduce the listed bugs; they do not mean the contract is safe. Blocking findings: - F1, P1 — apps/web/src/lib/files/uploads.svelte.ts:414; crates/plugins/files/src/uploads.rs:2193; crates/calternal-sync/src/remote.rs:849 and transfer.rs:158. A successful final PATCH deletes the retry row before sending its response. If that response is dropped, HEAD returns 404. Browser resume creates another ID: the real Files router produced two indexed Notes with the same Log line under rename, and a new replacement removed a later Log line from the current Note. The sync transport also classifies this dropped-success HEAD 404 as UploadExpired; send_snapshot restarts the ID. Its original If-Match limits destructive daemon replay, but the same-ID contract still fails. Add a bounded, actor- and Note-bound completed receipt and a lost-success regression. - F3, P1 — crates/plugins/files/src/uploads.rs:451 and :2305; crates/calternal-server/src/wire.rs:1783, :2045, :5852. A new-binary crash after rename can leave an unsealed intent. Only reservations are restored before HTTP; Files recovery runs later, after Notes backfills and Search. The actual Journal handler acknowledged a create with 201 over a modelled crash intent; recovery then returned unexpected content and the original-ID retry returned 500. The acknowledged bytes survived, but publication stayed stuck. This extends the legacy concern in #1325 to a current-binary crash/startup window. Recover source-write intents before accepting conflicting writes, or seal application durably at publication. Follow-ups: - F2, P2 — tests/adversarial/attack2.py:4388. The seven historical timeouts cannot be classified as complete or stuck. GET, POST and PATCH timeouts share one result shape; IDs/stages were not retained, and the fixture was deleted. Three uploads were reported complete. Preserve stage/ID/terminal proof and classify each admitted upload before fixture cleanup. - F4, P2 — crates/plugins/files/src/uploads.rs:1521, :1710, :2364. An active detached finalizer has no lease-enforced guard deadline. With the Notes writer held, request cancellation and row expiry left the Instance namespace and cleanup blocked until that writer was released. Partial abandoned uploads have the normal 15-minute/24-hour expiry; this is not a bound on active finalization. No normal-operation permanent leak was demonstrated. Test a safe recovery handoff rather than cancelling an active rename. - F5, P2 — crates/plugins/files/src/uploads.rs:1374. Conflicting PATCH destination metadata receives 204 and is ignored. The original Note is used and the other Note is untouched, but the brief's explicit refusal requirement is unmet. Validate a conflicting resume destination binding and test that neither Note changes. - F6, P2 — tests/adversarial/run.sh:280 and :289. Startup override bounds polls, not elapsed time: curl has no timeout. One slow mocked readiness call outlived an external 1-second deadline with a one-poll budget. Add per-probe timeouts and a total deadline. Defaults remain 120 polls; invalid overrides are refused and final readiness is still required. Readiness does not certify Files recovery completion; recovery failures are logged and startup continues. Passing areas: all six existing Journal upload regressions passed, including writer ownership across request cancellation, same-ID busy retry, stale precondition refusal and sealed-witness preservation of a later edit. Cross-User HEAD/PATCH/DELETE returned 404. Simultaneous same-ID PATCH returned 204/404 and installed one file. Sealed-witness recovery kept later source bytes. All ordinary idle/lifetime expiry tests passed. Files: artifacts/jdrev-findings.md; jdrev-rust-probes.rs; jdrev-sync-probes.rs; jdrev-upload.svelte.test.ts; jdrev-startup-budget.sh; jdrev-startup-stall.sh; and the jdrev-*.log evidence files. Temporary test files in source directories were removed after execution. Gate output (verbatim result lines): cargo fmt --check: no output, exit 0. cargo test -p calternal-sync -- --test-threads=4: ```text test result: ok. 65 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 4.37s test result: ok. 2 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 test -p calternal-plugin-files --lib -- --test-threads=4: ```text test result: ok. 266 passed; 0 failed; 4 ignored; 0 measured; 0 filtered out; finished in 240.97s ``` cargo test -p calternal-plugin-notes -- --test-threads=4: ```text test result: ok. 314 passed; 0 failed; 4 ignored; 0 measured; 0 filtered out; finished in 457.47s test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 3.43s test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s ``` Focused Files observation probes: ```text test result: ok. 7 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 11.76s ``` Focused sync observation probe: ```text test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s ``` cd apps/web && bunx vitest run src/lib/files/jdrev-upload.svelte.test.ts --maxWorkers=2: ```text Test Files 1 passed (1) Tests 17 passed (17) ``` Startup shell checks: ```text PASS default: 120 polls; final readiness fails; health diagnostics run PASS override: 360 polls; final readiness still fails PASS ready response: exits the loop and verifies readiness again PASS invalid budgets: refused PASS observation: one startup poll remained blocked past the external 1-second deadline ``` Known gaps: no production fixes under this read-only brief. The original seven timeouts remain unverified. Crash testing used durable-row/source fixtures and real Plugin handlers, not an actual process kill or full two-daemon campaign. Historical Versions were not checked in the current-source overwrite probe; this report does not claim irreversible deletion from Versions. Full server startup, clippy, full web checks, e2e and release builds were not run by this source review. Review runner notes: one initial observation fixture omitted the browser's rename header and got 412; only that new untracked fixture was corrected. Existing expectations were unchanged. The first sync test shell wrapper used a reserved zsh variable after Cargo completed; the wrapper was corrected and the final sync command exited 0. Initial logs are retained. Decisions: no product design choices. Preserve the supplied exact head instead of applying the generic merge/commit workflow, because this brief explicitly requires a read-only review. No new dependency or user-visible operation was added. UX gaps closed: none; UX gaps left: F1's duplicated/replaced current Note and incomplete retry confirmation. Cleanup (verbatim): ```text Removed 8907 files, 8.9GiB total ``` Web build output was removed. The worktree is clean and the head is unchanged. BLOCK
Author
Owner

journaldup3 started on job/journaldup at 777730599b (base 3601719b80). Read the independent BLOCK findings. Fixing durable completion receipts, pre-serving recovery, finalizer deadlines, destination refusal and retained timeout evidence. No push or deploy.

journaldup3 started on job/journaldup at 777730599b7752c1195530c35d962e1df077fa36 (base 3601719b80a39f712daf07b37879b22929dfffa0). Read the independent BLOCK findings. Fixing durable completion receipts, pre-serving recovery, finalizer deadlines, destination refusal and retained timeout evidence. No push or deploy.
Author
Owner

Finding confirmed: final PATCH currently retires its tus key, and source-write recovery currently waits until after HTTP bind. Added actor/destination-bound completion receipts and pre-serving install recovery; all three focused production-router regressions pass. Added a 60-second detached finalizer deadline with a synchronous post-rename Note witness, plus pre-write/post-rename guard regressions. Probe fix committed as e3f27871f: real stalled-peer startup regression passes; timeout classifier retains stage, ID, offset and terminal proof and preserves unresolved fixtures. Testing regressions against reviewed head 777730599 next, then restoring fixes for final gates and a live journalrace round.

Finding confirmed: final PATCH currently retires its tus key, and source-write recovery currently waits until after HTTP bind. Added actor/destination-bound completion receipts and pre-serving install recovery; all three focused production-router regressions pass. Added a 60-second detached finalizer deadline with a synchronous post-rename Note witness, plus pre-write/post-rename guard regressions. Probe fix committed as e3f27871f: real stalled-peer startup regression passes; timeout classifier retains stage, ID, offset and terminal proof and preserves unresolved fixtures. Testing regressions against reviewed head 777730599 next, then restoring fixes for final gates and a live journalrace round.
Author
Owner

Implementation progress: 43277971c retains completed tus identities and finishes upload source intents before HTTP serving. e3f27871f bounds startup HTTP probes and retains timeout evidence; 8d739d033 also settles a pending 503 under the original ID.

Regression evidence: the three production-router tests all fail on 777730599 and pass with the fix. The pre-write guard deadline fails on that head. Both current deadline tests pass (2 passed, 270 filtered out). The baseline post-rename probe had no deadline and needed SIGTERM; the current test now also has an external six-second assertion. The real stalled HTTP peer exceeds six seconds on 777730599 and returns within five seconds with the fix.

Decisions: completed receipts last 24 h after completion, outside live upload slots; their insert and live-row retirement use one FULL transaction because receipt loss could authorize replay. Detached finalization gets at most 60 s, capped by the original lease. Note proof is sealed synchronously before the first post-rename await. Cancellation cannot interrupt the synchronous rename/fsync region; a blocked kernel call cannot be preempted by this async deadline. Applied intents recover before expired staging cleanup. Conflicting resume metadata returns 400.

The final fetch/merge of origin/dev was already up to date. Files migration 29 is free there. Final gates and the live SIGKILL/journalrace probes are in progress. The original seven historical timeouts remain unclassifiable because their IDs and fixture were deleted; the new cohort will retain stage, ID, offset and terminal evidence.

Implementation progress: 43277971c retains completed tus identities and finishes upload source intents before HTTP serving. e3f27871f bounds startup HTTP probes and retains timeout evidence; 8d739d033 also settles a pending 503 under the original ID. Regression evidence: the three production-router tests all fail on 777730599 and pass with the fix. The pre-write guard deadline fails on that head. Both current deadline tests pass (2 passed, 270 filtered out). The baseline post-rename probe had no deadline and needed SIGTERM; the current test now also has an external six-second assertion. The real stalled HTTP peer exceeds six seconds on 777730599 and returns within five seconds with the fix. Decisions: completed receipts last 24 h after completion, outside live upload slots; their insert and live-row retirement use one FULL transaction because receipt loss could authorize replay. Detached finalization gets at most 60 s, capped by the original lease. Note proof is sealed synchronously before the first post-rename await. Cancellation cannot interrupt the synchronous rename/fsync region; a blocked kernel call cannot be preempted by this async deadline. Applied intents recover before expired staging cleanup. Conflicting resume metadata returns 400. The final fetch/merge of origin/dev was already up to date. Files migration 29 is free there. Final gates and the live SIGKILL/journalrace probes are in progress. The original seven historical timeouts remain unclassifiable because their IDs and fixture were deleted; the new cohort will retain stage, ID, offset and terminal evidence.
Author
Owner

journaldup3 gate findings:

  • The existing cancellation regression expected concurrent retry 404 after publication. #1295 F1 explicitly changes this to 204 from the durable receipt; the test now checks the result item ID and retains its writer-guard, source-byte and inode assertions. The migration count changes 28 to 29 for the added receipt table.
  • HEAD for an expired pending install now reads only the Index; source proof remains under publication/recovery guards.
  • Exact upload performance pins and the matching adoption checkpoint are refreshed. New exact call bindings describe Index primary-key reads and pure decoding, backed by the production-router regressions. Removed exceptions reduce the ratchet from 22548 to 22529; no rule or ceiling is weakened.
  • Files Clippy passes. Full crate tests, server gates, web check and full web tests are in progress.
journaldup3 gate findings: - The existing cancellation regression expected concurrent retry 404 after publication. #1295 F1 explicitly changes this to 204 from the durable receipt; the test now checks the result item ID and retains its writer-guard, source-byte and inode assertions. The migration count changes 28 to 29 for the added receipt table. - HEAD for an expired pending install now reads only the Index; source proof remains under publication/recovery guards. - Exact upload performance pins and the matching adoption checkpoint are refreshed. New exact call bindings describe Index primary-key reads and pure decoding, backed by the production-router regressions. Removed exceptions reduce the ratchet from 22548 to 22529; no rule or ceiling is weakened. - Files Clippy passes. Full crate tests, server gates, web check and full web tests are in progress.
Author
Owner

journaldup4 resumes on job/journaldup at c8a00d48dc. Reviewing interrupted source and exact perf-contract changes, then running regression, SIGKILL recovery, journalrace and required gates. No push, deploy or merge in this continuation.

journaldup4 resumes on job/journaldup at c8a00d48dc06aa0ede5112526bc24e42ff6e06d3. Reviewing interrupted source and exact perf-contract changes, then running regression, SIGKILL recovery, journalrace and required gates. No push, deploy or merge in this continuation.
Author
Owner

journaldup4 findings at f631c154a:

  • The interrupted perf refresh checked server source-call rules, but not API coverage. It removed nine still-required contract pins. Restore those original exact entries with current hashes; do not seed new debt or increase the original ratchet.
  • The stalled-peer startup regression exceeded its unchanged five-second assertion twice on the shared host. The runner repeated readiness after the polling budget. f631c154a returns on successful polling and runs only the bounded health diagnostic on timeout. The same regression now prints PASS startup: stalled readiness and diagnostics return within 5 seconds.
  • Retargeting regression now checks that both the original destination and the requested other destination remain unchanged after a refused HEAD/PATCH, before and after completion.
  • git fetch origin completed. Files migration 29 is free in origin/dev. The final job instruction prohibits merges, so this continuation leaves integration to the orchestrator.
journaldup4 findings at f631c154a: - The interrupted perf refresh checked server source-call rules, but not API coverage. It removed nine still-required contract pins. Restore those original exact entries with current hashes; do not seed new debt or increase the original ratchet. - The stalled-peer startup regression exceeded its unchanged five-second assertion twice on the shared host. The runner repeated readiness after the polling budget. f631c154a returns on successful polling and runs only the bounded health diagnostic on timeout. The same regression now prints `PASS startup: stalled readiness and diagnostics return within 5 seconds`. - Retargeting regression now checks that both the original destination and the requested other destination remain unchanged after a refused HEAD/PATCH, before and after completion. - `git fetch origin` completed. Files migration 29 is free in origin/dev. The final job instruction prohibits merges, so this continuation leaves integration to the orchestrator.
Author
Owner

Fresh Files crate output resolves the five named review regressions:

test tests::journal_deadline::journal_deadline_hands_off_applied_note_without_replay ... ok
test tests::journal_deadline::journal_deadline_releases_pre_write_guards ... ok
test tests::journal_retry::retarget_metadata_is_refused_before_and_after_completion ... ok
test tests::journal_retry::lost_success_receipt_preserves_later_log_and_one_note ... ok
test tests::journal_retry::startup_recovery_precedes_log_and_retains_original_retry ... ok

The changed concurrent-retry expectation also passes:
test tests::journal_upload_cancelled_request_keeps_publication_guards ... ok.
The full crate run and live crash/race counts remain in progress.

Fresh Files crate output resolves the five named review regressions: ``` test tests::journal_deadline::journal_deadline_hands_off_applied_note_without_replay ... ok test tests::journal_deadline::journal_deadline_releases_pre_write_guards ... ok test tests::journal_retry::retarget_metadata_is_refused_before_and_after_completion ... ok test tests::journal_retry::lost_success_receipt_preserves_later_log_and_one_note ... ok test tests::journal_retry::startup_recovery_precedes_log_and_retains_original_retry ... ok ``` The changed concurrent-retry expectation also passes: `test tests::journal_upload_cancelled_request_keeps_publication_guards ... ok`. The full crate run and live crash/race counts remain in progress.
Author
Owner

Schema-upgrade finding in the required server gate: 269 passed, 3 failed, 12 ignored. A focused isolated rerun reproduced the same three failures. Each is exactly the missing Files migration 29 introduced by #1295: the round-9 pending vector omits 29, the 7b count is 22 instead of 23, and the 7c history delta is 14 instead of 15.

Minimal test-only scope addition: crates/calternal-server/src/upgrade_tests.rs now requires Files 29 in the explicit pending sets, increases the affected migration counts by exactly one, updates the comments, and asserts the new receipt table contains zero invented completed uploads after upgrade. Production fixtures, old SQL/checksums, preserved User rows and old-receipt equality checks are unchanged. These expectation changes are required by the issue's new schema; no unrelated expectation is relaxed.

The focused upgrade suite and server Clippy will run on the corrected test file. The full server suite will not be repeated. The separate Files deadline/worker failures remain tracked in #1342.

Schema-upgrade finding in the required server gate: 269 passed, 3 failed, 12 ignored. A focused isolated rerun reproduced the same three failures. Each is exactly the missing Files migration 29 introduced by #1295: the round-9 pending vector omits 29, the 7b count is 22 instead of 23, and the 7c history delta is 14 instead of 15. Minimal test-only scope addition: `crates/calternal-server/src/upgrade_tests.rs` now requires Files 29 in the explicit pending sets, increases the affected migration counts by exactly one, updates the comments, and asserts the new receipt table contains zero invented completed uploads after upgrade. Production fixtures, old SQL/checksums, preserved User rows and old-receipt equality checks are unchanged. These expectation changes are required by the issue's new schema; no unrelated expectation is relaxed. The focused upgrade suite and server Clippy will run on the corrected test file. The full server suite will not be repeated. The separate Files deadline/worker failures remain tracked in #1342.
Author
Owner

journaldup4 finished on job/journaldup, head 4ed17d8452c2d4f6cc62a6c2a38b44d4e27c6cbd. No push, deploy or merge. The worktree is clean.

Built: completed the interrupted upload retry changes. HEAD now checks an expired pending install from the Index only. HEAD and PATCH refuse a different destination with 400. Source proof is sealed only after produced bytes match. The enabled production-router tests prove one Note and preservation of a later Log edit. Exact perf bindings describe bounded Index reads and in-memory name validation. No new broad exception or raised limit was added. The ratchet is 22,538, down from 22,548.

Files:

  • crates/plugins/files/src/lib.rs and src/uploads.rs.
  • crates/plugins/files/tests/journal_retry.rs moved to crates/plugins/files/src/tests/journal_retry.rs.
  • crates/plugins/files/kill_stress.py.
  • crates/calternal-server/src/upgrade_tests.rs: minimal test-only scope addition for migration 29.
  • tests/adversarial/run.sh and tests/adversarial/journal_finalize_crash.py.
  • contracts/perf/registry.json, exceptions.json, ratchet.json, and adoption-1058.json.

Commits in this continuation: f631c154a, b50bdfffa, b328df302, 13d6b4155, 0e893c95b, 4ed17d845. No dependency version was changed. Cargo used the preset target /home/kayg/build/targets/journaldup4; /mnt/hdd/targets/jobs/journaldup points to it.

Review results:

  • F1: both rename and replace policies retain the original retry ID, one Note, and later Log bytes. Concurrent cancellation/retry returns the completion receipt.
  • F2: the classifier tests keep admission stage, upload ID, offset and terminal proof. An unresolved ID keeps its fixture. The new live cohort has zero timeouts; the old seven remain unknown because their IDs and fixture were deleted.
  • F3: valid unsealed intents complete before Notes writes. The startup regression passes. The real server was killed after source rename with a live intent and no completion receipt, then restarted.
  • F4: both deadline regressions pass: release before source write and safe handoff after rename.
  • F5: retarget HEAD/PATCH returns 400 before and after completion. The original Note is unchanged and the other Note is absent.
  • F6: the unchanged stalled-peer regression passes within five seconds. The crash fixture's startup loop refused an unanswered peer in 1.254 seconds with a one-second polling budget.

Live reliability output, verbatim:

PASS SIGKILL mid-finalize: 1 crash, 1 later Log, 1 same-ID retry, 1 Note, 0 duplicate Notes; bytes preserved
journalrace: 2021-03-14: 6 seeds, 40 creates answered 201, 0 timed out (0 of them landed), 10 uploads, 46 entries
server alive at end: True
==== ROUND 2 FINDINGS 0
==== ROUND 2 SLOW 0

The crash Note was 1,520,045 bytes. Both Log lines occur once. A same-ID retry preserves all later bytes.

Gate output summaries below are verbatim. Complete logs are in this worktree's artifacts/jd4-* files.

  1. cd apps/web && bun run build — exit 0:
✓ built in 2m 32s
✓ built in 1.33s
✓ built in 6m 36s
Compressed 917 static variants; saved 21486154 bytes.
  1. cargo fmt --check — exit 0, no output. The check after the final doc-only commit also exits 0 with no output.
  2. cargo clippy -p calternal-plugin-files --all-targets -- -D warnings — exit 0:
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 2m 04s

cargo test -p calternal-plugin-files -- --test-threads=4 — exit 101:

test result: FAILED. 267 passed; 4 failed; 4 ignored; 0 measured; 0 filtered out; finished in 760.86s
error: test failed, to rerun pass `-p calternal-plugin-files --lib`

All five named Journal regressions and the changed concurrent-retry test passed. The four unrelated failures are filed at kayg/calternal#1342. No existing password or storm expectation was changed. In isolation the attempt-cap and parallel-password cases pass; the two-second rejection timeout still fails. The storm exceeded its existing five-minute bound.

cargo clippy -p calternal-server --all-targets -- -D warnings — exit 0. The check after the upgrade-test correction also exits 0:

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

cargo test -p calternal-server -- --test-threads=4 before the upgrade-test correction — exit 101:

test result: FAILED. 269 passed; 3 failed; 12 ignored; 0 measured; 0 filtered out; finished in 293.92s
error: test failed, to rerun pass `-p calternal-server --bin calternal-server`

Those three failures were exactly the omitted migration 29. The corrected pins add one pending receipt and one to each affected count, and require an empty completion table after upgrade. Old fixture SQL, checksums, receipt equality and User-data checks are unchanged. This expectation change follows #1295's new schema.

cargo test -p calternal-server wire::upgrade_tests -- --test-threads=4 after correction — exit 0:

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

The full server suite was not repeated. cargo build -p calternal-server exits 0.

  1. cd apps/web && bun run check — exit 0:
perf-lint: PASS; 0 violations; 22538 scoped exceptions
svelte-check found 0 errors and 1 warning in 1 file
  1. cd apps/web && bun run test --maxWorkers=2 — exit 0:
 Test Files  287 passed (287)
      Tests  2036 passed (2036)
   Duration  364.68s (transform 33%, environment 25%, import 21%, tests 16%, setup 5%)

Decisions: completed receipts last 24 h after completion and use no active upload slot. Receipt insertion and live-row retirement use one FULL transaction. Applied pending intents keep the retry identity after lease expiry. Detached finalization gets at most 60 s, capped by the lease. A Note's applied witness is sealed before the first post-rename await. Startup recovers source intents before accepting Notes writes and refuses ambiguous bytes. Conflicting destination metadata returns 400. Readiness returns on its first successful poll instead of sending another readiness call after timeout.

Expected cost: HEAD and completed retries read one actor-bound Index row by primary key. Metadata validation uses bounded in-memory names. New publication streams one file and updates its existing projections. A completed retry writes no source bytes and does not scan a Home. This reliability job ran no benchmark, as required by the current verification policy.

UX gaps closed: silent retargeting and replay after a lost success. No UI layout or visible control changed; no new screenshot set applies.

Known gaps / UX gaps left: the historical seven timeouts cannot be reconstructed. An async deadline cannot preempt a blocked kernel call in synchronous rename/fsync. The full Files gate still has four failures on #1342; this report does not claim all gates are green. Web check has one existing empty-CSS-rule warning.

For the merge round:

  • Integrate origin/dev once in the orchestrator's own worktree and check migration 29 is still free. This job fetched origin/dev once; migration 29 was free there. It did not merge because the final job instruction forbids merges.
  • cargo test -p calternal-plugin-files -- --test-threads=4: resolve or classify #1342 and confirm the full crate gate.
  • cargo test -p calternal-server -- --test-threads=4: confirm the corrected upgrade pins in the combined full suite.
  • cd apps/web && bun run test --maxWorkers=2, bun run test:e2e, and bash tests/adversarial/run.sh: check the combined web, protocol and cross-plugin changes. The job's focused crash and journalrace scenarios already ran to completion; they are not deferred.
  • Run the deployed/o2 checks before promotion. This job did not deploy.

Cleanup:

     Removed 19433 files, 16.0GiB total

Generated apps/web/build and apps/web/.svelte-kit/output were removed. No review artifact is committed.

journaldup4 finished on `job/journaldup`, head `4ed17d8452c2d4f6cc62a6c2a38b44d4e27c6cbd`. No push, deploy or merge. The worktree is clean. Built: completed the interrupted upload retry changes. HEAD now checks an expired pending install from the Index only. HEAD and PATCH refuse a different destination with 400. Source proof is sealed only after produced bytes match. The enabled production-router tests prove one Note and preservation of a later Log edit. Exact perf bindings describe bounded Index reads and in-memory name validation. No new broad exception or raised limit was added. The ratchet is 22,538, down from 22,548. Files: - `crates/plugins/files/src/lib.rs` and `src/uploads.rs`. - `crates/plugins/files/tests/journal_retry.rs` moved to `crates/plugins/files/src/tests/journal_retry.rs`. - `crates/plugins/files/kill_stress.py`. - `crates/calternal-server/src/upgrade_tests.rs`: minimal test-only scope addition for migration 29. - `tests/adversarial/run.sh` and `tests/adversarial/journal_finalize_crash.py`. - `contracts/perf/registry.json`, `exceptions.json`, `ratchet.json`, and `adoption-1058.json`. Commits in this continuation: `f631c154a`, `b50bdfffa`, `b328df302`, `13d6b4155`, `0e893c95b`, `4ed17d845`. No dependency version was changed. Cargo used the preset target `/home/kayg/build/targets/journaldup4`; `/mnt/hdd/targets/jobs/journaldup` points to it. Review results: - F1: both rename and replace policies retain the original retry ID, one Note, and later Log bytes. Concurrent cancellation/retry returns the completion receipt. - F2: the classifier tests keep admission stage, upload ID, offset and terminal proof. An unresolved ID keeps its fixture. The new live cohort has zero timeouts; the old seven remain unknown because their IDs and fixture were deleted. - F3: valid unsealed intents complete before Notes writes. The startup regression passes. The real server was killed after source rename with a live intent and no completion receipt, then restarted. - F4: both deadline regressions pass: release before source write and safe handoff after rename. - F5: retarget HEAD/PATCH returns 400 before and after completion. The original Note is unchanged and the other Note is absent. - F6: the unchanged stalled-peer regression passes within five seconds. The crash fixture's startup loop refused an unanswered peer in 1.254 seconds with a one-second polling budget. Live reliability output, verbatim: ``` PASS SIGKILL mid-finalize: 1 crash, 1 later Log, 1 same-ID retry, 1 Note, 0 duplicate Notes; bytes preserved journalrace: 2021-03-14: 6 seeds, 40 creates answered 201, 0 timed out (0 of them landed), 10 uploads, 46 entries server alive at end: True ==== ROUND 2 FINDINGS 0 ==== ROUND 2 SLOW 0 ``` The crash Note was 1,520,045 bytes. Both Log lines occur once. A same-ID retry preserves all later bytes. Gate output summaries below are verbatim. Complete logs are in this worktree's `artifacts/jd4-*` files. 1. `cd apps/web && bun run build` — exit 0: ``` ✓ built in 2m 32s ✓ built in 1.33s ✓ built in 6m 36s Compressed 917 static variants; saved 21486154 bytes. ``` 2. `cargo fmt --check` — exit 0, no output. The check after the final doc-only commit also exits 0 with no output. 3. `cargo clippy -p calternal-plugin-files --all-targets -- -D warnings` — exit 0: ``` Finished `dev` profile [unoptimized + debuginfo] target(s) in 2m 04s ``` `cargo test -p calternal-plugin-files -- --test-threads=4` — exit 101: ``` test result: FAILED. 267 passed; 4 failed; 4 ignored; 0 measured; 0 filtered out; finished in 760.86s error: test failed, to rerun pass `-p calternal-plugin-files --lib` ``` All five named Journal regressions and the changed concurrent-retry test passed. The four unrelated failures are filed at https://git.kayg.org/kayg/calternal/issues/1342. No existing password or storm expectation was changed. In isolation the attempt-cap and parallel-password cases pass; the two-second rejection timeout still fails. The storm exceeded its existing five-minute bound. `cargo clippy -p calternal-server --all-targets -- -D warnings` — exit 0. The check after the upgrade-test correction also exits 0: ``` Finished `dev` profile [unoptimized + debuginfo] target(s) in 13m 17s Finished `dev` profile [unoptimized + debuginfo] target(s) in 5m 10s ``` `cargo test -p calternal-server -- --test-threads=4` before the upgrade-test correction — exit 101: ``` test result: FAILED. 269 passed; 3 failed; 12 ignored; 0 measured; 0 filtered out; finished in 293.92s error: test failed, to rerun pass `-p calternal-server --bin calternal-server` ``` Those three failures were exactly the omitted migration 29. The corrected pins add one pending receipt and one to each affected count, and require an empty completion table after upgrade. Old fixture SQL, checksums, receipt equality and User-data checks are unchanged. This expectation change follows #1295's new schema. `cargo test -p calternal-server wire::upgrade_tests -- --test-threads=4` after correction — exit 0: ``` test result: ok. 4 passed; 0 failed; 0 ignored; 0 measured; 280 filtered out; finished in 6.35s test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 1 filtered out; finished in 0.00s test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 1 filtered out; finished in 0.00s ``` The full server suite was not repeated. `cargo build -p calternal-server` exits 0. 4. `cd apps/web && bun run check` — exit 0: ``` perf-lint: PASS; 0 violations; 22538 scoped exceptions svelte-check found 0 errors and 1 warning in 1 file ``` 5. `cd apps/web && bun run test --maxWorkers=2` — exit 0: ``` Test Files 287 passed (287) Tests 2036 passed (2036) Duration 364.68s (transform 33%, environment 25%, import 21%, tests 16%, setup 5%) ``` Decisions: completed receipts last 24 h after completion and use no active upload slot. Receipt insertion and live-row retirement use one FULL transaction. Applied pending intents keep the retry identity after lease expiry. Detached finalization gets at most 60 s, capped by the lease. A Note's applied witness is sealed before the first post-rename await. Startup recovers source intents before accepting Notes writes and refuses ambiguous bytes. Conflicting destination metadata returns 400. Readiness returns on its first successful poll instead of sending another readiness call after timeout. Expected cost: HEAD and completed retries read one actor-bound Index row by primary key. Metadata validation uses bounded in-memory names. New publication streams one file and updates its existing projections. A completed retry writes no source bytes and does not scan a Home. This reliability job ran no benchmark, as required by the current verification policy. UX gaps closed: silent retargeting and replay after a lost success. No UI layout or visible control changed; no new screenshot set applies. Known gaps / UX gaps left: the historical seven timeouts cannot be reconstructed. An async deadline cannot preempt a blocked kernel call in synchronous rename/fsync. The full Files gate still has four failures on #1342; this report does not claim all gates are green. Web check has one existing empty-CSS-rule warning. For the merge round: - Integrate origin/dev once in the orchestrator's own worktree and check migration 29 is still free. This job fetched origin/dev once; migration 29 was free there. It did not merge because the final job instruction forbids merges. - `cargo test -p calternal-plugin-files -- --test-threads=4`: resolve or classify #1342 and confirm the full crate gate. - `cargo test -p calternal-server -- --test-threads=4`: confirm the corrected upgrade pins in the combined full suite. - `cd apps/web && bun run test --maxWorkers=2`, `bun run test:e2e`, and `bash tests/adversarial/run.sh`: check the combined web, protocol and cross-plugin changes. The job's focused crash and journalrace scenarios already ran to completion; they are not deferred. - Run the deployed/o2 checks before promotion. This job did not deploy. Cleanup: ``` Removed 19433 files, 16.0GiB total ``` Generated `apps/web/build` and `apps/web/.svelte-kit/output` were removed. No review artifact is committed.
Author
Owner

Starting jdrev2 read-only independent review of job/journaldup at 4ed17d8452 (job base 3601719b80). I will verify prior review findings and the new receipt, deadline, and startup recovery paths with independent runs. Findings are recorded in artifacts/jdrev2-findings.md. No tracked edits, commit, merge, push or deploy; exact-head read-only instruction overrides the shared merge workflow.

Starting jdrev2 read-only independent review of job/journaldup at 4ed17d8452c2d4f6cc62a6c2a38b44d4e27c6cbd (job base 3601719b80a39f712daf07b37879b22929dfffa0). I will verify prior review findings and the new receipt, deadline, and startup recovery paths with independent runs. Findings are recorded in artifacts/jdrev2-findings.md. No tracked edits, commit, merge, push or deploy; exact-head read-only instruction overrides the shared merge workflow.
Author
Owner

jdrev3 read-only review started on job/journaldup at 4ed17d8452 (original base 3601719b80). Continuing artifacts/jdrev2-findings.md. I will test receipt expiry, restart recovery, same-ID retries and per-User isolation. No tracked edits, commits, merges or ref changes.

jdrev3 read-only review started on job/journaldup at 4ed17d8452c2d4f6cc62a6c2a38b44d4e27c6cbd (original base 3601719b80a39f712daf07b37879b22929dfffa0). Continuing artifacts/jdrev2-findings.md. I will test receipt expiry, restart recovery, same-ID retries and per-User isolation. No tracked edits, commits, merges or ref changes.
Author
Owner

jdrev3 independent production-router probes completed: 6 passed. Two P1 residuals reproduced at 4ed17d845: (1) expire a completed receipt -> HEAD 404 -> new-ID PATCH 204: rename duplicates the Note; replace removes the later Log from current bytes (Versions not evaluated). (2) a real pre-rename writer timeout -> PATCH 503 -> Journal Log 201 -> restore_upload_reservations fails with unexpected content; same-ID PATCH returns 412 and retains the intent. This new-binary path can stop the next Instance startup through wire.rs; it is not solely legacy #1325. Cross-User HEAD/PATCH/DELETE and concurrent same-ID retries passed. Continuing crate suites and real restart/journalrace evidence; full details in artifacts/jdrev2-findings.md.

jdrev3 independent production-router probes completed: 6 passed. Two P1 residuals reproduced at 4ed17d845: (1) expire a completed receipt -> HEAD 404 -> new-ID PATCH 204: rename duplicates the Note; replace removes the later Log from current bytes (Versions not evaluated). (2) a real pre-rename writer timeout -> PATCH 503 -> Journal Log 201 -> restore_upload_reservations fails with unexpected content; same-ID PATCH returns 412 and retains the intent. This new-binary path can stop the next Instance startup through wire.rs; it is not solely legacy #1325. Cross-User HEAD/PATCH/DELETE and concurrent same-ID retries passed. Continuing crate suites and real restart/journalrace evidence; full details in artifacts/jdrev2-findings.md.
Author
Owner

Orchestrator: re-review of 4ed17d845 (jdrev2/jdrev3, sessions ended early by a tool error; notes in artifacts/jdrev2-findings.md) = BLOCK on two P1 residuals: R1 completion-record expiry lets a 24 h-later browser retry replay old bytes under a new ID (duplicate Note or loss of a later line); R2 a pre-write timeout leaves an installing intent that makes recovery refuse and the whole server stop serving on the next start. Per-User isolation: no finding. journaldup5 is fixing both.

Orchestrator: re-review of 4ed17d845 (jdrev2/jdrev3, sessions ended early by a tool error; notes in artifacts/jdrev2-findings.md) = BLOCK on two P1 residuals: R1 completion-record expiry lets a 24 h-later browser retry replay old bytes under a new ID (duplicate Note or loss of a later line); R2 a pre-write timeout leaves an installing intent that makes recovery refuse and the whole server stop serving on the next start. Per-User isolation: no finding. journaldup5 is fixing both.
Author
Owner

journaldup5 starts on job/journaldup at 4ed17d8452. Read R1/R2 review probes. R1 will retain permanent actor-bound completion receipts; R2 will clear pre-write intents under publication guards and isolate ambiguous Notes without deleting proof. No new dependencies.

journaldup5 starts on job/journaldup at 4ed17d8452c2d4f6cc62a6c2a38b44d4e27c6cbd. Read R1/R2 review probes. R1 will retain permanent actor-bound completion receipts; R2 will clear pre-write intents under publication guards and isolate ambiguous Notes without deleting proof. No new dependencies.
Author
Owner

At 4ed17d845, the adapted independent production-router regressions all fail (artifacts/jd5-baseline-red.log): R1 HEAD returns 404 after receipt expiry; R2 ambiguous recovery returns upload install ... has unexpected content; R2 pre-write timeout leaves installing=1 instead of 0. Browser regression also fails: dropped final PATCH then HEAD 404 finishes a second upload. The fixed browser focused suite passes 19 tests, and the permanent receipt regression passes for rename and replace. Decisions: retain actor-bound completion proof permanently (one small row, no file bytes); treat missing proof after a possible final PATCH, including restored locations, as unresolved rather than authorize automatic replay. R2 will retain evidence and protect an undecidable target through calternal-fs rather than stop the Instance. No new dependency.

At 4ed17d845, the adapted independent production-router regressions all fail (artifacts/jd5-baseline-red.log): R1 HEAD returns 404 after receipt expiry; R2 ambiguous recovery returns `upload install ... has unexpected content`; R2 pre-write timeout leaves installing=1 instead of 0. Browser regression also fails: dropped final PATCH then HEAD 404 finishes a second upload. The fixed browser focused suite passes 19 tests, and the permanent receipt regression passes for rename and replace. Decisions: retain actor-bound completion proof permanently (one small row, no file bytes); treat missing proof after a possible final PATCH, including restored locations, as unresolved rather than authorize automatic replay. R2 will retain evidence and protect an undecidable target through calternal-fs rather than stop the Instance. No new dependency.
Author
Owner

journaldup5 findings and decisions at 651bc4274e:

R1 now retains permanent actor-bound completion proof. Tests force the old expiry, run cleanup, retry both rename and replace uploads, and retain the later Log bytes with one Note. The browser also stops if an attempted final publication loses its proof (including a restored upload location); it asks the User to check the destination and does not create a second upload ID. This covers proof removed by an earlier release.

R2 clears an unapplied intent with FULL durability while the namespace and Notes guards remain held. An ambiguous recovery protects that Note in calternal-fs and continues startup. Tests preserve the source, chunks, intent, and Versions; refuse writes, Trash, deletion, and ancestor moves; read the Note through HTTP; return a plain repair notice for a Journal edit; and write an unrelated Note and another User's Note. All three adapted reviewer tests failed on 4ed17d845 and pass after the fix. The browser's dropped-response regression also failed on that baseline and now passes.

Integrated origin/dev 0419170fe4 once before final gates. Retained both sides of migration and adversarial changes. Updated exact SQL exception pins without changing limits; scripts/perf-lint --check reports PASS, 0 violations, 22534 scoped exceptions.

Production web build, filesystem and Tags gates passed. Files clippy found a mutable watcher binding lost in conflict resolution; corrected it and the gate passed. Remaining crate and web gates, real restart and journalrace checks are running. No new dependencies. Automatic repair remains an operator task; the fix never guesses source bytes.

journaldup5 findings and decisions at 651bc4274e46db910f6952d02f358c5b342251aa: R1 now retains permanent actor-bound completion proof. Tests force the old expiry, run cleanup, retry both rename and replace uploads, and retain the later Log bytes with one Note. The browser also stops if an attempted final publication loses its proof (including a restored upload location); it asks the User to check the destination and does not create a second upload ID. This covers proof removed by an earlier release. R2 clears an unapplied intent with FULL durability while the namespace and Notes guards remain held. An ambiguous recovery protects that Note in calternal-fs and continues startup. Tests preserve the source, chunks, intent, and Versions; refuse writes, Trash, deletion, and ancestor moves; read the Note through HTTP; return a plain repair notice for a Journal edit; and write an unrelated Note and another User's Note. All three adapted reviewer tests failed on 4ed17d845 and pass after the fix. The browser's dropped-response regression also failed on that baseline and now passes. Integrated origin/dev 0419170fe456b58614befcb12d9c9d255118f1c0 once before final gates. Retained both sides of migration and adversarial changes. Updated exact SQL exception pins without changing limits; scripts/perf-lint --check reports PASS, 0 violations, 22534 scoped exceptions. Production web build, filesystem and Tags gates passed. Files clippy found a mutable watcher binding lost in conflict resolution; corrected it and the gate passed. Remaining crate and web gates, real restart and journalrace checks are running. No new dependencies. Automatic repair remains an operator task; the fix never guesses source bytes.
Author
Owner

Final gate evidence at 7e6864429:

Files clippy passed. The first Files suite had 272 passes, one failure, four ignored: the old test expected HEAD 404 after receipt expiry. R1 explicitly changes that behavior. Updated only that expectation to 200, retained all existing byte/isolation assertions, added a same-ID empty PATCH and later-byte assertion after cleanup; the focused test passes.

The next full Files suite had 272 passes, one failure, four ignored. The only failure was public_password_rejection_does_not_wait_for_data_mutation_lock: its unchanged two-second timeout elapsed. That test passed in the first suite and passed alone afterward (one passed, 2.68 seconds including setup). No status/lock/assertion/timeout changes were made. This is a SLOW-only shared-host finding, not a demonstrated authorization or lock failure. No further full-suite loop.

All reviewer R1/R2 regressions pass after dev integration:

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

They prove permanent completion for rename/replace, pre-write timeout intent reset followed by a real Journal write, and ambiguous Note protection while unrelated Notes and another User remain writable. Notes, Sync, server and web gates continue.

Final gate evidence at 7e6864429: Files clippy passed. The first Files suite had 272 passes, one failure, four ignored: the old test expected HEAD 404 after receipt expiry. R1 explicitly changes that behavior. Updated only that expectation to 200, retained all existing byte/isolation assertions, added a same-ID empty PATCH and later-byte assertion after cleanup; the focused test passes. The next full Files suite had 272 passes, one failure, four ignored. The only failure was public_password_rejection_does_not_wait_for_data_mutation_lock: its unchanged two-second timeout elapsed. That test passed in the first suite and passed alone afterward (one passed, 2.68 seconds including setup). No status/lock/assertion/timeout changes were made. This is a SLOW-only shared-host finding, not a demonstrated authorization or lock failure. No further full-suite loop. All reviewer R1/R2 regressions pass after dev integration: ``` test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 12.31s ``` They prove permanent completion for rename/replace, pre-write timeout intent reset followed by a real Journal write, and ambiguous Note protection while unrelated Notes and another User remain writable. Notes, Sync, server and web gates continue.
Author
Owner

Server final gate at 746dceb91: clippy passed. The test suite reported:

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

The sole failure is the live-app wrapper's large-Home latency profile, not a content/status/crash assertion:

search_reconcile_calendar_write_profile files=20000 writes=32 p50_ms=13957 p95_ms=14745 p95_budget_ms=10000
Calendar write p95 14.745179676s exceeded 10s

No timeout, budget, or assertion changes. This is recorded as SLOW-only shared-host evidence under the job rule. No full-suite retry loop. Continue web gates and the explicitly requested restart/journalrace reliability campaigns.

Server final gate at 746dceb91: clippy passed. The test suite reported: ``` test result: FAILED. 271 passed; 1 failed; 12 ignored; 0 measured; 0 filtered out; finished in 243.20s ``` The sole failure is the live-app wrapper's large-Home latency profile, not a content/status/crash assertion: ``` search_reconcile_calendar_write_profile files=20000 writes=32 p50_ms=13957 p95_ms=14745 p95_budget_ms=10000 Calendar write p95 14.745179676s exceeded 10s ``` No timeout, budget, or assertion changes. This is recorded as SLOW-only shared-host evidence under the job rule. No full-suite retry loop. Continue web gates and the explicitly requested restart/journalrace reliability campaigns.
Author
Owner

journaldup5 — #1295

Head: 746dceb915 (job/journaldup). No push, deploy, or merge into dev. Integrated origin/dev 0419170fe4 once before final gates.

Built:

  • R1: permanent actor-bound upload completion proof; late HEAD/PATCH retries acknowledge the original ID without publishing bytes. The browser stops automatic replay when a possible final publication has lost its proof, including restored upload locations.
  • R2: finalizers retain namespace and Notes guards while they clear unapplied intents with FULL durability. Recovery keeps ambiguous source, staging, intent, witness and Versions, protects the affected Note in calternal-fs, and continues serving other items and Users. Files/Notes/Tags return a plain repair notice on refused edits.
  • Regression tests derived from the independent reviewer prove both policies, timeout before source writes, HTTP reads, denied Journal edits, evidence retention, and unrelated writes. All three failed on 4ed17d845 before the fix. The browser dropped-response regression also failed there and now passes.

Files:

  • apps/web/src/lib/files/uploads.svelte.ts and uploads.svelte.test.ts
  • crates/plugins/files/src/uploads.rs, lib.rs, src/tests/journal_retry.rs, tests/jdrev2.rs, DATA-SAFETY.md
  • crates/calternal-fs/src/{root,error,write,journal,blob,versions}.rs
  • crates/calternal-tags/src/lib.rs; crates/plugins/notes/src/lib.rs
  • contracts/perf/{registry,exceptions,ratchet}.json and dev conflict integration in migration/adversarial tests. Exact pins refreshed; no guard limit raised.

Decisions:

  • Keep small completion records permanently (one indexed row per upload, no source bytes). Reuse the deployed table; no new migration. Existing expired receipt rows remain useful.
  • If completion proof is missing after a possible final PATCH, stop and ask the User to check the destination. Do not create another upload ID with old bytes.
  • Keep ambiguous evidence and deny source/namespace changes through the shared filesystem layer. Rebuild protection from retained intents at each startup. Repair requires an operator to confirm the intended bytes; do not guess or delete proof to pass startup.
  • Expected cost: normal retry is one indexed receipt lookup; normal writes check the empty repair set; recovery hashes each pending destination once. Protection checks scale with unresolved intents, not Home size. No new per-request full-Home scan. This safety job does not run a performance benchmark under the current verification policy.

UX gaps closed: missing-proof Retry no longer silently duplicates or overwrites; a protected Note remains readable and an edit returns a plain repair notice. Existing UploadToast and its shared Pill controls are reused; no new visual primitive or styling.
UX gaps left / known gaps: no automatic repair workflow or repair management screen. A deadline cannot interrupt a blocked synchronous kernel call (documented). Permanent receipts grow by one small row per completed upload and are removed with the User.

Gate output (verbatim summary lines; full logs in artifacts/jd5-final-*.log):

cd apps/web && bun run build (exit 0)

✓ built in 53.70s
✓ built in 19ms
✓ built in 1m 59s
Compressed 917 static variants; saved 21487383 bytes.

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

cargo clippy -p calternal-fs --all-targets -- -D warnings (exit 0)

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

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

test result: ok. 98 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 30.22s
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.19s
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 1.29s
test result: ok. 52 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 12.66s
test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.09s
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

cargo clippy -p calternal-tags --all-targets -- -D warnings (exit 0)

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

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

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

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

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

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

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

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

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

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

test result: ok. 317 passed; 0 failed; 4 ignored; 0 measured; 0 filtered out; finished in 609.76s
test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 5.96s
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

cargo clippy -p calternal-sync --all-targets -- -D warnings (exit 0)

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

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

test result: ok. 65 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 2.62s
test result: ok. 2 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.01s

cargo clippy -p calternal-server --all-targets -- -D warnings (exit 0)

    Finished `dev` profile [unoptimized + debuginfo] target(s) in 5m 44s

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

test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 283 filtered out; finished in 46.71s
test result: FAILED. 271 passed; 1 failed; 12 ignored; 0 measured; 0 filtered out; finished in 243.20s

Files password check alone (unchanged two-second deadline)

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

Updated existing completed-retry regression

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

Reviewer R1/R2 tests (final)

test ambiguous_recovery_serves_other_items_without_guessing ... JDREV2 ambiguous intent: recovery succeeds, target and ancestors protected, other Notes and Users writable, proof retained
test completion_never_expires_or_replays_source ... JDREV2 permanent receipt policy=rename: same-ID retry preserves later bytes and creates no duplicate
JDREV2 permanent receipt policy=replace: same-ID retry preserves later bytes and creates no duplicate
test pre_rename_timeout_then_log_edit_recovers_safely ... JDREV2 pre-write timeout: PATCH 503 -> intent cleared -> Log 201 -> recovery succeeds; bytes preserved
test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 12.31s

bun run check (exit 0)

perf-lint: PASS; 0 violations; 22534 scoped exceptions
svelte-check found 0 errors and 1 warning in 1 file

bun run test --maxWorkers=2 (exit 0)

Ran 140 tests in 0.165s
Ran 8 tests across 1 file. [923.00ms]
 Test Files  287 passed (287)
      Tests  2040 passed (2040)
   Duration  741.53s (transform 32%, environment 23%, import 23%, tests 16%, setup 5%)

SIGKILL restart (exit 0)

PASS SIGKILL mid-finalize: 1 crash, 1 later Log, 1 same-ID retry, 1 Note, 0 duplicate Notes; bytes preserved

journalrace reliability (exit 0)

journalrace: 2021-03-14: 6 seeds, 40 creates answered 201, 0 timed out (0 of them landed), 10 uploads, 46 entries
server alive at end: True
==== ROUND 2 FINDINGS 0
==== ROUND 2 SLOW 0

Production browser and macOS evidence (exit 0)

PASS macOS 390 light: missing completion proof has no Retry action
PASS macOS 390 dark: missing completion proof has no Retry action
PASS macOS 820 light: missing completion proof has no Retry action
PASS macOS 820 dark: missing completion proof has no Retry action
PASS macOS 1440 light: missing completion proof has no Retry action
PASS macOS 1440 dark: missing completion proof has no Retry action
PASS production browser: one upload ID, one Note, later Log retained; 6 screenshots

Gate findings: the full Files suite had one unchanged two-second password-check timeout; that test passed in the preceding run and alone afterward. The first Files run also exposed the old receipt-expiry expectation. R1 explicitly changes that behavior: HEAD now remains 200 after cleanup, followed by a same-ID PATCH and preserved later bytes. The server suite had one SLOW-only large-Home profile failure: 20,000 files, 32 writes, p50 13,957 ms, p95 14,745 ms, unchanged budget 10,000 ms. No budgets, deadlines, or safety assertions were weakened. No repeated full-suite loop. The requested runtime restart/journalrace/browser checks all passed with no findings or SLOWs.

Screenshots: six production captures at 390/820/1440 px, light/dark, with macOS platform emulation, in artifacts/jd5-screenshots/files-upload---mac.png. Screenshots are not committed. The installed CLI has no attachment command, and the direct attachment attempt found no usable CLI credential. The files remain local for the orchestrator to attach/review; no credentials were displayed. Visual quality review remains with the orchestrator.

For the merge round:

  • cargo test -p calternal-plugin-files -- --test-threads=4: run the unchanged suite on the combined build; confirm the password latency gate and all Files tests.
  • cargo test -p calternal-server -- --test-threads=4: run the unchanged large-Home profile and the remaining live-app child checks.
  • ADVERSARIAL_SERVER_BIN="$CARGO_TARGET_DIR/debug/calternal-server" ADVERSARIAL_SKIP_WEB_BUILD=1 bash tests/adversarial/run.sh: full adversarial matrices on the combined build. The focused journalrace round already passed here.

Cleanup completed after evidence capture. Cargo output:

     Removed 25281 files, 21.3GiB total

Production web build/output removed. Working tree clean. Review artifacts remain local. No new dependencies.

journaldup5 — #1295 Head: 746dceb91581988498e41371ea91dd98c74cea22 (job/journaldup). No push, deploy, or merge into dev. Integrated origin/dev 0419170fe456b58614befcb12d9c9d255118f1c0 once before final gates. Built: - R1: permanent actor-bound upload completion proof; late HEAD/PATCH retries acknowledge the original ID without publishing bytes. The browser stops automatic replay when a possible final publication has lost its proof, including restored upload locations. - R2: finalizers retain namespace and Notes guards while they clear unapplied intents with FULL durability. Recovery keeps ambiguous source, staging, intent, witness and Versions, protects the affected Note in calternal-fs, and continues serving other items and Users. Files/Notes/Tags return a plain repair notice on refused edits. - Regression tests derived from the independent reviewer prove both policies, timeout before source writes, HTTP reads, denied Journal edits, evidence retention, and unrelated writes. All three failed on 4ed17d845 before the fix. The browser dropped-response regression also failed there and now passes. Files: - apps/web/src/lib/files/uploads.svelte.ts and uploads.svelte.test.ts - crates/plugins/files/src/uploads.rs, lib.rs, src/tests/journal_retry.rs, tests/jdrev2.rs, DATA-SAFETY.md - crates/calternal-fs/src/{root,error,write,journal,blob,versions}.rs - crates/calternal-tags/src/lib.rs; crates/plugins/notes/src/lib.rs - contracts/perf/{registry,exceptions,ratchet}.json and dev conflict integration in migration/adversarial tests. Exact pins refreshed; no guard limit raised. Decisions: - Keep small completion records permanently (one indexed row per upload, no source bytes). Reuse the deployed table; no new migration. Existing expired receipt rows remain useful. - If completion proof is missing after a possible final PATCH, stop and ask the User to check the destination. Do not create another upload ID with old bytes. - Keep ambiguous evidence and deny source/namespace changes through the shared filesystem layer. Rebuild protection from retained intents at each startup. Repair requires an operator to confirm the intended bytes; do not guess or delete proof to pass startup. - Expected cost: normal retry is one indexed receipt lookup; normal writes check the empty repair set; recovery hashes each pending destination once. Protection checks scale with unresolved intents, not Home size. No new per-request full-Home scan. This safety job does not run a performance benchmark under the current verification policy. UX gaps closed: missing-proof Retry no longer silently duplicates or overwrites; a protected Note remains readable and an edit returns a plain repair notice. Existing UploadToast and its shared Pill controls are reused; no new visual primitive or styling. UX gaps left / known gaps: no automatic repair workflow or repair management screen. A deadline cannot interrupt a blocked synchronous kernel call (documented). Permanent receipts grow by one small row per completed upload and are removed with the User. Gate output (verbatim summary lines; full logs in artifacts/jd5-final-*.log): cd apps/web && bun run build (exit 0) ``` ✓ built in 53.70s ✓ built in 19ms ✓ built in 1m 59s Compressed 917 static variants; saved 21487383 bytes. ``` cargo fmt --check: exit 0, no output. cargo clippy -p calternal-fs --all-targets -- -D warnings (exit 0) ``` Finished `dev` profile [unoptimized + debuginfo] target(s) in 6.60s ``` cargo test -p calternal-fs -- --test-threads=4 ``` test result: ok. 98 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 30.22s test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.19s test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 1.29s test result: ok. 52 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 12.66s test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.09s test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s ``` cargo clippy -p calternal-tags --all-targets -- -D warnings (exit 0) ``` Finished `dev` profile [unoptimized + debuginfo] target(s) in 1m 08s ``` cargo test -p calternal-tags -- --test-threads=4 ``` test result: ok. 52 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 74.57s test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s ``` cargo clippy -p calternal-plugin-files --all-targets -- -D warnings (exit 0) ``` Finished `dev` profile [unoptimized + debuginfo] target(s) in 28.12s ``` cargo test -p calternal-plugin-files -- --test-threads=4 ``` test result: FAILED. 272 passed; 1 failed; 4 ignored; 0 measured; 0 filtered out; finished in 385.17s ``` cargo clippy -p calternal-plugin-notes --all-targets -- -D warnings (exit 0) ``` Finished `dev` profile [unoptimized + debuginfo] target(s) in 1m 55s ``` cargo test -p calternal-plugin-notes -- --test-threads=4 ``` test result: ok. 317 passed; 0 failed; 4 ignored; 0 measured; 0 filtered out; finished in 609.76s test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 5.96s test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s ``` cargo clippy -p calternal-sync --all-targets -- -D warnings (exit 0) ``` Finished `dev` profile [unoptimized + debuginfo] target(s) in 1m 56s ``` cargo test -p calternal-sync -- --test-threads=4 ``` test result: ok. 65 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 2.62s test result: ok. 2 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.01s ``` cargo clippy -p calternal-server --all-targets -- -D warnings (exit 0) ``` Finished `dev` profile [unoptimized + debuginfo] target(s) in 5m 44s ``` cargo test -p calternal-server -- --test-threads=4 ``` test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 283 filtered out; finished in 46.71s test result: FAILED. 271 passed; 1 failed; 12 ignored; 0 measured; 0 filtered out; finished in 243.20s ``` Files password check alone (unchanged two-second deadline) ``` test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 276 filtered out; finished in 2.68s ``` Updated existing completed-retry regression ``` test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 276 filtered out; finished in 3.13s ``` Reviewer R1/R2 tests (final) ``` test ambiguous_recovery_serves_other_items_without_guessing ... JDREV2 ambiguous intent: recovery succeeds, target and ancestors protected, other Notes and Users writable, proof retained test completion_never_expires_or_replays_source ... JDREV2 permanent receipt policy=rename: same-ID retry preserves later bytes and creates no duplicate JDREV2 permanent receipt policy=replace: same-ID retry preserves later bytes and creates no duplicate test pre_rename_timeout_then_log_edit_recovers_safely ... JDREV2 pre-write timeout: PATCH 503 -> intent cleared -> Log 201 -> recovery succeeds; bytes preserved test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 12.31s ``` bun run check (exit 0) ``` perf-lint: PASS; 0 violations; 22534 scoped exceptions svelte-check found 0 errors and 1 warning in 1 file ``` bun run test --maxWorkers=2 (exit 0) ``` Ran 140 tests in 0.165s Ran 8 tests across 1 file. [923.00ms] Test Files 287 passed (287) Tests 2040 passed (2040) Duration 741.53s (transform 32%, environment 23%, import 23%, tests 16%, setup 5%) ``` SIGKILL restart (exit 0) ``` PASS SIGKILL mid-finalize: 1 crash, 1 later Log, 1 same-ID retry, 1 Note, 0 duplicate Notes; bytes preserved ``` journalrace reliability (exit 0) ``` journalrace: 2021-03-14: 6 seeds, 40 creates answered 201, 0 timed out (0 of them landed), 10 uploads, 46 entries server alive at end: True ==== ROUND 2 FINDINGS 0 ==== ROUND 2 SLOW 0 ``` Production browser and macOS evidence (exit 0) ``` PASS macOS 390 light: missing completion proof has no Retry action PASS macOS 390 dark: missing completion proof has no Retry action PASS macOS 820 light: missing completion proof has no Retry action PASS macOS 820 dark: missing completion proof has no Retry action PASS macOS 1440 light: missing completion proof has no Retry action PASS macOS 1440 dark: missing completion proof has no Retry action PASS production browser: one upload ID, one Note, later Log retained; 6 screenshots ``` Gate findings: the full Files suite had one unchanged two-second password-check timeout; that test passed in the preceding run and alone afterward. The first Files run also exposed the old receipt-expiry expectation. R1 explicitly changes that behavior: HEAD now remains 200 after cleanup, followed by a same-ID PATCH and preserved later bytes. The server suite had one SLOW-only large-Home profile failure: 20,000 files, 32 writes, p50 13,957 ms, p95 14,745 ms, unchanged budget 10,000 ms. No budgets, deadlines, or safety assertions were weakened. No repeated full-suite loop. The requested runtime restart/journalrace/browser checks all passed with no findings or SLOWs. Screenshots: six production captures at 390/820/1440 px, light/dark, with macOS platform emulation, in artifacts/jd5-screenshots/files-upload-<width>-<theme>-mac.png. Screenshots are not committed. The installed CLI has no attachment command, and the direct attachment attempt found no usable CLI credential. The files remain local for the orchestrator to attach/review; no credentials were displayed. Visual quality review remains with the orchestrator. For the merge round: - `cargo test -p calternal-plugin-files -- --test-threads=4`: run the unchanged suite on the combined build; confirm the password latency gate and all Files tests. - `cargo test -p calternal-server -- --test-threads=4`: run the unchanged large-Home profile and the remaining live-app child checks. - `ADVERSARIAL_SERVER_BIN="$CARGO_TARGET_DIR/debug/calternal-server" ADVERSARIAL_SKIP_WEB_BUILD=1 bash tests/adversarial/run.sh`: full adversarial matrices on the combined build. The focused journalrace round already passed here. Cleanup completed after evidence capture. Cargo output: ``` Removed 25281 files, 21.3GiB total ``` Production web build/output removed. Working tree clean. Review artifacts remain local. No new dependencies.
Author
Owner

jdrev4 read-only review started. Branch job/journaldup, reviewed head 746dceb915; original base 3601719b80. Independently checking permanent completion proof, browser text recovery, item-scoped repair protection, crate tests, SIGKILL restart and one journalrace run. No tracked edits, commits or merge; exact-head read-only brief takes precedence. Notes: artifacts/jdrev4-notes.md.

jdrev4 read-only review started. Branch job/journaldup, reviewed head 746dceb91581988498e41371ea91dd98c74cea22; original base 3601719b80a39f712daf07b37879b22929dfffa0. Independently checking permanent completion proof, browser text recovery, item-scoped repair protection, crate tests, SIGKILL restart and one journalrace run. No tracked edits, commits or merge; exact-head read-only brief takes precedence. Notes: artifacts/jdrev4-notes.md.
Author
Owner

jdrev4 independent receipt measurement at 746dceb915: deployed 0029 schema, 100,000 synthetic rows, all indexes included. Typical 27-byte Note path: 400.10 bytes/row; 10 uploads/minute for 365 days = 5,256,000 rows, projected 1.958 GiB/User. A 3,999-byte path: 8,877.96 bytes/row, projected 43.458 GiB/User. No source bytes; primary-key lookup uses an index. Lifetime row count is unbounded while the User exists; User cleanup deletes owner/actor receipts. These estimates exclude WAL/free pages/backups. This is a growth follow-up, not a recommendation to expire completion proof. Browser focused tests passed: 2 files, 20 tests. Full crate tests and live cancellation/restart evidence are in progress.

jdrev4 independent receipt measurement at 746dceb91581988498e41371ea91dd98c74cea22: deployed 0029 schema, 100,000 synthetic rows, all indexes included. Typical 27-byte Note path: 400.10 bytes/row; 10 uploads/minute for 365 days = 5,256,000 rows, projected 1.958 GiB/User. A 3,999-byte path: 8,877.96 bytes/row, projected 43.458 GiB/User. No source bytes; primary-key lookup uses an index. Lifetime row count is unbounded while the User exists; User cleanup deletes owner/actor receipts. These estimates exclude WAL/free pages/backups. This is a growth follow-up, not a recommendation to expire completion proof. Browser focused tests passed: 2 files, 20 tests. Full crate tests and live cancellation/restart evidence are in progress.
Author
Owner

jdrev4 independent live-server finding at 746dceb915 — BLOCK / R3.

A seeded consistent legacy-style ambiguous installation starts correctly: readyz 200, protected Note GET 200, Journal edit 409 with a read-only notice; sibling and other User Log writes return 201. Source, intent, staging and Versions match their pre-start digests. A same-ID retry returns 412 and preserves proof.

Then the actor's ordinary DELETE /api/v1/files/uploads/ returns 204. The installing row count becomes 0 and the staging directory is removed. After a real server restart, a Log edit on the formerly protected Note returns 201. Cancellation erased the evidence and the durable basis for protection without resolving the source. uploads.rs::terminate calls rollback_failed_dav_upload, but that helper's early return does not prevent terminate's unconditional DELETE and remove_upload.

The author needs a regression that attempts to cancel a recovery-needed installation, checks retained intent/chunks/witness/Versions, restarts, and confirms that the Note remains protected. Refuse cancellation while applied/ambiguous publication proof is needed; normal partial cancellation can keep its current behavior. No production edits were made by this review.

Fresh verification so far: 3/3 R1/R2 router regressions passed; permanent expired-field receipt gives HEAD 200 and same-ID full-byte PATCH 204 without replay or later Log loss; other User HEAD/PATCH/DELETE gives 404. SIGKILL passed: 1 crash, 1 later Log, 1 same-ID retry, 1 Note, 0 duplicates. Two full-suite latency failures passed individually with unchanged bounds. Full journalrace and browser evidence are still in progress. The fixture's final admin deletion request was denied correctly because it lacked asserted_at; receipt cleanup will be checked separately with a correctly seeded recent-assertion fixture.

jdrev4 independent live-server finding at 746dceb91581988498e41371ea91dd98c74cea22 — BLOCK / R3. A seeded consistent legacy-style ambiguous installation starts correctly: readyz 200, protected Note GET 200, Journal edit 409 with a read-only notice; sibling and other User Log writes return 201. Source, intent, staging and Versions match their pre-start digests. A same-ID retry returns 412 and preserves proof. Then the actor's ordinary DELETE /api/v1/files/uploads/<id> returns 204. The installing row count becomes 0 and the staging directory is removed. After a real server restart, a Log edit on the formerly protected Note returns 201. Cancellation erased the evidence and the durable basis for protection without resolving the source. uploads.rs::terminate calls rollback_failed_dav_upload, but that helper's early return does not prevent terminate's unconditional DELETE and remove_upload. The author needs a regression that attempts to cancel a recovery-needed installation, checks retained intent/chunks/witness/Versions, restarts, and confirms that the Note remains protected. Refuse cancellation while applied/ambiguous publication proof is needed; normal partial cancellation can keep its current behavior. No production edits were made by this review. Fresh verification so far: 3/3 R1/R2 router regressions passed; permanent expired-field receipt gives HEAD 200 and same-ID full-byte PATCH 204 without replay or later Log loss; other User HEAD/PATCH/DELETE gives 404. SIGKILL passed: 1 crash, 1 later Log, 1 same-ID retry, 1 Note, 0 duplicates. Two full-suite latency failures passed individually with unchanged bounds. Full journalrace and browser evidence are still in progress. The fixture's final admin deletion request was denied correctly because it lacked asserted_at; receipt cleanup will be checked separately with a correctly seeded recent-assertion fixture.
Author
Owner

BLOCK

jdrev4 final independent reliability review of #1295.
Head: 746dceb915, branch job/journaldup.

R3 — blocking: Cancel deletes undecidable publication proof.

The real server starts with a seeded consistent legacy-style ambiguous installation. readyz returns 200; the protected Note opens with 200; its Journal edit returns 409 with a read-only notice. A sibling Note and another User accept Log writes with 201. Source, staging, Versions and installing proof retain their digests. A same-ID retry returns 412 and retains proof.

The actor's ordinary DELETE /api/v1/files/uploads/ then returns 204. The installing row count becomes 0 and staging is removed. After a real restart, the formerly protected Note accepts a Log edit with 201. Cancellation deletes the evidence and removes the durable basis for protection without deciding the source. uploads.rs:2522 (terminate) calls rollback_failed_dav_upload, but its early return does not stop terminate's unconditional row and staging deletion. This is a non-SLOW finding. No duplicate or loss of an acknowledged Log was observed in this probe; loss of unresolved evidence and repair protection is itself the failed safety invariant.

Required author fix: retain the installing record and all proof when cancellation encounters applied or ambiguous publication. Refuse that cancellation with a plain repair notice. Add a regression for cancel -> retained proof -> restart -> still-protected Note. Keep normal partial-upload cancellation behavior. No tracked files were edited by this review.

R1 — late retry verified.

The permanent receipt lookup has no expiry predicate and selects id+actor_id. The live test sets expires_at=0, then observes HEAD 200 and a full-byte same-ID PATCH 204 with the later Log bytes unchanged. One receipt row remains. Another User gets 404 for HEAD/PATCH/DELETE. The dedicated regression also verifies rename and replace, including cleanup. FULL authority publication commits the receipt and retires live state in one transaction. No later-time expiry path remains in reads or cleanup.

Receipt growth — follow-up, not bounded.

One row per successful upload; retries do not add rows. No file bytes are stored. A local SQLite size measurement uses deployed migration 0029, 100,000 rows and all four indexes. A typical 27-byte destination uses 400.10 bytes/row. At 10 uploads/minute for 365 days: 5,256,000 rows, projected 2,102,911,304 bytes (1.958 GiB) per User. A valid 3,999-byte path uses 8,877.96 bytes/row, projected 43.458 GiB/year. These are size projections, not perf-VM latency measurements; they exclude WAL, free-page fragmentation and backups. Lifetime growth has no cap, and metadata does not consume a live-upload slot. Do not expire safety proof to reduce this growth. Compact representation, accounting and batched receipt cleanup need follow-up.

Source cleanup deletes receipts by owner_id OR actor_id. A separate live test with a correctly seeded recent admin assertion confirms DELETE User 202 and receipt count 1 -> 0. Scope and normal User cleanup pass.

Browser — replay stops; pending-byte recovery is incomplete.

The User sees: “Upload result could not be confirmed. Check the destination before uploading again.” Retry is absent. The summary offers Open Files, Show upload list and Close; the expanded component offers Cancel. The task retains its File only in the in-memory queue. There is no copy/download recovery action or queue persistence. The real production test observes zero recovery actions and the queue/notice disappearing after reload. A selected disk file still has its external original; this is not evidence of lost acknowledged Journal text. A generated File has no durable recovery path in this queue.

Production browser safety passes: one upload ID, one Note, later Log retained. Six captures cover macOS emulation at 390/820/1440 px, light/dark, under artifacts/jdrev4-screenshots/. Browser plugin not available; used the existing Playwright harness. No new visual primitive or local styling. Visual quality review remains with the orchestrator. The installed fj CLI exposes no attachment command; screenshots remain local for attachment/review. Console-health assertions were not added to this read-only browser probe.

R2 — timeout and initial isolated recovery verified, with R3 exception above.

Dedicated production-router tests confirm pre-write PATCH timeout returns 503, installing becomes 0 before guards release, later Log returns 201, and recovery preserves bytes. Ambiguous recovery starts and serves other items and Users; the target and ancestors reject source/namespace changes, reads work, and Versions thinning retains proof. The live restart confirms availability and evidence retention until Cancel. No automatic operator repair workflow exists.

Restart and journalrace ran once each. Verbatim output:

PASS SIGKILL mid-finalize: 1 crash, 1 later Log, 1 same-ID retry, 1 Note, 0 duplicate Notes; bytes preserved
journalrace: 2021-03-14: 6 seeds, 40 creates answered 201, 0 timed out (0 of them landed), 10 uploads, 46 entries
server alive at end: True
==== ROUND 2 FINDINGS 0
==== ROUND 2 SLOW 0

Built / files:

  • Built this head's production web app and server for verification, then removed generated output.
  • No tracked source, test expectations, dependency files or refs changed; no commits, merges, pushes or deploys.
  • Added only ignored review notes, probes, logs and screenshots: artifacts/jdrev4-notes.md, jdrev4-live.py, jdrev4-user-delete.py, jdrev4-receipt-size.py, jdrev4-browser.mjs, jdrev4-gates.sh, jdrev4-probes.sh, jdrev4-*.log and jdrev4-screenshots/.

Gate output — verbatim result lines (full output in artifacts/jdrev4-*.log):

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

cargo test -p calternal-plugin-files -- --test-threads=4 (exit 101)

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

cargo test -p calternal-plugin-notes -- --test-threads=4 (exit 101)

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

cargo test -p calternal-tags -- --test-threads=4 (exit 0)

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

cargo test -p calternal-sync -- --test-threads=4 (exit 0)

test result: ok. 65 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 1.70s
test result: ok. 2 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

The only full-suite failures were unchanged latency bounds: Files public_password_rejection_does_not_wait_for_data_mutation_lock (2 seconds, Elapsed(())); Notes journal_read_does_not_wait_for_reconciliation (100 ms, Elapsed(())). Both passed once individually, with no deadline or assertion change. The full-suite failures remain in this report; no full suite was repeated.

Focused password check and focused Notes read check (each exit 0):

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 276 filtered out; finished in 4.04s
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 3 filtered out; finished in 0.03s
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 320 filtered out; finished in 3.01s
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 2 filtered out; finished in 0.01s

cargo test -p calternal-plugin-files --test jdrev2 -- --nocapture --test-threads=1 (exit 0)

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

cd apps/web && bun run build (exit 0)

✓ built in 1m 59s
✓ built in 1.03s
✓ built in 3m 8s
Compressed 917 static variants; saved 21487583 bytes.

cargo build -p calternal-server (exit 0)

    Finished `dev` profile [unoptimized + debuginfo] target(s) in 10m 05s

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

perf-lint: PASS; 0 violations; 22534 scoped exceptions
svelte-check found 0 errors and 1 warning in 1 file

cd apps/web && bunx vitest run src/lib/files/uploads.svelte.test.ts src/lib/files/UploadToast.svelte.test.ts --maxWorkers=2 (exit 0)

 Test Files  2 passed (2)
      Tests  20 passed (20)

Known gaps / UX gaps left:

  • R3 requires an author fix and a focused restart regression before approval.
  • Missing-proof bytes are kept only in memory and are not offered for recovery.
  • Permanent receipt growth has no lifetime bound; long paths make records larger. Receipt deletion is currently one DELETE rather than a bounded batch.
  • Repair needs an operator; synchronous blocked kernel IO is still outside the async deadline.
  • Full shared clippy/web suites and unrelated matrices were not repeated by this read-only review. Existing focused adversarial runner setup also ran its built-in checks. The requested restart and journalrace scenarios were completed here.

UX gaps closed (verified in reviewed changes): automatic missing-proof replay stops; protected edit refusal returns a plain notice. This reviewer made no UX changes.

Decisions:

  • Kept exact reviewed head instead of applying the shared merge/commit workflow, because this job explicitly requires read-only review with no tracked edits or commits.
  • No product design or dependency choices made. Corrected two disposable fixture setup requirements: 43-character unpadded tokens and a recent admin assertion. The first fixture failed before recovery testing; the corrected one confirmed R3, then its final admin cleanup check was denied for lacking the assertion. A separate valid admin fixture verified receipt cleanup. Retained all logs.
  • Verification used the specifically requested /mnt/hdd/targets/jobs/jdrev4 target, four build jobs, line tables, no incremental output and worktree target/tmp. No perf VM benchmark was run for this reliability review.

Cleanup (exit 0):

Removed 14453 files, 15.4GiB total

Generated apps/web/build, .svelte-kit, renderer/build and static/fonts/excalidraw are removed. Tracked tree is clean and HEAD is unchanged. Review artifacts remain local. No secrets were displayed.

BLOCK jdrev4 final independent reliability review of #1295. Head: 746dceb91581988498e41371ea91dd98c74cea22, branch job/journaldup. R3 — blocking: Cancel deletes undecidable publication proof. The real server starts with a seeded consistent legacy-style ambiguous installation. readyz returns 200; the protected Note opens with 200; its Journal edit returns 409 with a read-only notice. A sibling Note and another User accept Log writes with 201. Source, staging, Versions and installing proof retain their digests. A same-ID retry returns 412 and retains proof. The actor's ordinary DELETE /api/v1/files/uploads/<id> then returns 204. The installing row count becomes 0 and staging is removed. After a real restart, the formerly protected Note accepts a Log edit with 201. Cancellation deletes the evidence and removes the durable basis for protection without deciding the source. uploads.rs:2522 (terminate) calls rollback_failed_dav_upload, but its early return does not stop terminate's unconditional row and staging deletion. This is a non-SLOW finding. No duplicate or loss of an acknowledged Log was observed in this probe; loss of unresolved evidence and repair protection is itself the failed safety invariant. Required author fix: retain the installing record and all proof when cancellation encounters applied or ambiguous publication. Refuse that cancellation with a plain repair notice. Add a regression for cancel -> retained proof -> restart -> still-protected Note. Keep normal partial-upload cancellation behavior. No tracked files were edited by this review. R1 — late retry verified. The permanent receipt lookup has no expiry predicate and selects id+actor_id. The live test sets expires_at=0, then observes HEAD 200 and a full-byte same-ID PATCH 204 with the later Log bytes unchanged. One receipt row remains. Another User gets 404 for HEAD/PATCH/DELETE. The dedicated regression also verifies rename and replace, including cleanup. FULL authority publication commits the receipt and retires live state in one transaction. No later-time expiry path remains in reads or cleanup. Receipt growth — follow-up, not bounded. One row per successful upload; retries do not add rows. No file bytes are stored. A local SQLite size measurement uses deployed migration 0029, 100,000 rows and all four indexes. A typical 27-byte destination uses 400.10 bytes/row. At 10 uploads/minute for 365 days: 5,256,000 rows, projected 2,102,911,304 bytes (1.958 GiB) per User. A valid 3,999-byte path uses 8,877.96 bytes/row, projected 43.458 GiB/year. These are size projections, not perf-VM latency measurements; they exclude WAL, free-page fragmentation and backups. Lifetime growth has no cap, and metadata does not consume a live-upload slot. Do not expire safety proof to reduce this growth. Compact representation, accounting and batched receipt cleanup need follow-up. Source cleanup deletes receipts by owner_id OR actor_id. A separate live test with a correctly seeded recent admin assertion confirms DELETE User 202 and receipt count 1 -> 0. Scope and normal User cleanup pass. Browser — replay stops; pending-byte recovery is incomplete. The User sees: “Upload result could not be confirmed. Check the destination before uploading again.” Retry is absent. The summary offers Open Files, Show upload list and Close; the expanded component offers Cancel. The task retains its File only in the in-memory queue. There is no copy/download recovery action or queue persistence. The real production test observes zero recovery actions and the queue/notice disappearing after reload. A selected disk file still has its external original; this is not evidence of lost acknowledged Journal text. A generated File has no durable recovery path in this queue. Production browser safety passes: one upload ID, one Note, later Log retained. Six captures cover macOS emulation at 390/820/1440 px, light/dark, under artifacts/jdrev4-screenshots/. Browser plugin not available; used the existing Playwright harness. No new visual primitive or local styling. Visual quality review remains with the orchestrator. The installed fj CLI exposes no attachment command; screenshots remain local for attachment/review. Console-health assertions were not added to this read-only browser probe. R2 — timeout and initial isolated recovery verified, with R3 exception above. Dedicated production-router tests confirm pre-write PATCH timeout returns 503, installing becomes 0 before guards release, later Log returns 201, and recovery preserves bytes. Ambiguous recovery starts and serves other items and Users; the target and ancestors reject source/namespace changes, reads work, and Versions thinning retains proof. The live restart confirms availability and evidence retention until Cancel. No automatic operator repair workflow exists. Restart and journalrace ran once each. Verbatim output: ``` PASS SIGKILL mid-finalize: 1 crash, 1 later Log, 1 same-ID retry, 1 Note, 0 duplicate Notes; bytes preserved journalrace: 2021-03-14: 6 seeds, 40 creates answered 201, 0 timed out (0 of them landed), 10 uploads, 46 entries server alive at end: True ==== ROUND 2 FINDINGS 0 ==== ROUND 2 SLOW 0 ``` Built / files: - Built this head's production web app and server for verification, then removed generated output. - No tracked source, test expectations, dependency files or refs changed; no commits, merges, pushes or deploys. - Added only ignored review notes, probes, logs and screenshots: artifacts/jdrev4-notes.md, jdrev4-live.py, jdrev4-user-delete.py, jdrev4-receipt-size.py, jdrev4-browser.mjs, jdrev4-gates.sh, jdrev4-probes.sh, jdrev4-*.log and jdrev4-screenshots/. Gate output — verbatim result lines (full output in artifacts/jdrev4-*.log): cargo fmt --check: exit 0, no output. cargo test -p calternal-plugin-files -- --test-threads=4 (exit 101) ``` test result: FAILED. 272 passed; 1 failed; 4 ignored; 0 measured; 0 filtered out; finished in 358.01s ``` cargo test -p calternal-plugin-notes -- --test-threads=4 (exit 101) ``` test result: FAILED. 316 passed; 1 failed; 4 ignored; 0 measured; 0 filtered out; finished in 459.33s ``` cargo test -p calternal-tags -- --test-threads=4 (exit 0) ``` test result: ok. 52 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 86.58s test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s ``` cargo test -p calternal-sync -- --test-threads=4 (exit 0) ``` test result: ok. 65 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 1.70s test result: ok. 2 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 ``` The only full-suite failures were unchanged latency bounds: Files public_password_rejection_does_not_wait_for_data_mutation_lock (2 seconds, Elapsed(())); Notes journal_read_does_not_wait_for_reconciliation (100 ms, Elapsed(())). Both passed once individually, with no deadline or assertion change. The full-suite failures remain in this report; no full suite was repeated. Focused password check and focused Notes read check (each exit 0): ``` test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 276 filtered out; finished in 4.04s test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 3 filtered out; finished in 0.03s test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 320 filtered out; finished in 3.01s test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 2 filtered out; finished in 0.01s ``` cargo test -p calternal-plugin-files --test jdrev2 -- --nocapture --test-threads=1 (exit 0) ``` test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 44.90s ``` cd apps/web && bun run build (exit 0) ``` ✓ built in 1m 59s ✓ built in 1.03s ✓ built in 3m 8s Compressed 917 static variants; saved 21487583 bytes. ``` cargo build -p calternal-server (exit 0) ``` Finished `dev` profile [unoptimized + debuginfo] target(s) in 10m 05s ``` cd apps/web && bun run check (exit 0) ``` perf-lint: PASS; 0 violations; 22534 scoped exceptions svelte-check found 0 errors and 1 warning in 1 file ``` cd apps/web && bunx vitest run src/lib/files/uploads.svelte.test.ts src/lib/files/UploadToast.svelte.test.ts --maxWorkers=2 (exit 0) ``` Test Files 2 passed (2) Tests 20 passed (20) ``` Known gaps / UX gaps left: - R3 requires an author fix and a focused restart regression before approval. - Missing-proof bytes are kept only in memory and are not offered for recovery. - Permanent receipt growth has no lifetime bound; long paths make records larger. Receipt deletion is currently one DELETE rather than a bounded batch. - Repair needs an operator; synchronous blocked kernel IO is still outside the async deadline. - Full shared clippy/web suites and unrelated matrices were not repeated by this read-only review. Existing focused adversarial runner setup also ran its built-in checks. The requested restart and journalrace scenarios were completed here. UX gaps closed (verified in reviewed changes): automatic missing-proof replay stops; protected edit refusal returns a plain notice. This reviewer made no UX changes. Decisions: - Kept exact reviewed head instead of applying the shared merge/commit workflow, because this job explicitly requires read-only review with no tracked edits or commits. - No product design or dependency choices made. Corrected two disposable fixture setup requirements: 43-character unpadded tokens and a recent admin assertion. The first fixture failed before recovery testing; the corrected one confirmed R3, then its final admin cleanup check was denied for lacking the assertion. A separate valid admin fixture verified receipt cleanup. Retained all logs. - Verification used the specifically requested /mnt/hdd/targets/jobs/jdrev4 target, four build jobs, line tables, no incremental output and worktree target/tmp. No perf VM benchmark was run for this reliability review. Cleanup (exit 0): ``` Removed 14453 files, 15.4GiB total ``` Generated apps/web/build, .svelte-kit, renderer/build and static/fonts/excalidraw are removed. Tracked tree is clean and HEAD is unchanged. Review artifacts remain local. No secrets were displayed.
Author
Owner

Started journaldup6 on job/journaldup, base/head 746dceb915. Read contract, glossary, design and jdrev4 reports. Fixing cancellation evidence retention, User-scoped pending-byte recovery, and compact bounded receipts, with focused regressions. No push or deployment.

Started journaldup6 on job/journaldup, base/head 746dceb91581988498e41371ea91dd98c74cea22. Read contract, glossary, design and jdrev4 reports. Fixing cancellation evidence retention, User-scoped pending-byte recovery, and compact bounded receipts, with focused regressions. No push or deployment.
Author
Owner

journaldup6 progress: branch job/journaldup, commits 30cbc7620 and 8d0cc2515.

Cancel now returns 409 when installation is ambiguous and keeps the intent and staging. The focused regression starts a separate process with a fresh Root registry: the Note remains protected after Cancel and restart, and becomes writable only after the fresh-Admin hash-bound repair and restart. Repair dry-run is read-only; apply keeps current source and all Versions. DATA-SAFETY.md documents the exact action.

The browser stores pending Blob bytes and a small manifest through User-scoped userStorage before final publication. Missing completion proof stops replay; Cancel and reload retain generated text with Show text, Copy and Save file controls. New focused queue recovery tests pass. The existing toast test and retry-deadline test each passed unchanged when run alone after host-load timeouts in combined runs.

Receipt compaction is in progress: fixed-size binary facts, no paths or metadata, a 30-day server-issued browser replay deadline and 32-day receipt retention. The reviewer R1/R2 tests and compact-schema/pruning regression pass. A new legacy-conversion fixture had a body-size mismatch; its fixture is corrected and the focused test is queued. This does not change any existing expectation. Final gates and real-server/browser evidence are still pending.

journaldup6 progress: branch job/journaldup, commits 30cbc7620 and 8d0cc2515. Cancel now returns 409 when installation is ambiguous and keeps the intent and staging. The focused regression starts a separate process with a fresh Root registry: the Note remains protected after Cancel and restart, and becomes writable only after the fresh-Admin hash-bound repair and restart. Repair dry-run is read-only; apply keeps current source and all Versions. DATA-SAFETY.md documents the exact action. The browser stores pending Blob bytes and a small manifest through User-scoped userStorage before final publication. Missing completion proof stops replay; Cancel and reload retain generated text with Show text, Copy and Save file controls. New focused queue recovery tests pass. The existing toast test and retry-deadline test each passed unchanged when run alone after host-load timeouts in combined runs. Receipt compaction is in progress: fixed-size binary facts, no paths or metadata, a 30-day server-issued browser replay deadline and 32-day receipt retention. The reviewer R1/R2 tests and compact-schema/pruning regression pass. A new legacy-conversion fixture had a body-size mismatch; its fixture is corrected and the focused test is queued. This does not change any existing expectation. Final gates and real-server/browser evidence are still pending.
Author
Owner

journaldup6 progress: head 543bd39d0 (job/journaldup).

All seven focused jdrev2 production-router regressions pass. The Cancel regression now retains the exact staging and witness bytes, retains Versions, and verifies protection in a separate process before explicit Admin repair. The standalone Admin mutation contract also passes: unauthorized malformed body -> 403, dry-run -> 200 with proof retained, wrong hash -> 412, correct hash -> 200 with current bytes kept.

The receipt measurement at 460,800 rows includes the table and all three indexes: 391.55 bytes/row; 32-day live proof at 10 uploads/minute is 172.07 MiB. Unpruned yearly churn would be 1.917 GiB. Identity lookup uses the primary key; pruning uses the completion-time index. This is a local schema space measurement, not a latency result.

Fetched origin and merged origin/dev once before final gates: already up to date. Files migration 0030 is free on origin/dev (latest deployed Files migration there is 0028; this job already owns 0029).

A review of the new browser persistence found that two tabs could race a shared JSON manifest. The follow-up uses independent per-upload User-scoped records and adds a single-snapshot keys method to the existing userStorage facade. Existing storage behavior is unchanged; new focused concurrency and namespace tests are running. Final production build and ordered Rust gates have started. No pushes or deploys.

journaldup6 progress: head 543bd39d0 (job/journaldup). All seven focused jdrev2 production-router regressions pass. The Cancel regression now retains the exact staging and witness bytes, retains Versions, and verifies protection in a separate process before explicit Admin repair. The standalone Admin mutation contract also passes: unauthorized malformed body -> 403, dry-run -> 200 with proof retained, wrong hash -> 412, correct hash -> 200 with current bytes kept. The receipt measurement at 460,800 rows includes the table and all three indexes: 391.55 bytes/row; 32-day live proof at 10 uploads/minute is 172.07 MiB. Unpruned yearly churn would be 1.917 GiB. Identity lookup uses the primary key; pruning uses the completion-time index. This is a local schema space measurement, not a latency result. Fetched origin and merged origin/dev once before final gates: already up to date. Files migration 0030 is free on origin/dev (latest deployed Files migration there is 0028; this job already owns 0029). A review of the new browser persistence found that two tabs could race a shared JSON manifest. The follow-up uses independent per-upload User-scoped records and adds a single-snapshot keys method to the existing userStorage facade. Existing storage behavior is unchanged; new focused concurrency and namespace tests are running. Final production build and ordered Rust gates have started. No pushes or deploys.
Author
Owner

journaldup6 verification, head 3d602f8a1f30f30d0ed1761d4421b2fd72c18520.

Repair now retires proof without a completion receipt: keeping current source bytes cannot prove that staged upload bytes completed. The latest Cancel/repair regression passed across a child-process restart and checks zero receipts after repair. API, client types and exact live perf pins are committed. Classification checks pass: 430 operations, 1206 generated tool entry points, 54 Admin operations.

Real browser (Node, macOS platform) captured Files at 390/820/1440 px in light and dark. Its first run stopped on a new e2e strict selector that matched the Cancel message in both the summary and expanded row; scoped to the row and rerunning. No production assertion changed.

Latest reviewer regressions: 6 passed, 1 failed. pre_rename_timeout_then_log_edit_recovers_safely misses its unchanged admission poll (intent must precede source IO); an isolated rerun also misses it. The fixture grants only 3 seconds of upload lifetime and polls roughly 2 seconds; isolated total time was 56.72 seconds. This is recorded as a failed gate, not a pass or an assumed harmless finding. Earlier focused run passed all seven on this branch.

SIGKILL probe stopped at startup: AssertionError: server did not become ready (180 seconds), before any crash assertion. Journalrace is running after the classification fix. Production web build, fmt and Files clippy passed; ordered Rust gates continue.

journaldup6 verification, head `3d602f8a1f30f30d0ed1761d4421b2fd72c18520`. Repair now retires proof without a completion receipt: keeping current source bytes cannot prove that staged upload bytes completed. The latest Cancel/repair regression passed across a child-process restart and checks zero receipts after repair. API, client types and exact live perf pins are committed. Classification checks pass: 430 operations, 1206 generated tool entry points, 54 Admin operations. Real browser (Node, macOS platform) captured Files at 390/820/1440 px in light and dark. Its first run stopped on a new e2e strict selector that matched the Cancel message in both the summary and expanded row; scoped to the row and rerunning. No production assertion changed. Latest reviewer regressions: 6 passed, 1 failed. `pre_rename_timeout_then_log_edit_recovers_safely` misses its unchanged admission poll (`intent must precede source IO`); an isolated rerun also misses it. The fixture grants only 3 seconds of upload lifetime and polls roughly 2 seconds; isolated total time was 56.72 seconds. This is recorded as a failed gate, not a pass or an assumed harmless finding. Earlier focused run passed all seven on this branch. SIGKILL probe stopped at startup: `AssertionError: server did not become ready` (180 seconds), before any crash assertion. Journalrace is running after the classification fix. Production web build, fmt and Files clippy passed; ordered Rust gates continue.
Author
Owner

NOT READY FOR MERGE. journaldup6, branch job/journaldup, head 9c08db27b4c725e8314a52a7b10c510a81566add. No push, deploy, or merge to another branch. The one instructed origin/dev merge returned Already up to date.

What was built

  • Cancel and failed finalization keep ambiguous intent, staging chunks, applied witness, Versions and Note protection. A process restart still protects the Note.
  • Explicit fresh, unrestricted Admin-only POST /api/v1/files/uploads/{id}/repair: required dry-run, keep/discard plan, current-hash-bound apply, no staged overwrite. Keep current Source and all Versions. Apply resolves the intent and staging proof; restart releases the old in-memory protection. Repair never issues a false completion receipt. DATA-SAFETY.md documents the action.
  • Pending browser bytes are stored through User-scoped userStorage before final publication. Missing proof, Cancel and reload retain them. Show text, exact Copy and Save file use shared Pill, OverlaySurface, TextView and copyText. Two tabs use independent queue records. A shared TextView Blob input fixes the CSP failure found on the real production build; no security policy was relaxed.
  • Migration 0030 stores fixed-size completion facts and hashed owner/actor authority, with indexed bounded pruning. Browser replay uses the absolute server deadline; expired or unproved restored uploads stay inspection-only.

Decisions

  • Replay window is 30 days; receipt retention is 32 days. The API header is the browser's contract, so no second browser duration constant can drift. Completed HEAD conservatively supplies 29 days because the original upload could have lived one day. A known creation deadline never extends.
  • Legacy receipts convert in FULL transactions of 256. Unknown historical content hashes use an all-zero sentinel, never write authority; existing proof gets a fresh 32-day grace. Pruning uses FULL batches of 4096. Authority hashes are needed for User/actor isolation.
  • Operator repair keeps only the inspected current file and all Versions. It does not guess a merge. Its protection ends on restart. Keeping current bytes does not prove completion of original staging bytes, so repair leaves no receipt.
  • Reload restores pending bytes for inspection only. Existing #555 User session cleanup still owns cache deletion. Local-storage failure stops final publication and leaves the in-memory File for recovery.
  • Used the preset CARGO_TARGET_DIR, per the do-not-override rule; it is /home/kayg/build/targets/journaldup6 rather than the older /mnt/hdd/targets/jobs/journaldup symlink.

Cost and space
One extra native browser cache write per pending File is O(file bytes). Queue recovery is O(pending records), with three Blob reads at a time. Repair hashes one file outside writer locks and updates one indexed item. Receipt HEAD uses indexed identity and item lookups. Pruning work is O(expired receipts), in bounded transactions; no request scans a Home.

The local schema-space profile used 460800 rows and all three receipt indexes: 391.55 bytes/row (maximum raw facts: 160 bytes). At 10 uploads/minute the 32-day live set is about 172.07 MiB per User. Yearly churn is 5256000 rows; without pruning it would be 1.917 GiB/year, compared with the review's about 1.96 GiB/year. With successful maintenance it reuses the bounded live set each year. Existing allocated SQLite pages do not shrink automatically. This is a local space measurement, not perf-VM latency. Profile: bench/upload-receipt-footprint.py; output: artifacts/journaldup6-receipt-space.log.

Gate output, verbatim
cargo fmt --check passed with no output. Rust gates used line-tables-only, no incremental, four build jobs, worktree TMPDIR and four test threads. All full crate tests ran once. Server clippy passed; Server tests stopped during compilation at the job time limit, with no test pass claimed.

preview-web-build

✓ built in 2m 22s
✓ built in 226ms
✓ built in 5m 38s
Compressed 917 static variants; saved 21501447 bytes.

final-files-clippy

    Finished `dev` profile [unoptimized + debuginfo] target(s) in 36m 13s

final-server-clippy

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

final-files-test

test result: FAILED. 269 passed; 5 failed; 4 ignored; 0 measured; 0 filtered out; finished in 1547.22s

final-notes-test

test result: ok. 317 passed; 0 failed; 4 ignored; 0 measured; 0 filtered out; finished in 733.25s
test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 6.49s
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

final-tags-test

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

final-sync-test

test result: ok. 65 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 7.95s
test result: ok. 2 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

latest-reviewer-regressions

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 6 filtered out; finished in 0.13s
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 6 filtered out; finished in 7.63s
test result: FAILED. 6 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 117.41s

local-preview-fixed

 Test Files  1 passed (1)
      Tests  2 passed (2)

finalize-crash-retry

PASS SIGKILL mid-finalize: 1 crash, 1 later Log, 1 same-ID retry, 1 Note, 0 duplicate Notes; bytes preserved

Verification findings and known gaps

  • Files full gate failed: Finder concurrency received ServiceUnavailable; four other tests expired deadlines (HTTP Index checkout, internal-temp reconcile storm, applied Journal deadline and public-password rejection). No existing status, assertion or deadline was changed. The latest reviewer set is 6 passed / 1 failed; the unchanged pre-rename admission poll fails in isolation too (intent must precede source IO, total 56.72 s). Earlier branch-focused run passed all seven, but that is not substituted for the latest result.
  • Real browser confirms Cancel -> reload -> Show text -> exact Copy. Full e2e is not passing: the existing Daily Note bridge adds frontmatter after the source-byte snapshot, so the unchanged strict byte assertion fails. That stops the foreground multi-tab portion. Keep the assertion; fixture isolation needs review. A prior background-tab multi-row pointer click was intercepted; the foreground correction is committed, not proven by a complete run.
  • Twelve actual production screenshots exist for Files and pending text: 390/820/1440 px, light/dark, macOS platform. Shared toast overflow behind another notification is filed as #1388. No visual approval is claimed. Files are under artifacts/journaldup6-screenshots/; no artifacts are committed. Forgejo CLI has no issue attachment command and direct asset authentication was unavailable. No credential-store content was displayed. Screenshot attachment remains for orchestration.
  • Requested SIGKILL finalization probe passed on one bounded retry after initial 180-second startup failure. One bounded journalrace round finished with one real upload-create 503 and 13 30-second request timeouts, plus one SLOW seed. The non-SLOW 503 is recorded on #1383; its independent fresh-DAV fixture 403 is on #1382. No corruption or duplicate Note finding was reported by that round.
  • The extra live Admin/sibling probe did not finish: the later attempt timed out on the first PATCH. An earlier real-server check passed 31-day receipt ACK, unchanged later bytes and cross-User HEAD/PATCH/DELETE 404, but the sibling response was not captured in that first attempt. Do not substitute that partial probe for complete live repair/R2 verification.
  • Final web check and full web test passed. Files, Server-test completion and the full browser e2e still prevent readiness. No baseline 746dceb91 run was executed in this job; regression assertions target its missing retention/repair/deadline/recovery behavior, but a measured baseline contrast is not claimed.

UX gaps closed
Pending text survives missing proof, Cancel and reload; exact Copy works; Save file retains binary bytes; expired/missing deadlines do not replay; concurrent tabs have independent records; Blob preview works with the existing CSP.

UX gaps left
Shared collapsed toast overflow (#1388), foreground multi-tab pointer confirmation, complete e2e byte-preservation fixture isolation, and screenshot attachment/Claude review. Operator repair is an API action documented for Admins, with no new Admin screen.

Work left (continuation, not a claimed completed merge round)

  • Resolve the failed Files/reviewer gates while keeping existing expectations, and rerun the specific failures.
  • Finish cargo test -p calternal-server -- --test-threads=4.
  • Complete CALTERNAL_SERVER_BIN="$CARGO_TARGET_DIR/debug/calternal-server" node apps/web/e2e/upload-recovery-1295.mjs without weakening its source assertion, then verify the foreground multi-tab portion.
  • Complete the focused live repair/R2 probe and attach/review the 12 screenshots.
  • Web check and full web test passed after the origin/dev merge; rerun only if further changes require them.

Files

  • apps/web/e2e/upload-recovery-1295.mjs
  • apps/web/src/lib/files/TextView.svelte.test.ts
  • apps/web/src/lib/files/UploadToast.svelte
  • apps/web/src/lib/files/upload-recovery.svelte.test.ts
  • apps/web/src/lib/files/uploads.svelte.test.ts
  • apps/web/src/lib/files/uploads.svelte.ts
  • apps/web/src/lib/userStorage.svelte.test.ts
  • apps/web/src/lib/userStorage.ts
  • apps/web/src/routes/+layout.svelte
  • bench/upload-receipt-footprint.py
  • contracts/action-authority.json
  • contracts/action-policy.json
  • contracts/actions.json
  • contracts/openapi.json
  • contracts/perf/adoption-1058.json
  • contracts/perf/exceptions.json
  • contracts/perf/ratchet.json
  • contracts/perf/registry.json
  • crates/calternal-server/src/upgrade_tests.rs
  • crates/plugins/files/DATA-SAFETY.md
  • crates/plugins/files/migrations/0030_compact_upload_receipts.sql
  • crates/plugins/files/src/lib.rs
  • crates/plugins/files/src/tests/journal_retry.rs
  • crates/plugins/files/src/uploads.rs
  • crates/plugins/files/tests/jdrev2.rs
  • packages/api-client/src/generated.ts
  • packages/ui/README.md
  • packages/ui/src/components/viewer/TextView.svelte
  • tests/adversarial/authz_matrix.py
  • tests/adversarial/journal_finalize_crash.py
  • tests/adversarial/xuser_matrix.py

Final web gates and cleanup, verbatim
cd apps/web && bun run check — exit 0:

perf-lint: PASS; 0 violations; 22636 scoped exceptions
svelte-check found 0 errors and 1 warning in 1 file

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

 Test Files  289 passed (289)
      Tests  2047 passed (2047)
   Start at  20:13:37
   Duration  439.95s (transform 27%, import 26%, environment 26%, tests 15%, setup 5%)

cargo clean:

     Removed 22666 files, 18.7GiB total

Web production output and SvelteKit output were deleted; review artifacts remain local and ignored. Working tree is clean. Full source-file doc comments were reviewed. Job stopped at about four hours; no further source changes are pending.

NOT READY FOR MERGE. journaldup6, branch `job/journaldup`, head `9c08db27b4c725e8314a52a7b10c510a81566add`. No push, deploy, or merge to another branch. The one instructed origin/dev merge returned `Already up to date.` What was built - Cancel and failed finalization keep ambiguous intent, staging chunks, applied witness, Versions and Note protection. A process restart still protects the Note. - Explicit fresh, unrestricted Admin-only `POST /api/v1/files/uploads/{id}/repair`: required dry-run, keep/discard plan, current-hash-bound apply, no staged overwrite. Keep current Source and all Versions. Apply resolves the intent and staging proof; restart releases the old in-memory protection. Repair never issues a false completion receipt. DATA-SAFETY.md documents the action. - Pending browser bytes are stored through User-scoped userStorage before final publication. Missing proof, Cancel and reload retain them. Show text, exact Copy and Save file use shared Pill, OverlaySurface, TextView and copyText. Two tabs use independent queue records. A shared TextView Blob input fixes the CSP failure found on the real production build; no security policy was relaxed. - Migration 0030 stores fixed-size completion facts and hashed owner/actor authority, with indexed bounded pruning. Browser replay uses the absolute server deadline; expired or unproved restored uploads stay inspection-only. Decisions - Replay window is 30 days; receipt retention is 32 days. The API header is the browser's contract, so no second browser duration constant can drift. Completed HEAD conservatively supplies 29 days because the original upload could have lived one day. A known creation deadline never extends. - Legacy receipts convert in FULL transactions of 256. Unknown historical content hashes use an all-zero sentinel, never write authority; existing proof gets a fresh 32-day grace. Pruning uses FULL batches of 4096. Authority hashes are needed for User/actor isolation. - Operator repair keeps only the inspected current file and all Versions. It does not guess a merge. Its protection ends on restart. Keeping current bytes does not prove completion of original staging bytes, so repair leaves no receipt. - Reload restores pending bytes for inspection only. Existing #555 User session cleanup still owns cache deletion. Local-storage failure stops final publication and leaves the in-memory File for recovery. - Used the preset CARGO_TARGET_DIR, per the do-not-override rule; it is `/home/kayg/build/targets/journaldup6` rather than the older `/mnt/hdd/targets/jobs/journaldup` symlink. Cost and space One extra native browser cache write per pending File is O(file bytes). Queue recovery is O(pending records), with three Blob reads at a time. Repair hashes one file outside writer locks and updates one indexed item. Receipt HEAD uses indexed identity and item lookups. Pruning work is O(expired receipts), in bounded transactions; no request scans a Home. The local schema-space profile used 460800 rows and all three receipt indexes: 391.55 bytes/row (maximum raw facts: 160 bytes). At 10 uploads/minute the 32-day live set is about 172.07 MiB per User. Yearly churn is 5256000 rows; without pruning it would be 1.917 GiB/year, compared with the review's about 1.96 GiB/year. With successful maintenance it reuses the bounded live set each year. Existing allocated SQLite pages do not shrink automatically. This is a local space measurement, not perf-VM latency. Profile: `bench/upload-receipt-footprint.py`; output: `artifacts/journaldup6-receipt-space.log`. Gate output, verbatim `cargo fmt --check` passed with no output. Rust gates used line-tables-only, no incremental, four build jobs, worktree TMPDIR and four test threads. All full crate tests ran once. Server clippy passed; Server tests stopped during compilation at the job time limit, with no test pass claimed. `preview-web-build` ``` ✓ built in 2m 22s ✓ built in 226ms ✓ built in 5m 38s Compressed 917 static variants; saved 21501447 bytes. ``` `final-files-clippy` ``` Finished `dev` profile [unoptimized + debuginfo] target(s) in 36m 13s ``` `final-server-clippy` ``` Finished `dev` profile [unoptimized + debuginfo] target(s) in 11m 00s ``` `final-files-test` ``` test result: FAILED. 269 passed; 5 failed; 4 ignored; 0 measured; 0 filtered out; finished in 1547.22s ``` `final-notes-test` ``` test result: ok. 317 passed; 0 failed; 4 ignored; 0 measured; 0 filtered out; finished in 733.25s test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 6.49s test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s ``` `final-tags-test` ``` test result: ok. 52 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 194.37s test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s ``` `final-sync-test` ``` test result: ok. 65 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 7.95s test result: ok. 2 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 ``` `latest-reviewer-regressions` ``` test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 6 filtered out; finished in 0.13s test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 6 filtered out; finished in 7.63s test result: FAILED. 6 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 117.41s ``` `local-preview-fixed` ``` Test Files 1 passed (1) Tests 2 passed (2) ``` `finalize-crash-retry` ``` PASS SIGKILL mid-finalize: 1 crash, 1 later Log, 1 same-ID retry, 1 Note, 0 duplicate Notes; bytes preserved ``` Verification findings and known gaps - Files full gate failed: Finder concurrency received ServiceUnavailable; four other tests expired deadlines (HTTP Index checkout, internal-temp reconcile storm, applied Journal deadline and public-password rejection). No existing status, assertion or deadline was changed. The latest reviewer set is 6 passed / 1 failed; the unchanged pre-rename admission poll fails in isolation too (`intent must precede source IO`, total 56.72 s). Earlier branch-focused run passed all seven, but that is not substituted for the latest result. - Real browser confirms Cancel -> reload -> Show text -> exact Copy. Full e2e is not passing: the existing Daily Note bridge adds frontmatter after the source-byte snapshot, so the unchanged strict byte assertion fails. That stops the foreground multi-tab portion. Keep the assertion; fixture isolation needs review. A prior background-tab multi-row pointer click was intercepted; the foreground correction is committed, not proven by a complete run. - Twelve actual production screenshots exist for Files and pending text: 390/820/1440 px, light/dark, macOS platform. Shared toast overflow behind another notification is filed as #1388. No visual approval is claimed. Files are under `artifacts/journaldup6-screenshots/`; no artifacts are committed. Forgejo CLI has no issue attachment command and direct asset authentication was unavailable. No credential-store content was displayed. Screenshot attachment remains for orchestration. - Requested SIGKILL finalization probe passed on one bounded retry after initial 180-second startup failure. One bounded journalrace round finished with one real upload-create 503 and 13 30-second request timeouts, plus one SLOW seed. The non-SLOW 503 is recorded on #1383; its independent fresh-DAV fixture 403 is on #1382. No corruption or duplicate Note finding was reported by that round. - The extra live Admin/sibling probe did not finish: the later attempt timed out on the first PATCH. An earlier real-server check passed 31-day receipt ACK, unchanged later bytes and cross-User HEAD/PATCH/DELETE 404, but the sibling response was not captured in that first attempt. Do not substitute that partial probe for complete live repair/R2 verification. - Final web check and full web test passed. Files, Server-test completion and the full browser e2e still prevent readiness. No baseline 746dceb91 run was executed in this job; regression assertions target its missing retention/repair/deadline/recovery behavior, but a measured baseline contrast is not claimed. UX gaps closed Pending text survives missing proof, Cancel and reload; exact Copy works; Save file retains binary bytes; expired/missing deadlines do not replay; concurrent tabs have independent records; Blob preview works with the existing CSP. UX gaps left Shared collapsed toast overflow (#1388), foreground multi-tab pointer confirmation, complete e2e byte-preservation fixture isolation, and screenshot attachment/Claude review. Operator repair is an API action documented for Admins, with no new Admin screen. Work left (continuation, not a claimed completed merge round) - Resolve the failed Files/reviewer gates while keeping existing expectations, and rerun the specific failures. - Finish `cargo test -p calternal-server -- --test-threads=4`. - Complete `CALTERNAL_SERVER_BIN="$CARGO_TARGET_DIR/debug/calternal-server" node apps/web/e2e/upload-recovery-1295.mjs` without weakening its source assertion, then verify the foreground multi-tab portion. - Complete the focused live repair/R2 probe and attach/review the 12 screenshots. - Web check and full web test passed after the origin/dev merge; rerun only if further changes require them. Files - `apps/web/e2e/upload-recovery-1295.mjs` - `apps/web/src/lib/files/TextView.svelte.test.ts` - `apps/web/src/lib/files/UploadToast.svelte` - `apps/web/src/lib/files/upload-recovery.svelte.test.ts` - `apps/web/src/lib/files/uploads.svelte.test.ts` - `apps/web/src/lib/files/uploads.svelte.ts` - `apps/web/src/lib/userStorage.svelte.test.ts` - `apps/web/src/lib/userStorage.ts` - `apps/web/src/routes/+layout.svelte` - `bench/upload-receipt-footprint.py` - `contracts/action-authority.json` - `contracts/action-policy.json` - `contracts/actions.json` - `contracts/openapi.json` - `contracts/perf/adoption-1058.json` - `contracts/perf/exceptions.json` - `contracts/perf/ratchet.json` - `contracts/perf/registry.json` - `crates/calternal-server/src/upgrade_tests.rs` - `crates/plugins/files/DATA-SAFETY.md` - `crates/plugins/files/migrations/0030_compact_upload_receipts.sql` - `crates/plugins/files/src/lib.rs` - `crates/plugins/files/src/tests/journal_retry.rs` - `crates/plugins/files/src/uploads.rs` - `crates/plugins/files/tests/jdrev2.rs` - `packages/api-client/src/generated.ts` - `packages/ui/README.md` - `packages/ui/src/components/viewer/TextView.svelte` - `tests/adversarial/authz_matrix.py` - `tests/adversarial/journal_finalize_crash.py` - `tests/adversarial/xuser_matrix.py` Final web gates and cleanup, verbatim `cd apps/web && bun run check` — exit 0: ``` perf-lint: PASS; 0 violations; 22636 scoped exceptions svelte-check found 0 errors and 1 warning in 1 file ``` `cd apps/web && bun run test -- --maxWorkers=2` — exit 0: ``` Test Files 289 passed (289) Tests 2047 passed (2047) Start at 20:13:37 Duration 439.95s (transform 27%, import 26%, environment 26%, tests 15%, setup 5%) ``` `cargo clean`: ``` Removed 22666 files, 18.7GiB total ``` Web production output and SvelteKit output were deleted; review artifacts remain local and ignored. Working tree is clean. Full source-file doc comments were reviewed. Job stopped at about four hours; no further source changes are pending.
Author
Owner

journaldup7 starts on job/journaldup, base/head 9c08db27b4c725e8314a52a7b10c510a81566add. Read CLAUDE.md, CONTEXT.md, DESIGN and journaldup6 report/comment. Rebuild pending text with the shared Quick Look viewer, investigate admission ordering without changing assertions, isolate the browser byte fixture, rerun isolated Files failures and complete Server tests. No push or deploy. The instructed origin/dev integration will run once before final gates.

journaldup7 starts on `job/journaldup`, base/head `9c08db27b4c725e8314a52a7b10c510a81566add`. Read CLAUDE.md, CONTEXT.md, DESIGN and journaldup6 report/comment. Rebuild pending text with the shared Quick Look viewer, investigate admission ordering without changing assertions, isolate the browser byte fixture, rerun isolated Files failures and complete Server tests. No push or deploy. The instructed origin/dev integration will run once before final gates.
Author
Owner

journaldup7 UI slice committed as c5df5c5ac. Pending text now uses shared Quick Look, TextView, PillGroup and CopyLink feedback. Upload summaries use shared ToastBody with one title line and one truncated detail line; icon controls use shared Pills. Collapsed non-front cards clip content within Sonner's box (#1388).

Found a focus-transfer defect in AppToaster: every toast button moved focus to the next toast, even when an upload control did not dismiss its toast. Show text could therefore focus Update available while opening the viewer. Transfer now waits for Sonner to mark the card removed. The shared overlay focus option permits quiet initial focus without changing data-input or later Tab rings.

Focused UI checks: 35 tests passed for the initial shared viewer/toast slice, followed by 5 passing focus/toaster tests after the focus-transfer correction. Browser fixture isolation and production screenshots remain in progress. Rust admission regression is compiling in the prescribed target directory. No new dependencies.

journaldup7 UI slice committed as `c5df5c5ac`. Pending text now uses shared Quick Look, TextView, PillGroup and CopyLink feedback. Upload summaries use shared ToastBody with one title line and one truncated detail line; icon controls use shared Pills. Collapsed non-front cards clip content within Sonner's box (#1388). Found a focus-transfer defect in AppToaster: every toast button moved focus to the next toast, even when an upload control did not dismiss its toast. Show text could therefore focus Update available while opening the viewer. Transfer now waits for Sonner to mark the card removed. The shared overlay focus option permits quiet initial focus without changing data-input or later Tab rings. Focused UI checks: 35 tests passed for the initial shared viewer/toast slice, followed by 5 passing focus/toaster tests after the focus-transfer correction. Browser fixture isolation and production screenshots remain in progress. Rust admission regression is compiling in the prescribed target directory. No new dependencies.
Author
Owner

journaldup7 progress: head 61e39e2ca, after the required origin/dev merge (d395b6e25). No push or deploy.

Production web build passes: ✓ built in 1m 6s, ✓ built in 135ms, ✓ built in 2m 15s, Compressed 914 static variants; saved 21524531 bytes. Exact merged performance pins pass with perf-lint: PASS; 0 violations; 22606 scoped exceptions; no waiver or limit was added.

The original isolated admission test passed with the unchanged assertion: test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 6 filtered out; finished in 5.35s. Its fixture starts a three-second hard lifetime before unrelated writer setup and chunk durability, and uses a guessed 200 ms readiness sleep. The follow-up stages bytes first, waits for the held writer's first input poll, and stamps the same lifetime in SQLite immediately before the final byte. The admission assertion, poll, six-second completion bound and all source/proof assertions remain unchanged. This corrected fixture is queued for the final isolated run.

The merge moved Files profile_stage to an origin-labelled three-argument helper. Clippy found one branch-only thumbnail-enqueue call still using two arguments; that call now uses WriterOrigin::Upload. Final clippy will be rerun after this merge correction.

The shared prebuilt server has no files_upload_receipts table, so the exact branch fixture cannot remove its proof there. Building the branch server for browser evidence; do not treat the failed shared-server fixture as a product pass. Full web tests, ordered isolated Files tests, Files full tests and Server completion remain in progress.

journaldup7 progress: head `61e39e2ca`, after the required origin/dev merge (`d395b6e25`). No push or deploy. Production web build passes: `✓ built in 1m 6s`, `✓ built in 135ms`, `✓ built in 2m 15s`, `Compressed 914 static variants; saved 21524531 bytes.` Exact merged performance pins pass with `perf-lint: PASS; 0 violations; 22606 scoped exceptions`; no waiver or limit was added. The original isolated admission test passed with the unchanged assertion: `test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 6 filtered out; finished in 5.35s`. Its fixture starts a three-second hard lifetime before unrelated writer setup and chunk durability, and uses a guessed 200 ms readiness sleep. The follow-up stages bytes first, waits for the held writer's first input poll, and stamps the same lifetime in SQLite immediately before the final byte. The admission assertion, poll, six-second completion bound and all source/proof assertions remain unchanged. This corrected fixture is queued for the final isolated run. The merge moved Files profile_stage to an origin-labelled three-argument helper. Clippy found one branch-only thumbnail-enqueue call still using two arguments; that call now uses WriterOrigin::Upload. Final clippy will be rerun after this merge correction. The shared prebuilt server has no files_upload_receipts table, so the exact branch fixture cannot remove its proof there. Building the branch server for browser evidence; do not treat the failed shared-server fixture as a product pass. Full web tests, ordered isolated Files tests, Files full tests and Server completion remain in progress.
Author
Owner

journaldup7 finding: all five earlier Files gate failures pass in isolation after the single origin/dev integration. No assertion or deadline was weakened. The admission fixture now stages before its three-second remaining lifetime and waits for actual writer readiness; its original pre-source-IO assertion also passes. Full Files and Server gates continue.

concurrent_finder_puts_keep_all_uploads

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

http_index_write_checkout_timeout_returns_retryable_service_unavailable

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

internal_temp_paths_never_enter_index_during_atomic_write_reconcile_storm

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

journal_deadline_hands_off_applied_note_without_replay

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

public_password_rejection_does_not_wait_for_data_mutation_lock

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 281 filtered out; finished in 0.67s
journaldup7 finding: all five earlier Files gate failures pass in isolation after the single origin/dev integration. No assertion or deadline was weakened. The admission fixture now stages before its three-second remaining lifetime and waits for actual writer readiness; its original pre-source-IO assertion also passes. Full Files and Server gates continue. `concurrent_finder_puts_keep_all_uploads` ```text test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 281 filtered out; finished in 14.20s ``` `http_index_write_checkout_timeout_returns_retryable_service_unavailable` ```text test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 281 filtered out; finished in 6.03s ``` `internal_temp_paths_never_enter_index_during_atomic_write_reconcile_storm` ```text test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 281 filtered out; finished in 89.96s ``` `journal_deadline_hands_off_applied_note_without_replay` ```text test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 281 filtered out; finished in 3.10s ``` `public_password_rejection_does_not_wait_for_data_mutation_lock` ```text test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 281 filtered out; finished in 0.67s ```
Author
Owner

journaldup7 browser and crash evidence (head 4d7002591). All strict source-byte and upload-count assertions pass. The Daily note bridge completes before the snapshot; its source byte assertion stays strict. Both simultaneous tabs retain their own pending text. Copy and Save file return the original pending bytes.

PASS shared stack: truncated upload detail cannot spill through another notification
PASS macOS 390 light: missing completion proof has no Retry action
PASS macOS 390 dark: missing completion proof has no Retry action
PASS macOS 820 light: missing completion proof has no Retry action
PASS macOS 820 dark: missing completion proof has no Retry action
PASS macOS 1440 light: missing completion proof has no Retry action
PASS macOS 1440 dark: missing completion proof has no Retry action
PASS Cancel retains a reviewable pending upload
PASS reload restores pending text without another upload
PASS Show text opens the retained browser bytes
PASS Copy returns the exact original text
PASS Save file downloads the exact retained bytes
PASS browser recovery: missing proof -> Cancel -> reload -> exact Copy; simultaneous tabs retain both texts; later Log retained; 12 macOS screenshots
PASS SIGKILL mid-finalize: 1 crash, 1 later Log, 1 same-ID retry, 1 Note, 0 duplicate Notes; bytes preserved

22 unique macOS-emulated screenshots are attached: 12 requested screen/width/theme captures, 4 real existing TextView references, 2 focus captures, and 4 actual-pixel alignment close-ups. The API returned one transient 500; the missing capture was uploaded on retry.

pending-text-1440-light-mac.png

pending-text-390-dark-mac.png

files-upload-1440-dark-mac.png

pending-text-opening-keyboard-mac.png

pending-text-after-mouse-copy-mac.png

alignment-files-upload-1440-dark-mac.png

alignment-pending-text-390-dark-mac.png

Full web rerun:

 Test Files  299 passed (299)
      Tests  2130 passed (2130)

Server clippy and the complete Server test command remain in progress. No push or deploy.

journaldup7 browser and crash evidence (head `4d7002591`). All strict source-byte and upload-count assertions pass. The Daily note bridge completes before the snapshot; its source byte assertion stays strict. Both simultaneous tabs retain their own pending text. Copy and Save file return the original pending bytes. ```text PASS shared stack: truncated upload detail cannot spill through another notification PASS macOS 390 light: missing completion proof has no Retry action PASS macOS 390 dark: missing completion proof has no Retry action PASS macOS 820 light: missing completion proof has no Retry action PASS macOS 820 dark: missing completion proof has no Retry action PASS macOS 1440 light: missing completion proof has no Retry action PASS macOS 1440 dark: missing completion proof has no Retry action PASS Cancel retains a reviewable pending upload PASS reload restores pending text without another upload PASS Show text opens the retained browser bytes PASS Copy returns the exact original text PASS Save file downloads the exact retained bytes PASS browser recovery: missing proof -> Cancel -> reload -> exact Copy; simultaneous tabs retain both texts; later Log retained; 12 macOS screenshots PASS SIGKILL mid-finalize: 1 crash, 1 later Log, 1 same-ID retry, 1 Note, 0 duplicate Notes; bytes preserved ``` 22 unique macOS-emulated screenshots are attached: 12 requested screen/width/theme captures, 4 real existing TextView references, 2 focus captures, and 4 actual-pixel alignment close-ups. The API returned one transient 500; the missing capture was uploaded on retry. [pending-text-1440-light-mac.png](https://git.kayg.org/attachments/5a3e00f5-294b-4f95-92cf-535cf3b5c62f) [pending-text-390-dark-mac.png](https://git.kayg.org/attachments/9d1cafa5-be0a-48b6-bde4-03f37661c40b) [files-upload-1440-dark-mac.png](https://git.kayg.org/attachments/f5278e07-f8e7-4ca1-ba7e-4271e1a52c08) [pending-text-opening-keyboard-mac.png](https://git.kayg.org/attachments/b4b69a32-8ff6-4465-8eb8-fe1072bc59c5) [pending-text-after-mouse-copy-mac.png](https://git.kayg.org/attachments/cc1cdc29-ac5c-48aa-b43f-1353678265a0) [alignment-files-upload-1440-dark-mac.png](https://git.kayg.org/attachments/496f2602-701e-484b-9a84-089a28baa0d4) [alignment-pending-text-390-dark-mac.png](https://git.kayg.org/attachments/5fc7c38e-726e-4a63-9d8c-d4608d4ef6fc) Full web rerun: ```text Test Files 299 passed (299) Tests 2130 passed (2130) ``` Server clippy and the complete Server test command remain in progress. No push or deploy.
Author
Owner

journaldup7 finding: the full Server gate exposes two upgrade-fixture pins left behind by receipt compaction. production_round_9_schema_upgrades_once_with_original_receipts and production_7b_schema_copy_upgrades_combined_pending_migrations report FAILED. The tests explicitly require Files 0029 and a 24-migration pending set, while this issue also registers Files 0030 (0030_compact_upload_receipts.sql). The earlier #1295 comment describes the same test-only update for adding 0029; compaction also needs its own pin.

Minimal test-only addition in crates/calternal-server/src/upgrade_tests.rs: add 0030 to the exact pending/required sets; require final Files frontier 30; increment the exact pending count from 24 to 25; update module reasoning. These are schema-frontier expectation changes required by #1295's new migration, explicitly listed for orchestrator review. No historical fixture SQL, historical migration receipt/checksum, preserved User row assertion, HTTP status expectation, admission assertion or deadline changes. The new requirement strengthens upgrade coverage by making omission of compaction fail.

Focused upgrade tests are running before commit. The original full Server command continues to completion, including its isolated live-app processes; final Server gates will run after this fix.

journaldup7 finding: the full Server gate exposes two upgrade-fixture pins left behind by receipt compaction. `production_round_9_schema_upgrades_once_with_original_receipts` and `production_7b_schema_copy_upgrades_combined_pending_migrations` report FAILED. The tests explicitly require Files 0029 and a 24-migration pending set, while this issue also registers Files 0030 (`0030_compact_upload_receipts.sql`). The earlier #1295 comment describes the same test-only update for adding 0029; compaction also needs its own pin. Minimal test-only addition in `crates/calternal-server/src/upgrade_tests.rs`: add 0030 to the exact pending/required sets; require final Files frontier 30; increment the exact pending count from 24 to 25; update module reasoning. These are schema-frontier expectation changes required by #1295's new migration, explicitly listed for orchestrator review. No historical fixture SQL, historical migration receipt/checksum, preserved User row assertion, HTTP status expectation, admission assertion or deadline changes. The new requirement strengthens upgrade coverage by making omission of compaction fail. Focused upgrade tests are running before commit. The original full Server command continues to completion, including its isolated live-app processes; final Server gates will run after this fix.
Author
Owner

journaldup7 schema pin fix committed. The complete failing Server run confirms left: 25 / right: 24 in the 7b pending count, and the Round 9 pending list adds exactly Files 0030. A focused run then found its total applied count also needed the same single addition (+25 to +26). All four upgrade regressions now pass; historical preservation and restart assertions are unchanged.

test wire::upgrade_tests::production_7b_schema_copy_upgrades_combined_pending_migrations ... ok
test wire::upgrade_tests::production_7c_upgrades_content_types_once ... ok
test wire::upgrade_tests::production_round_9_schema_upgrades_once_with_original_receipts ... ok
test wire::upgrade_tests::production_schema_copy_upgrades_once_without_reinterpreting_notes_0028 ... ok
test result: ok. 4 passed; 0 failed; 0 ignored; 0 measured; 280 filtered out; finished in 5.86s

Final Server clippy:

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

The full Server rerun is in progress. A separate full Files run follows it to capture a clean command exit after the earlier outer gate wrapper was terminated. Final source perf-lint also passes: 0 violations, 22606 scoped exceptions.

journaldup7 schema pin fix committed. The complete failing Server run confirms `left: 25 / right: 24` in the 7b pending count, and the Round 9 pending list adds exactly Files 0030. A focused run then found its total applied count also needed the same single addition (+25 to +26). All four upgrade regressions now pass; historical preservation and restart assertions are unchanged. ```text test wire::upgrade_tests::production_7b_schema_copy_upgrades_combined_pending_migrations ... ok test wire::upgrade_tests::production_7c_upgrades_content_types_once ... ok test wire::upgrade_tests::production_round_9_schema_upgrades_once_with_original_receipts ... ok test wire::upgrade_tests::production_schema_copy_upgrades_once_without_reinterpreting_notes_0028 ... ok test result: ok. 4 passed; 0 failed; 0 ignored; 0 measured; 280 filtered out; finished in 5.86s ``` Final Server clippy: ```text Finished `dev` profile [unoptimized + debuginfo] target(s) in 1m 23s ``` The full Server rerun is in progress. A separate full Files run follows it to capture a clean command exit after the earlier outer gate wrapper was terminated. Final source perf-lint also passes: 0 violations, 22606 scoped exceptions.
Author
Owner

READY — 5fe2b4715d

journaldup7 — Forgejo #1295

Branch: job/journaldup. Start: 9c08db27b. Head: 5fe2b4715ded39998f0a722894633affed743e9c. Integrated origin/dev once at d395b6e25 in 75aa09125. No push, deploy, delivery merge, or issue closure.

What was built

  • Pending text now uses the real shared Quick Look / TextView surface. Its filename title includes (not uploaded). Copy uses CopyLink confirmation; Save file and Close use the standard header actions and warm tooltips. The held Blob avoids a network fetch.
  • Upload summaries use ToastBody and shared Pill controls. Title and detail each have one line with truncation. Collapsed Sonner cards contain tall content (#1388). Persistent actions no longer move focus into a sibling toast. Opening Quick Look keeps programmatic focus quiet; Tab remains normal.
  • The admission regression now stages bytes before the short remaining lease and waits for actual Root writer readiness. The original intent must precede source IO assertion, six-second request bound, and status assertions are unchanged.
  • The real browser waits for the Daily note bridge before its strict source snapshot. It verifies readable layout, exact Copy/download, missing-proof Cancel/reload, both simultaneous tabs, and no second upload or duplicate Note. Dev integration preserves Upload diagnostic origin in thumbnail and publication stages.

Shared visible controls

QuickLook, TextView, CopyLink, Pill/PillGroup, FileName, ToastBody and AppToaster. No new independent viewer, button, toast surface, or runtime alignment observer.

Files

  • apps/web/src/lib/files/UploadToast.svelte, TextView.svelte.test.ts, and apps/web/e2e/upload-recovery-1295.mjs.
  • apps/web/src/lib/components/AppToaster.svelte, its test, and ToastBody.svelte.
  • packages/ui/src/components/viewer/QuickLook.svelte, CopyLink.svelte, OverlaySurface.svelte, and packages/ui/README.md.
  • apps/web/src/lib/a11y/focusTrap.ts, inputModality.ts and its test.
  • crates/plugins/files/src/uploads.rs, crates/plugins/files/tests/jdrev2.rs, and the minimal schema-fixture pins in crates/calternal-server/src/upgrade_tests.rs.
  • Existing exact records in contracts/perf/{registry,exceptions,adoption-1058,ratchet}.json. A partial refresh removed four live contracts; the final refresh restores these existing entries and hashes. Final inventory is 22,606 exact live exceptions, with no new waiver or raised rule limit.

UX gaps closed

The zero-width text column, loose Copied label, foreign pending panel, multi-line upload detail, collapsed toast overflow, sibling focus jump, missing byte-preservation fixture isolation, and unproved foreground multi-tab recovery. Exact Save file and opening/mouse focus checks now run in the real production app.

Decisions

No new product policy. The implementation adds optional local Blob and download-label inputs to QuickLook, an optional plain-text resolver to CopyLink, and an opt-in quiet initial-focus policy to OverlaySurface. Existing callers retain their defaults. The test starts its remaining hard lease after staging and proved writer readiness, rather than spending it on fixture setup.

Cost

Preview is O(text bytes), bounded by the existing 2 MiB TextView preview cap; Copy is O(file bytes), and download uses the held Blob. Rendering shows one source and shares the existing highlight limits. No new API request, full-Home scan, collection IO loop, or benchmark dependency. This is a UI/reliability correction, so perf-VM timing is left to the merge round under the current verification policy.

Evidence

22 unique actual-production, macOS-emulated captures are attached: 12 requested screen/width/theme captures, four existing TextView references, two focus captures and four alignment close-ups. Source items are real API uploads. The requested review captures have no build-update notice and assert the real text loaded before capture. Close-ups were inspected for icon/label alignment; visual approval remains with Claude.

files-upload, 1440: light, dark

pending-text, 1440: light, dark

files-upload, 820: light, dark

pending-text, 820: light, dark

files-upload, 390: light, dark

pending-text, 390: light, dark

References: existing-text-viewer-1440-light-mac.png, existing-text-viewer-1440-dark-mac.png, existing-text-viewer-390-light-mac.png, existing-text-viewer-390-dark-mac.png

Focus proof: pending-text-opening-keyboard-mac.png, pending-text-after-mouse-copy-mac.png

Changed expectations for review

The first full Server run completed with 270 passed / 2 failed. All four focused upgrade tests pass after the pin update. Both failures were exact upgrade-frontier pins: actual pending count 25 vs expected 24, and the Round 9 pending list contained the new Files 0030. The final fixture requires Files 0030 in both pending/required sets, frontier 30, 7b pending count 25, and Round 9 applied count before.len() + 26 (formerly +25). These are exact additions for #1295 receipt compaction. Historical SQL/checksums, old receipt equality, preserved User rows, snapshot count, second-start idempotence, HTTP status assertions, original admission poll and its deadlines remain unchanged. Module reasoning was updated.

Gates — final output excerpts, verbatim

cargo fmt --check: exit 0, no output. Cargo commands use line-tables-only debug, no incremental compilation, four build jobs and the worktree TMPDIR.

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

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

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

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

cargo test -p calternal-server -- --test-threads=4 — exit 0

test result: ok. 272 passed; 0 failed; 12 ignored; 0 measured; 0 filtered out; finished in 207.56s
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 38.02s
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.37s

cargo test -p calternal-plugin-files -- --test-threads=4 — exit 0

test result: ok. 278 passed; 0 failed; 4 ignored; 0 measured; 0 filtered out; finished in 252.69s
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 6 filtered out; finished in 0.04s
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 6 filtered out; finished in 0.12s
test result: ok. 7 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 6.26s
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

The earlier ordered wrapper was terminated with signal status 143 after emitting successful Files results and before starting Server gates. The final standalone ordered run above records clean exit 0 for both complete crate commands.

cd apps/web && bun run check

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

cd apps/web && bun run test

 Test Files  299 passed (299)
      Tests  2130 passed (2130)

The first full web run had one five-second AppPasswords test timeout; the unchanged exact test passed in isolation, then all 2,130 tests passed on the final full run. The web check has four non-blocking warnings in two unchanged files.

cargo test -p calternal-plugin-files --test jdrev2 pre_rename_timeout_then_log_edit_recovers_safely -- --exact --nocapture

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

All five earlier Files failures passed with --exact --test-threads=1; no expectation or deadline was changed. Verbatim isolated results:

concurrent_finder_puts_keep_all_uploads

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

http_index_write_checkout_timeout_returns_retryable_service_unavailable

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

internal_temp_paths_never_enter_index_during_atomic_write_reconcile_storm

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

journal_deadline_hands_off_applied_note_without_replay

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

public_password_rejection_does_not_wait_for_data_mutation_lock

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

The storm verified 1,000 indexed rows, 1,001 journal/change-feed rows, and no private temp paths.

node apps/web/e2e/upload-recovery-1295.mjs

PASS shared stack: truncated upload detail cannot spill through another notification
PASS macOS 390 light: missing completion proof has no Retry action
PASS macOS 390 dark: missing completion proof has no Retry action
PASS macOS 820 light: missing completion proof has no Retry action
PASS macOS 820 dark: missing completion proof has no Retry action
PASS macOS 1440 light: missing completion proof has no Retry action
PASS macOS 1440 dark: missing completion proof has no Retry action
PASS Cancel retains a reviewable pending upload
PASS reload restores pending text without another upload
PASS Show text opens the retained browser bytes
PASS Copy returns the exact original text
PASS Save file downloads the exact retained bytes
PASS browser recovery: missing proof -> Cancel -> reload -> exact Copy; simultaneous tabs retain both texts; later Log retained; 12 macOS screenshots

python3 tests/adversarial/journal_finalize_crash.py --server "$CARGO_TARGET_DIR/debug/calternal-server"

PASS SIGKILL mid-finalize: 1 crash, 1 later Log, 1 same-ID retry, 1 Note, 0 duplicate Notes; bytes preserved

Known gaps / UX gaps left

Claude visual review remains external. Operator repair remains the documented Admin API action; this continuation adds no Admin screen. The predecessor’s broad journalrace upload-create 503 is tracked by #1383 and DAV fixture failures by #1382; those broad campaigns were not re-run in this UI/reliability correction. No credential-store contents or credentials were displayed.

For the merge round

  • tests/adversarial/run.sh: full hostile payload, authz and cross-User matrices against the combined branch; review #1382/#1383.
  • cd apps/web && bun run test:e2e plus bun run test:e2e:files and bun run test:e2e:notes: combined shell, Files and Notes UI suites. Re-run the predecessor’s live Admin/sibling probe for repair and item-scoped recovery.
  • Release build, staging/o2 checks and real Mac interop under the required locks. No deployment was performed here.
  • Any perf timing uses perf-run calternal <job> <minutes> -- <command> and a copied release binary; never build on that VM.

Cleanup

     Removed 19460 files, 16.4GiB total

Web build and .svelte-kit output removed with worktree-bound path checks. Artifacts remain ignored and available locally; no screenshots are committed. Git status is clean. Doc comments in the changed source files were read again after the final fix.

READY — 5fe2b4715d

READY — 5fe2b4715ded39998f0a722894633affed743e9c journaldup7 — Forgejo #1295 Branch: `job/journaldup`. Start: `9c08db27b`. Head: `5fe2b4715ded39998f0a722894633affed743e9c`. Integrated `origin/dev` once at `d395b6e25` in `75aa09125`. No push, deploy, delivery merge, or issue closure. What was built - Pending text now uses the real shared Quick Look / TextView surface. Its filename title includes `(not uploaded)`. Copy uses CopyLink confirmation; Save file and Close use the standard header actions and warm tooltips. The held Blob avoids a network fetch. - Upload summaries use ToastBody and shared Pill controls. Title and detail each have one line with truncation. Collapsed Sonner cards contain tall content (#1388). Persistent actions no longer move focus into a sibling toast. Opening Quick Look keeps programmatic focus quiet; Tab remains normal. - The admission regression now stages bytes before the short remaining lease and waits for actual Root writer readiness. The original `intent must precede source IO` assertion, six-second request bound, and status assertions are unchanged. - The real browser waits for the Daily note bridge before its strict source snapshot. It verifies readable layout, exact Copy/download, missing-proof Cancel/reload, both simultaneous tabs, and no second upload or duplicate Note. Dev integration preserves Upload diagnostic origin in thumbnail and publication stages. Shared visible controls QuickLook, TextView, CopyLink, Pill/PillGroup, FileName, ToastBody and AppToaster. No new independent viewer, button, toast surface, or runtime alignment observer. Files - `apps/web/src/lib/files/UploadToast.svelte`, `TextView.svelte.test.ts`, and `apps/web/e2e/upload-recovery-1295.mjs`. - `apps/web/src/lib/components/AppToaster.svelte`, its test, and `ToastBody.svelte`. - `packages/ui/src/components/viewer/QuickLook.svelte`, `CopyLink.svelte`, `OverlaySurface.svelte`, and `packages/ui/README.md`. - `apps/web/src/lib/a11y/focusTrap.ts`, `inputModality.ts` and its test. - `crates/plugins/files/src/uploads.rs`, `crates/plugins/files/tests/jdrev2.rs`, and the minimal schema-fixture pins in `crates/calternal-server/src/upgrade_tests.rs`. - Existing exact records in `contracts/perf/{registry,exceptions,adoption-1058,ratchet}.json`. A partial refresh removed four live contracts; the final refresh restores these existing entries and hashes. Final inventory is 22,606 exact live exceptions, with no new waiver or raised rule limit. UX gaps closed The zero-width text column, loose Copied label, foreign pending panel, multi-line upload detail, collapsed toast overflow, sibling focus jump, missing byte-preservation fixture isolation, and unproved foreground multi-tab recovery. Exact Save file and opening/mouse focus checks now run in the real production app. Decisions No new product policy. The implementation adds optional local Blob and download-label inputs to QuickLook, an optional plain-text resolver to CopyLink, and an opt-in quiet initial-focus policy to OverlaySurface. Existing callers retain their defaults. The test starts its remaining hard lease after staging and proved writer readiness, rather than spending it on fixture setup. Cost Preview is O(text bytes), bounded by the existing 2 MiB TextView preview cap; Copy is O(file bytes), and download uses the held Blob. Rendering shows one source and shares the existing highlight limits. No new API request, full-Home scan, collection IO loop, or benchmark dependency. This is a UI/reliability correction, so perf-VM timing is left to the merge round under the current verification policy. Evidence 22 unique actual-production, macOS-emulated captures are attached: 12 requested screen/width/theme captures, four existing TextView references, two focus captures and four alignment close-ups. Source items are real API uploads. The requested review captures have no build-update notice and assert the real text loaded before capture. Close-ups were inspected for icon/label alignment; visual approval remains with Claude. files-upload, 1440: [light](https://git.kayg.org/attachments/60706b81-d2c8-4903-96f2-7e74a357f6bb), [dark](https://git.kayg.org/attachments/f5278e07-f8e7-4ca1-ba7e-4271e1a52c08) pending-text, 1440: [light](https://git.kayg.org/attachments/5a3e00f5-294b-4f95-92cf-535cf3b5c62f), [dark](https://git.kayg.org/attachments/c0f16196-068e-42bd-a153-581d2d59202e) files-upload, 820: [light](https://git.kayg.org/attachments/b01c3255-231c-4d38-a291-96a492797739), [dark](https://git.kayg.org/attachments/ebdc1a3e-a1ea-4275-b0f5-28b737ab478d) pending-text, 820: [light](https://git.kayg.org/attachments/f3a36167-02b3-4cda-84f0-7b7ec8447e25), [dark](https://git.kayg.org/attachments/8f992522-4226-4377-a7e0-03257c85cbe8) files-upload, 390: [light](https://git.kayg.org/attachments/abdae40e-2e9a-486a-8470-d569843f8a6d), [dark](https://git.kayg.org/attachments/a480b1e2-f609-43ea-b8ac-e956ba105629) pending-text, 390: [light](https://git.kayg.org/attachments/d45058f3-94a0-4196-84cc-ef5462de36e6), [dark](https://git.kayg.org/attachments/9d1cafa5-be0a-48b6-bde4-03f37661c40b) References: [existing-text-viewer-1440-light-mac.png](https://git.kayg.org/attachments/adecce4b-9b35-4148-91ec-c923072e1f32), [existing-text-viewer-1440-dark-mac.png](https://git.kayg.org/attachments/bfe9147c-a320-4e53-a492-f051b597eb25), [existing-text-viewer-390-light-mac.png](https://git.kayg.org/attachments/9bcf3c04-693f-4b09-9e3d-de6ada9355a3), [existing-text-viewer-390-dark-mac.png](https://git.kayg.org/attachments/992e9f44-ce6c-4e27-8a22-8a295d681f0f) Focus proof: [pending-text-opening-keyboard-mac.png](https://git.kayg.org/attachments/b4b69a32-8ff6-4465-8eb8-fe1072bc59c5), [pending-text-after-mouse-copy-mac.png](https://git.kayg.org/attachments/cc1cdc29-ac5c-48aa-b43f-1353678265a0) Changed expectations for review The first full Server run completed with 270 passed / 2 failed. All four focused upgrade tests pass after the pin update. Both failures were exact upgrade-frontier pins: actual pending count 25 vs expected 24, and the Round 9 pending list contained the new Files 0030. The final fixture requires Files 0030 in both pending/required sets, frontier 30, 7b pending count 25, and Round 9 applied count `before.len() + 26` (formerly +25). These are exact additions for #1295 receipt compaction. Historical SQL/checksums, old receipt equality, preserved User rows, snapshot count, second-start idempotence, HTTP status assertions, original admission poll and its deadlines remain unchanged. Module reasoning was updated. Gates — final output excerpts, verbatim `cargo fmt --check`: exit 0, no output. Cargo commands use line-tables-only debug, no incremental compilation, four build jobs and the worktree TMPDIR. `cargo clippy -p calternal-plugin-files --all-targets -- -D warnings` ```text Finished `dev` profile [unoptimized + debuginfo] target(s) in 25.33s ``` `cargo clippy -p calternal-server --all-targets -- -D warnings` ```text Finished `dev` profile [unoptimized + debuginfo] target(s) in 1m 23s ``` `cargo test -p calternal-server -- --test-threads=4` — exit 0 ```text test result: ok. 272 passed; 0 failed; 12 ignored; 0 measured; 0 filtered out; finished in 207.56s test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 38.02s test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.37s ``` `cargo test -p calternal-plugin-files -- --test-threads=4` — exit 0 ```text test result: ok. 278 passed; 0 failed; 4 ignored; 0 measured; 0 filtered out; finished in 252.69s test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 6 filtered out; finished in 0.04s test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 6 filtered out; finished in 0.12s test result: ok. 7 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 6.26s test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s ``` The earlier ordered wrapper was terminated with signal status 143 after emitting successful Files results and before starting Server gates. The final standalone ordered run above records clean exit 0 for both complete crate commands. `cd apps/web && bun run check` ```text perf-lint: PASS; 0 violations; 22606 scoped exceptions svelte-check found 0 errors and 4 warnings in 2 files ``` `cd apps/web && bun run test` ```text Test Files 299 passed (299) Tests 2130 passed (2130) ``` The first full web run had one five-second AppPasswords test timeout; the unchanged exact test passed in isolation, then all 2,130 tests passed on the final full run. The web check has four non-blocking warnings in two unchanged files. `cargo test -p calternal-plugin-files --test jdrev2 pre_rename_timeout_then_log_edit_recovers_safely -- --exact --nocapture` ```text test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 6 filtered out; finished in 6.95s ``` All five earlier Files failures passed with `--exact --test-threads=1`; no expectation or deadline was changed. Verbatim isolated results: `concurrent_finder_puts_keep_all_uploads` ```text test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 281 filtered out; finished in 14.20s ``` `http_index_write_checkout_timeout_returns_retryable_service_unavailable` ```text test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 281 filtered out; finished in 6.03s ``` `internal_temp_paths_never_enter_index_during_atomic_write_reconcile_storm` ```text test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 281 filtered out; finished in 89.96s ``` `journal_deadline_hands_off_applied_note_without_replay` ```text test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 281 filtered out; finished in 3.10s ``` `public_password_rejection_does_not_wait_for_data_mutation_lock` ```text test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 281 filtered out; finished in 0.67s ``` The storm verified 1,000 indexed rows, 1,001 journal/change-feed rows, and no private temp paths. `node apps/web/e2e/upload-recovery-1295.mjs` ```text PASS shared stack: truncated upload detail cannot spill through another notification PASS macOS 390 light: missing completion proof has no Retry action PASS macOS 390 dark: missing completion proof has no Retry action PASS macOS 820 light: missing completion proof has no Retry action PASS macOS 820 dark: missing completion proof has no Retry action PASS macOS 1440 light: missing completion proof has no Retry action PASS macOS 1440 dark: missing completion proof has no Retry action PASS Cancel retains a reviewable pending upload PASS reload restores pending text without another upload PASS Show text opens the retained browser bytes PASS Copy returns the exact original text PASS Save file downloads the exact retained bytes PASS browser recovery: missing proof -> Cancel -> reload -> exact Copy; simultaneous tabs retain both texts; later Log retained; 12 macOS screenshots ``` `python3 tests/adversarial/journal_finalize_crash.py --server "$CARGO_TARGET_DIR/debug/calternal-server"` ```text PASS SIGKILL mid-finalize: 1 crash, 1 later Log, 1 same-ID retry, 1 Note, 0 duplicate Notes; bytes preserved ``` Known gaps / UX gaps left Claude visual review remains external. Operator repair remains the documented Admin API action; this continuation adds no Admin screen. The predecessor’s broad journalrace upload-create 503 is tracked by #1383 and DAV fixture failures by #1382; those broad campaigns were not re-run in this UI/reliability correction. No credential-store contents or credentials were displayed. For the merge round - `tests/adversarial/run.sh`: full hostile payload, authz and cross-User matrices against the combined branch; review #1382/#1383. - `cd apps/web && bun run test:e2e` plus `bun run test:e2e:files` and `bun run test:e2e:notes`: combined shell, Files and Notes UI suites. Re-run the predecessor’s live Admin/sibling probe for repair and item-scoped recovery. - Release build, staging/o2 checks and real Mac interop under the required locks. No deployment was performed here. - Any perf timing uses `perf-run calternal <job> <minutes> -- <command>` and a copied release binary; never build on that VM. Cleanup ```text Removed 19460 files, 16.4GiB total ``` Web build and .svelte-kit output removed with worktree-bound path checks. Artifacts remain ignored and available locally; no screenshots are committed. Git status is clean. Doc comments in the changed source files were read again after the final fix. READY — 5fe2b4715ded39998f0a722894633affed743e9c
Author
Owner

jdrev4 independent read-only review started on job/journaldup at 5fe2b4715d. No tracked edits or ref changes. Checking R1 receipt pruning/client replay, R2 timeout/recovery, migration safety, User isolation, and three real-server finalize SIGKILL windows. Evidence will be appended to artifacts/jdrev4-findings.md. Author reports/results are excluded.

jdrev4 independent read-only review started on job/journaldup at 5fe2b4715ded39998f0a722894633affed743e9c. No tracked edits or ref changes. Checking R1 receipt pruning/client replay, R2 timeout/recovery, migration safety, User isolation, and three real-server finalize SIGKILL windows. Evidence will be appended to artifacts/jdrev4-findings.md. Author reports/results are excluded.
Author
Owner

journaldup8 start: branch job/journaldup; base 5fe2b4715d.
Read jdrev4 findings. The current head already includes later fixes. Verify them, add the exact real-server Cancel/restart regression, and document the bounded replay contract in DESIGN. No pushes or deploys.

journaldup8 start: branch job/journaldup; base 5fe2b4715ded39998f0a722894633affed743e9c. Read jdrev4 findings. The current head already includes later fixes. Verify them, add the exact real-server Cancel/restart regression, and document the bounded replay contract in DESIGN. No pushes or deploys.
Author
Owner

journaldup8 finding: current head already contains the prior R1/R3 and browser persistence fixes. Two remaining gaps were found by source inspection.

  1. installed_intent_needs_recovery checked the applied witness only inside a successful source fingerprint. NotFound therefore returned false, allowing Cancel to remove sealed applied proof. The witness now precedes the fingerprint; missing replacement source remains ambiguous. Added cancel_keeps_applied_proof_when_source_is_missing and the tracked jdrev4 real-server Cancel/restart probe.
  2. userStorage.setItem can silently skip a write when the storage area is unavailable. The upload queue now reads back the task record before final PATCH. The focused browser storage/retry tests passed: Test Files 2 passed (2) / Tests 24 passed (24).

Merged origin/dev once (af202e1514), merge 368e6d8cbe. No migration number collision: origin/dev Files frontier remains 0028. DESIGN §26 now states the existing 30-day replay/32-day receipt policy and forbids new-ID replay after a possible final send. No dependency changes. Full requested gates and real-server probe are in progress.

journaldup8 finding: current head already contains the prior R1/R3 and browser persistence fixes. Two remaining gaps were found by source inspection. 1. installed_intent_needs_recovery checked the applied witness only inside a successful source fingerprint. NotFound therefore returned false, allowing Cancel to remove sealed applied proof. The witness now precedes the fingerprint; missing replacement source remains ambiguous. Added cancel_keeps_applied_proof_when_source_is_missing and the tracked jdrev4 real-server Cancel/restart probe. 2. userStorage.setItem can silently skip a write when the storage area is unavailable. The upload queue now reads back the task record before final PATCH. The focused browser storage/retry tests passed: `Test Files 2 passed (2)` / `Tests 24 passed (24)`. Merged origin/dev once (af202e1514955ddf0f8b4b3d2503c780d807ed84), merge 368e6d8cbea8a510b43616ce148ad3f3d4e0b7c9. No migration number collision: origin/dev Files frontier remains 0028. DESIGN §26 now states the existing 30-day replay/32-day receipt policy and forbids new-ID replay after a possible final send. No dependency changes. Full requested gates and real-server probe are in progress.
Author
Owner

journaldup8 R1 boundary finding: the daemon journal retained an upload ID without a final-send fence or server deadline. transfer::upload_file reset that ID on HEAD 404/410, while send_snapshot restarted on UploadExpired. remote::upload_chunk_with_path propagated UploadExpired when an ambiguous PATCH was followed by HEAD 404. This can replay old bytes after completed receipt pruning.

The necessary client-side correction is limited to calternal-sync journal/remote/transfer: retain Upload-Replay-Until; FULL-commit a possible-final-send fence before network IO; classify missing proof after ambiguity as UnknownWriteResult; preserve snapshot and ID across reopen. Legacy durable IDs are conservative. Definitely refused partial uploads still restart, with unchanged old assertions. Successful verification removes the fence in the existing journal transaction. Added an upload_id index for legacy lookup, plus restart, missing-proof and no-network-after-deadline regressions. calternal-sync clippy/test will run in addition to the requested Files/Notes gates. No public method shape, dependency or server migration changed.

Decision: a missing legacy fence means unknown publication, rather than permission to discard the ID. This is required to preserve R1 when receipts have bounded retention.

journaldup8 R1 boundary finding: the daemon journal retained an upload ID without a final-send fence or server deadline. transfer::upload_file reset that ID on HEAD 404/410, while send_snapshot restarted on UploadExpired. remote::upload_chunk_with_path propagated UploadExpired when an ambiguous PATCH was followed by HEAD 404. This can replay old bytes after completed receipt pruning. The necessary client-side correction is limited to calternal-sync journal/remote/transfer: retain Upload-Replay-Until; FULL-commit a possible-final-send fence before network IO; classify missing proof after ambiguity as UnknownWriteResult; preserve snapshot and ID across reopen. Legacy durable IDs are conservative. Definitely refused partial uploads still restart, with unchanged old assertions. Successful verification removes the fence in the existing journal transaction. Added an upload_id index for legacy lookup, plus restart, missing-proof and no-network-after-deadline regressions. calternal-sync clippy/test will run in addition to the requested Files/Notes gates. No public method shape, dependency or server migration changed. Decision: a missing legacy fence means unknown publication, rather than permission to discard the ID. This is required to preserve R1 when receipts have bounded retention.
Author
Owner

journaldup8 — #1295 continuation

Branch: job/journaldup. Base: 5fe2b4715d.
Head: 6fd36fa23d.
Integrated origin/dev af202e1514 once, before final gates. No push, deployment, delivery merge or issue closure.

Built and verified

The starting head already contained the main Cancel guard, compact receipt schema and pending-text viewer. This continuation verifies those changes and closes three further safety gaps.

  • Cancel and startup retain proof even if the current source is absent. Matching applied proof, legacy unmatched proof and a missing replacement source remain ambiguous. The protected name cannot receive a new write after restart. A definite partial upload can still be cancelled.
  • The real-server regression reproduces jdrev4's unsealed install, changed Daily note, Cancel and restart. It compares staging, intent and Versions; the affected Note stays readable and read-only. A sibling Note and another User remain writable.
  • A pending browser upload must save and read back its task record before final PATCH. The shared storage wrapper can silently refuse a write. A saved Blob without a record cannot be found after reload. The queue now stops before sending in that case and keeps the File in memory for recovery.
  • The sync daemon stores the original server deadline and final-send uncertainty in its FULL local journal. Missing completion proof cannot create a new upload identity, including after journal reopen. Creation facts and the pending row share one transaction. Verified acknowledgement removes the fence in the same transaction as the pending row. This is necessary to keep R1 safe when receipts are pruned.
  • A year-growth regression invokes production cleanup with daily samples. At 10 uploads/min, 5,256,000 completions leave 460,800 live receipts, the 32-day window. The existing fixed-size schema remains independent of path length.
  • DESIGN §26 and Files DATA-SAFETY now state the client/server replay window and retained Cancel proof. All prior test expectations remain unchanged.

Files

Files: crates/plugins/files/src/uploads.rs; crates/plugins/files/tests/jdrev2.rs; crates/plugins/files/DATA-SAFETY.md.
Sync: crates/calternal-sync/src/journal.rs, remote.rs, transfer.rs.
Browser: apps/web/src/lib/files/uploads.svelte.ts; upload-recovery.svelte.test.ts; apps/web/e2e/upload-recovery-1295.mjs.
Regression: tests/adversarial/journal_cancel_restart.py. Contract: docs/DESIGN.md.
Upstream integration also carries origin/dev's unrelated Markdown changes. They are not journaldup8 changes.

Decisions

Retain the existing 30-day absolute client retry deadline and 32-day completion retention. Cleanup batches at most 4,096 rows per transaction; unresolved intents never expire. Keep all current source, staging, witness and Versions if source identity or publication is uncertain. Legacy daemon IDs without a durable final-send fence are treated as possibly published. Missing proof requires recovery, never a new ID.

The browser record readback and daemon write-ahead fence are the smallest changes that close the discovered persistence gaps. No new visual component, style or dependency was added.

UX gaps closed

Reload restores inspection without replay. Show text, Copy and Save file use exact retained local bytes. Two tabs keep both pending texts. Cancel keeps reviewable recovery. A later Log edit remains intact. The browser campaign found no unhandled page exception.

Visible controls reuse the existing QuickLook, TextView, CopyLink, Pill/PillGroup, FileName, ToastBody and AppToaster. No local restyling or runtime layout observer was added.

Space and expected cost

Local SQLite schema measurement, 460,800 rows:

local schema space: rows=460800, table+indexes bytes=180371456, bytes/row=391.43
yearly churn=5256000 rows; unpruned projection=1.916 GiB
32-day live cap at 10/min=460800 rows; yearly retained estimate=172.02 MiB

The live estimate excludes WAL, free pages and backups. SQLite reuses freed pages; the database file does not shrink on DELETE. There is no receipt-space baseline in docs/perf/baseline.json. The predecessor short-path measurement was about 1.96 GiB/year without pruning; variable path storage is removed. This is a local schema-space result, not a VM latency benchmark.

For each upload, daemon fence creation shares the existing pending transaction. Final sending adds one FULL journal commit before network IO. Fence lookup is indexed by upload ID. Cancel checks only the intent, source proof and witness; it does not scan a Home. Receipt cleanup visits expired rows through the completion-time index in bounded batches. The new browser check reads back one small task record after its existing durable byte save.

Production visual evidence

Real production build, macOS platform emulation, widths 390/820/1440, light and dark. The campaign asserts loaded content and clears build mismatch notices and leftover hover. It includes the closest existing text viewer and captures after opening by keyboard and Copy by mouse. Claude remains the visual reviewer. No rendering-time claim is made.

Gates (verbatim)

Commands ran with CARGO_BUILD_JOBS=4, CARGO_INCREMENTAL=0, CARGO_PROFILE_DEV_DEBUG=line-tables-only and worktree target/tmp. Cargo used the preset per-job target. Tests used --test-threads=4. No existing expectation or perf-lint rule was weakened.

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

cargo clippy -p calternal-plugin-files -p calternal-plugin-notes --all-targets -- -D warnings:

    Finished `dev` profile [unoptimized + debuginfo] target(s) in 42m 13s

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

test result: ok. 278 passed; 0 failed; 4 ignored; 0 measured; 0 filtered out; finished in 282.12s
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 8 filtered out; finished in 0.03s
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 8 filtered out; finished in 0.03s
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 8 filtered out; finished in 0.23s
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 8 filtered out; finished in 0.05s
test result: ok. 9 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 7.34s
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

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

test result: ok. 317 passed; 0 failed; 4 ignored; 0 measured; 0 filtered out; finished in 578.01s
test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 9.23s
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.12s

cargo test -p calternal-sync -- --test-threads=4:

test result: ok. 68 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 6.05s
test result: ok. 2 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 clippy -p calternal-sync --all-targets -- -D warnings:

    Finished `dev` profile [unoptimized + debuginfo] target(s) in 37m 03s

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

    Finished `dev` profile [unoptimized + debuginfo] target(s) in 7m 45s

cd apps/web && bun run check:

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

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

 Test Files  299 passed (299)
      Tests  2135 passed (2135)

The clippy durations include Cargo lock waits. Notes latency tests passed in the first full run; no individual retry was needed. The four ignored tests in each plugin suite are the existing opt-in tests.

Known gaps and UX gaps left

No failing data-safety regression remains in the requested scenarios. Unresolved bytes still need the existing explicit repair decision; this job adds no Admin repair UI. A missing current source or a legacy daemon ID with unknown publication state remains conservative and can require operator recovery. Browser recovery depends on the User's local storage and is cleared at session end. When durable storage is unavailable, final sending stops; in-memory recovery remains available.

Claude must review the attached visual evidence. Real macOS timing, a release build and the broad adversarial matrices were not run in this feature job, under the latest verification policy. No server latency or GPU rendering result is claimed.

For the merge round

  • cargo fmt --check, workspace clippy/tests and the combined branch's web gates: verify integration with other jobs.
  • cargo build --release -p calternal-server: produce the merged server before staging checks.
  • ADVERSARIAL_SERVER_BIN=<merged-server> bash tests/adversarial/run.sh: run the XUser, authorization and hostile-input matrices once on the combined branch. Retain all prior #1295 assertions. Check existing predecessor-round findings #1382/#1383 in that round.
  • python3 tests/adversarial/journal_cancel_restart.py --server <merged-server> and python3 tests/adversarial/journal_finalize_crash.py --server <merged-server>: retain Cancel/restart and real SIGKILL proofs.
  • CALTERNAL_SERVER_BIN=<merged-server> node apps/web/e2e/upload-recovery-1295.mjs: check production recovery against matching merged builds. Full E2E, staging/o2 and Apple-client interop remain merge-round work.

Comments in every journaldup8 file were read again before this report. No secrets were displayed. No dependency was added or changed.

journaldup8 — #1295 continuation Branch: job/journaldup. Base: 5fe2b4715ded39998f0a722894633affed743e9c. Head: 6fd36fa23da8f5d93fd5ea9fbf74fa207bb6f81d. Integrated origin/dev af202e1514955ddf0f8b4b3d2503c780d807ed84 once, before final gates. No push, deployment, delivery merge or issue closure. ## Built and verified The starting head already contained the main Cancel guard, compact receipt schema and pending-text viewer. This continuation verifies those changes and closes three further safety gaps. - Cancel and startup retain proof even if the current source is absent. Matching applied proof, legacy unmatched proof and a missing replacement source remain ambiguous. The protected name cannot receive a new write after restart. A definite partial upload can still be cancelled. - The real-server regression reproduces jdrev4's unsealed install, changed Daily note, Cancel and restart. It compares staging, intent and Versions; the affected Note stays readable and read-only. A sibling Note and another User remain writable. - A pending browser upload must save and read back its task record before final PATCH. The shared storage wrapper can silently refuse a write. A saved Blob without a record cannot be found after reload. The queue now stops before sending in that case and keeps the File in memory for recovery. - The sync daemon stores the original server deadline and final-send uncertainty in its FULL local journal. Missing completion proof cannot create a new upload identity, including after journal reopen. Creation facts and the pending row share one transaction. Verified acknowledgement removes the fence in the same transaction as the pending row. This is necessary to keep R1 safe when receipts are pruned. - A year-growth regression invokes production cleanup with daily samples. At 10 uploads/min, 5,256,000 completions leave 460,800 live receipts, the 32-day window. The existing fixed-size schema remains independent of path length. - DESIGN §26 and Files DATA-SAFETY now state the client/server replay window and retained Cancel proof. All prior test expectations remain unchanged. ## Files Files: crates/plugins/files/src/uploads.rs; crates/plugins/files/tests/jdrev2.rs; crates/plugins/files/DATA-SAFETY.md. Sync: crates/calternal-sync/src/journal.rs, remote.rs, transfer.rs. Browser: apps/web/src/lib/files/uploads.svelte.ts; upload-recovery.svelte.test.ts; apps/web/e2e/upload-recovery-1295.mjs. Regression: tests/adversarial/journal_cancel_restart.py. Contract: docs/DESIGN.md. Upstream integration also carries origin/dev's unrelated Markdown changes. They are not journaldup8 changes. ## Decisions Retain the existing 30-day absolute client retry deadline and 32-day completion retention. Cleanup batches at most 4,096 rows per transaction; unresolved intents never expire. Keep all current source, staging, witness and Versions if source identity or publication is uncertain. Legacy daemon IDs without a durable final-send fence are treated as possibly published. Missing proof requires recovery, never a new ID. The browser record readback and daemon write-ahead fence are the smallest changes that close the discovered persistence gaps. No new visual component, style or dependency was added. ## UX gaps closed Reload restores inspection without replay. Show text, Copy and Save file use exact retained local bytes. Two tabs keep both pending texts. Cancel keeps reviewable recovery. A later Log edit remains intact. The browser campaign found no unhandled page exception. Visible controls reuse the existing QuickLook, TextView, CopyLink, Pill/PillGroup, FileName, ToastBody and AppToaster. No local restyling or runtime layout observer was added. ## Space and expected cost Local SQLite schema measurement, 460,800 rows: ``` local schema space: rows=460800, table+indexes bytes=180371456, bytes/row=391.43 yearly churn=5256000 rows; unpruned projection=1.916 GiB 32-day live cap at 10/min=460800 rows; yearly retained estimate=172.02 MiB ``` The live estimate excludes WAL, free pages and backups. SQLite reuses freed pages; the database file does not shrink on DELETE. There is no receipt-space baseline in docs/perf/baseline.json. The predecessor short-path measurement was about 1.96 GiB/year without pruning; variable path storage is removed. This is a local schema-space result, not a VM latency benchmark. For each upload, daemon fence creation shares the existing pending transaction. Final sending adds one FULL journal commit before network IO. Fence lookup is indexed by upload ID. Cancel checks only the intent, source proof and witness; it does not scan a Home. Receipt cleanup visits expired rows through the completion-time index in bounded batches. The new browser check reads back one small task record after its existing durable byte save. ## Production visual evidence Real production build, macOS platform emulation, widths 390/820/1440, light and dark. The campaign asserts loaded content and clears build mismatch notices and leftover hover. It includes the closest existing text viewer and captures after opening by keyboard and Copy by mouse. Claude remains the visual reviewer. No rendering-time claim is made. - [existing-text-viewer-1440-dark-mac.png](https://git.kayg.org/attachments/90e3d36d-48a5-4e1f-8d55-2d7cfa76bb0a) - [existing-text-viewer-1440-light-mac.png](https://git.kayg.org/attachments/116a487b-9e89-497e-ab10-f448f83398ab) - [existing-text-viewer-390-dark-mac.png](https://git.kayg.org/attachments/7a3c7df1-1c16-44ba-bda2-47ea692a80b2) - [existing-text-viewer-390-light-mac.png](https://git.kayg.org/attachments/e93f12c8-eb01-40f2-b923-03ea387730e9) - [files-upload-1440-dark-mac.png](https://git.kayg.org/attachments/089f0af0-2a3b-4efe-b98e-8da6f6b5f11f) - [files-upload-1440-light-mac.png](https://git.kayg.org/attachments/03c67012-8e24-4e67-93e5-ce57ee1cd0c2) - [files-upload-390-dark-mac.png](https://git.kayg.org/attachments/8329776c-72d9-4ec2-b2a1-8b8ed2c490ec) - [files-upload-390-light-mac.png](https://git.kayg.org/attachments/b28cf51c-f1f5-400b-a083-6b642ac0b6d0) - [files-upload-820-dark-mac.png](https://git.kayg.org/attachments/ed6acaad-22f8-4cf4-b18c-7df4ab4b228c) - [files-upload-820-light-mac.png](https://git.kayg.org/attachments/7339486e-4601-4bcc-95bf-9c8584e13347) - [pending-text-1440-dark-mac.png](https://git.kayg.org/attachments/f43dd007-dd79-4600-9c08-3cfc5a91915d) - [pending-text-1440-light-mac.png](https://git.kayg.org/attachments/8a585c22-53c1-4328-8e56-337bd379e7e3) - [pending-text-390-dark-mac.png](https://git.kayg.org/attachments/a51d74a7-7b80-44d0-9a7c-83971bc75e15) - [pending-text-390-light-mac.png](https://git.kayg.org/attachments/06c5ed51-6bca-43a9-a4bc-1911cea106b7) - [pending-text-820-dark-mac.png](https://git.kayg.org/attachments/ec2651d9-5402-430d-a5eb-9c6ef0f8ce8a) - [pending-text-820-light-mac.png](https://git.kayg.org/attachments/57dff5fa-215a-43f1-ba78-bf8d52afff28) - [pending-text-after-mouse-copy-mac.png](https://git.kayg.org/attachments/bdd4142b-bec0-4d2f-b0f5-a8c7ac843160) - [pending-text-opening-keyboard-mac.png](https://git.kayg.org/attachments/dd4a7974-6d4b-4645-9349-c62241940741) ## Gates (verbatim) Commands ran with CARGO_BUILD_JOBS=4, CARGO_INCREMENTAL=0, CARGO_PROFILE_DEV_DEBUG=line-tables-only and worktree target/tmp. Cargo used the preset per-job target. Tests used --test-threads=4. No existing expectation or perf-lint rule was weakened. `cargo fmt --check`: exit 0, no output. `cargo clippy -p calternal-plugin-files -p calternal-plugin-notes --all-targets -- -D warnings`: ``` Finished `dev` profile [unoptimized + debuginfo] target(s) in 42m 13s ``` `cargo test -p calternal-plugin-files -- --test-threads=4`: ``` test result: ok. 278 passed; 0 failed; 4 ignored; 0 measured; 0 filtered out; finished in 282.12s test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 8 filtered out; finished in 0.03s test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 8 filtered out; finished in 0.03s test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 8 filtered out; finished in 0.23s test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 8 filtered out; finished in 0.05s test result: ok. 9 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 7.34s test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s ``` `cargo test -p calternal-plugin-notes -- --test-threads=4`: ``` test result: ok. 317 passed; 0 failed; 4 ignored; 0 measured; 0 filtered out; finished in 578.01s test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 9.23s test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.12s ``` `cargo test -p calternal-sync -- --test-threads=4`: ``` test result: ok. 68 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 6.05s test result: ok. 2 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 clippy -p calternal-sync --all-targets -- -D warnings`: ``` Finished `dev` profile [unoptimized + debuginfo] target(s) in 37m 03s ``` `cargo clippy -p calternal-server --all-targets -- -D warnings`: ``` Finished `dev` profile [unoptimized + debuginfo] target(s) in 7m 45s ``` `cd apps/web && bun run check`: ``` perf-lint: PASS; 0 violations; 22606 scoped exceptions svelte-check found 0 errors and 4 warnings in 2 files ``` `cd apps/web && bun run test --maxWorkers=2`: ``` Test Files 299 passed (299) Tests 2135 passed (2135) ``` The clippy durations include Cargo lock waits. Notes latency tests passed in the first full run; no individual retry was needed. The four ignored tests in each plugin suite are the existing opt-in tests. ## Known gaps and UX gaps left No failing data-safety regression remains in the requested scenarios. Unresolved bytes still need the existing explicit repair decision; this job adds no Admin repair UI. A missing current source or a legacy daemon ID with unknown publication state remains conservative and can require operator recovery. Browser recovery depends on the User's local storage and is cleared at session end. When durable storage is unavailable, final sending stops; in-memory recovery remains available. Claude must review the attached visual evidence. Real macOS timing, a release build and the broad adversarial matrices were not run in this feature job, under the latest verification policy. No server latency or GPU rendering result is claimed. ## For the merge round - `cargo fmt --check`, workspace clippy/tests and the combined branch's web gates: verify integration with other jobs. - `cargo build --release -p calternal-server`: produce the merged server before staging checks. - `ADVERSARIAL_SERVER_BIN=<merged-server> bash tests/adversarial/run.sh`: run the XUser, authorization and hostile-input matrices once on the combined branch. Retain all prior #1295 assertions. Check existing predecessor-round findings #1382/#1383 in that round. - `python3 tests/adversarial/journal_cancel_restart.py --server <merged-server>` and `python3 tests/adversarial/journal_finalize_crash.py --server <merged-server>`: retain Cancel/restart and real SIGKILL proofs. - `CALTERNAL_SERVER_BIN=<merged-server> node apps/web/e2e/upload-recovery-1295.mjs`: check production recovery against matching merged builds. Full E2E, staging/o2 and Apple-client interop remain merge-round work. Comments in every journaldup8 file were read again before this report. No secrets were displayed. No dependency was added or changed.
Author
Owner

jdrev5 independent read-mostly review started on job/journaldup at 6fd36fa23d. Base: origin/dev. I will inspect the diff and run independent behavior probes without reading author reports or changing product code. Evidence will be recorded in artifacts/jdrev5-findings.md.

jdrev5 independent read-mostly review started on job/journaldup at 6fd36fa23da8f5d93fd5ea9fbf74fa207bb6f81d. Base: origin/dev. I will inspect the diff and run independent behavior probes without reading author reports or changing product code. Evidence will be recorded in artifacts/jdrev5-findings.md.
Author
Owner

jdrev5 independent review progress at 6fd36fa23: fetch/merge origin/dev completed (Already up to date; origin/dev af202e151). No product code changes. Diff checks found no established defect in retained Cancel proof, fixed-size 32-day receipt pruning, or FULL sync final-send fences. Focused browser regressions passed: 2 files, 24 tests. Files gate is building; independent real-server probes are prepared for stage interruptions, day 29/31/33, missing source, and daemon SIGKILL before acknowledgement. Evidence: artifacts/jdrev5-findings.md.

jdrev5 independent review progress at 6fd36fa23: fetch/merge origin/dev completed (Already up to date; origin/dev af202e151). No product code changes. Diff checks found no established defect in retained Cancel proof, fixed-size 32-day receipt pruning, or FULL sync final-send fences. Focused browser regressions passed: 2 files, 24 tests. Files gate is building; independent real-server probes are prepared for stage interruptions, day 29/31/33, missing source, and daemon SIGKILL before acknowledgement. Evidence: artifacts/jdrev5-findings.md.
Author
Owner

jdrev5 candidate finding from independent code review; runtime confirmation is compiling:

The sync transport loses uncertainty if a final PATCH gets an unknown result, HEAD reports the full length, and the empty same-ID finalization then returns 404/410. remote.rs maps that last response to UploadExpired. transfer.rs send_chunks uses the possible_publication value read before the current final attempt (false), clears the just-written final_sent fence, and send_snapshot permits a replacement POST. This does not preserve DESIGN §26's missing-proof rule across transport recovery. A new deterministic regression is in the existing cfg(test) module only; no product logic or old expectations were changed. The scripted peer supplies a replacement ID and success response to expose actual byte replay instead of a timeout. I will confirm the result before assigning severity/verdict.

The existing browser tests passed (24/24). The Rust gate is compiling the branch's native dependencies at CARGO_BUILD_JOBS=4. Real-server probes remain prepared, not yet counted as passes.

jdrev5 candidate finding from independent code review; runtime confirmation is compiling: The sync transport loses uncertainty if a final PATCH gets an unknown result, HEAD reports the full length, and the empty same-ID finalization then returns 404/410. remote.rs maps that last response to UploadExpired. transfer.rs send_chunks uses the possible_publication value read before the current final attempt (false), clears the just-written final_sent fence, and send_snapshot permits a replacement POST. This does not preserve DESIGN §26's missing-proof rule across transport recovery. A new deterministic regression is in the existing cfg(test) module only; no product logic or old expectations were changed. The scripted peer supplies a replacement ID and success response to expose actual byte replay instead of a timeout. I will confirm the result before assigning severity/verdict. The existing browser tests passed (24/24). The Rust gate is compiling the branch's native dependencies at CARGO_BUILD_JOBS=4. Real-server probes remain prepared, not yet counted as passes.
Author
Owner

jdfix9 started on job/journaldup at 6fd36fa23d. Running the uncommitted lost-final-response/full-HEAD/missing-receipt regression first, then fixing confirmed replay and completing the bounded reliability checks in jdrev5 items 1–5. No dependency changes planned.

jdfix9 started on job/journaldup at 6fd36fa23da8f5d93fd5ea9fbf74fa207bb6f81d. Running the uncommitted lost-final-response/full-HEAD/missing-receipt regression first, then fixing confirmed replay and completing the bounded reliability checks in jdrev5 items 1–5. No dependency changes planned.
Author
Owner

CONFIRMED data-safety defect: the regression returned Ok(()) with replacement upload ID 00000000-0000-0000-0000-000000001296. Observed requests: final PATCH original ID, HEAD original at full length, empty PATCH original returns 404, POST new ID, PATCH new ID. Log artifacts/jdfix9/candidate.log. Keeping and renaming the failing test as requested, before the fix. Decision: preserve transport uncertainty through all same-ID recovery responses; a later missing receipt cannot disprove the earlier publication.

CONFIRMED data-safety defect: the regression returned Ok(()) with replacement upload ID 00000000-0000-0000-0000-000000001296. Observed requests: final PATCH original ID, HEAD original at full length, empty PATCH original returns 404, POST new ID, PATCH new ID. Log artifacts/jdfix9/candidate.log. Keeping and renaming the failing test as requested, before the fix. Decision: preserve transport uncertainty through all same-ID recovery responses; a later missing receipt cannot disprove the earlier publication.
Author
Owner

Sync fix committed at 2884999b2. Combined origin/dev cc1af3c12 with receipt migrations 29/30 unchanged and unoccupied on dev. Merge resolves focus using dev #1391 quiet programmatic focus; retained initialFocusVisible and dev active=!leaving trap control. Upgrade assertions sum both sets: core migration 16 plus Files 29/30 (27 round-9 additions, 26 7b additions, 18 7c additions). The xuser fixture uses dev #1297 instance_feature_flag_id key; every existing expected value is retained. 24 classification tests pass. Three exact perf hashes refreshed, zero new exceptions and no increased ratchet. Final Rust gates and real-process build are running sequentially with four build jobs. Step-2 review bound starts 2026-10-08T19:29:50Z.

Sync fix committed at 2884999b2. Combined origin/dev cc1af3c12 with receipt migrations 29/30 unchanged and unoccupied on dev. Merge resolves focus using dev #1391 quiet programmatic focus; retained initialFocusVisible and dev active=!leaving trap control. Upgrade assertions sum both sets: core migration 16 plus Files 29/30 (27 round-9 additions, 26 7b additions, 18 7c additions). The xuser fixture uses dev #1297 instance_feature_flag_id key; every existing expected value is retained. 24 classification tests pass. Three exact perf hashes refreshed, zero new exceptions and no increased ratchet. Final Rust gates and real-process build are running sequentially with four build jobs. Step-2 review bound starts 2026-10-08T19:29:50Z.
Author
Owner

CONFIRMED follow-up recovery defect: full-offset resume returned Err(UploadExpired) after its same-ID finalization got 404; a reopened final-send fence returned a raw RemotePreconditionFailed after 412. Logs: artifacts/jdfix9/prior-refusal-before.log and pre-fix sync-test.log. Raw 409/412 can enter the engine conflict-copy branch and move local text despite the original upload outcome being unknown. Fix: when the durable fence already records possible publication, preserve UnknownWriteResult on recovery failure; full-offset finalization failures also remain unknown. New regression matrices retain original success expectations, source bytes, pending ID and fence. Final gates repeat only because these new regressions found a material concern.

CONFIRMED follow-up recovery defect: full-offset resume returned Err(UploadExpired) after its same-ID finalization got 404; a reopened final-send fence returned a raw RemotePreconditionFailed after 412. Logs: artifacts/jdfix9/prior-refusal-before.log and pre-fix sync-test.log. Raw 409/412 can enter the engine conflict-copy branch and move local text despite the original upload outcome being unknown. Fix: when the durable fence already records possible publication, preserve UnknownWriteResult on recovery failure; full-offset finalization failures also remain unknown. New regression matrices retain original success expectations, source bytes, pending ID and fence. Final gates repeat only because these new regressions found a material concern.
Author
Owner

Restart/full-offset recovery fix committed. Final sync gate passes: 72 library tests and 2 daemon tests. Final cargo fmt --check passes. Clippy for calternal-sync and calternal-plugin-files passes with -D warnings. Files tests are compiling; then the same branch server and daemon binaries build for one bounded real-process review of items 1–5. Both the 404/410 missing-proof and 409/412 refusal matrices retain the original ID, FULL final-send fence and exact local bytes. No existing success assertion was weakened.

Restart/full-offset recovery fix committed. Final sync gate passes: 72 library tests and 2 daemon tests. Final cargo fmt --check passes. Clippy for calternal-sync and calternal-plugin-files passes with -D warnings. Files tests are compiling; then the same branch server and daemon binaries build for one bounded real-process review of items 1–5. Both the 404/410 missing-proof and 409/412 refusal matrices retain the original ID, FULL final-send fence and exact local bytes. No existing success assertion was weakened.
Author
Owner

Head 8ffb05a58 includes repeatable publication/retention/isolation/recovery probes and a real-daemon final-send SIGKILL probe, derived from jdrev5 scratch scripts and reusing the existing campaigns. Imports, CLI parsing and Python compilation pass. Real execution remains pending the branch server build; no real-server PASS is claimed yet. bun run check passes (0 errors, 4 warnings); bun run test --maxWorkers=2 passes (303 files, 2183 tests). Final sync gate passes 72 library + 2 daemon tests. Files tests are running with --test-threads=4 and no failure reported so far. The step-2 time limit ends 2026-10-08T21:29:50Z.

Head 8ffb05a58 includes repeatable publication/retention/isolation/recovery probes and a real-daemon final-send SIGKILL probe, derived from jdrev5 scratch scripts and reusing the existing campaigns. Imports, CLI parsing and Python compilation pass. Real execution remains pending the branch server build; no real-server PASS is claimed yet. bun run check passes (0 errors, 4 warnings); bun run test --maxWorkers=2 passes (303 files, 2183 tests). Final sync gate passes 72 library + 2 daemon tests. Files tests are running with --test-threads=4 and no failure reported so far. The step-2 time limit ends 2026-10-08T21:29:50Z.
Author
Owner

Files full gate: 277 passed, 1 failed, 4 ignored. Sole failure is existing five-minute internal-temp reconcile storm deadline: all four scans completed, profile had 835/1000 watcher events at 300039 ms, total 305034 ms. No invariant assertion failed. The test and its 300-second bound are unchanged. One focused run of that exact binary/test will classify this SLOW-only candidate; no wait for a quiet host and no full-suite loop. Remaining integration target will run separately because cargo stops after the failed lib target. Exact original log: artifacts/jdfix9/files-test.log. Server/daemon build proceeds for the bounded real-process checks.

Files full gate: 277 passed, 1 failed, 4 ignored. Sole failure is existing five-minute internal-temp reconcile storm deadline: all four scans completed, profile had 835/1000 watcher events at 300039 ms, total 305034 ms. No invariant assertion failed. The test and its 300-second bound are unchanged. One focused run of that exact binary/test will classify this SLOW-only candidate; no wait for a quiet host and no full-suite loop. Remaining integration target will run separately because cargo stops after the failed lib target. Exact original log: artifacts/jdfix9/files-test.log. Server/daemon build proceeds for the bounded real-process checks.
Author
Owner

SLOW-only classification: the single focused storm diagnostic also reached only its existing 300-second deadline. All four during-burst scans completed; watcher progress was 769/1000 (original concurrent gate 835/1000). No data, path-isolation, corruption, crash or authorization assertion failed. Exact focused result: FAILED. 0 passed; 1 failed; 281 filtered out; 303.84 s. No more reruns, no quiet-host wait, no test changes. All nine Files jdrev2 integration regressions pass in 12.89 s. The full Files gate remains failed and will be quoted as failed, rather than reported green. Server build and real-process review continue within the two-hour bound.

SLOW-only classification: the single focused storm diagnostic also reached only its existing 300-second deadline. All four during-burst scans completed; watcher progress was 769/1000 (original concurrent gate 835/1000). No data, path-isolation, corruption, crash or authorization assertion failed. Exact focused result: FAILED. 0 passed; 1 failed; 281 filtered out; 303.84 s. No more reruns, no quiet-host wait, no test changes. All nine Files jdrev2 integration regressions pass in 12.89 s. The full Files gate remains failed and will be quoted as failed, rather than reported green. Server build and real-process review continue within the two-hour bound.
Author
Owner

jdfix9 final report — #1295

Branch: job/journaldup
Base: 6fd36fa23
Head: 15a5a589c0
Merged origin/dev cc1af3c12 once before final gates. No push, deploy or subsequent merge.

What changed

The inherited regression confirmed a duplicate-apply path. A final PATCH lost its response, HEAD reported full length, and an empty final PATCH returned 404. The old transport returned UploadExpired. The caller cleared the final-send fence and created a second upload ID. The test observed PATCH/HEAD/PATCH/POST/PATCH and success under the replacement ID.

The transport now retains UnknownWriteResult after the first ambiguous final send. A later recovery refusal cannot prove that the earlier send did not publish. The transfer code also retains durable uncertainty across HEAD, full-offset completion, restart and 404/410/409/412 refusals. It keeps the original ID, source and fence for the existing completion-receipt recovery path. A definite refusal without earlier publication uncertainty retains its existing behavior.

Committed the inherited failing regression first, then the fix and passing tests. Added crash-reopen and refusal-matrix coverage. Added repeatable real-server publication-stage, retention, missing-source and User-isolation probes. Added a real daemon SIGKILL probe with a response-only barrier after publication. The campaign has an optional bounded startup budget; its existing default remains 400 attempts.

Files

  • crates/calternal-sync/src/remote.rs: transport uncertainty and documentation.
  • crates/calternal-sync/src/transfer.rs: durable fence handling and regression tests.
  • crates/calternal-sync/integration_campaign.py: optional probe startup budget and documentation.
  • tests/adversarial/journal_recovery_boundaries.py: publication stages, retention, missing-source recovery and User isolation.
  • tests/adversarial/journal_sync_finalize_crash.py: real daemon final-send kill/restart.
  • crates/plugins/files/DATA-SAFETY.md: repeatable verification commands.

The origin/dev merge also reconciled the shared focus helper/OverlaySurface, upgrade-test migration counts, XUser classification fixture and exact performance pins. Both sides' receipt and focus safeguards remain. Files migrations 29/30 were not occupied on origin/dev. No test expectation was weakened. No new dependencies or production UI were added. Changed doc comments were read again before this report.

Review items 1–5

Completed one bounded real-server review, with focused diagnostics for failures, within the two-hour review budget. Reused journal_cancel_restart.py and journal_finalize_crash.py; both passed.

  1. Ten publication boundary cases passed: before staging, partial staging, full staging before installation, installation intent, and receipt; each with and without Cancel/restart. Later Log bytes remained exact, acknowledged Versions remained, and retries did not apply bytes twice.
  2. Initialized Daily note fixture passed at days 29, 31 and 33. Real cleanup retained receipts at 29/31 and pruned them at 33. Same-ID retries did not change source or Versions.
  3. Real daemon SIGKILL after final send and before acknowledgement passed. The FULL journal retained the original ID, final_sent=1 and original 30-day deadline. Restart recovered completion and retired pending/fence atomically. Exactly one POST, one receipt and one Note were observed.
  4. Two Users with identical Daily note filenames remained isolated. Foreign upload-ID HEAD/PATCH/DELETE returned 404 before and after completion; no path/item headers leaked.
  5. The canonical protected Note remained protected through Cancel and two restarts. A sibling Note stayed writable. Exact-source recovery restored target Log writes, and same-ID retry preserved the later bytes.

Verbatim real-server results:

PASS day 29: cleanup receipt count=1, same-ID HEAD/PATCH=200/204; source and Versions unchanged
PASS day 31: cleanup receipt count=1, same-ID HEAD/PATCH=200/204; source and Versions unchanged
PASS day 33: cleanup receipt count=0, same-ID HEAD/PATCH=404/404; source and Versions unchanged
PASS missing-source Cancel: proof survives two restarts; sibling stays writable; exact-source recovery restores target writes
PASS daemon SIGKILL after final send: durable same ID + final_sent=1 + original 30-day deadline survive; restart verifies exact published bytes, retires pending/fence atomically; 1 POST, 1 receipt, 1 Note, no replay
PASS two Users: identical Daily note filenames isolated; same foreign upload ID HEAD/PATCH/DELETE=404 before and after completion; no path/item leakage or cross-User writes

Gates (verbatim result lines)

Every Cargo command used CARGO_PROFILE_DEV_DEBUG=line-tables-only, CARGO_INCREMENTAL=0, CARGO_BUILD_JOBS=4 and worktree target/tmp. The preset job target directory was kept.

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

cargo clippy -p calternal-sync -p calternal-plugin-files --all-targets -- -D warnings: exit 0.

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

cargo test -p calternal-sync -- --test-threads=4: exit 0.

test result: ok. 72 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 12.19s
test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.01s
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

cargo test -p calternal-plugin-files -- --test-threads=4: exit 101.

failures:
    tests::internal_temp_paths_never_enter_index_during_atomic_write_reconcile_storm

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

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

The unchanged reconcile storm timed out at its 300-second deadline. All four scans completed and 835 watcher events progressed; there was no failed path/data invariant. One focused diagnostic run also timed out with 769 events and completed scans. This is SLOW-only throughput evidence on the shared host. It is not a passing gate. No timeout or expectation was changed, and no further retry loop was run.

FILES_RECONCILE_STORM_PROFILE {"scans_before_write_burst_ms":[363,220,38,64],"scans_during_write_burst_ms":[368,17,54,66],"status":"incomplete","total_test_ms":305034,"watcher_events":835,"write_and_scan_ms":300039,"writes":1000}
FILES_RECONCILE_STORM_PROFILE {"scans_before_write_burst_ms":[35,32,9,8],"scans_during_write_burst_ms":[160,45,38,35],"status":"incomplete","total_test_ms":303828,"watcher_events":769,"write_and_scan_ms":302120,"writes":1000}
test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 281 filtered out; finished in 303.84s

The remaining already-built Files integration binary was run directly after Cargo stopped at the library failure:

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

cd apps/web && bun run check: exit 0.

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

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

 Test Files  303 passed (303)
      Tests  2183 passed (2183)
   Duration  967.64s (transform 29%, import 27%, environment 26%, tests 13%, setup 5%)

XUser classification (24 tests) and journal receipt probe unit tests passed. Exact performance pin refresh found zero unpinned entries; no rule or ratchet was weakened. Real server/daemon debug binaries built successfully for the probes.

Known gaps and decisions

  • Required Files gate is not green because of the existing SLOW-only reconcile storm timeout. No data-safety failure was found in the new recovery probes.
  • The original metadata-free retention fixture reports byte/Version changes from lawful startup metadata adoption (date, last edited, tags, calternal-id; DESIGN §17). Its original strict assertions remain. The separate initialized fixture isolates receipt replay and passes exact source/Version assertions.
  • The original imported-root missing-source fixture expects a day-level Log refusal. It instead receives 201 for a different item at Notes/20210314-dailynote.md. The protected imported root item retains its proof. The existing Notes fallback selects the canonical path when the imported source is absent. This is an owner review question about same-date fallback, not evidence that the protected item was overwritten. Its original assertion remains. The canonical exact-target fixture passes protection/recovery checks. No Notes behavior was changed.
  • No new product design was selected. Protection stays per item under DESIGN §26. Test fixture separation distinguishes metadata adoption and a different destination from a replay of the protected item.
  • Runtime cost is O(1) state checks per attempt, with no additional IO, scans, locks or requests. The defective replacement POST/PATCH is removed. This is not a performance issue; no VM measurement was run under the current verification policy.
  • UX gaps closed: duplicate apply after lost final response and after journal reopen; conflict-copy handling cannot bypass durable uncertainty. UX gaps left: owner interpretation of absent imported Daily note fallback above. No new visible controls.

For the merge round

  • cargo test -p calternal-plugin-files -- --test-threads=4: confirm the required full Files gate, including its storm, on the combined branch.
  • cargo test -p calternal-server upgrade -- --test-threads=4: confirm combined core/Files migration reconciliation.
  • Full server gates, combined e2e/adversarial matrices and staging/Mac checks remain merge-round work under the verification policy.

Evidence is retained in artifacts/jdfix9/*.log and final-report.md. Build cleanup completed: cargo clean removed 14.5 GiB; web build and .svelte-kit/output removed. Working tree is clean.

BLOCK — required Files test gate timed out (SLOW-only); head 15a5a589c0

jdfix9 final report — #1295 Branch: job/journaldup Base: 6fd36fa23 Head: 15a5a589c02ebfea81cdb539864d82b93c4a4d0b Merged origin/dev cc1af3c12 once before final gates. No push, deploy or subsequent merge. What changed The inherited regression confirmed a duplicate-apply path. A final PATCH lost its response, HEAD reported full length, and an empty final PATCH returned 404. The old transport returned UploadExpired. The caller cleared the final-send fence and created a second upload ID. The test observed PATCH/HEAD/PATCH/POST/PATCH and success under the replacement ID. The transport now retains UnknownWriteResult after the first ambiguous final send. A later recovery refusal cannot prove that the earlier send did not publish. The transfer code also retains durable uncertainty across HEAD, full-offset completion, restart and 404/410/409/412 refusals. It keeps the original ID, source and fence for the existing completion-receipt recovery path. A definite refusal without earlier publication uncertainty retains its existing behavior. Committed the inherited failing regression first, then the fix and passing tests. Added crash-reopen and refusal-matrix coverage. Added repeatable real-server publication-stage, retention, missing-source and User-isolation probes. Added a real daemon SIGKILL probe with a response-only barrier after publication. The campaign has an optional bounded startup budget; its existing default remains 400 attempts. Files - crates/calternal-sync/src/remote.rs: transport uncertainty and documentation. - crates/calternal-sync/src/transfer.rs: durable fence handling and regression tests. - crates/calternal-sync/integration_campaign.py: optional probe startup budget and documentation. - tests/adversarial/journal_recovery_boundaries.py: publication stages, retention, missing-source recovery and User isolation. - tests/adversarial/journal_sync_finalize_crash.py: real daemon final-send kill/restart. - crates/plugins/files/DATA-SAFETY.md: repeatable verification commands. The origin/dev merge also reconciled the shared focus helper/OverlaySurface, upgrade-test migration counts, XUser classification fixture and exact performance pins. Both sides' receipt and focus safeguards remain. Files migrations 29/30 were not occupied on origin/dev. No test expectation was weakened. No new dependencies or production UI were added. Changed doc comments were read again before this report. Review items 1–5 Completed one bounded real-server review, with focused diagnostics for failures, within the two-hour review budget. Reused journal_cancel_restart.py and journal_finalize_crash.py; both passed. 1. Ten publication boundary cases passed: before staging, partial staging, full staging before installation, installation intent, and receipt; each with and without Cancel/restart. Later Log bytes remained exact, acknowledged Versions remained, and retries did not apply bytes twice. 2. Initialized Daily note fixture passed at days 29, 31 and 33. Real cleanup retained receipts at 29/31 and pruned them at 33. Same-ID retries did not change source or Versions. 3. Real daemon SIGKILL after final send and before acknowledgement passed. The FULL journal retained the original ID, final_sent=1 and original 30-day deadline. Restart recovered completion and retired pending/fence atomically. Exactly one POST, one receipt and one Note were observed. 4. Two Users with identical Daily note filenames remained isolated. Foreign upload-ID HEAD/PATCH/DELETE returned 404 before and after completion; no path/item headers leaked. 5. The canonical protected Note remained protected through Cancel and two restarts. A sibling Note stayed writable. Exact-source recovery restored target Log writes, and same-ID retry preserved the later bytes. Verbatim real-server results: ```text PASS day 29: cleanup receipt count=1, same-ID HEAD/PATCH=200/204; source and Versions unchanged PASS day 31: cleanup receipt count=1, same-ID HEAD/PATCH=200/204; source and Versions unchanged PASS day 33: cleanup receipt count=0, same-ID HEAD/PATCH=404/404; source and Versions unchanged PASS missing-source Cancel: proof survives two restarts; sibling stays writable; exact-source recovery restores target writes PASS daemon SIGKILL after final send: durable same ID + final_sent=1 + original 30-day deadline survive; restart verifies exact published bytes, retires pending/fence atomically; 1 POST, 1 receipt, 1 Note, no replay PASS two Users: identical Daily note filenames isolated; same foreign upload ID HEAD/PATCH/DELETE=404 before and after completion; no path/item leakage or cross-User writes ``` Gates (verbatim result lines) Every Cargo command used CARGO_PROFILE_DEV_DEBUG=line-tables-only, CARGO_INCREMENTAL=0, CARGO_BUILD_JOBS=4 and worktree target/tmp. The preset job target directory was kept. `cargo fmt --check`: exit 0, no output. `cargo clippy -p calternal-sync -p calternal-plugin-files --all-targets -- -D warnings`: exit 0. ```text Finished `dev` profile [unoptimized + debuginfo] target(s) in 16.44s ``` `cargo test -p calternal-sync -- --test-threads=4`: exit 0. ```text test result: ok. 72 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 12.19s test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.01s test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s ``` `cargo test -p calternal-plugin-files -- --test-threads=4`: exit 101. ```text failures: tests::internal_temp_paths_never_enter_index_during_atomic_write_reconcile_storm test result: FAILED. 277 passed; 1 failed; 4 ignored; 0 measured; 0 filtered out; finished in 482.90s error: test failed, to rerun pass `-p calternal-plugin-files --lib` ``` The unchanged reconcile storm timed out at its 300-second deadline. All four scans completed and 835 watcher events progressed; there was no failed path/data invariant. One focused diagnostic run also timed out with 769 events and completed scans. This is SLOW-only throughput evidence on the shared host. It is not a passing gate. No timeout or expectation was changed, and no further retry loop was run. ```text FILES_RECONCILE_STORM_PROFILE {"scans_before_write_burst_ms":[363,220,38,64],"scans_during_write_burst_ms":[368,17,54,66],"status":"incomplete","total_test_ms":305034,"watcher_events":835,"write_and_scan_ms":300039,"writes":1000} FILES_RECONCILE_STORM_PROFILE {"scans_before_write_burst_ms":[35,32,9,8],"scans_during_write_burst_ms":[160,45,38,35],"status":"incomplete","total_test_ms":303828,"watcher_events":769,"write_and_scan_ms":302120,"writes":1000} test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 281 filtered out; finished in 303.84s ``` The remaining already-built Files integration binary was run directly after Cargo stopped at the library failure: ```text test result: ok. 9 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 12.89s ``` `cd apps/web && bun run check`: exit 0. ```text svelte-check found 0 errors and 4 warnings in 2 files ``` `cd apps/web && bun run test --maxWorkers=2`: exit 0. ```text Test Files 303 passed (303) Tests 2183 passed (2183) Duration 967.64s (transform 29%, import 27%, environment 26%, tests 13%, setup 5%) ``` XUser classification (24 tests) and journal receipt probe unit tests passed. Exact performance pin refresh found zero unpinned entries; no rule or ratchet was weakened. Real server/daemon debug binaries built successfully for the probes. Known gaps and decisions - Required Files gate is not green because of the existing SLOW-only reconcile storm timeout. No data-safety failure was found in the new recovery probes. - The original metadata-free retention fixture reports byte/Version changes from lawful startup metadata adoption (date, last edited, tags, calternal-id; DESIGN §17). Its original strict assertions remain. The separate initialized fixture isolates receipt replay and passes exact source/Version assertions. - The original imported-root missing-source fixture expects a day-level Log refusal. It instead receives 201 for a different item at Notes/20210314-dailynote.md. The protected imported root item retains its proof. The existing Notes fallback selects the canonical path when the imported source is absent. This is an owner review question about same-date fallback, not evidence that the protected item was overwritten. Its original assertion remains. The canonical exact-target fixture passes protection/recovery checks. No Notes behavior was changed. - No new product design was selected. Protection stays per item under DESIGN §26. Test fixture separation distinguishes metadata adoption and a different destination from a replay of the protected item. - Runtime cost is O(1) state checks per attempt, with no additional IO, scans, locks or requests. The defective replacement POST/PATCH is removed. This is not a performance issue; no VM measurement was run under the current verification policy. - UX gaps closed: duplicate apply after lost final response and after journal reopen; conflict-copy handling cannot bypass durable uncertainty. UX gaps left: owner interpretation of absent imported Daily note fallback above. No new visible controls. For the merge round - `cargo test -p calternal-plugin-files -- --test-threads=4`: confirm the required full Files gate, including its storm, on the combined branch. - `cargo test -p calternal-server upgrade -- --test-threads=4`: confirm combined core/Files migration reconciliation. - Full server gates, combined e2e/adversarial matrices and staging/Mac checks remain merge-round work under the verification policy. Evidence is retained in artifacts/jdfix9/*.log and final-report.md. Build cleanup completed: cargo clean removed 14.5 GiB; web build and .svelte-kit/output removed. Working tree is clean. BLOCK — required Files test gate timed out (SLOW-only); head 15a5a589c02ebfea81cdb539864d82b93c4a4d0b
kayg referenced this issue from a commit 2026-10-09 11:11:17 +00:00
Author
Owner

Deployed to calternal.cloud in merge round 35c (build 5a2c02c13, live 2026-10-09 ~16:35 IST). Closing.

Deployed to calternal.cloud in merge round 35c (build 5a2c02c13, live 2026-10-09 ~16:35 IST). Closing.
kayg closed this issue 2026-10-09 11:11:35 +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#1295
No description provided.