perf(notes): revalidate restart snapshots without rewriting unchanged indexes #828
Closed
kayg
wants to merge 0 commits from
perf/list-after-restart into dev
pull from: perf/list-after-restart
merge into: kayg:dev
kayg:main
kayg:feat/contrast
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: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!828
Loading…
Reference in a new issue
No description provided.
Delete branch "perf/list-after-restart"
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?
dev integration
77b94678: mergeable against55f35fcd; fmt, clippy -D warnings, notes and workspace tests pass. clean-page ≤1.2× budget remains unconfirmed (+23.2% pooled); backlinks improve. both five-pair sets and pooled values:integration plan for dev
55f35fcd: preserve generation publication and executor recovery before startup readers; retain compatible core/plugin rows with ctime/inode validation; keep independent startup scans and immediate retained backlinks. each scan batch publishes accepted source versions through MetaDb::apply and Published::commit, then wakes list waiters. reader pins hold no writer admission lock. schema 4 migrates to 5 by retaining compatible rows and forcing source backfill; existing schema 5 generations survive. batches remain 128 first / 4096 thereafter, O(notes + links) rebuild, O(page size) validation.failure → effect → detection → recovery → test: pending executor recovery → old retained rows unavailable → journal presence → await owned Home initialization → recovery regression; missing accepted sources → incomplete snippets/search → source-version backfill → normal generation commit → migration regression; concurrent publication → reader generation moves → snapshot validation → caller retries → existing generation tests; offline edit/delete → retained row invalid → ctime/inode stamp → startup reconcile → existing restart tests. gates: fmt, workspace clippy -D warnings, notes tests, workspace tests -j4; five paired clean first-page/backlinks runs vs dev.
Focused clean-path qualification passed: dev 7.016 → PR 5.958 ms median first HTTP, versus the 1.2× budget of 8.419 ms. First nonempty is 7.061 → 5.989 ms. Five alternating pairs per scenario, current dev
c823fb0fagainst this PR at 100k notes on dev-01:Rebuild first HTTP remains an explicit tradeoff: dev initially returns zero items, while this PR waits for filesystem-consistent rows. The raw trials record first HTTP, first nonempty and completion separately. Completion and first nonempty include polling resolution. Schema and missing-cache full rebuilds remain faster than dev.
Focused clean-path findings
The first page validates exactly its 50 returned rows, serially, after releasing the SQL reader lock. The extra cursor lookahead row is not validated. Five instrumented clean restarts measured median reader-lock wait 1 µs, blocking-worker queue wait 17 µs, SQL query 935 µs, validation 161 µs, total Notes page work 1,283 µs, and initial engine runtime acquisition 1,844 µs. None waited for a reconcile batch. Diagnostic first-HTTP medians were dev 4.383 ms, PR 4.750 ms; second-request medians were 1.717 / 1.628 ms.
A separate probe during one ordinary workspace compilation reproduced a 24.008 ms first response: engine runtime opening 9.581 ms, total engine work 11.824 ms, Notes page 2.034 ms, of which validation was 0.197 ms, reader-lock wait 3 µs and worker queue wait 36 µs. The runtime acquisition alone was 7.737 ms above the earlier median; another 12.184 ms was outside engine execution. This locates the delay in lazy runtime/store acquisition and surrounding HTTP/client work rather than extra page stats or a reconcile lock/batch wait. It does not retroactively establish the exact cause of the prior 7.327 → 14.125 ms median.
This pass adds debug timing for runtime acquisition, total read-action execution, reader-lock wait and blocking-worker queue delay. The existing timing covers SQL and validation. No parallel stat tasks, shutdown marker, validation bypass or background-priority mechanism was added: the measured validation work is under 0.4 ms, and the formal unchanged-path comparison already meets the target. Existing cached list lookup and the yield before identity-index loading remain. The earlier failing clean series and its initial series are retained in the r4 archive; this pass has exactly one formal five-pair series, plus explicitly separate tracing probes. This is a shared-host observation, not a hard latency guarantee.
Cause and fix
The original #764 invalidation trigger remains unproven because incident logs lacked the opening error and pre-reset versions. Earlier schema/open-error handling could discard durable rows; listing then immediately returned the empty derived store while rebuilding. Info-level diagnostics now report cache path, invalidation reason and relevant schema/plugin versions or SQLite error. Future-schema and transient-open failures preserve the cache.
Compatible schema/plugin snapshots are retained. Returned candidates must match a shared v2 file identity: size, mtime, ctime, device and inode. The original dev scan and polling path also used only size/mtime, so this closes that older timestamp-preserving edit gap for both paths. Legacy stamps fail closed and revalidate once. Validation is O(page size), scans O(notes), with no clean-path content hashing.
Startup enumerates the union of state/data Homes through four workers. Initialization belongs to Notes, continues independently of list-request cancellation, and is joined at shutdown. Every Home reconciles without requests. One 60-second deadline covers DB opening, initialization/recovery, candidate reads/validation and the first committed batch. Deleted-note open returns NotFound and drops the row.
An empty cache commits its first 128-note read chunk before expanding read concurrency, then keeps the original 4,096-row transactions. A schema refresh re-describes notes but updates only the unindexed stamp when preserved identity, core fields, expanded tags and links match. Changed files or plugins use the normal update path. This avoids the rejected 58.554 s revision's rewrites of unchanged indexed/plugin data. Historical strace evidence and earlier revisions are archived under r2/r3/r4; they are not mixed with this qualification.
Verification and method
All gates passed on dev-01 at
121ae772da0bc979d89085f883f3c7778ce116d7, through Nix and~/bin/slot:cargo fmt --all -- --checkcargo clippy --workspace --all-targets -j4 -- -D warningscargo test -p calternal-notes -j4: 468 passed, 6 ignoredcargo test --workspace -j4: 1268 passed, 20 ignoredcargo build --release -p calternal -p calternal-fixtures -j4The separate release HTTP probe also passed equal-size edits with restored mtime, deletions and additions on both normal and schema refresh. Every returned row was filesystem-consistent, deleted IDs were absent, and completion had exactly the expected three identities and titles. The two utimensat tests and first-batch probe failed before their earlier fixes and stay green.
Method: five alternating head-order pairs per scenario, same seed-1 100k files and each head's separate fully populated state backup. Dev uses schema 5, PR schema 4. Schema refresh sets user_version=3; missing-cache removes only meta.db/WAL/SHM. Wait only for health, POST notes.list limit 50, poll every 50 ms, terminate and wait for the exact child. OS caches warm, GLIBC_TUNABLES=glibc.malloc.arena_max=2 on both heads, same as the prior run. No owned build/test overlaps the formal trials. Tracing probes are separate; only the explicitly loaded probe overlaps an ordinary workspace compile.
The release binary was built at
6d1df5d7; final head121ae772only formats its reader-timing macro. Raw JSON, logs, scripts, binary SHA256s and source heads:/home/kayg/perf-reports/list-after-restart-20261101-r5/, with matching small reports on dev-01. Large generated Homes, binaries and both owned targets are removed after qualification. Earlier r4 evidence remains intact.Refs #764, review #issuecomment-73150 and the clean-path follow-up. No merge or deployment.
WIP: preserve note lists across restarts and rebuildsto fix(notes): preserve restart snapshots and serve the first rebuild pagefix(notes): preserve restart snapshots and serve the first rebuild pageto perf(notes): revalidate restart snapshots without rewriting unchanged indexesIndependent review, round 1
Reviewed
48b5f5530c69fcee8937c687788172efad5c403fagainstd0a2819a. Verdict: request changes.Findings
P1: retained schema snapshots can return stale titles and deleted notes before filesystem validation.
crates/notes/src/meta.rs:736–741preserves every compatible row and only prefixes its stamp.populatedis initialized from row existence, andNotes::pageat lines 1500–1529 therefore bypasses discovery waiting and returns these rows directly. Reproduction: build a populated cache, stop the server, edit one note's title and delete another file, then restart with an older compatible cache schema and requestnotes.listbefore the scan reconciles those files. The old title and deleted identity are still eligible for the first page.incomplete:truedoes not make these entries correct under this review's stated requirement. If onlynotes.listis called and no other path opens the Home, this path does not even start the scan, so stale rows can persist. A crash during refresh similarly leaves some unvalidated rows eligible after the next restart. Validate candidate rows against current files before exposing them, excluding missing identities and refreshing changed descriptions, and ensure retained-cache list requests initiate reconciliation. Add restart regressions covering offline title edits/deletions, including an interrupted refresh. The current preservation tests only assert that old rows remain available.P2: the first-page timeout does not bound the initialization it now waits for.
crates/notes/src/meta.rs:1506awaitsself.home(user)before starting the 60-second timeout at line 1513. Home initialization loads the identity index, opens history, and awaitsdeletion::recover(lib.rs:270–287); recovery iterates all pending deletion intents and performs file/history/Trash operations. Slow initialization or recovery can therefore hold an empty-cache first list request beyond the advertised wait, without returning its timeout error. Apply a deadline across Home acquisition and first-batch waiting, taking care that cancellation cannot leave partially initialized Home background work behind. Test delayed initialization/recovery as well as a delayed first commit.No P0 or P3 findings.
Other requested checks
transaction()is deferred, not absent. Startup schema/plugin changes still commit atomically;applyalso commits core, tag/link, plugin rows and count together. WAL readers see committed state, not a partially written batch. A concurrent writer can cause a deferred transaction's write upgrade to fail; the new error handling preserves the cache rather than deleting it. Separate count/item SELECTs are not one read transaction, so a concurrent commit can change their relative view; that behavior predates this PR.Validation: source/diff and regression-test inspection only; no builds/tests run and no code changed or pushed. The performance measurements and gates in the PR were not independently rerun. The original historical reset trigger remains unproven.
finding: reproduced both P1 failures on the reviewed head: the first page returned an offline note's old title and a deleted identity. Startup already called
open_all(), but it opened data directories serially and missed retained state when the whole data directory was removed. P2 also put initialization outside the first-batch timeout.fix:
de49a6f371f36f54fcfad8345d46eb16068732a8starts tracked Home initialization independently of request cancellation, joins it at shutdown, and opens Homes from both data and state directories with four startup workers. Every returned retained candidate carries its saved stamp in the same SQL row and must match the current file size/mtime. Changed/missing candidates wait for reconciliation; invalidated blank stamps wait for committed rows. Missing files cannot seed empty rooms, and a failed deleted-note open reconciles its list row. One 60-second deadline covers list-store open, initialization/recovery, candidate reads, and first-batch waiting.test: the original edit/deletion regressions failed before the fix; the removed-data-directory startup regression also failed before its fix. All eight new regressions now pass, covering offline edits/deletions, interrupted schema refresh, startup without list requests, retained state without a data directory, deleted-note open cleanup, delayed initialization, and a delayed first commit. On dev-01 through Nix/slot, fmt and clippy
-D warningspass; notes tests: 463 passed / 6 ignored; workspace: 1263 passed / 20 ignored. Release build passed. Re-measured on the same restored 100k fixture: first nonempty page 435.117 → 671.261 ms; full schema refresh 12.341 → 12.203 s; normal restart first request 10.112 → 6.704 ms (reviewed head → fixed head). Full rebuild remains below 24.189 s. First responses returned 50 items; these are single shared-host samples, with 50 ms completion polling. The historical #764 invalidation trigger remains unproven; info-level reason logs remain in place.final head:
de49a6f371f36f54fcfad8345d46eb16068732a8. The last commit records the formatter’s test-module ordering already present during the passing gates; measured release code is unchanged. Benchmark targets, binaries and seeded Homes have been removed; small reports/logs remain.Independent review, round 2
Reviewed
de49a6f371f36f54fcfad8345d46eb16068732a8. Independent runtime probes and uncommitted tests on dev-01; no commits or pushes. Performance comparator: current devc823fb0fdb8e2b18d953ff9346d18788cc2c2825.Status
Findings
P0: none.
P1: size/mtime equality still allows retained rows to contradict file contents. restart.rs:68 validates only file size, mtime and path. Independent reproduction: populate the cache, stop, replace
# Old titlewith equal-length# New title, restore the original mtime withFile::set_times, set compatible schema version 3, then reopen with initialization paused. The first page returns Old title, although the file contains New title. The uncommitted testindependent_r2_same_size_preserved_mtime_offline_editfails with exactly that mismatch.A separate release-binary HTTP probe used an ordinary warm restart, without the pause or schema change: the file contained Request free swap, while both the first page and a later page with
incomplete:falsecontained Request free edit. The before/after mtime was identical. The warm scan also compares size/mtime, so it does not repair this condition. Timestamp-preserving copy/restore workflows therefore remain outside the claimed freshness guarantee. Validate retained content with a reliable content identity, or re-describe candidates, and cover timestamp-preserving edits during schema refresh and normal restart. Under the stated “first page must never show a row the filesystem contradicts” requirement, round 1 P1 is only partially fixed.P2: first HTTP responses are slower than dev in matched rebuild scenarios. Five runs per head/scenario confirm a schema-refresh median of 381.775 → 582.097 ms (+52.5%), and missing-cache median of 659.850 → 1,304.207 ms (+97.6%). Dev initially returns an empty page in these scenarios; the PR waits and returns 50 entries. That wait improves first-nonempty latency, but it is still a first-response latency regression and should be an explicitly accepted tradeoff with both metrics retained in performance qualification.
Schema first-response samples, ms: dev
300.409, 429.062, 425.547, 381.775, 374.981; PR539.754, 582.097, 461.078, 604.908, 614.624.Missing-cache samples: dev
710.279, 659.850, 1132.556, 258.503, 181.713; PR1055.437, 1213.279, 2028.794, 1608.557, 1304.207.Clean restart also has a slightly higher observed median, 5.493 → 7.188 ms; its ranges overlap substantially (dev 4.311–16.120, PR 4.391–42.856 ms), so these five shared-host samples do not establish a stable clean-restart slowdown.
P3: none.
Clarified numbers
48b5f55348b5f553→ fixed PRde49a6f3The 765 ms and 435 ms figures are separate runs of the same forced-schema scenario on the same reviewed PR head. They are not different startup paths. The 435 → 671, 12.34 → 12.20 and 10.1 → 6.7 comparisons are PR revision comparisons, not dev comparisons. These historical results are single shared-host samples.
Independent results below are medians of five runs each, 100k seed-1 notes, dev-01, default limit 50:
Independent full-refresh medians: forced schema 26.979 → 10.820 s; missing cache 30.203 → 18.953 s. No full-rebuild regression observed. First-nonempty medians improve substantially in both rebuild scenarios.
Method: same generated note files; each head's fully populated state restored before every trial because current dev uses schema 5 and the PR uses schema 4. Forced refresh sets
user_version=3; missing-cache trials remove onlymeta.dband its WAL/SHM. Alternate head order, wait only for health, POSTnotes.list, poll every 50 ms, terminate and wait for the exact child. First HTTP is request duration; first nonempty and completion are measured after health and include polling resolution. OS caches warm; shared host. The earlier dev comparator predates current dev, so its single samples are not interchangeable with this table.Commands: release builds via
nix develop -c bash -c '~/bin/slot cargo build --release -p calternal -j4'(PR also buildscalternal-fixtures); targeted probes via~/bin/slot cargo test -p calternal-notes -j4 independent_r2 -- --nocaptureand... timeout_bounds_ -- --nocapture; runtime scripts through~/bin/slot python3. Three timeout checks passed; the content-validation test intentionally exposes the failure above. Small evidence, scripts, raw 30-trial JSON, binary hashes and the uncommitted test patch:dev-01:/home/claude/review-828-r2/. Source tests remain uncommitted in/home/claude/Developer/Worktrees/review-828-r2. Generated Homes, fixtures and build targets have been removed; all owned jobs have exited.Verdict: request changes. P2 from round 1 is fixed; P1 remains for timestamp-preserving edits. The first-response performance tradeoff is now independently measured.
finding: reproduced the same-size edit with the original mtime restored through utimensat. Both the schema-refresh first page and a completed request-free normal startup scan returned the old title. The existing dev scan and polling snapshots also used size/mtime only, so this revision closes that older gap for both paths.
fix: shared v2 file stamps include size, mtime, ctime, device and inode. Retained validation, list/search descriptions, saved-file stamps, persisted scan state and polling all use the same identity. Legacy stamps require revalidation. A first-batch probe also showed 485 descriptions before the first store; the empty-cache path now reads and commits one 128-note chunk before restoring normal read concurrency and 4096-row batches. A scheduler yield after list DB open lets waiting readers queue before identity-index loading; cached list DB lookup avoids rebuilding paths/plugin vectors.
test: both utimensat regressions failed before the fix and pass now. The first-batch read-ahead regression failed before its fix. The notes suite is green; final clippy/workspace gates, release build, first-page stage profiling and five-run alternating comparisons against dev
c823fb0fare in progress. Timings will retain both first HTTP and first nonempty metrics for clean, schema and missing-cache restarts. No merge or deployment.finding → same-size edits with mtime restored by utimensat remained stale in both retained lists and the completed dev-style scan; both used size/mtime only. Clean-stage profiling measured 207 µs median for 50 file checks, 10 µs list acquisition and 1,721 µs total page work; the review's 1.7 ms difference cannot be attributed solely to validation.
fix →
4f78ae61ad2ad1d597e6a4d80823524372670717uses shared size/mtime/ctime/device/inode stamps in retained validation, scan persistence/reconciliation, search/list descriptions and polling. Legacy stamps revalidate once. Cached list DB lookup avoids rebuilding setup vectors; initialization yields to waiting readers. Missing-cache startup commits its first 128-note chunk before normal read concurrency/4096-row batching.test → both utimensat regressions failed before the fix and now pass (schema first page and request-free normal reconciliation). The first-batch read-ahead regression also failed before its fix. All gates pass through Nix/slot: fmt; clippy --workspace --all-targets -j4 -- -D warnings; notes 468 passed/6 ignored; workspace 1268 passed/20 ignored; release build. Five-run matched medians versus dev
c823fb0f:Both clean series are retained, including the initial 25.769 → 10.752 ms series. Exactly one final clean series was scheduled in advance after rebuilds; its result is reported above. P2 remains unresolved: final clean HTTP median regressed 7.327 → 14.125 ms, so this PR is not speed-qualified. This busy shared host also did not reproduce the reviewer's absolute 5.493 ms baseline. Diagnostic requests spent much of the HTTP delay outside Notes::page (8.832/2.111 ms and 23.284/4.358 ms HTTP/page); runtime startup/scheduling remains unisolated. No speculative follow-up source change was made. First HTTP and first nonempty are deliberately separate. The PR top has the full method, limitations and artifact path. No merge or deployment.
finding → only the requested page's 50 rows are stat-validated; the cursor lookahead is not checked. Clean tracing medians: reader-lock wait 1 µs, worker queue 17 µs, SQL 935 µs, validation 161 µs, total page 1,283 µs, engine runtime acquisition 1,844 µs. No reconcile batch wait. A loaded 24.008 ms request spent 9.581 ms acquiring the runtime (7.737 ms above the clean median), 2.034 ms in Notes::page, and 12.184 ms outside engine execution. This isolates the observed slow request from per-row stats/reconcile waiting; the exact old median's cause cannot be proven retroactively.
change →
121ae772da0bc979d89085f883f3c7778ce116d7adds the missing debug timing boundaries. Validation and reconciliation remain unchanged; the data does not justify parallel stat overhead or a clean-marker bypass. Exactly one formal new five-pair clean series passes: 7.016 → 5.958 ms, below dev × 1.2 = 8.419 ms. Diagnostic series: dev 4.383 / PR 4.750 ms. All earlier series remain archived, including the failing 7.327 → 14.125 ms result.test → fmt, clippy --workspace --all-targets -j4 -- -D warnings, notes (468 passed/6 ignored), workspace (1268 passed/20 ignored), and release build pass in Nix/slot. Restored-mtime, deletion and startup regressions stay green. Separate release HTTP probes for offline equal-size/restored-mtime edits, deletions and additions pass on normal and schema restarts, including exact final rows/titles.
Five-run medians versus dev
c823fb0f:The PR top has the method and limits. No owned build/test overlaps formal measurements; the loaded tracing probe was separate. Reports:
/home/kayg/perf-reports/list-after-restart-20261101-r5/. No merge or deployment.Independent review, round 3 (final)
Reviewed
121ae772da0bc979d89085f883f3c7778ce116d7; independent release builds and runtime probes on dev-01. Comparator: devc823fb0fdb8e2b18d953ff9346d18788cc2c2825. Review only; no commits or pushes.utimensat; size and nanosecond mtime unchanged, ctime changed; normal and schema-refresh first pages showed the new titleincomplete:true; PR median 7.149 ms versus dev 6.431 ms, within the stated dev × 1.2 budgetnotes.backlinksexplicitly waits for scan readiness; separate HTTP sample took 1.569 → 1.922 sde49a6f3Findings
P0: none.
P1: none. The round-2 timestamp-preserving edit finding is fixed in the exercised Unix filesystem paths.
P2: the clean completion regression is not entirely detached from request latency. Clean
notes.listdoes not wait for the whole scan: all first pages returned while it was still incomplete. However, ops.rs:55 waits up to five seconds forbacklinks::ready, which callshome.settled()and therefore waits on the same scan completion reported byincomplete. My separate clean-restart probe returned the first list page in 4.644 / 7.551 ms, then immediately requested backlinks for a returned note: dev took 1,568.555 ms, PR 1,921.878 ms. PR tracing put 1,920.547 ms inside the backlinks action with only 5 µs acquiring the engine runtime. This is one diagnostic pair, not a five-run backlinks qualification. Unknown-note discovery and other readiness-dependent operations also have scan waits in source. These waits predate this revision; they are not a new concurrency defect, but they invalidate the requested “nothing waits on it” acceptance condition.Startup scanning already ran on dev (
Home::start,open_all, andscan::run); it was not newly enabled by this stamp fix. Both heads perform the full clean scan. The PR parses, compares and writes larger v2 identities: this fixture's saved scan state grows from 4,626,843 to 8,127,743 bytes. That is additional work, but this review does not isolate an exact causal breakdown of the 461 ms median difference.For the final-round design decision, keep the demonstrated per-page freshness validation and treat scan completion as request-visible work. Either qualify/accept the latency budget for scan-dependent requests explicitly, or separate their required readiness from trailing background work while preserving freshness. The current evidence supports only the narrower claim that clean list pages avoid waiting for completion.
P3: none.
Clean measurements
Exactly one formal five-pair clean series, alternating head order, seed-1 100k notes, limit 50, warm OS caches, each head's independently populated state restored before every trial. Same files/inodes throughout; dev schema 5, PR schema 4. Wait only for health; poll completion every 50 ms.
GLIBC_TUNABLES=glibc.malloc.arena_max=2on both; no owned compilation overlapped measurements. Separate tracing and backlinks probes are excluded from these medians. Shared-host variance remains substantial.First HTTP samples, ms: dev
6.431, 16.136, 6.741, 4.496, 5.507; PR7.149, 19.326, 7.068, 5.235, 8.347.Completion samples, ms: dev
1831.452, 4133.533, 1989.022, 1493.125, 4509.498; PR3889.372, 2450.425, 1861.076, 1814.099, 5446.168.Validation: exact-head
nix develop -c bash -c '~/bin/slot cargo build --release -p calternal -p calternal-fixtures -j4'passed on both heads. Runtime commands, through Nix and~/bin/slot:calternal-fixtures --notes 100000 --seed 1 --out ~/review-828-r3/fixtures;python3 ~/review-828-r3/bench.py seed;python3 ~/review-828-r3/correctness.py;python3 ~/review-828-r3/bench.py bench clean;python3 ~/review-828-r3/bench.py profile;python3 ~/review-828-r3/backlinks.py. No full test-suite rerun in this review. Scripts, raw JSON, logs, heads and binary SHA256s remain atdev-01:/home/claude/review-828-r3/. All owned jobs exited; generated Homes, binaries and both owned build targets were removed.Verdict: request changes under the stated performance acceptance condition, P2 only. The freshness blocker is resolved and clean list latency meets the stated budget, but completion remains visible to scan-dependent requests. This is the final review round; no further iterative review is proposed.
P2 backlinks follow-up at
f812e3e17445f3a81576dd5f554af036236e973a.Diff:
Notes::backlinksreads the current committed backlink rows without the scan-readiness timeout or unknown-note discovery wait. It reportsincompletewhile scan/import/search work remains. Readiness for mutating operations is unchanged.Regression: a real startup reconcile is held at the metadata writer while backlinks answer from retained rows; unknown IDs return NotFound promptly. It also covers import-in-progress, deleted-source cleanup after release, and graceful NotFound when opening that deleted source. The test failed on the old code with “backlinks waited for the scan”; the fix passes in 20 ms.
100k clean restart, five alternating pairs: backlinks median 2187.696 → 186.033 ms (
121ae772→ this head). Every response returned 8 backlinks; 5/5 fixed responses reported incomplete. After health, request the first list page, then backlinks for the same known target. Same seed-1 files/inodes and restored per-head state; warm OS caches; no owned build/test overlaps measurement. Raw JSON, scripts, heads, hashes and logs:/home/kayg/perf-reports/backlinks-after-restart-20261101-r6/.All gates passed on dev-01 through Nix/slot:
cargo fmt --all -- --checkcargo clippy --workspace --all-targets -j4 -- -D warningscargo test -p calternal-notes -j4: 469 passed, 6 ignoredcargo test --workspace -j4: 1269 passed, 20 ignoredBoth release builds passed. All owned jobs exited; generated Homes, binaries and targets are removed after archiving. Ready for your verification of #issuecomment-73385.
Orchestrator verification of the round-3 P2 fix @
f812e3e1: ready for BM6LINKS_WAIT) for the link map. They answer from the retained rows, withincomplete: truewhile the scan or an import runs. The 100k clean-restart backlinks median is 2,188 → 186 ms over five paired runs.notes.geton it fails gracefully.ensure_known(id)only identified an unindexed day file during a scan. Without it, a day note that isn't identified yet can have empty backlinks for a moment, withincomplete: true. That's acceptable, and it no longer blocks on file identification.-D warnings, notes 469 passed, workspace 1,269 passed.All three review rounds found no P0/P1 at the end. Ready for train BM6.
integration with dev
55f35fcde3bc91ca3781055577b93e93819f6cd4is pushed at77b94678c8f4493b1bb5b0ae31edb5f0ac6d678f; Forgejo reports mergeable. the four requested gates pass. the earlier clean-page ≤1.2× budget is not confirmed: pooled median is +23.2%; both five-pair sets are retained below. backlinks improve in both sets.conflict resolutions:
lib.rs: owned startup initialization now recovers executor writes before deletion recovery and starting scan/watch; either recovery failure shuts the partial Home down. the whole list deadline also covers waiting for executor recovery, so retained file stamps cannot bypass generation recovery.meta.rs: schema 5 andsource_versionsstay. compatible core/plugin snapshots survive migration and schema 4 sources backfill through five-field Source-bearing upserts. every startup reconcile batch usesPublished::commit; the population signal follows that commit. keep the consistent read transaction, short pin lock, executor availability guards, ctime/device/inode stamps, and first 128 / later 4096 batches. pending executor files retain their last accepted rows; recovered images gain a reusable stamp only after matching bytes and unchanged before/after file stamps.tests: added executor-recovery deadline, schema-4 accepted-source backfill, pinned reader during startup publication, and offline title edit after an executor write. inherited action-phase, writer-admission, restored-mtime, deletion, independent reconcile, and retained-backlinks tests pass. the first gate run exposed an accepted-row/validator conflict; that was fixed before the green runs.
passed on dev-01 through Nix and slots for heavy commands:
cargo fmt --all -- --checkcargo clippy --workspace --all-targets -j4 -- -D warningscargo test -p calternal-notes -j4: 536 passed, 6 ignoredcargo test --workspace -j4: 1,419 passed, 22 ignored100k notes, five alternating paired clean restarts vs current dev, then one unchanged-code replication. each first page returned 50 real rows, total 100000; backlinks returned 8 rows without waiting for scan completion. no owned builds/tests overlapped sampling.
three diagnostic pairs: validation checked exactly 50 rows in 141–229 µs; reader-lock waits 2–4 µs, blocking-worker queues 21–30 µs. the complete notes-page path took 1.260–2.663 ms; engine runtime opening took 2.429–5.570 ms. those measurements do not establish the cause of the clean HTTP delta, so no speculative latency change was added. clean-page performance still needs qualification; this is not a claim that the earlier budget passed.
raw samples, both sets, debug profiles, binary hashes, scripts, source heads and gate logs: control
/home/kayg/perf-reports/list-restart-integration-r7/, dev-01~/list-restart-integration-r7/. owned binaries, fixture Homes and build targets are being removed after archiving.Orchestrator decision after the rebase onto dev (BM5 executor) @
77b94678: ready for the next trainI'm accepting the extra ~2 ms on the clean first page. It's imperceptible, it buys correct lists after a restart (no stale rows, no empty pages) and backlinks that are 4.8× faster, and the earlier rounds measured noise of a similar size. Follow-up (separate): profile the clean path on top of the executor to win back those 2 ms.
bm7 bisect and source fix: pushed
fe46caf501.first bad browser merge is this PR's
1b4db39e. base55f35fcdand0b6accf1pass 11/11;1b4db39eand both later sampled merges fail the same four tests. narrowing the composer selector preserves stale daily-note state and reproduces all cataloged empty/glass/link-suggest failures too.root cause: file stamps gained ctime, but room/save.rs captured Prepared metadata before rename/exchange. placement changes ctime; meta/restart.rs then rejects accepted rows and fails entire notes.list pages. composer fails in snippetOf after task creation, not in the task action. saved and actual stamps were observed differing only in ctime.
the minimal fix uses existing byte-verified saved_meta handling to obtain the final file stamp. saved_file_stamps_validate_first_writes_and_replacements fails on the original source with that exact mismatch, and passes with this fix. it covers first writes, replacements, stamp equality and page contents. this may add a file read on save; no performance claim is made.
local merge of all eight fixed heads:
b05d4ccd10, unpushed. requested four-spec chromium-1440 + webkit-1440 matrix: repeat passed 22/22, workers=1, CI=1, retries=0. first run had 21 passes and one distinct composer daily-note creation timeout, retained as an open intermittent risk.cargo fmt --all -- --check passes. full cargo test --workspace -j4 with strace supplied failed in unchanged kill_nine_mid_append_on_a_long_note: 96 confirmed appends, final >100 assertion; durability assertions passed. it passed in the prior attempt. running the remainder with that test skipped failed later in #833 upcoming_uses_when_else_deadline_and_orders_days_before_months (Kept done vs Tomorrow); 1479 tests passed across executed result groups, but Cargo stopped there, so this is not a green workspace gate. both added regressions and the shipping capability inventory pass. logs retained under ~/bm7-bisect-report on the dev VMs and archived on control. no train branch changed.
BM8 full-suite evidence found a second cancellation issue: the owned Home initializer failed with
note list: database is locked.list_dbcurrently awaits spawn_blocking inside a request-owned OnceCell initializer. Request cancellation drops the initializer permit while the blocking SQLite open continues; another request/Home can start a second schema open.Plan: retain each list initialization waiter in Notes’ existing owned initialization task set, using the shared OnceCell and a oneshot observer. Cancelling a request drops only its observer. Shutdown closes admission under the same initialization mutex before draining those tasks. O(1) per pending waiter; one SQLite open per successful user cell. No retry or database-error masking.
Gate: regression red before fix and green after, restart_listing tests, full
cargo test --workspace -j4, final two-browser selectors. Product append path unchanged; final append diagnostic will be refreshed.BM8 validation at scratch
b9dac07806a398f53f8a9acaf1506d4b6f718a30:cargo fmt --all -- --checkandcargo test --workspace -j4passed on dev-01 in the standard Nix/slot shell, 1,483 passed and 22 ignored, with no skips or test-thread override. Four report selectors passed 22/22 on Chromium/WebKit, zero retries. Final production code passed 30 fresh Chromium composer invocations (90 tests, zero retries) during one ordinary slot build. Exact commands, head provenance, append samples, retained failures and attached raw evidence: #844 (comment). No merge or train change; owned jobs finished and VM targets/temp Homes cleaned.kayg referenced this pull request2026-11-03 02:09:05 +00:00
Closing: head
5d7b9b36is already in dev (reached viaa20cd5f1); nothing left to merge. Branch kept.Pull request closed