Keep temporary storage in each Home private directory #750

Closed
kayg wants to merge 6 commits from fix/storage-private-tmp-642-dev into dev
Owner

Temporary notes, uploads, import images and metadata snapshots now start in one private .calternal/tmp directory per Home on the target filesystem. Publication uses atomic rename. Temporary cleanup refuses public paths; explicit Trash, creation undo and backdrop deletion use separate user-action APIs.

Replaces #749 and #744 for #642. The accepted ADR updates from current dev are preserved. Rust and Cargo inputs are byte-for-byte identical to the tested runtime tree after this documentation reconciliation.

Private recovery covers data and split state roots. Format owners authorize legacy migration; a creator receipt alone cannot make authoritative state disposable. Unknown legacy files retain their original names. Hard links and existing descriptors prevent disposal, including a read-only descriptor later reopened for writing. Case-only moves retain a durable restoration intent. Destination group and ACL inheritance are preserved before placement.

The production cards lint exemption is removed. Removal, rename and overwrite bans cover the standard and Tokio filesystem APIs. Tests verify direct production removal and async overwrite calls are rejected. Private content stays out of note scans, watchers, lists, search, sync and attachment serving; future WebDAV and File Provider bridges must keep that boundary.

Validation passed: formatting, workspace Clippy with warnings denied, workspace tests, all 74 fsio tests, the permanent reviewer regressions from #737/#740/#742/#744, ordinary-binary startup cases, upload memory bounds, watcher publication and tree confinement. The settled 1,000-stop run preserved every acknowledged Unicode marker exactly once, matched canonical bytes to notes.get, and left no staging entries in either root. Final Rust and Cargo inputs match that binary; only five static async overwrite bans were added afterward and independently checked.

Legacy replay cleared 211 proven file images from a local 511-entry old state tree. It retained 285 directories and 15 files without sufficient proof; retained file bytes were unchanged and new private staging was empty. This is the conservative choice required by the rule to leave unproven legacy entries alone. ADR 0062 and docs/storage.md document it and the separate Trash lifecycle.

The designated performance VM was unreachable through NetBird and its direct hostname could not resolve, so there is no latency measurement claim. Detailed gate output and earlier failed checks are recorded on #642. Evidence and run artifacts remain outside the commit.

Temporary notes, uploads, import images and metadata snapshots now start in one private `.calternal/tmp` directory per Home on the target filesystem. Publication uses atomic rename. Temporary cleanup refuses public paths; explicit Trash, creation undo and backdrop deletion use separate user-action APIs. Replaces #749 and #744 for #642. The accepted ADR updates from current dev are preserved. Rust and Cargo inputs are byte-for-byte identical to the tested runtime tree after this documentation reconciliation. Private recovery covers data and split state roots. Format owners authorize legacy migration; a creator receipt alone cannot make authoritative state disposable. Unknown legacy files retain their original names. Hard links and existing descriptors prevent disposal, including a read-only descriptor later reopened for writing. Case-only moves retain a durable restoration intent. Destination group and ACL inheritance are preserved before placement. The production cards lint exemption is removed. Removal, rename and overwrite bans cover the standard and Tokio filesystem APIs. Tests verify direct production removal and async overwrite calls are rejected. Private content stays out of note scans, watchers, lists, search, sync and attachment serving; future WebDAV and File Provider bridges must keep that boundary. Validation passed: formatting, workspace Clippy with warnings denied, workspace tests, all 74 fsio tests, the permanent reviewer regressions from #737/#740/#742/#744, ordinary-binary startup cases, upload memory bounds, watcher publication and tree confinement. The settled 1,000-stop run preserved every acknowledged Unicode marker exactly once, matched canonical bytes to notes.get, and left no staging entries in either root. Final Rust and Cargo inputs match that binary; only five static async overwrite bans were added afterward and independently checked. Legacy replay cleared 211 proven file images from a local 511-entry old state tree. It retained 285 directories and 15 files without sufficient proof; retained file bytes were unchanged and new private staging was empty. This is the conservative choice required by the rule to leave unproven legacy entries alone. ADR 0062 and docs/storage.md document it and the separate Trash lifecycle. The designated performance VM was unreachable through NetBird and its direct hostname could not resolve, so there is no latency measurement claim. Detailed gate output and earlier failed checks are recorded on #642. Evidence and run artifacts remain outside the commit.
Author
Owner

Verdict: fix first. Independent verification of PR #750 at 1f3cf05f5ed8d24db0d6ae450ddb0ff756c7860b, based on dev d83e54dbe571b625504001a8b6add90d44ca6161. Detached worktree /home/agent/wt/verify-750. All tracked files are restored byte for byte. No commits, pushes, merges, deployments or issue closures.

  1. P2: cold note Home recovery moves a live upload into a public folder and breaks completion. History::clean_staging scans the whole Home. The scanner traverses live locked transactions, and recover_staging claims and restores an unknown private image without checking its transaction lock. Stopping note writers does not stop other plugins' upload writers.

    Reproduction: register a Home, create an actual Folder::create_temp upload in Photos, write a partial body and keep its writer alive. Open the cold Notes::home in the same process. Its private source disappears and a public conflict appears. Append through the original writer and attempt persist: publication fails. The ordinary recover_cleanup control correctly preserves the locked source. The ordinary uninstrumented server reproduces the same behavior when it opens that Home while the actual TempFile owner remains alive.

    Verbatim independent output:

    Same-process cold note Home with actual live TempFile: image remains private=false; public entries before completion=1; publication succeeds=false
    Ordinary startup while an actual TempFile writer is alive: private image remains=false; public entries before completion=1; upload publication succeeds=false
    

    The public conflict is still being written before upload completion. This is a live-writer isolation and placement failure; these reproductions do not demonstrate loss of acknowledged bytes.

  2. P2: staging enumeration removes a cancellation transaction during construction and leaves an abandoned image. staging_files removes empty transaction directories while enumerating. Pause Quarantine::new_in after mkdirat and before openat/locking/manifest creation. Run the real scanner, then resume cancellation. The scanner has removed the new directory; construction gets NotFound; TempFile::Drop ignores the cleanup error and leaves its original image. Normal cancellation without the scan passes the empty-directory control.

    Verbatim deterministic output:

    After cancellation and a concurrent production scan: 1 private images, 1 private root entries
    After restart recovery: 0 private root entries
    

    This uses one cfg(test) pause with a channel handshake, without a scheduling sleep, preload or syscall interception. Restart recovers the image; the defect is failed cancellation cleanup.

The storage boundary needs consistent handling of live transactions across every plugin. Format-owned legacy migration must respect transaction locks, and enumeration must not remove directories that producers can be constructing. Correct line reference for the earlier finding comment: the unknown-private branch is staging.rs:110-115.

Additional unresolved gate: importing 70 contacts, undoing the import and checking the existing card invariant reproducibly leaves a card with no live or trashed contact. tests::undo::undo_of_an_import_takes_every_contact_back fails both in the complete workspace run and alone with test threads=1 and a process-local descriptor limit of 8192. Isolated output: import undone: card 0478ceda-096f-8080-9f53-ead3d31ba4e5 has no contact. I have not established whether #750 introduced that regression.

The complete workspace gate finished with 119 passed/11 failed in contacts and 429 passed/2 failed/6 ignored in notes. Most other failures were SQLite CannotOpen errors under the original soft descriptor limit of 1024. The seven naming tests and the before-history import crash passed in isolation with limit 8192. The initial upload-cancellation timeout passed isolated and concurrent reruns. These results do not establish a common cause for the workspace failures; they remain recorded as failed gates.

Checks that passed: original fsio suite, 74 tests, both initially and within the complete run; eight independent placement/confinement tests; ordinary-binary list/search/journal/get/live-room/attachment exclusion; visible conflict recovery after ordinary restart; Clippy with warnings denied. Direct removal probes in fsio/src/lib.rs and contacts-actions/src/cards.rs both failed compilation with the intended disallowed-method diagnostic and were restored.

The fresh settled workload passed 1,000/1,000 stops: 250 saves, 250 renames, 250 Trash operations and 250 restores. All 1,000 acknowledged Unicode markers survived exactly once after each restart; same-key retries completed; auxiliary title/path/body stayed correct; final canonical bytes equaled notes.get. Both Home and separate state roots were empty of private transactions after discovery/save barriers settled. Deterministic tests supply separate boundary coverage; randomized after-send kills do not identify an interrupted syscall.

After the complete workspace run, a whole-tree scan found zero public temporary names and 48 retained private transaction directories in one test fixture. I inventoried them before running the original fsio recovery in a fresh process: before=48; after=0. The final scan across all retained workload roots and the full-test directory reports zero public temporary entries and zero nonempty private roots. Earlier failed scans remain recorded.

Reproductions and evidence: /home/agent/wt/verify-750/findings.md and .verification/REPRODUCE.md. Independent sources and patches: constructor-race.rs/.patch, live-home-notes.rs/.patch, live-upload-startup.py, independent.rs and review-tests.patch. From the restored reviewed tree, source /etc/calternal/env.sh, set TMPDIR to this job's .verification/full-tmp, and run /usr/local/bin/build-slot.sh bash .verification/run-followup.sh. It installs the test-only hooks, reproduces the lifecycle failures, restores source, and runs the isolated contacts checks. Logs and gate output remain uncommitted.

Earlier reviewer files on 6by32-compute01 were inaccessible through the requested hostname and peer IP; I read their published independent PR verdicts through Forgejo instead. Local #737/#740 findings were read directly. The earlier byte-loss mechanisms are addressed by private-only ordinary cleanup, creator-written receipts, link-count rejection and exclusive leases rejecting existing readers/writers. The new failures concern another recovery path bypassing live transaction ownership.

This verification covers Linux process stops. It does not establish disk power-cut behavior or non-Linux execution. WebDAV and File Provider adapters are absent in this checkout; their exclusion requirement is documented for future implementation.

Gate output, verbatim. Nonzero reproduction gates are failing preservation/lifecycle assertions. The first two independent failures include the corrected fixture length and a conservative parallel legacy-disposal refusal; the first loop scan overlapped a live background scan-state write. None is silently converted into a safety pass.

fsio-baseline exit=0
build exit=0
independent exit=101
independent-corrected exit=101
independent-serial exit=0
durability-1000 exit=1
restart-scan exit=0
durability-1000-settled exit=0
independent-expanded exit=0
isolation exit=0
workspace exit=101
clippy exit=0
lint-probe-calternal-fsio rejected=True compiler-exit=101
lint-probe-calternal-contacts-actions rejected=True compiler-exit=101
independent-confined exit=0
whole-tree-scan exit=0
upload-cancel-isolated exit=0
workspace-complete exit=101
whole-tree-scan-final exit=1
constructor-race exit=101
live-home-notes exit=101
contacts-names-isolated exit=0
import-private-isolated exit=0
import-undo-isolated exit=101
whole-tree-scan-followup exit=1
recovery-helper-build exit=0
retained-fixture-restart exit=0
whole-tree-scan-settled exit=0

Final head: 1f3cf05f5ed8d24db0d6ae450ddb0ff756c7860b. git diff --exit-code and git diff --check pass. Only findings.md and .verification/ remain untracked.

Verdict: **fix first**. Independent verification of PR #750 at `1f3cf05f5ed8d24db0d6ae450ddb0ff756c7860b`, based on dev `d83e54dbe571b625504001a8b6add90d44ca6161`. Detached worktree `/home/agent/wt/verify-750`. All tracked files are restored byte for byte. No commits, pushes, merges, deployments or issue closures. 1. **P2: cold note Home recovery moves a live upload into a public folder and breaks completion.** [History::clean_staging](https://git.kayg.org/kayg/calternal/src/commit/1f3cf05f5ed8d24db0d6ae450ddb0ff756c7860b/crates/notes/src/history/staging.rs#L23) scans the whole Home. The scanner traverses live locked transactions, and [recover_staging](https://git.kayg.org/kayg/calternal/src/commit/1f3cf05f5ed8d24db0d6ae450ddb0ff756c7860b/crates/fsio/src/staging.rs#L110) claims and restores an unknown private image without checking its transaction lock. Stopping note writers does not stop other plugins' upload writers. Reproduction: register a Home, create an actual `Folder::create_temp` upload in Photos, write a partial body and keep its writer alive. Open the cold `Notes::home` in the same process. Its private source disappears and a public conflict appears. Append through the original writer and attempt `persist`: publication fails. The ordinary `recover_cleanup` control correctly preserves the locked source. The ordinary uninstrumented server reproduces the same behavior when it opens that Home while the actual TempFile owner remains alive. Verbatim independent output: ```text Same-process cold note Home with actual live TempFile: image remains private=false; public entries before completion=1; publication succeeds=false Ordinary startup while an actual TempFile writer is alive: private image remains=false; public entries before completion=1; upload publication succeeds=false ``` The public conflict is still being written before upload completion. This is a live-writer isolation and placement failure; these reproductions do not demonstrate loss of acknowledged bytes. 2. **P2: staging enumeration removes a cancellation transaction during construction and leaves an abandoned image.** [staging_files](https://git.kayg.org/kayg/calternal/src/commit/1f3cf05f5ed8d24db0d6ae450ddb0ff756c7860b/crates/fsio/src/staging.rs#L41) removes empty transaction directories while enumerating. Pause [Quarantine::new_in](https://git.kayg.org/kayg/calternal/src/commit/1f3cf05f5ed8d24db0d6ae450ddb0ff756c7860b/crates/fsio/src/quarantine.rs#L84) after mkdirat and before openat/locking/manifest creation. Run the real scanner, then resume cancellation. The scanner has removed the new directory; construction gets NotFound; TempFile::Drop ignores the cleanup error and leaves its original image. Normal cancellation without the scan passes the empty-directory control. Verbatim deterministic output: ```text After cancellation and a concurrent production scan: 1 private images, 1 private root entries After restart recovery: 0 private root entries ``` This uses one cfg(test) pause with a channel handshake, without a scheduling sleep, preload or syscall interception. Restart recovers the image; the defect is failed cancellation cleanup. The storage boundary needs consistent handling of live transactions across every plugin. Format-owned legacy migration must respect transaction locks, and enumeration must not remove directories that producers can be constructing. Correct line reference for the earlier finding comment: the unknown-private branch is staging.rs:110-115. **Additional unresolved gate:** importing 70 contacts, undoing the import and checking the existing card invariant reproducibly leaves a card with no live or trashed contact. `tests::undo::undo_of_an_import_takes_every_contact_back` fails both in the complete workspace run and alone with test threads=1 and a process-local descriptor limit of 8192. Isolated output: `import undone: card 0478ceda-096f-8080-9f53-ead3d31ba4e5 has no contact`. I have not established whether #750 introduced that regression. The complete workspace gate finished with 119 passed/11 failed in contacts and 429 passed/2 failed/6 ignored in notes. Most other failures were SQLite CannotOpen errors under the original soft descriptor limit of 1024. The seven naming tests and the before-history import crash passed in isolation with limit 8192. The initial upload-cancellation timeout passed isolated and concurrent reruns. These results do not establish a common cause for the workspace failures; they remain recorded as failed gates. **Checks that passed:** original fsio suite, 74 tests, both initially and within the complete run; eight independent placement/confinement tests; ordinary-binary list/search/journal/get/live-room/attachment exclusion; visible conflict recovery after ordinary restart; Clippy with warnings denied. Direct removal probes in fsio/src/lib.rs and contacts-actions/src/cards.rs both failed compilation with the intended disallowed-method diagnostic and were restored. The fresh settled workload passed **1,000/1,000** stops: 250 saves, 250 renames, 250 Trash operations and 250 restores. All 1,000 acknowledged Unicode markers survived exactly once after each restart; same-key retries completed; auxiliary title/path/body stayed correct; final canonical bytes equaled notes.get. Both Home and separate state roots were empty of private transactions after discovery/save barriers settled. Deterministic tests supply separate boundary coverage; randomized after-send kills do not identify an interrupted syscall. After the complete workspace run, a whole-tree scan found zero public temporary names and 48 retained private transaction directories in one test fixture. I inventoried them before running the original fsio recovery in a fresh process: `before=48; after=0`. The final scan across all retained workload roots and the full-test directory reports zero public temporary entries and zero nonempty private roots. Earlier failed scans remain recorded. Reproductions and evidence: `/home/agent/wt/verify-750/findings.md` and `.verification/REPRODUCE.md`. Independent sources and patches: constructor-race.rs/.patch, live-home-notes.rs/.patch, live-upload-startup.py, independent.rs and review-tests.patch. From the restored reviewed tree, source `/etc/calternal/env.sh`, set TMPDIR to this job's `.verification/full-tmp`, and run `/usr/local/bin/build-slot.sh bash .verification/run-followup.sh`. It installs the test-only hooks, reproduces the lifecycle failures, restores source, and runs the isolated contacts checks. Logs and gate output remain uncommitted. Earlier reviewer files on 6by32-compute01 were inaccessible through the requested hostname and peer IP; I read their published independent PR verdicts through Forgejo instead. Local #737/#740 findings were read directly. The earlier byte-loss mechanisms are addressed by private-only ordinary cleanup, creator-written receipts, link-count rejection and exclusive leases rejecting existing readers/writers. The new failures concern another recovery path bypassing live transaction ownership. This verification covers Linux process stops. It does not establish disk power-cut behavior or non-Linux execution. WebDAV and File Provider adapters are absent in this checkout; their exclusion requirement is documented for future implementation. Gate output, verbatim. Nonzero reproduction gates are failing preservation/lifecycle assertions. The first two independent failures include the corrected fixture length and a conservative parallel legacy-disposal refusal; the first loop scan overlapped a live background scan-state write. None is silently converted into a safety pass. ```text fsio-baseline exit=0 build exit=0 independent exit=101 independent-corrected exit=101 independent-serial exit=0 durability-1000 exit=1 restart-scan exit=0 durability-1000-settled exit=0 independent-expanded exit=0 isolation exit=0 workspace exit=101 clippy exit=0 lint-probe-calternal-fsio rejected=True compiler-exit=101 lint-probe-calternal-contacts-actions rejected=True compiler-exit=101 independent-confined exit=0 whole-tree-scan exit=0 upload-cancel-isolated exit=0 workspace-complete exit=101 whole-tree-scan-final exit=1 constructor-race exit=101 live-home-notes exit=101 contacts-names-isolated exit=0 import-private-isolated exit=0 import-undo-isolated exit=101 whole-tree-scan-followup exit=1 recovery-helper-build exit=0 retained-fixture-restart exit=0 whole-tree-scan-settled exit=0 ``` Final head: `1f3cf05f5ed8d24db0d6ae450ddb0ff756c7860b`. `git diff --exit-code` and `git diff --check` pass. Only findings.md and .verification/ remain untracked.
Author
Owner

Finished in PR #759 on fix/storage-owner-liveness-642, based on the reviewed #750 head 1f3cf05f5ed8d24db0d6ae450ddb0ff756c7860b.

Head: 257a1af579932a78b22599bda86d03ec062d98df. The committed contents match all 18 frozen code/test files used for the final gates. Evidence and artifacts are excluded from the commit.

Finding → fix → test:

  • P2, recovery seized a live upload: every private producer holds a directory owner lock; a short shared root lock covers creation until that owner lock is acquired. Recovery skips live owners and holds its claim through journal proof and moves. The permanent cold-Home test reports image remains private=true; public entries before completion=0; publication succeeds=true. The fsio test also appends later bytes and verifies the complete published body; both recovery paths skip the live image even when given a journal predicate.
  • P2, scans defeated cancellation: enumeration only observes entries and does not remove directories. Constructor and recovery use the same root/owner handshake. cancellation_and_staging_scan_do_not_orphan_a_private_upload requires zero private root entries before restart cleanup runs. A second permanent test runs recovery during the mkdir/owner-lock gap. Both pass.
  • A basename must not bypass ownership: the roots module identifies the registered root, rather than treating every directory called tmp as a root. The permanent locked-child test fails before this correction and passes afterward, including its positive abandoned-entry control.
  • Import cleanup: prepared folders use the same ownership check; recovery closes its own legacy marker descriptor before requesting the private disposal lease. The reviewer's private-files-before-history crash test passes.
  • Import undo could race a selected card copy: the Contacts sweep waits for the user's copier before taking its snapshot. The paused-copy regression fails with exit 101 when only this mutex change is removed, and passes with the fix. The original import-undo assertion passes in all three full runs.
  • A published create could be missing from the index after a crash: startup identifies planned creates through the existing note identity parser before replay. Matching identities recover; a different identity's bytes remain untouched. The 1,000-card file-placement crash case passes.
  • Repeated clock values could reuse a private name: allocation advances a process-wide logical clock while retaining the previous name width. Permanent frozen-clock and long Unicode destination tests pass; the valid 207-byte Unicode destination is preserved.

The original Notes tag failure logged EMFILE immediately before SQLite CannotOpen. Nine Contacts CannotOpen failures did not capture their underlying OS errno, so I do not claim every one had the same cause. Final gates use the normal user, disk-backed job-local temporary files, descriptor limit 8192, cargo -j3, and one test thread per binary. All three consecutive full workspace runs pass, including documentation tests: Contacts 131, fsio 82 and Notes 434 passed in each run. Existing ignored perf, release-stress and helper cases remain configured; no new ignores were added.

The independent eight-case preservation matrix passes again, covering outside in-place writes and replacements, open public descriptors, exclusive destination collisions, unconditional metadata writers and deterministic save crash boundaries. The two requested reproductions are permanent tests. contact-copy-red below is a successful negative-control wrapper: it requires the old implementation's exit 101 and restores the verified source before the positive gates.

Verbatim final gate output:

contact-copy-red exit=0
independent-matrix exit=0
fmt-write exit=0
fmt exit=0
clippy exit=0
fsio exit=0
notes-recovery exit=0
notes-staging exit=0
attachments exit=0
auth-stream exit=0
contact-copy exit=0
contact-placement exit=0
contacts-undo exit=0
fmt-confirm exit=0
clippy-confirm exit=0
final-workspace-1 exit=0
final-workspace-2 exit=0
final-workspace-3 exit=0
binary exit=0
durability-1000 exit=0
diff-check exit=0

Verbatim settled-loop result:

Independent PR750 broad Home/state scan. Check 5 PASS: 1000/1000 abrupt stops and restarts completed: 250 saves, 250 renames, 250 Trash operations, 250 restores. All 1000 acknowledged text markers survived exactly once after every restart; final canonical bytes equal notes.get; no staging leftovers after restart and explicit save barriers in any round. Randomized SIGKILL timing does not prove a particular syscall was interrupted; deterministic boundary checks supply that coverage.
Finished in [PR #759](https://git.kayg.org/kayg/calternal/pulls/759) on `fix/storage-owner-liveness-642`, based on the reviewed #750 head `1f3cf05f5ed8d24db0d6ae450ddb0ff756c7860b`. Head: `257a1af579932a78b22599bda86d03ec062d98df`. The committed contents match all 18 frozen code/test files used for the final gates. Evidence and artifacts are excluded from the commit. Finding → fix → test: - P2, recovery seized a live upload: every private producer holds a directory owner lock; a short shared root lock covers creation until that owner lock is acquired. Recovery skips live owners and holds its claim through journal proof and moves. The permanent cold-Home test reports `image remains private=true; public entries before completion=0; publication succeeds=true`. The fsio test also appends later bytes and verifies the complete published body; both recovery paths skip the live image even when given a journal predicate. - P2, scans defeated cancellation: enumeration only observes entries and does not remove directories. Constructor and recovery use the same root/owner handshake. `cancellation_and_staging_scan_do_not_orphan_a_private_upload` requires zero private root entries before restart cleanup runs. A second permanent test runs recovery during the mkdir/owner-lock gap. Both pass. - A basename must not bypass ownership: the roots module identifies the registered root, rather than treating every directory called `tmp` as a root. The permanent locked-child test fails before this correction and passes afterward, including its positive abandoned-entry control. - Import cleanup: prepared folders use the same ownership check; recovery closes its own legacy marker descriptor before requesting the private disposal lease. The reviewer's private-files-before-history crash test passes. - Import undo could race a selected card copy: the Contacts sweep waits for the user's copier before taking its snapshot. The paused-copy regression fails with exit 101 when only this mutex change is removed, and passes with the fix. The original import-undo assertion passes in all three full runs. - A published create could be missing from the index after a crash: startup identifies planned creates through the existing note identity parser before replay. Matching identities recover; a different identity's bytes remain untouched. The 1,000-card file-placement crash case passes. - Repeated clock values could reuse a private name: allocation advances a process-wide logical clock while retaining the previous name width. Permanent frozen-clock and long Unicode destination tests pass; the valid 207-byte Unicode destination is preserved. The original Notes tag failure logged EMFILE immediately before SQLite CannotOpen. Nine Contacts CannotOpen failures did not capture their underlying OS errno, so I do not claim every one had the same cause. Final gates use the normal user, disk-backed job-local temporary files, descriptor limit 8192, cargo `-j3`, and one test thread per binary. All three consecutive full workspace runs pass, including documentation tests: Contacts 131, fsio 82 and Notes 434 passed in each run. Existing ignored perf, release-stress and helper cases remain configured; no new ignores were added. The independent eight-case preservation matrix passes again, covering outside in-place writes and replacements, open public descriptors, exclusive destination collisions, unconditional metadata writers and deterministic save crash boundaries. The two requested reproductions are permanent tests. `contact-copy-red` below is a successful negative-control wrapper: it requires the old implementation's exit 101 and restores the verified source before the positive gates. Verbatim final gate output: ```text contact-copy-red exit=0 independent-matrix exit=0 fmt-write exit=0 fmt exit=0 clippy exit=0 fsio exit=0 notes-recovery exit=0 notes-staging exit=0 attachments exit=0 auth-stream exit=0 contact-copy exit=0 contact-placement exit=0 contacts-undo exit=0 fmt-confirm exit=0 clippy-confirm exit=0 final-workspace-1 exit=0 final-workspace-2 exit=0 final-workspace-3 exit=0 binary exit=0 durability-1000 exit=0 diff-check exit=0 ``` Verbatim settled-loop result: ```text Independent PR750 broad Home/state scan. Check 5 PASS: 1000/1000 abrupt stops and restarts completed: 250 saves, 250 renames, 250 Trash operations, 250 restores. All 1000 acknowledged text markers survived exactly once after every restart; final canonical bytes equal notes.get; no staging leftovers after restart and explicit save barriers in any round. Randomized SIGKILL timing does not prove a particular syscall was interrupted; deterministic boundary checks supply that coverage. ```
Author
Owner

housekeeping #1009: needs-decision.

Old private-temp implementation is a predecessor of #759 and the simpler #759b/#788 redesign. Replaying it would restore the older staging design. Preserve its regression coverage for salvage.

original head: 1f3cf05f5ed8d24db0d6ae450ddb0ff756c7860b. against dev cd7f84432febfc63b788fbb9b9f9950452982d74, git cherry reports 6 unmatched and 0 equivalent patches. the landing audit lists each candidate missing commit and stable patch match in pr-750.md; unmatched patches can include superseded behavior.

left open, source branch unchanged. no rebase or new test claim for this decision lane.

housekeeping #1009: needs-decision. Old private-temp implementation is a predecessor of #759 and the simpler #759b/#788 redesign. Replaying it would restore the older staging design. Preserve its regression coverage for salvage. original head: `1f3cf05f5ed8d24db0d6ae450ddb0ff756c7860b`. against dev `cd7f84432febfc63b788fbb9b9f9950452982d74`, git cherry reports 6 unmatched and 0 equivalent patches. the [landing audit](https://git.kayg.org/attachments/fe3c09dc-dea3-47a0-92e2-b44a777083e5) lists each candidate missing commit and stable patch match in `pr-750.md`; unmatched patches can include superseded behavior. left open, source branch unchanged. no rebase or new test claim for this decision lane.
Author
Owner

Superseded by the private-staging redesign #788. The branch and original tips are archived under archive/ (see #1009), so nothing is lost; useful regression vectors are noted there for the active lanes. Closing.

Superseded by the private-staging redesign #788. The branch and original tips are archived under `archive/` (see #1009), so nothing is lost; useful regression vectors are noted there for the active lanes. Closing.
kayg closed this pull request 2026-11-07 21:21:20 +00:00
Some checks failed
CI / server (pull_request) Successful in 1m22s
CI / rust (pull_request) Failing after 8m1s
CI / web (pull_request) Has been cancelled

Pull request closed

Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
kayg/calternal!750
No description provided.