storage: portable pinned readers and resilient Notes scans (#761 B) #791
Closed
kayg
wants to merge 12 commits from
feat/tiering-761-b-reader into feat/tiering-761-a-migration
pull from: feat/tiering-761-b-reader
merge into: kayg:feat/tiering-761-a-migration
kayg:main
kayg:feat/style-sheet-fixes
kayg:storage/wal-checkpoint-off-save-1051
kayg:t3/paged-search-reconcile-final
kayg:feat/pass8
kayg:review/calendar-2
kayg:fix/shared-row-swipes
kayg:feat/contrast
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: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!791
Loading…
Reference in a new issue
No description provided.
Delete branch "feat/tiering-761-b-reader"
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?
Plan — pinned readers and resilient note discovery (#761), B of A → B → C → D
Stacked on A, ultimately into
dev. Separate runtime reader behavior from the offline migration in #784. Keep the existing identity index here; C changes its representation.Cost: O(depth) descriptor operations per read (one openat2 on Linux); O(entries × depth) descriptor operations for metadata discovery and polling in background, including absolute-root validation; content reads add O(bytes). Raw names do not gain normalization copies. Inventory access remains an explicit privileged method; product paths reject hidden names.
Failure → effect → detection → recovery → test
reader::tests::missing_root_is_never_created_and_protected_names_are_never_servedreader::tests::nofollow_raw_identity_aliases_and_sparse_lengthsreader::tests::pinned_descriptor_survives_replacement_and_rechecks_auth_and_rootsone_unreadable_or_odd_entry_never_stops_the_scanvanished_note_does_not_drop_other_discovered_headsmigrated_decomposed_name_keeps_its_id_and_remains_readableValidation
PASS at
58ffcc7182a8c7c1ff64ecc366d0e52ebe2eddf8on dev-01: fmt, clippy with-D warnings, and the full workspace suite; 1187 passed, 0 failed, 20 ignored, job exit 0. All heavy commands ran in Nix through~/bin/slot. Evidence:~/tier-r2-final-b.logand~/tier-r2-final-b.exit.Round-2 findings
r2_metadata_refresh_never_reads_through_an_ancestor_symlinkreproduces Sub/Deep/a.md, swaps Sub for a foreign-tree symlink, rejects refresh and preserves title/snippet/link index.r2_a_root_ancestor_symlink_cannot_repin_authoritycovers an alias pointing back to the same moved root. Both failed on original B, pass after.r2_replaced_root_scan_stays_incomplete_and_keeps_indexes_and_stateswaps Notes after Home construction, requires incomplete status, identical saved state/list and no foreign index entry. Original B failed, fixed B passes.Earlier broader Mac suites were not green: Linux
/proc/self/taskassumptions, delayed WAL/SHM cleanup, and the case-only collision expectation remain separately recorded portability failures. No final-head Mac pass is claimed.Decisions and remaining risks
Stack: A #790 → B #791 → C #792 → D #793. Independent review of this replacement stack remains pending.
Final-head macOS checks were not run: the shared lock is held by
dav-recorder PR 789. Earlier targeted Mac results apply only to older heads. This change rejects symlinked ancestors, including aliases to the same physical root; configure physical paths. Real media errors, power cuts, 100k-note polling costs and latency qualification remain unrun.Stack: A #790 → B #791 → C #792 → D #793. Ready for final round-3 review after these fixes; nothing merged.
Independent review, round 2
Reviewed B at
977d26c851a44e92549b37dd8f0c4a729017d620, stacked on Ac5eaf6af. Verdict: fix first, both for R2-B1 below and the inherited A blockers in my round-2 comment on #790. No code pushed.one_unreadable_or_odd_entry_never_stops_the_scanchecks healthy notes, completion, link/raw-name diagnostics; permission assertions are conditional when permissions are not enforced.vanished_note_does_not_drop_other_discovered_headsproves one vanished head does not discard the other. Root replacement is not covered end-to-end: R2-B2.New findings
R2-B1, P1: note-list metadata reads can still escape through an ancestor symlink.
crates/fsio/src/reader.rs:198-204, called bycrates/notes/src/search.rs:110-112andmeta.rs:879-880/:1064-1076. The adapter openspath.parent()as a fresh root.O_NOFOLLOWprotects only that parent's final component; earlier ancestors are resolved normally. The path is joined from the index, not already resolved beneath the retained Home reader.Scenario: index
Notes/Sub/Deep/a.md, then replaceSubwith a symlink to another readable Home tree. The retained reader correctly refusesSub/Deep/a.md; metadata refresh instead pinsNotes/Sub/Deepafter followingSuband reads the other file. Its title/text-derived metadata can enter this Home's list/link index. Root replacement likewise gets silently repinned here. This gap existed in the older path-based reader, but B's claimed no-symlink read boundary still does not cover this production path.Independent dev-01 reproduction linked a small scratch Rust program against B's built fsio rlib: retained
Root::readfailed, whilereader::readof the same indexed path returnedother home secret. Output:PINNED_READ_DENIED; METADATA_ADAPTER_READ_OTHER_HOME=other home secret. Fix: pass the retained Home/NotesArc<Root>and full relative path through metadata description/refresh, and take metadata from the opened descriptor. Do not re-root at a path-derived parent. Add a production metadata-refresh/list regression with an intermediate symlink and assert no foreign title/snippet/links are indexed.R2-B2, P2: a scan can report complete after the pinned Notes root was replaced.
crates/notes/src/scan.rs:192-204,:265-279,:433-447;watch.rs:577-578and:281-284.stat_all/walk_reportingopen and validate a fresh Root, rather thanhome.reader. If Notes was replaced before the walk, that validation succeeds on the replacement. Head reads skip failures from the retained reader; reconciliation silently returns when its validation fails, butscan::runproceeds to metadata refresh/save-state and returns Ok, clearing incomplete status. Metadata refresh can also read replacement data via R2-B1. Source-verified, not reproduced through a whole-server scan. Fix: validate the retained reader before and after enumeration and before committing scan results, and propagate replacement as a retryable scan error. Add a test replacing Notes between Home construction and scan and assert incomplete, unchanged index/list/state, and no successful completion.Test/evidence assessment
The inherited round-trip script does diff hashes and metadata, including directory mtimes and installation-marker equality before new writes. After new writes it compares rollback against the current roots. It does not cover B's intermediate-symlink metadata path, pinned-root replacement during a full scan, or actual crashes/disk-full/power-cut ordering. Atime is a separate Rust regression, not an E2E manifest field. A's comment records its limits and the new migration findings.
No workspace suite was rerun independently. Existing Linux gate/strict-E2E logs were inspected on dev-01; the latter ends ALL PASS. Scratch reproduction used Nix and
~/bin/slot rustc --edition=2024 /tmp/tier761-r2-reader.rs --extern calternal_fsio=<B rlib> -L dependency=target/debug/deps -o /tmp/tier761-r2-reader, then executed the result on a fresh temporary fixture. It changed no repository files. On the Mac,~/tier761-b-exact-mac.logand.exitare still absent; I did not disturb the shared benchmark lock or claim that pending run passed. The wider unrelated Mac failures remain accurately disclosed in the PR.Round-2 implementation plan (last fix before final round 3): remove the path-parent reader adapter. Metadata/search receive the retained Home reader and full relative path, and use metadata from the same descriptor. All root path components are walked with openat/O_NOFOLLOW. Validate the retained Notes reader before/after enumeration and before scan mutations, metadata commits and state save; root replacement is a retryable incomplete scan. Existing per-file failures continue to skip only that entry.
Cost: O(path components) safe initial root pin/validation, bounded per-file descriptor access, existing O(entries) scan.
Rebase inherited A fixes, then C/D. Exact-head fmt, clippy -D warnings and workspace tests for each PR. No merge.
Round-2 fixes ready for final round-3 review at
58ffcc7182a8c7c1ff64ecc366d0e52ebe2eddf8. Nothing merged.r2_metadata_refresh_never_reads_through_an_ancestor_symlinkreproduces Sub/Deep/a.md, swaps Sub for a foreign-tree symlink, rejects refresh and preserves title/snippet/link index.r2_a_root_ancestor_symlink_cannot_repin_authoritycovers an alias pointing back to the same moved root. Both failed on original B, pass after.r2_replaced_root_scan_stays_incomplete_and_keeps_indexes_and_stateswaps Notes after Home construction, requires incomplete status, identical saved state/list and no foreign index entry. Original B failed, fixed B passes.PASS at
58ffcc7182a8c7c1ff64ecc366d0e52ebe2eddf8on dev-01: fmt, clippy with-D warnings, and the full workspace suite; 1187 passed, 0 failed, 20 ignored, job exit 0. All heavy commands ran in Nix through~/bin/slot. Evidence:~/tier-r2-final-b.logand~/tier-r2-final-b.exit. Commands inside Nix through~/bin/slot:5441212fd8b445fb80ff8ed640a4b33c17ae1d0758ffcc7182a8c7c1ff64ecc366d0e52ebe2eddf89c8c287357240912daf895c4166bf00f2212ce4a659b0f4e420f6272e801ea78eba8fe10d66c1ca5A's final end-to-end gate on dev-02 also passed (
ALL PASS): 211 entries, 161 regular files, three users and three contact originals; 36 notes before the new write and 37 after. It verifies split, immediate unsplit, unchanged old-root refusal, new split-layout writes, unsplit against the current roots and old-binary startup.Old binary:
d83e54db. Evidence: dev-02~/tier-r2-final-a.log,~/tier-r2-final-a.exit= 0; fixture~/tier-r2-final-roundtrip.Before/after evidence on dev-02:
~/tier-r2-a-red.log(four expected failures),~/tier-r2-b-red.log(two expected failures),~/tier-r2-reader-ancestor-red.log(one expected failure),~/tier-r2-fsync-probe.logand~/tier-r2-xattr-rss.log(probe wrappers exit 0). External fsync/RSS probes usede688361c, whose runtime implementation is identical to final A; the later A change fixes only the layout test's live-SHM comparison race. The final workspace gates reran after that fix and the C/D needless-borrow fix.Limits: this qualifies injected syscall failures, not real-media EIO/ENOSPC, SIGKILL or power-cut ordering. Persistent filesystem errors can prevent retraction; errors report this explicitly and retain ownership evidence for operator recovery. All outside writers must remain stopped. Final-head macOS validation was not run: shared
/tmp/mac-bench.lockremains held bydav-recorder PR 789; no other job was disturbed. Descriptor-per-note scan/poll cost and 100k-note performance remain unqualified. No production operation or merge.C/D rows updated after C round-2 fixes. Final isolated C performance remains pending; see #792 status.
Independent review, round 3 (final)
Reviewed B at
58ffcc7182a8c7c1ff64ecc366d0e52ebe2eddf8, round-2 comment 71055 and the final fix table. Verdict: ready in the stated reader/discovery scope.r2_metadata_refresh_never_reads_through_an_ancestor_symlinkindexesSub/Deep/a.md, swaps Sub for a foreign-tree link, requires refresh failure and unchanged title/snippet with no foreign link.r2_a_root_ancestor_symlink_cannot_repin_authoritycovers an ancestor alias back to the same moved root.r2_replaced_root_scan_stays_incomplete_and_keeps_indexes_and_staterequires an error, incomplete status, unchanged saved state/list and no foreign identity. It does not simulate every concurrent replacement boundary.r2_regressions passed in the independent downstream run.New findings, P0–P3: none. The per-entry skip policy remains distinct from a root-authority failure. I found no remaining production path-parent re-rooting adapter in the changed metadata/search flow.
Independent verification on dev-01 at downstream D
659b0f4e, inside Nix through~/bin/slot:22 passed, zero failed, including the three B regressions above. Evidence:
~/tier-r3-independent.{log,exit}, exit 0. I inspected B's exact-head gate log and exit 0 and the recorded failing-before metadata/root regressions. The full workspace suite was not independently rerun. No code pushed or production access.Open gates/limits: final-head macOS validation remains unrun; earlier wider Mac failures are not a final-head pass. Privileged mount races and 100k-note descriptor-based scan/poll cost remain unqualified. Root/ancestor changes still require the documented offline coordination and physical paths.
B on dev
41f2efa3: build fix, resolutionsNew head
efcaaaf74147f144acffcb7f64834695a102420f(waseeb9db4f). Force-pushed with a lease on the old head;eeb9db4fis its parent, so no pushed work was dropped.Why the new commit.
eeb9db4fdid not compile on its own (cargo clippyon dev-01: 8 errors incalternal-notes).meta.rshad lost itsPathBufimport. The room executor still called the removed path-basedload::read(self.path()). The earlier agent fixed both in C's896babb4, which left B broken.efcaaaf7moves those two hunks into B, so every PR in the stack builds by itself. C's tree is unchanged by the move.Resolutions (dev's side kept)
generation::Snapshotand readsgeneration.source(item).peek.rsis byte-identical to dev. B only changes working-file reads, the ones dev did withstd::fs, so they go through the Home's pinned reader. It never replaces an accepted-generation read.room/executor.rs): the check is dev's; only the read changes. It compares the on-disk bytes with the expected pre-image throughload::read_root(home.reader, rel), the pinned root, instead of a fresh path open. The executor is still the only writer; nothing bypasses it.meta/restart.rsis untouched. Scans persist dev's fullFileStamp.executor_path_available,executor_available) and the per-identity lifecycle guard are unchanged.Gates at
efcaaaf7(dev-01, Nix, slot): fmt pass; clippy-D warningspass;cargo test --workspace1,504 passed, 0 failed, 22 ignored. Full stack table, perf and dry run: see the gate comment below and #790.Gate table — stack on dev
41f2efa3(takeover after the Codex usage limit)Heads: #790 A
91c034eb→ #791 Befcaaaf7→ #792 C487e0589→ #793 Dd422d0ca. Base: dev41f2efa387b74175971a838f602535089d0d5fb4(what prod runs). Nothing merged.~/bin/slot)91c034ebefcaaaf7487e0589d422d0cacargo fmt --all --checkcargo clippy -j4 --workspace --all-targets --locked -- -D warningscargo test -j4 --workspace --locked -- --test-threads=2¹ Run by the earlier agent at
89989e62;git diff 89989e62 d422d0cais empty (same tree).² Run at
896babb4;487e0589differs only by the order of two#[cfg(test)] modlines (cargo fmt).Perf VMs (binaries built on dev-01 in release at the D tree, relayed through the control host, SHA-256 checked on both perf VMs: C
2006ab8e…, dev724535bd…, harness980045d9…):41f2efa3notes.append, 30 alternating pairs, perf-02, median totalProtocol unchanged from the
fab01191run:~/bin/perf-lock ~/bin/slot run-perf.sh, per samplecalternal-perf --sizes 100k --runs 1 --cold-runs {1,1,1,0} --seed 1 --idle-secs 60 --budgets {"open.note@100000":{"p95":15},"idle.rss@100000":{"p95":100}}, C then dev, same VM, no page-cache drop; all 8 reports have no scenario failures. No limit was changed.Notes:
fab01191run (deva55521f912.6 s → dev41f2efa320.9 s on the same harness and VM), so only the ratio is comparable. The absolute memory numbers are from a different source (harnesscold.mem_peakon perf-01 vs one dev-01 sample earlier); the ratio to dev improved.~/Developer/perf-results/pr792-41f2efa3/. Perf VM binaries and work dirs deleted.Perf pass on the stack (branch
perf/tiering-761-fix, head3a65e27c): nothing in this PR's files changed. A/B tables, causes and the still-open cold-index/first-page gap are on #792 (comment above) and #793. The stack stays not mergeable under the no-regressions rule until the gap on #792 is closed or kayg decides.kayg referenced this pull request2026-11-05 23:21:11 +00:00
housekeeping #1009: needs-decision.
Old pinned-reader implementation belongs to the superseded two-root tiering stack. Retain reader identity/authority tests for the active v3 reader lane.
original head:
efcaaaf74147f144acffcb7f64834695a102420f. against devcd7f84432febfc63b788fbb9b9f9950452982d74, git cherry reports 18 unmatched and 0 equivalent patches. the landing audit lists each candidate missing commit and stable patch match inpr-791.md; unmatched patches can include superseded behavior.left open, source branch unchanged. no rebase or new test claim for this decision lane.
Superseded by tiering v3 (#968/#970/#1008). 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.Pull request closed