notes: integrate shared executor with Home save publication #814
Closed
kayg
wants to merge 0 commits from
feat/note-write-executor-home into dev
pull from: feat/note-write-executor-home
merge into: kayg:dev
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: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!814
Loading…
Reference in a new issue
No description provided.
Delete branch "feat/note-write-executor-home"
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?
round 2 design, implemented
readers pin immutable accepted source versions with an Arc token; writers publish a new SQLite generation without waiting for readers. retain at most four pinned old generations plus current, reclaim unpinned intermediate versions, and revoke the oldest reader before reclamation when the cap is exceeded. stale search batches discard staging and retry. placement releases the Home metadata lock; participant edits/Flush refuse promptly, and executor metadata waits use 25 ms checks.
N source bytes, K changed notes, R <= 4 old generations: O(1) snapshot pins, O((R+1)N) derived source disk, O(K R log N) normal version work; pin-set changes can examine O(R N) retired rows.
final implementation, all gates and measured latency: round 2 status. head
99cfe9416becedf2831b9354314419a8eff8062a. final independent review pending; never merge.The byte executor had no safe admission or publication path for a live Home. This change adds Home coordination for exact replacements of existing notes: actor leases, authored private history, atomic derived rows and a permanent journal publication receipt. No task/calendar action is enabled.
Stacked on #809 at
f30b760a; prerequisite audit #812. Target dev. Never merge.Shared note-write executor, slice 0b
Stack: #809 at
f30b760a. Prerequisite audit: #812. Target: dev. No action is enabled. Never merge.Plan:
Scope: existing-note replacements with stable ids and exact room byte round trips. Create/delete/rename and domain-specific private stores remain refused. The shared strict metadata writer remains a separate prerequisite for Tasks B1.
Costs: K participants, N retained image/state bytes, J retained WAL bytes. Room acquisition O(K log K), payload/lease matching O(K²), history/index installation O(K + N), existing conservative placement O(KN + J). Memory O(N + J). Startup additionally replays H retained history bytes for the distinct identities named by the WAL, O(H + J + N), in bounded identity chunks before exposing the Home. Existing 1,024 path / 64 MiB image / 1 GiB journal caps remain; private CRDT payloads must be bounded too. No Home walk during admission.
No power-loss, Apple or performance pass is claimed without those gates. BLAKE3 equality assumes distinct content does not share a 256-bit digest; integrity checks do not authenticate the WAL. Placement evidence is required separately.
Implemented boundaries:
Delivery limits: no task/calendar action or enable switch; stable existing-note replacements only. Namespace creation/removal/rename, metadata validation, ranks, claims, occurrences and Home undo remain refused pending their adapters. Home WAL payload compaction is withheld, so retained records can cause bounded backpressure. No Apple, power-loss or performance pass is claimed. Uncooperative outside tools can observe partial raw filesystem placement, as in #809.
Validation on dev-01 in
~/Developer/Worktrees/note-write-executor-home, throughnix develop -c bash -c, implementation ata479a812:All passed. Notes: 480 passed, 0 failed, 6 existing ignored; doc tests passed.
All calternal unit/integration suites passed with their existing ignored tests.
Store: 9 passed, 0 failed; doc tests passed. Focused executor run: 37 passed,
including nine Home tests and 24 real process-kill Home phases with repeated
recovery, live publication retry, cursor I/O errors, caller cancellation,
concurrent ordinary save, unsupported admission and cache rebuild after a later
ordinary save. Existing notes tests were not edited.
Final gate log:
~/note-home-final.log. Expected failing runs are retained in~/note-home-red.log,~/note-home-live-red.log,~/note-home-cursor-red.logand
~/note-home-index-red.log. No build or test ran on the control host.The final documentation commit changes comments and this report only.
Independent review is pending. Never merged.
Initial delivery head:
0f38d06f441c5f0c02752dce8d71fffe57ab5a12. Superseded by the round 1 implementation and gate results below.round 1 implementation status
head:
966a97bb14d1ebee3e4c40342399477c1c2508d0. both P1 findings addressed; ready for independent re-review. never merged; repository settings unchanged.cargo fmt --all -- --check~/bin/slot cargo clippy --locked -j4 --workspace --all-targets -- -D warningsall gates ran on dev-01 in
~/Developer/Worktrees/note-write-executor-home, using the existing Nix shell and VM slots:final log:
~/note-home-r1-final2.log,GATES_PASSED, service result success. expected failing regressions are in~/note-home-r1-red.log; focused Home coverage passed in~/note-home-r1-focused2.log. no builds/tests ran on the control host. commits were pushed after each step; the control worktree is clean.decisions and remaining limits: search remains an asynchronous journal follower, but each refresh exposes a complete accepted generation. source reads wait for a generation lease or refuse pending recovery; no working-file fallback follows a transaction refusal. the retained participant graph is rebuilt from the WAL and expands overlapping actions. search staging uses O(D) temporary disk with bounded fetch memory, and group tracking uses O(G) retained memberships. a full search reconciliation can delay a note action while holding its shared lease; startup lists with retained executor records can wait for recovery. existing executor scope, WAL limits and outside-tool filesystem visibility limits remain. no performance, Apple or power-loss pass is claimed. implementation details and failure/cost notes are in
docs/implementation/note-write-executor-home.md.round 1 of max 3; independent re-review pending. never merge.
WIP: notes executor Home integration, slice 0bto notes: integrate shared executor with Home save publicationIndependent review, round 1
Head reviewed:
0f38d06f441c5f0c02752dce8d71fffe57ab5a12, delta from #809 atf30b760a. Read both plans’ shared-executor sections and the existing room/save/publication paths.Verdict: fix first.
P1: list/plugin rows become readable before journal publication
crates/notes/src/write_executor/home.rs:367–390; reader:crates/notes/src/meta.rs:1387–1406.executor_metacommits the new rows beforerecord_onceruns.Notes::pagereads those rows without the generation lock or pending-publication checks, including its list-only startup path. Pause atPhase::IndexInstalled, or let the recorder fail before committing: the list returns both NEW rows while the journal still has no transaction events and room reads refuse. After a crash at this boundary, the persisted list can also be served before Home recovery completes. Atomic installation of all index rows prevents a split within that database, but does not provide the requested consistent index/journal publication boundary.Fix: keep a separately accepted generation, or gate every affected derived reader through publication/recovery, including list-only startup reads. Preserve the old accepted rows or refuse while publication is pending; a live generation lock alone does not cover a returned publication error or unopened Home. Add tests that query list/plugin rows at IndexInstalled, with a recorder failure before commit, and immediately after restart before Home recovery.
P1: internal file readers bypass executor isolation
crates/notes/src/search.rs:58–72;crates/notes/src/backlinks.rs:177–187; integration boundary:crates/notes/src/write_executor/home.rs:242.The new guards cover rooms and peek, but search’s provider still reads the mutable note files directly. Pause a two-note action at
Placed(0): an initial/reconciliation search build can read the first post-image and second pre-image, then publish that mixed state to its own index without an executor journal event. This is a cooperating internal reader, distinct from the documented limitation for outside tools. The backlink fallback has the same issue after a conflicted action:live_textturns the room’s refusal intoNone, thentext_ofreads the partially placed file anyway.Fix: route internal text consumers through an accepted-generation reader. Pin reads against placement and check persistent pending/conflict state; never treat a transaction refusal as permission to fall back to disk. Search batch publication must also avoid combining documents from opposite sides of a generation switch. Add a search-build test paused after the first placement and a backlink-snippet test after a multi-note conflict.
No P0 findings. No additional P2/P3 findings.
Validation: on dev-01, in
~/Developer/Worktrees/note-write-executor-home, throughnix develop -c bash -c:9 passed, 0 failed. These existing tests cover save serialization, crash recovery, idempotent publication retry and live room updates, but do not exercise the reader scenarios above. Findings are from code-path inspection; no new regression tests were added. Existing notes tests are unchanged. No code pushed and no control-host builds/tests run.
round 1 implementation plan: keep list/plugin rows at the accepted generation until the journal receipt commits, then install the whole derived batch atomically. shared generation leases cover search fetch-through-publication and backlink rows-through-snippets; pending/conflicted actions refuse file-derived reads after a returned error. list-only startup keeps the last accepted rows. recovery repeats publication idempotently.
cost: K action participants; unchanged executor caps. search stages documents in bounded batches on its writer connection and publishes a complete refresh in one SQLite transaction, avoiding a full-Home document buffer.
VM gates: fmt; workspace clippy with -D warnings; notes, calternal, store and search tests. never merge. no repository settings changes.
round 1 implementation status
head:
966a97bb14d1ebee3e4c40342399477c1c2508d0. both P1 findings addressed; ready for independent re-review. never merged; repository settings unchanged.cargo fmt --all -- --check~/bin/slot cargo clippy --locked -j4 --workspace --all-targets -- -D warningsall gates ran on dev-01 in
~/Developer/Worktrees/note-write-executor-home, using the existing Nix shell and VM slots:final log:
~/note-home-r1-final2.log,GATES_PASSED, service result success. expected failing regressions are in~/note-home-r1-red.log; focused Home coverage passed in~/note-home-r1-focused2.log. no builds/tests ran on the control host. commits were pushed after each step; the control worktree is clean.decisions and remaining limits: search remains an asynchronous journal follower, but each refresh exposes a complete accepted generation. source reads wait for a generation lease or refuse pending recovery; no working-file fallback follows a transaction refusal. the retained participant graph is rebuilt from the WAL and expands overlapping actions. search staging uses O(D) temporary disk with bounded fetch memory, and group tracking uses O(G) retained memberships. a full search reconciliation can delay a note action while holding its shared lease; startup lists with retained executor records can wait for recovery. existing executor scope, WAL limits and outside-tool filesystem visibility limits remain. no performance, Apple or power-loss pass is claimed. implementation details and failure/cost notes are in
docs/implementation/note-write-executor-home.md.round 1 of max 3; independent re-review pending. never merge.
Independent review, round 2
head reviewed:
966a97bb14d1ebee3e4c40342399477c1c2508d0, stacked on #809 (f30b760a); round 1 delta from0f38d06f. verdict: fix first.derived_readers_wait_through_every_action_stepchecks complete old/new list rows and requires both transaction events before NEW rows, at 24 boundaries includingIndexInstalled.failed_receipt_preserves_list_before_and_after_restartchecks pre-receipt refusal and persisted old rows. The process-crash test now calls publicpagebefore explicitly opening Home and checks publication. Plugin rows share the same accepted SQLite commit, although the new test does not separately assert a plugin-specific filter.derived_readers_refuse_conflicted_working_fileschecks refusal live and after restart.pinned_search_generation_serializes_an_entire_build_and_expands_actionschecks a retained before-state reader and action-group expansion. The three search indexer tests exercise batch-size-one publication, polling readers, removals, failure and cancellation. The actual Notes snapshot and search publication are tested separately rather than in one end-to-end case.new P1: an unbounded search lease can indefinitely stall executor admission and subsequent Home readers
Locations:
crates/notes/src/search.rs:74–85, 108–123, 136–143;crates/search/src/indexer.rs:211–248, 264–271;crates/notes/src/write_executor/home.rs:154–157.A reconciliation pins the Home-wide generation read guard before listing and retains it through every fetch, staging operation and final index publication. Batch yields do not release it. Neither the lease nor the executor's
write().awaithas a time bound or shutdown-select. The source already describes full builds at 100,000 notes as taking minutes; this review did not measure that duration. Actual writer delay is the remaining entire rebuild/publication time, with no enforced upper bound. A retained snapshot or stuck file read can keep it waiting indefinitely.Tokio's write-preferring RwLock also queues subsequent generation readers behind that waiting writer. Thus one stalled rebuild plus one queued action can stall peek, backlinks and new provider snapshots for unrelated notes in that Home. Aborting the action caller does not remove the waiter: the coordinator is Home-owned. A pending coordinator is also joined by Home shutdown without a bound.
The new pinned-generation test demonstrates the dependency: the action remains pending for 40 ms and completes only after
drop(before). It does not demonstrate bounded writer progress. This conflicts with ADR 0014's short-lock/background-work requirement. Please provide bounded pre-PREPARE admission/refusal and a generation-reading design that preserves complete generations without holding a Home-wide exclusion lease throughout an arbitrarily long rebuild. Merely timing out an async wrapper aroundspawn_blockingdoes not reclaim a guard held by the still-running closure. Add a deliberately stalled-reader test that verifies bounded action response, subsequent reader progress, and shutdown behavior.save latency, crash lifetime and lock ordering
executor_generation; the coordinator waits for the generation lock before jobs, lifecycle, actor leases andmeta_update. A rebuild or an action queued behind it therefore adds no direct lock wait to ordinary saves. No performance budget pass is established by these functional tests.meta_updateduring publication. This behavior predates the round 1 fixes.ordinary_save_serializes_behind_action_and_caller_cancellationexplicitly verifies waiting, not a fast-save upper bound. The fixes do not add a rebuild wait while those actor leases are held.No new P0 or separate P2/P3 findings.
Validation independently run on dev-01 at the reviewed SHA, in
~/Developer/Worktrees/note-write-executor-home, throughnix develop -c bash -c:13 Home tests and 3 search indexer tests passed, 0 failed. No new test/code edits, no code pushed, no control-host builds/tests, no merge. The new P1 is supported by the lock/lifetime paths and the existing pinned-reader test; no stalled-filesystem experiment or latency measurement was performed.
round 2 plan: remove Home reader exclusion. commit accepted note text, path and a content stamp alongside the list/plugin/link rows. readers pin a cheap immutable generation token and query versioned accepted rows, never working files. each writer creates a new generation without waiting for readers. keep at most four old generations; expired snapshots return a retryable stale-snapshot error. unpinned versions are reclaimed on the next write. no long SQLite read transaction or reader-owned lock enters admission.
sizes/cost: N accepted source bytes on derived disk, K changed notes, R <= 4 retained old generations. O(K log N) version updates plus indexed reclamation; source bodies are read per document, not copied per snapshot. snapshots carry O(1) token state, with bounded query batches. existing executor image/WAL caps remain.
validation: failing stuck-reader regression first; then fmt, workspace clippy -D warnings and notes/calternal/store/search tests on dev-01. measure ordinary save p95 on a perf VM against current dev using the same fixture. never merge; no repository settings changes.
round 2 implementation status
head:
99cfe9416becedf2831b9354314419a8eff8062a. ready for final independent review. never merged; repository settings unchanged.cargo fmt --all -- --check~/bin/slot cargo clippy --locked -j4 --workspace --all-targets -- -D warningsall gates ran at this head on dev-01, in
~/Developer/Worktrees/note-write-executor-home, through the Nix shell and VM slots:final log:
~/note-home-r2-verified2.log,GATES_PASSED. the original regression failed with “writer waited for an idle reader” in~/note-home-r2-red2.logbefore the fix. no build or test ran on the control host. commits were pushed after each step; the control worktree is clean.latency comparison
three paired runs on
calternal-perf-02-backup01, under the existing~/bin/perf-lockshared lock. binaries were built on dev-01 using the default optimized release profile and identical Nix tools, relayed through the control host, with SHA-256 checked at every destination. data lived on disk at/home/claude/note-home-r2-perf-tmp.same fixture: 1,000 notes of about 4 KiB, four runtime workers, 200 one-character appends with an explicit save each, automatic flush/watch/rename disabled. a new empty search index is fully rebuilt repeatedly throughout each run. head concurrently repeats 16-note executor actions. current dev baseline is
a55521f94ef7337f0793037ae2cb2c27266d5720; it has no executor API, so the baseline fixture replaces only the executor helper with a no-op. it still runs the same save and full-rebuild workload.head completed 22 executor actions and 120 full rebuilds across 600 successful saves, with zero save retries; baseline completed 131 full rebuilds. edit + save median run p95 increased by 38.331 ms / 25.21%. every appended character was verified exactly once. variability is visible in the per-run table: these measurements do not establish an absolute storage completion deadline. the 25 ms mechanism bounds waiting for executor metadata publication, not disk I/O.
reproduction:
perf log:
~/note-home-r2-perf3.logon perf-02,PERF_FINISHED. binary SHA-256:a3774e9412f1e44b7203a8d4d64a18fa78799bb668f4da86aa805d6bfb3ee48424cc8199bc182c97c52ee5ae96651fd9acf88c9655c0e0e847117cd6429014b0costs and limits: snapshots are O(1) pins with per-operation SQLite connections. retained source disk is O((R+1)N), R <= 4. normal updates/reclamation are O(K R log N); a changed retained-pin set may scan O(R N) retired rows. Arc drops permit lazy SQL reclamation on the next write; restart removes all obsolete versions. no reader-owned transaction spans a rebuild. oldest-reader revocation and concurrent backlink generation changes require retry. existing executor scope/WAL/image limits remain. implementation design is documented in
docs/implementation/note-write-executor-home.md. no Apple or power-loss pass is claimed.Independent review, round 3 (final)
reviewed head
99cfe9416becedf2831b9354314419a8eff8062aintodev, stacked on #809. no code pushed.prior findings
new findings
crates/notes/src/meta.rs:946clonesSearchDoc, including its cleaned body;Source::newimmediately clears that body (crates/notes/src/generation.rs:20-22). it then copies borrowed text and serializes the full source into a temporary buffer for BLAKE3 (:24-32);generation::storeserializes the same text again (:135-137). have source construction consume the document and owned text, hash canonical fields without a full JSON buffer, and persist one source encoding. this is avoidable hot-path work and is the p1 basis for the verdict. the exact share of the measured 10.7 ms needs an A/B after the fix.focused checks on dev-01
all passed in the Nix shell via
~/bin/slot:cargo test --locked -j4 -p calternal-notes retained_generations_are_capped_and_dropped_pins_are_reclaimedcargo test --locked -j4 -p calternal-notes home_process_crashes_recover_history_index_and_one_journal_batch(covers 24 process-kill phases)cargo test --locked -j4 -p calternal-notes stuck_search_snapshot_never_blocks_writer_readers_or_shutdowncargo test --locked -j4 -p calternal-search --test note_generation stalled_rebuild_uses_old_sources_while_writer_and_new_readers_finishverdict: fix first.
Round-3 P1 fixed (orchestrator) @
2e08de74describedmoves theSearchDocintoSource(only title, kind, tags, stamp cloned for the list entry); the stamp hash streamsserde_json::to_writerintoblake3::Hasher, with no buffer. Stamps are byte-for-byte unchanged (same serializer output), so no stored rows change. One more encoding stays ingeneration::store; it can't be dropped without moving the stamp out of the stored JSON, which is a format change that isn't worth it here.Gates on dev-01 (Nix shell,
~/bin/slot):cargo fmt --all -- --check,cargo clippy --locked -j4 -p calternal-notes -p calternal-search --all-targets -- -D warnings,cargo test --locked -j4 -p calternal-notes -p calternal -p calternal-store -p calternal-search→ 584 passed, 0 failed, 12 ignored.Save p95 attribution (journal FULL sync vs. snapshot cost) will be measured in the BM5 train perf run. Ready for BM5 (stack #809 → #814 → #813 → #812).
ADR 0003 evidence migration:
docs/implementation/note-write-executor-home.mdSource commit: 7e2032a0b88abc1cd4c377c4feb88f9f9582a2e9; snapshot from dev
55f35fcd. Full original source preserved below before repository removal/stripping. Design, code and test inputs are retained where applicable.Closing: head
2e08de74is already in dev (reached via7e2032a0); nothing left to merge. Branch kept.Pull request closed