Require creator receipts for all storage cleanup (#642) #744
Closed
kayg
wants to merge 5 commits from
fix/storage-exact-file-quarantine-642-4 into dev
pull from: fix/storage-exact-file-quarantine-642-4
merge into: kayg:dev
kayg:main
kayg:feat/style-sheet-fixes
kayg:storage/wal-checkpoint-off-save-1051
kayg:feat/contrast
kayg:t3/paged-search-reconcile-final
kayg:feat/pass8
kayg:review/calendar-2
kayg:fix/shared-row-swipes
kayg:dev
kayg:feat/collections-db
kayg:fix/instant-keys-1056
kayg:feat/money-round
kayg:perf/stalls-1054
kayg:wip/tiering-v3-cold4
kayg:wip/tiering-v3-cold5
kayg:port/rows-actions
kayg:port/rows-drop
kayg:port/hidden-blocks
kayg:port/rows
kayg:port/port-tables
kayg:port/port-tables-2
kayg:t3/mail-1011-liveness
kayg:port/devices
kayg:port/port-attachments
kayg:port/port-attachments-2
kayg:port/port-attachments-3
kayg:docs/design-consistency
kayg:docs/engineering-standards
kayg:fix/rusqlite-0.41-rustsec-2026-0459
kayg:feat/iphone-fixes
kayg:shared/restore-and-stale-918-919
kayg:fix/phone-top-band-contrast
kayg:feat/notes-approve
kayg:perf/soak-max-gate
kayg:feat/files-s1-identity
kayg:fix/lifecycle-event-id
kayg:feat/quickfix
kayg:wip/tiering-v3-cold
kayg:perf/web-mockup-frame-fixes
kayg:port/contacts-merge
kayg:port/contacts-edit
kayg:test/shared-room-no-deleted-text
kayg:perf/first-paint-credits
kayg:fix/shared-history-after-grant
kayg:fix/phone-swipe-regressions
kayg:feat/contrast-r1
kayg:review/sharing-pr3-review
kayg:feat/tiering-v3-s2-tags
kayg:feat/folder-drop
kayg:fix/deskpills-lazy-share
kayg:feat/sharing-s1-pr3
kayg:tmp/money-round-before
kayg:fix/phone-pane-backdrop-roots
kayg:fix/palette-preload-chips
kayg:fix/invite-defaults
kayg:port/tasks-matrix
kayg:fix/restore-green-gates
kayg:fix/sharing-fast-path-hardening
kayg:t3/photos-s1
kayg:feat/tiering-v3-s1-namespace
kayg:notes-archive-hide
kayg:feat/tasks-actions
kayg:t3/photos-plan-slice-one
kayg:feat/whiteboard-s1
kayg:t3/paged-search-reconcile
kayg:t3/smooth-pane-transitions
kayg:t3/index-position-startup-scan
kayg:fix/private-staging-759b-r2
kayg:feat/dav-transport
kayg:feat/imap-notes-fetch
kayg:feat/imap-notes-projection
kayg:feat/imap-notes-readonly
kayg:feat/imap-notes-auth
kayg:feat/imap-notes-server-foundation
kayg:docs/undo-block-ids-plan
kayg:fix/undo-768
kayg:proto/block-identity-v7d
kayg:issue/carddav-read-perf-fix-r2
kayg:issue/carddav-read-r2
kayg:docs/imap-766-plan-v2
kayg:docs/imap-notes-plan
kayg:docs/quota-plan-2
kayg:fix/parallel-test-flakes
kayg:feat/contacts-companion-pure
kayg:docs/calendar-backend-v2-plan
kayg:feat/calendar-ical-converter
kayg:docs/tasks-writes-v2-plan
kayg:docs/carddav-writes-v2-plan
kayg:docs/contacts-import-v2-plan
kayg:issue/610-pm-midnight
kayg:feat/calendar-v2-s1-containment
kayg:docs/dav-recorder-v2-plan
kayg:plan/previews-865
kayg:plan/save-log-durable-entry
kayg:fix/e2e-data-on-ram
kayg:feat/appwindow3
kayg:feat/appwindow2
kayg:feat/appwindow
kayg:feat/money-p1
kayg:feat/keys-sheet
kayg:review/calendar-2-themes
kayg:feat/smooth-cursor
kayg:fix/float-style
kayg:review/calendar-2-float
kayg:release/2026-11-06-hotfix
kayg:archive/port/rows-drop-code
kayg:archive/port/rows-actions
kayg:archive/port/rows
kayg:scratch/tasks-894-ui-gates
kayg:review/calendar-2-night-wip
kayg:release/2026-11-05
kayg:archive/feat/tiering-v3-s1-namespace
kayg:archive/flaky/rows-drop-fixed
kayg:archive/flaky/rows-actions
kayg:archive/feat/tiering-v3-reader
kayg:archive/feat/tiering-v3-roots
kayg:archive/flaky/rows
kayg:sim/bm15-final
kayg:sim/bm15-fix
kayg:sim/bm15-bis-932
kayg:sim/bm15-bis-909
kayg:sim/bm15
kayg:sim/bm15-bis-887
kayg:perf/tiering-option-b
kayg:port/style-3
kayg:port/style-2
kayg:port/style
kayg:fix/sw-lazy-precache
kayg:fix/vim-w-waits-for-save
kayg:fix/signout-test-races
kayg:fp-scratch/all
kayg:sim/bm15-first-paint
kayg:archive/bm15/rows-drop
kayg:archive/bm15/rows-actions
kayg:fix/palette-snippet-contrast
kayg:archive/bm15/rows
kayg:archive/bm15/hidden
kayg:archive/plan/save-log-durable-entry
kayg:mock/money-fix2
kayg:archive/fix/e2e-data-on-ram
kayg:mock/appearance-all
kayg:mock/pill-press
kayg:archive/docs/design-consistency
kayg:mock/auto-swipes
kayg:mock/mail-actions
kayg:archive/feat/mail-p1
kayg:mock/money-static
kayg:archive/review/standards-917
kayg:archive/docs/engineering-standards
kayg:perf/tiering-761-fix
kayg:mock/type-audit
kayg:mock/third-pane
kayg:feat/contacts-import-v2-s1
kayg:perf/executor-hot-path
kayg:archive/port/hidden-blocks
kayg:archive/port/devices
kayg:scratch/executor-on-894
kayg:scratch/executor-spans2
kayg:scratch/executor-spans
kayg:train/2026-11-03-bm14c
kayg:archive/port/rows-drop
kayg:feat/tiering-761-d-scale
kayg:feat/tiering-761-c-index
kayg:feat/tiering-761-b-reader
kayg:archive/review/sharing-pr3-review-9fec3d1f
kayg:train/2026-11-03-bm14b
kayg:perf/ports-lazy-budgets
kayg:feat/tiering-761-a-migration
kayg:train/2026-11-03-bm14
kayg:train/2026-11-03-bm12
kayg:archive/review/sharing-pr3-review
kayg:archive/feat/sharing-s1-pr3
kayg:train/2026-11-03-bm11
kayg:archive/feat/imap-notes-fetch
kayg:train/2026-11-03-bm10
kayg:archive/review/sharing-pr3-review-code
kayg:archive/plan/previews-865
kayg:train/2026-11-02-bm9
kayg:archive/port/port-attachments-3
kayg:archive/port/contacts-merge
kayg:fix/motion-audit-859
kayg:train/2026-11-02-bm8
kayg:archive/scratch/bm8-prep
kayg:archive/port/port-pickers
kayg:archive/port/port-tables-2
kayg:archive/port/port-tables
kayg:archive/feat/sharing-s1-pr3-code
kayg:archive/scratch/bm7-fixed
kayg:train/2026-11-02-bm7
kayg:archive/fix/parallel-test-flakes-code-minipc01
kayg:train/2026-11-02-bm6
kayg:docs/imap-766-readonly-slice
kayg:feat/dav-recorder-v3
kayg:research/788-diagnosis
kayg:archive/fix/parallel-test-flakes
kayg:archive/perf/pr792-cold-index-edit
kayg:docs/sharing-slice-1
kayg:archive/docs/imap-766-plan-v2
kayg:feat/dav-recorder-v2
kayg:archive/docs/dav-recorder-v2-plan
kayg:spike/imap-766-s0-cases
kayg:archive/fix/undo-768
kayg:feat/dav-recorder
kayg:archive/docs/contacts-import-v2-plan
kayg:archive/feat/calendar-ical-converter
kayg:feat/contacts-import
kayg:perf/cold-growth-on-764
kayg:perf/cold-growth-on-tiering
kayg:archive/docs/tasks-writes-v2-plan
kayg:archive/docs/calendar-backend-v2-plan
kayg:archive/feat/contacts-companion-pure
kayg:feat/tasks-set-status
kayg:feat/tasks-move-reorder
kayg:archive/docs/carddav-writes-v2-plan
kayg:archive/feat/calendar-v2-s1-containment
kayg:feat/tasks-delete-promote-duplicate
kayg:archive/feat/dav-transport
kayg:archive/fix/carddav-rebuild-r1
kayg:archive/fix/carddav-retention-r1
kayg:feat/carddav-writes
kayg:perf/quota-on-tiering
kayg:perf/quota-simple
kayg:perf/cold-growth-on-quota-stack
kayg:feat/calendar-identity
kayg:feat/calendar-event-parser
kayg:feat/calendar-props-maps
kayg:port/glass-when-ring
kayg:feat/tiering-761-s1
kayg:wip/10by32-01-impl-759b-scratch-20261030
kayg:wip/6by32-01-bm3-webkit-pause-20261030
kayg:wip/10by32-01-bm3-chromium-pause-20261030
kayg:wip/6by32-01-tier-761-s1-pause-20261030
kayg:spike/imap-766-s0
kayg:wip/6by32-02-calternal-pause-20261030
kayg:wip/8by64-01-review-688-pause-20261030
kayg:wip/6by32-01-verify-744-pause-20261030
kayg:wip/6by32-01-verify-742-pause-20261030
kayg:fix/private-staging-759b
kayg:wip/6by32-01-review-748-pause-20261030
kayg:wip/6by32-01-review-733c-pause-20261030
kayg:wip/6by32-01-review-733b-pause-20261030
kayg:wip/6by32-01-perf-idle-8-pause-20261030
kayg:wip/6by32-01-perf767-base-pause-20261030
kayg:wip/6by32-01-perf767b-767-pause-20261030
kayg:wip/6by32-01-perf767b-764-pause-20261030
kayg:wip/6by32-01-perf767-767-pause-20261030
kayg:wip/6by32-01-perf767-764-pause-20261030
kayg:wip/6by32-01-lists-b-pause-20261030
kayg:wip/6by32-01-ids-verify5-pause-20261030
kayg:wip/6by32-01-ids-verify4-pause-20261030
kayg:review/calendar-month
kayg:wip/10by32-02-undo-768-20261030
kayg:test/ids-verify3
kayg:wip/10by32-02-bm3-chromium-20261030
kayg:wip/10by32-01-review-753-20261030
kayg:wip/10by32-01-perf-idle-2-20261030
kayg:wip/10by32-01-bm2-webkit2-20261030
kayg:plan/759b-staging
kayg:train/2026-10-30-bm2
kayg:review/758b-tests
kayg:review/758-tests
kayg:review/764d-tests
kayg:review/767b-tests
kayg:review/preview-2026-10-29
kayg:review/767-tests
kayg:docs/tiering-731-plan
kayg:wip/c6b02-when2
kayg:wip/c6b02-tasks-create-fix5
kayg:wip/c6b02-settings-frost-mock
kayg:wip/c6b02-settings-frost-base
kayg:wip/c6b02-settings-frost
kayg:wip/c6b02-ring
kayg:wip/c6b02-review-733d
kayg:wip/c6b02-bm1-full-a
kayg:wip/compute02-when-field
kayg:wip/compute02-webkit-lists-repro
kayg:wip/compute02-train-bl2-dev
kayg:wip/compute02-dev-green-pw164
kayg:docs/deploy-plan
kayg:review/764c-tests
kayg:review/764b-tests
kayg:review/748g-tests
kayg:review/764-tests
kayg:review/759b-tests
kayg:fix/storage-owner-liveness-642
kayg:fix/storage-fix-7
kayg:wip/compute02-storage-fix-7
kayg:review/759-tests
kayg:feat/tiering-731
kayg:wip/tiering-731-first-attempt
kayg:wip/compute02-storage-fix-1
kayg:review/754g-tests
kayg:perf/idle-honest-2
kayg:review/754f-tests
kayg:review/754e-tests
kayg:review/755-tests
kayg:review/754d-tests
kayg:review/754c-tests
kayg:review/754b-tests
kayg:review/754-tests
kayg:fix/storage-private-tmp-642-dev
kayg:wip/compute02-verify-750
kayg:test/ids-verify5
kayg:test/ids-verify4
kayg:fix/storage-exact-file-quarantine-642
kayg:wip/compute02-verify-740
kayg:perf/one-flush-save
kayg:review/calendar-static
kayg:wip/compute02-verify-737
kayg:review/indexing-ring
kayg:review/when-field-2
kayg:wip/compute02-review-733
kayg:proto/block-identity-2-review
kayg:proto/block-identity-review
kayg:wip/c6b02-tc-design
kayg:review/when-field
kayg:issue/tasks-create-ids
kayg:issue/tasks-create
kayg:review/combined
kayg:wip/compute02-review-combined
kayg:review/task-polish
kayg:review/top-buttons
kayg:review/q1-q5
kayg:train/2026-10-26-bl2
kayg:archive/wt-398h
kayg:archive/train-bm-proptest-seed
kayg:archive/integ325-293
kayg:archive/integ325-ci
kayg:archive/client-auth-review-baseline
kayg:archive/wt-sim-4853
kayg:archive/wt-sim-4811
kayg:archive/wt-448m
kayg:archive/wt-398a-allocator
kayg:issue/calendar-adr
kayg:archive/old/train/2026-10-23bk2
kayg:archive/old/train/2026-10-23bk
kayg:issue/469-mockup-9a
kayg:issue/smart-tasks-mockup
kayg:issue/469-menus
kayg:issue/652-signout-flake
kayg:issue/652-history-fix7
kayg:issue/652-history-fix6
kayg:archive/old/issue/spring-check-perf
kayg:issue/spring-check-perf
kayg:issue/659-rename-fast
kayg:archive/old/train/2026-10-21ar
kayg:issue/search-hardening-3
kayg:issue/652-history-fix5
kayg:issue/660-port-sheets-glass
kayg:issue/652-history-fix4
kayg:issue/652-history-fix3
kayg:issue/652-history-fix2
kayg:issue/652-history-flake
kayg:train/2026-10-21an
kayg:issue/settings-admin-port
kayg:issue/search-port
kayg:train/2026-10-20am
kayg:issue/storage-split-fix2
kayg:issue/storage-split
kayg:archive/old/issue/folder-ids-fix
kayg:train/2026-10-20al
kayg:archive/old/issue/folder-ids
kayg:train/2026-10-20ak
kayg:issue/tables-mockup
kayg:train/2026-10-19aj
kayg:train/2026-10-19ai
kayg:issue/469-merge-fixes
kayg:issue/sidebar-band
kayg:archive/old/issue/608-settings-spec
kayg:train/2026-10-19ah
kayg:issue/swipe-offscreen
kayg:train/2026-10-19ag
kayg:archive/old/issue/590-nlp-adr
kayg:archive/old/issue/587-event-after-write-2
kayg:train/2026-10-19af
kayg:archive/old/issue/587-event-after-write
kayg:issue/469-pill-room-c
kayg:issue/469-pill-room
kayg:train/2026-10-19ae
kayg:issue/469-narrow-handle
kayg:issue/397-ios-swipe-2
kayg:archive/old/issue/adrs-photos-files-tasks
kayg:issue/469-desk-fixes
kayg:archive/old/issue/auto-update-adr
kayg:issue/469-filter-gap
kayg:issue/469-port-1b
kayg:issue/442-opacity-flake
kayg:archive/397-ios-swipe-2
kayg:issue/327-web-fast-3
kayg:archive/old/issue/469-port-1
kayg:issue/469-port-1
kayg:issue/327-web-fast-2
kayg:archive/old/issue/327-web-fast
kayg:archive/old/issue/425-stt-bench-vq1
kayg:archive/old/issue/445-no-bleed
kayg:archive/old/issue/400-swipe-mockup-2
kayg:issue/426-client-review
kayg:issue/426-client-2
kayg:issue/426-client
kayg:archive/old/issue/476-safe-area-lab
kayg:archive/445-top-light-2
kayg:archive/old/issue/445-top-light
kayg:issue/471-blocks-mockup
kayg:archive/old/issue/448-links-app-2
kayg:archive/old/issue/448-links-app
kayg:archive/old/issue/398-cold-links
kayg:issue/434-442-small-2
kayg:issue/434-442-small
kayg:archive/old/issue/398-unload
kayg:archive/old/issue/445-bottom-band
kayg:issue/445-bottom-band
kayg:issue/351-rem-3
kayg:archive/312-views-mockup
kayg:issue/351-rem-2
kayg:issue/351-rem
kayg:archive/old/issue/327-first-note
kayg:issue/395-width-phone
kayg:archive/old/issue/327-typing
kayg:issue/396-ios-edges
kayg:issue/397-ios-swipe
kayg:archive/398-allocator
kayg:archive/old/issue/327-notes-index
kayg:issue/345-347-contrast-empty-2
kayg:archive/old/issue/44-arenas
kayg:issue/44-arenas
kayg:archive/integ325
kayg:archive/old/issue/327-perf-harness
kayg:archive/old/issue/44-thp
kayg:issue/44-thp
kayg:archive/old/issue/285-sticky-pills
kayg:archive/old/issue/44-trim-3
kayg:issue/44-trim-3
kayg:archive/old/issue/165-cards
kayg:archive/old/issue/165-picker-2
kayg:archive/old/issue/212-multi-select
No reviewers
Labels
Milestone
Clear milestone
No items
No milestone
Projects
Clear projects
No items
No project
Assignees
Clear assignees
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!744
Loading…
Reference in a new issue
No description provided.
Delete branch "fix/storage-exact-file-quarantine-642-4"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
A cleanup path could check one object and later unlink a replacement written by another program. All storage removal and overwriting replacement now go through fsio::quarantine. The module atomically claims the entry, requires the creator's device/inode/size/BLAKE3/name receipt, flushes that existing proof, and verifies content while holding a read lease before unlinking. A pathname, pending marker, equal length or journal match cannot create new ownership proof.
Unknown or changed bytes return as visible numbered conflict copies. Startup drains abandoned transactions, including those without a pending marker, and respects active directory locks. Streaming writers maintain hashes from their input; cleanup verifies large files through a fixed 64 KiB buffer. Interrupted prefixes without exact proof are retained, and the upload regression verifies their bytes rather than demanding unsafe deletion.
The workspace lint bans direct removals, recursive removal, overwriting rename entry points and raw unlink wrappers outside this module. Test fixtures and synthetic benchmarks have explicit exceptions for their own scratch trees.
Refs #642. This PR supersedes #742. A new branch is necessary because this forge ignores updates to open PR branches.
Call sites now using the shared removal and replacement boundary:
Creation proofs are written by RecordedFile, including the upload Receiver's bounded chunks, and by the anonymous bulk and lock-file creation paths. Device, inode, size, BLAKE3 and the public-name binding travel with the inode in a durable xattr. Exclusive app moves can change the binding; an external move cannot transfer deletion authority. A held read lease covers the final verification and unlink. The verifier flushes an existing creator receipt before using it, including cancellation before the writer reached its final flush. Unknown bytes return to exclusively numbered visible conflict names. Locked live private directories are skipped by startup recovery.
The generic preservation property covers 14 entry points at BeforeCheck, BeforeMove, AfterMove and AfterCheck, with independent Python writers, generated binary payloads, inode replacement and completed in-place rewrites. In-place aliases are tested both before acquisition and as lease breakers at the final check; the alias is removed after the writer finishes so it cannot conceal a missing survivor. Every path also uses an explicit equal-length payload. The same 14-entry table also runs abrupt child-process kills at all four pauses. Tests separately cover an app-created replacement carrying another valid receipt, unknown import-cache bytes, live prepared-image exclusion, all three #742 repros and the ordinary startup binary with and without markers.
The retained private namespaces stay on the source filesystem inside each Home. Unsupported receipt or lease operations fail conservatively. These Linux tests cover process death and ordinary outside writers, not hostile changes to private application metadata or block-device power cuts. The designated performance VM cannot be resolved through either its direct or NetBird hostname, so there is no before/after latency claim.
Validation used build-slot.sh and cargo -j3, with one sequential final gate script. The full workspace suite, 14-path generated writer property, 14-path process-stop property, three reviewer repros, ordinary startup repros, nested recovery race, bounded upload memory and settled 1,000-stop loop pass. Workspace performance-budget tests remain intentionally ignored; the designated perf VM cannot be resolved. There is no latency-improvement claim. Receipt writing requires inode xattrs; unsupported receipt/lease operations retain bytes or fail safely. Destructive verification and upload publication were validated on Linux.
Head:
c19aef3072Gate output, verbatim:
Stop-loop result, verbatim:
No evidence, logs, run data or screenshots are committed. No merge or deployment was performed.
Verdict: fix first. Independent review of PR #744 at
c19aef3072, into dev, on local branch verify/744-independent. No product edits remain, and no commits, pushes, merges, deployments or issue closures were performed.P1: a writer can break the read lease after the final check, and cleanup then loses its completed bytes. quarantine.rs:215-218 and :247-250 check unbroken(), then call unlink_verified; the unlink itself is at :184-188. staging_lease.rs:53-61 implements the check as F_GETLEASE. A lease-break request can arrive after that query. Holding the lease while unlinking does not make this query and deletion atomic.
Reproduction: create a recorded file and a hard-link alias; pause immediately before unlinkat, after the last unbroken() returned true. A separate Python process tries O_WRONLY|O_NONBLOCK on the alias and must receive EWOULDBLOCK, then waits in blocking open. Resume cleanup. Cleanup unlinks the application-held name and closes the lease. The writer is admitted, writes, fsyncs, closes and removes its alias. No copy of those completed outside bytes remains for recovery. The same writer at the earlier AfterCheck pause is correctly preserved. This follows the PR's own alias-removal survivor check, but exercises the later scheduling window its four pauses miss. The outside writer never accesses private metadata in these alias cases.
Confirmed through all fifteen cleanup paths: remove_file; Folder::remove; attachment remove_staging; upload Drop; rejected persist; note recover_staging; guarded cancellation/discard; atomic replacement; guarded save displacement; replace_many; startup drain; Prepared::Drop; rejected bulk creation; import-image Drop; import-image restart cleanup. The last four tests observe the actual generated private file before creating the ordinary alias. Final independent suite: 6 passed, 2 failed, both failures for this same P1 flaw. The first test lists eleven public-file paths; the second reports:
actual private-image cleanup lost outside bytes: [(PreparedDrop, BeforeUnlink, false), (BulkReject, BeforeUnlink, false), (ImportDrop, BeforeUnlink, false), (ImportRestart, BeforeUnlink, false)]
The complete test-only reproduction patch and command are in this issue comment. Adding another final query alone would leave the same scheduling window.
P2: private transactions under the separate state root are never drained on startup. The fresh 1,000-stop client passed its Notes/Trash check and preserved all acknowledged text. A broader scan found 487 old hidden staging entries under state: 286 directories and 201 distinct files. They include scan-state.tsv images written through fsio at notes/scan.rs:443. attachments/sweep.rs:31-32 drains only the data Home; note staging recovery enumerates Home Notes/Trash. Neither covers state/users//notes.
Start the ordinary uninstrumented server on the completed stop-loop root, list notes and issue save barriers. Verbatim:
before startup: 487 hidden staging entries; 286 private directories; 201 files inside them
after ordinary startup and save barriers: 487 of 487 old hidden entries remain
old private files still retained: 201 of 201
AssertionError: ordinary startup did not drain state-root storage transactions
The restart assertion exits 1. This is an accumulating hidden-state cleanup defect and fails the broader no-leftovers requirement; it is not another acknowledged-note-text-loss claim. Counts depend on scheduling. Full evidence.
P2: the removal lint is bypassed in a production module. contacts-actions/src/cards.rs:18 retains a file-wide allow(clippy::disallowed_methods). A temporary direct std::fs::remove_file function there passes Clippy with warnings denied. Removing only that original allowance makes the same probe fail with the intended disallowed-method diagnostic. Restoring the original file passes. Command: cargo clippy -p calternal-contacts-actions -j3 --lib --features tokio/rt-multi-thread,tokio/fs -- -D warnings. The corresponding probe in fsio/src/lib.rs is correctly rejected. The audit found the actual production removals routed through quarantine; this finding is the missing enforcement of that boundary. Probe evidence.
Other checks passed: both runs of the original 60 fsio tests; public replacements and child deaths at four cleanup boundaries across fifteen entry points; same-file private-image replacement/rewrite at the original four boundaries; all three previous equal-length upload rewrite failures; external replacement claimed before SIGKILL and returned after restart; sixteen conflict-name collisions across repeated recovery; exchange and rollback boundaries including a second outside replacement; ordinary startup recovery with and without markers; three interrupted-rename placement/index/title tests; note staging and acknowledged split-save recovery. Exclusive normal/case-only rename, missing-destination linking, upload/directory publication and empty-directory disposal were also traced in the code and exercised by the baseline tests.
The ordinary server excludes private content from note lists, settled search, journal catch-up, notes.get and live WebSocket room joins. Both ordinary markdown and hidden staging basenames were checked. Conflict copies are filesystem-visible recovery files, not indexed notes.
The fresh stop loop completed 250 saves, 250 renames, 250 Trash operations and 250 restores. All 1,000 acknowledged Unicode markers survived exactly once after every restart; same-key retries finished; auxiliary path/title/body checks passed; final canonical bytes equaled notes.get; no staging remained in Home Notes/Trash after save barriers. Its narrower pass does not clear finding 2. No exact syscall interruption is inferred from this after-send loop; test-only pauses provide that coverage.
All local heavy commands ran sequentially through build-slot.sh, with cargo -j3. No preload, syscall interposition or fixed sleep was used in the review clients/tests. Linux process-death coverage does not establish block-device power-cut or non-Linux lease behavior. The earlier remote reviewer hosts were inaccessible; their findings and clients were read from the local sibling review worktree and Forgejo comments.
Gate output, verbatim:
The independent preservation exits of 101 and state-root-startup exit 1 are real failures. lint-outside-rejected and lint-cards-control-final exit 101 are expected lint rejection controls; lint-cards-bypass-final exit 0 demonstrates the gap. Earlier contacts probe attempts encountered an isolated Tokio feature error, then a probe formatting error; earlier private-image fixture attempts counted an untouched setup file or incorrectly required success when cleanup conservatively returned DirectoryNotEmpty. Those attempts are retained in the transcript, not counted as additional product defects or safety passes. The corrected final tests produce the results described above.
Tracked files are restored byte for byte; the final reproduction patch applies cleanly. Local evidence and instructions: /home/agent/wt/verify-744/findings.md and .verification/REPRODUCE.md. Head remains
c19aef3072.Closing: superseded by #749, then #750 (named in the PR body or comments). Branch kept.
Pull request closed