docs: revise IMAP Notes plan after slice 0 (#766) #775
Open
kayg
wants to merge 8 commits from
docs/imap-766-plan-v2 into docs/imap-notes-plan
pull from: docs/imap-766-plan-v2
merge into: kayg:docs/imap-notes-plan
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-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!775
Loading…
Reference in a new issue
No description provided.
Delete branch "docs/imap-766-plan-v2"
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?
Revises the Apple Notes over IMAP plan (#766) after the 1 November native evidence and independent review 72369. Documentation only; no implementation code.
Base branch
This PR targets
spike/imap-766-s0because the plan and slice 0 evidence exist there. Merging it will not put the plan ondev.Plan changes
Notesmailbox name per account and fixed UIDVALIDITY for the mailbox life. Allocate strictly increasing UIDs only from the server-owned counter; routine state changes preserve the name, UIDVALIDITY and counter.(UIDVALIDITY, next_uid)authority and restore freshness witness outside every restorable VM/Home/content set. On every content restore, usemax(restored_next_uid, authority_next_uid) + 4096; missing, stale or inconsistent authority disables writes until an admin recovers a trustworthy floor.(mailbox_id, UIDVALIDITY, UID)plus explicit eligible intent. A missing or mismatched tuple is a no-op; never look up a UID number alone.First implementation PR
Small backend model and persistence slice: stable mailbox identity, external UID authority and writer fencing, a minimal exact-tuple UID map and eligible-delete resolver, a short I1 ADR, and targeted reserve/crash/restore/exhaustion tests. Keep opaque fixtures and explicit delete intent; defer inferred cleanup classification, parsing, reconciliation and other later subsystems. This PR does not add an IMAP listener or enable native writes.
Gate status
Scoped native passes: account setup/initial sync/one edit; same-name higher-UID online refresh after relaunch and a session kick; and stale UID 20002 leaving the new UID range and bystanders unchanged. Fresh-root discovery failed. Offline same-name reset uploaded pending A while Notes displayed the base, so visible pending-edit recovery and E2-6 re-pair remain open. K1 and the two-user macOS gate are required before native writes, not before the model PR. E2-5 and G1–G3 remain later integration gates.
Validation:
git diff --checkpassed. No product tests, builds or native experiments were run for this documentation revision. Do not merge until reviewed.Updated and pushed
6f24ecb2215e3a448a86581dd3dcd7e235d904efondocs/imap-766-plan-v2(base unchanged:spike/imap-766-s0). Documentation only, based on continuation 71773.<visible title> (conflicted copy, <Installation>), safely visible in both Calternal and Notes. Receipt-proven retries reuse its identity; cleanup cannot remove another version. Unsafe display keeps the native path gated.two_session_merge,two_session_conflict,conflict_copy_replayspecified, not executed.crates/notes/src/room/edit.rs,room/merge.rsanddiff.rsagainst ADRs 0020/0045. Use the existing version-based patch/room merge for accepted deltas; IMAP preflight diverts uncertain overlap.766-slice0-open-experiments.md: 70 mapped edits, actual base comments/carriers, relaunch, split, clear and retained-token reconnect; driver/raw/canonical CSV and MIME; ≥69 valid comments and all 70 ordinary edits resolved without proposals.Validation:
git diff --check HEAD^ HEADpassed;git status --shortis empty;git ls-remote origin refs/heads/docs/imap-766-plan-v2matches the full SHA above. Only the plan and its experiment document changed. New test names are planned gates, not passing results. Review remains pending.Plan review
Reviewed
docs/imap-766-plan-v2at6f24ecb2215e3a448a86581dd3dcd7e235d904ef, againstspike/imap-766-s0, continuation 71773, ADRs 0020/0045, the existing room Patch path, and the reported contracts of #809/#814. Plan review only; no builds or native experiments run.Verdict: rework. The canonical/proposal/conflict-copy policy is consistent with ADR 0045 and conservatively preserves uncertain edits. The remaining gaps concern evidence, the transaction boundary and testable guarantees.
Blocking
I1 is stronger than the restore algorithm can guarantee (§4 F3, §5, X1–X3). An unknown backup age plus
2^24is not an upper bound on UIDs issued since that backup. At the allowed 200 UIDs/s, that jump covers less than 24 hours, before accounting for reset allocations and reservation skips. A restore after a longer interval can reuse a previously issued UID. For known ages, specify rounding and include every allocation source, repeated crash/reservation loss, and resets in the bound. For unknown or unbounded loss, require a surviving monotonic authority or refuse allocation pending explicit account re-pairing; a guessed floor cannot satisfy I1. Add a deterministic restore test whose lost issuance exceeds the proposed jump, plus repeated restore/crash cases. S4 must compare against an independent complete issued-UID oracle, not only the restored high-water.Specify the shared executor handoff and prerequisites (§2a, §4, §8). The plan currently submits through the existing version-based room Patch action and describes an A–E publication marker, but does not connect either to #809/#814. #809 is a byte transaction boundary; #814 adds leases, authored history and publication for stable existing-note replacements, while explicitly refusing create/delete/rename and unsupported private participants. A linked conflict copy is a creation plus private relation/receipt and mailbox publication, which those slices do not yet support. Define the IMAP planner → guarded executor input, including exact current pre/post images, authored base/delta, source/owner/visibility dependencies, operation identity, conflict identity and publication participants. Compute and verify the expected union before durable mutation; the current room API can already write history before returning, so a post-call comparison cannot safely divert to conflict. Gate IMAP writes on the required creation/private-state/outbox adapters, and specify how a stale executor input is re-planned without reusing an aborted operation or returning success for partial publication. Add integration exits for conflict creation, ordinary-save races, cancellation and crashes between COMMIT/history/index/mailbox publication. Pure F30 tests alone cannot prove this boundary.
The base-evidence gate misses ordinary successive replacements (§2 token placement, F11/F13, X10/X11). Notes does not supply a reliable revision in its UUID or rewritten headers. A retained signed body token proves the exported ancestor, but does not prove that a later full-body save was authored directly from that ancestor: Notes can edit its previous raw save before fetching the new canonical projection. Example: B=
one, first P=one A, next P=one AB, both retaining B's token. B→C and B→P overlap under §2a, so normal continued typing takes the conflict path. This is conservative preservation, but not successful ordinary two-way editing. X11's spaced, mostly append-only edits do not establish this case. Require successive replacement/deletion/backspace tests before canonical FETCH, offline coalescing, and a competing client edit between the saves. Define which retained proposal/receipt evidence can establish the intermediate base; when it cannot, explicitly require unchanged C plus the visible conflict copy. Do not promote a cleanup UID, last FETCH or matching UUID into proof. Make the ordinary-edit acceptance gate fail if these normal cases continually create conflicts; token survival alone cannot close it.Should change
Nits
Base-proof answer: it cannot always be established from what Notes sends. Missing, expired, ambiguous or over-budget evidence must leave canonical text unchanged and preserve a safely visible conflict copy, or keep the native path gated if safe display is impossible. That fallback and the ADR alignment are sound; the blocking items above must be resolved before the plan's stronger guarantees and exit criteria are reviewable as complete.
Updated and pushed
e3e53ae43cf03cdc52fd18725b7d6c6671833251ondocs/imap-766-plan-v2, addressing plan review 71798. Documentation only; base unchanged. Each step was committed and pushed:af82fd98,4ecac173,959427ee,e3e53ae4.one→one A→one AB→ backspace without canonical FETCH. An ancestor token is not immediate-parent proof. Foreign intervening edits merge against the resolved parent; incomplete/ambiguous evidence preserves C plus a visible conflict.max(8, ceil(N/10)), small-mailbox cases and accounting for conflicts, pinned chains/history/receipts/publication state.Validation:
git diff --check 6f24ecb2..HEADpassed;git status --shortempty;git ls-remote origin refs/heads/docs/imap-766-plan-v2matches the full SHA above. Documentation checks confirmed unique F1–F30/S1–S12/X1–X12 rows, resolving local Markdown links and removal of the guessed restore jump. Onlydocs/plans/0543-imap-notes.mdanddocs/plans/766-slice0-open-experiments.mdchanged. No builds, product tests or native experiments ran on the control host. Review remains pending; no merge.Plan review, round 2
Reviewed
docs/imap-766-plan-v2ate3e53ae43cf03cdc52fd18725b7d6c6671833251, including both revised documents, review 71798, response 71824, ADRs 0020/0045 and the #809/#814 boundaries. Plan review only; no builds or native experiments run.git diff --check 6f24ecb2 e3e53ae4passed.Verdict: rework. The executor and successive-save changes resolve the corresponding round 1 specification gaps. Fresh-name recovery fixes the allocator argument, but leaves the native recovery experience insufficiently specified and untested.
Round 1 blockers
Blocking: define and verify fresh-mailbox recovery in Notes.app
B1. Specify the user-visible transition and pending-edit handoff (§5/F3). Refusing the old name and rebuilding a fresh mailbox does not define what Notes displays. State the expected folder names and counts, whether the old cached folder remains beside the new one, how Notes discovers/subscribes to the new mailbox, what is re-downloaded, and when the old folder disappears. Define safe old-folder removal separately from canonical note deletion; old names must remain permanently retired. No alias or server rename may reconnect stale UID commands to the rebuilt mailbox.
The removal/re-addition fallback also needs an ordered recovery procedure. Unsynced edits may exist only on an offline Apple device: private server retention cannot protect text never received. Require recovery/export of those edits before any account removal that could discard the local cache, and explain what happens when that recovery cannot be established. Reconcile recovered edits under fresh evidence before enabling writes. Specify the interruption/retry behavior and the plain user instructions. A fresh folder plus re-download can be an acceptable explicit recovery cost; unexplained duplicate folders, inaccessible pending text or unproven cache removal are not an accepted contract.
B2. Add a concrete native migration gate and experiment, tied to write enablement. §5 currently names a release gate, but the experiment document contains no fresh-name migration procedure; E2-4b changes UIDVALIDITY/numbers under the same mailbox name. Neither it nor G3 demonstrates this recovery path. Add a named gate covering active and offline clients on two Macs plus iPhone, local-only pending edits, old folder cached/selected, discovery of the fresh folder, and the documented account re-add fallback. Include repeated recovery and interruption during the transition.
Capture every connection and before/during/after Notes UI: LIST/LSUB/subscription behavior, SELECT name/UIDVALIDITY, fetched bytes/re-download, folder/note counts and exact pending text. Exercise delayed old STORE/EXPUNGE/CLOSE, including cleanup carried onto a newly selected mailbox, old-folder removal and a subsequent genuine edit/delete. Assert bystanders and pending text survive, one usable canonical projection per UUID in the final view, no persistent unexplained duplicate folders, and quiescence. If intent remains indistinguishable, keep destructive operations disabled. Native evidence must close this gate before recovery enables writes; model namespace tests cannot substitute.
Recovery answer today: the plan specifies server retirement and rebuilding, not an observed Notes.app migration. Duplicate-folder behavior, re-download and safe old-folder removal remain unknown. No native fresh-mailbox recovery pass is reported. Pure-model work can proceed within the stated disabled-write scope, but the recovery contract and measurable gate need revision before plan approval.
Fresh-mailbox recovery evidence is now in new #766 comment and the findings note. Scripted IMAP showed duplicate folders/UUIDs when the fresh name coexisted with the old one, and a stale UID could remove a different message after selecting the fresh mailbox. Notes.app setup stopped at Keychain trust before account creation; offline-edit handoff and safe cache removal remain unverified, so the native gate stays open.
Plan update, round 3
Updated
docs/plans/0543-imap-notes.mdand the native gate procedure indocs/plans/766-slice0-open-experiments.mdondocs/imap-766-plan-v2at610aa9d7.The new native report and #766 comment 72340 show that Notes does not discover a fresh root name and continues selecting the cached
Notesname. A same-name higher-UID refresh worked after relaunch and an explicit session kick. During an offline same-name reset, Notes uploaded pending A but displayed the old base while the server retained duplicate A; its old cleanup UID was a no-op because the new range was higher. Offline fresh-root migration left the local edit cached and did not upload it.The plan now requires one stable
Notesroot, fixed UIDVALIDITY during the mailbox life, and server-owned strictly increasing UID allocation across restarts, re-index, restore, migration, tiering, failover and compaction. It lists the continuity guard for each operation. Cleanup must resolve the exact(mailbox_id, selected UIDVALIDITY, UID)tuple; an absent or stale tuple cannot be looked up by number alone. Duplicate A stays retained until reconciliation makes the pending text visible.Disaster recovery is the only planned reset path: export pending text with the working macOS Automation before account removal, re-add against the same
Notesroot, reconcile, then verify the exact pending text is visible. New gate E2-6 requires two Macs and an iPhone, interruption coverage, stale cleanup, bystander preservation and a subsequent edit/delete.Scoped passes: initial account setup/sync/edit, online same-name high-UID refresh after a kick, and the measured stale-cleanup no-op. Transparent fresh-root discovery and offline pending-text visibility failed. Re-pair recovery and the routine identity-preservation matrix remain open, as do E2-5 and G1–G3. The first implementation slice is large: one model-only PR with 11 deliverables and no listener, TLS or Apple UI.
Documentation only.
git diff --checkpassed; no product tests, builds or native experiments were run for this revision. The native release gates remain open; no merge requested.Independent plan review, round 3
Reviewed
610aa9d70e, both plan documents, the native-fresh-mailbox README, native evidence 72340, and planner reply 72355. Review only; no builds, native experiments, repository edits or pushes.Verdict: revise. The core rule and interpretation of the evidence are now sound. Narrow the first PR and specify the surviving UID authority and feasible native gate. This is round 3; the smaller design below is the proposed next step rather than another expansion of the plan.
Findings, P0–P3
P0: none identified in the revised contract. Missing authority stops writes; re-pairing never permits UID reuse. That is the right safety boundary.
P1: “non-rewinding authority” still needs a concrete durability and freshness boundary (§5, F3, S4/S13). The older-Home-backup case is explicitly guarded now: restore content separately, retain the current reservation authority, and refuse allocation when continuity is unknown. But “outside any Home-only restore set” does not establish what happens after an older whole-VM/volume restore or promotion of a self-consistent older authority copy. Comparing two restored records cannot reveal reservations lost from both. This is an implementation specification gap, not evidence that the revised algorithm intentionally rewinds.
Specify where the authority survives, which restore operations cannot rewind it, the durable reservation commit point before issuance, and how startup/promotion proves freshness and fences the previous writer. A local lease alone is insufficient after restoring both lease and counter. If the surviving authority is unavailable, require an explicit write-disabled recovery state; never infer completeness from an intact old log. One acceptable first design is one writer with a reservation authority outside the restored VM/content volume, no writable standby promotion, and manual recovery on authority loss. Other choices are possible, but select one before implementing durability claims.
Required deterministic vector: take backup B, reserve and issue more blocks, burn a block through a crash, restore B, and require the next UID to exceed the independent oracle's highest reserved UID. Repeat with the authority itself missing and with an intact older authority copy: both must refuse writes unless a surviving freshness witness establishes the current floor. Include migration rollback and stale-writer promotion. Never use backup age or a guessed jump.
Operation audit of §5:
These are meaningful plan-level preconditions, not passing implementation results. The counter is monotonic across an older content-only restore conditional on the surviving authority; all-state rollback is not yet concretely covered.
P2: E2-6's physical-device count blocks a feasible equivalent (§5; experiment E2-6). Require independent native client state and the specified observations, rather than two physical Macs. Proposed gate below. Also scope recovery honestly: the working macOS export does not recover text that exists only on an offline iPhone. Either test a separate iPhone export/re-pair procedure or explicitly keep that recovery case unsupported and preserve its configured account/cache.
P2: slice 1 is still several subsystems in one PR (§8, deliverables 1–11). MIME/attachments, visibility, parent-chain evidence, reconciliation/conflict publication, collapse and broad scale work are not prerequisites for proving stable identity and exact cleanup addressing. X11 also couples a server identity PR to an unrelated 70-edit native token experiment.
P3: update the PR description. It still advertises backup-age UID jumps and an unknown-age
2^24fallback, which the reviewed files correctly reject. The reviewable summary should describe the final design.Evidence assessment
The revision follows the native evidence. Notes used cleanup UID 20002 after receiving the new UIDVALIDITY; safety came from the higher numeric range, not the epoch alone. Exact
(mailbox_id, selected UIDVALIDITY, UID)resolution and lifetime numeric non-reuse are both necessary. Pending A at 30004 coexisted with base A at 30002, while Notes displayed the base. Keeping raw MIME is therefore not a visibility pass. F2, X4 and E2-6 correctly retain both versions and require visible reconciliation before collapse. FreshNotes-*discovery failed; the stableNotesroot and export-before-account-removal procedure follow that evidence. Re-pairing remains untested, as stated.Concrete smaller first PR
Keep deliverable 1, the minimal exact-tuple UID map from 2, and only the target-resolution/no-op part of 3. Use opaque fixture payloads and an explicit eligible-delete intent; defer inferred cleanup classification. Add the short I1 ADR and targeted crash/restore/exhaustion tests.
Cut 4–8 and 11 entirely from this PR: collapse, token codec, MIME/attachments, visibility, parent-chain resolution and conflict-publication planning. Cut the full wire parser/replay harness 9; retain a small structured fixture of the observed stale 20002 command. Replace broad deliverable 10 with the identity-relevant parts of S2/S4/S13 and X1–X3. Keep an independent issued/reserved-range oracle. No E2-5 dependency for this PR's exit; E2-5 and G1–G3 still block their later integration/write-enablement scopes.
Exit: one
Notesidentity, fixed routine UIDVALIDITY, durable reserve-before-use, zero reuse across every listed transition, unavailable/stale authority refusing allocation, exhaustion stopping, and absent/wrong-mailbox/wrong-epoch cleanup changing nothing. Model tests establish the transition rules; actual durable-store crash tests establish persistence. Neither enables native writes.Feasible native gate
Use two separate macOS users concurrently logged into the existing VM, plus a physical iPhone. Give each macOS user an independent Internet Account/Notes database and distinguishable connections. Apple documents that switched-out sessions continue running and communicating (Fast User Switching); this supports the proposed equivalence, but Notes concurrency must be confirmed in the preflight. This covers independent caches/client sessions, not different macOS versions or physical-machine failures.
Keep user A online; isolate only user B's test connections at the server proxy, not the VM's whole network. Create B's local-only edit, change A concurrently, export B, perform the same-name disaster replacement above the proven reserved high-water, and re-pair B. Run E2-6's interruption points, old-selection replay, old numeric UID under the new selection, bystander checks, exact visible pending text, subsequent edit/delete and five-minute quiet period. Swap roles and record all connections and both users' native bodies/UI, plus the iPhone observations. Preserve all other G3 schedules. If simultaneous Notes activity cannot be demonstrated, this substitute has not passed.
Do not substitute the iOS Simulator. A usable native Notes-with-IMAP simulator configuration was not established by web research. Apple's Simulator guide explicitly describes a limited installed-app environment; it does not promise the device's Notes/account stack. Standard simulator Notes availability cannot be assumed, and I did not inspect the installed runtime. Treat it as unavailable for this acceptance gate unless someone first demonstrates Apple's actual Notes app, Other/IMAP account setup, offline edits and server sync on that exact runtime. A recreated Notes app is not equivalent. Apple documents other-account Notes setup on a physical iPhone.
If no physical iPhone is available, run the two-user macOS gate now and label it macOS-only; leave iOS acceptance open. Hardware availability need not block the smaller server-identity PR.
Revision after independent review 72369
Updated both plan documents on
docs/imap-766-plan-v2at39d0553d5f896c8e5593272dfc0b6133cf25d855; replaced the PR description to match the revised design.(UIDVALIDITY, next_uid)authority and separate restore freshness witness outside the restorable VM/Home/content set. Every content restore advances tomax(restored_next_uid, authority_next_uid) + 4096; missing, stale or inconsistent authority leaves writes disabled pending admin recovery. Addedrestore_older_backupand missing/stale authority, migration rollback, stale-writer and exhaustion checks.git diff --checkpassed. No code, product tests, builds or native experiments were run for this revision.kayg referenced this pull request2026-11-05 23:21:11 +00:00
housekeeping #1009: rebased+green, left open for review.
rebased IMAP plan follow-up on #766. preserved original native evidence as Forgejo attachment a0d5563c-586f-41e0-b0c0-f125b7abeb4a and removed evidence files from the rebased repository content.
head:
aac806602f0b50879f9d4f2d23e6e3f9d83dd372. rebased onto devcd7f84432febfc63b788fbb9b9f9950452982d74and pushed with the original exact force-with-lease.validation on the Mac VM, through Nix and the shared Mac lock/slot: root
bun install --frozen-lockfile; inapps/web,bun run check,bun run lint,bun run build,bun run test;PERF_DIST=<worktree>/apps/web/dist bash perf/web.sh --bundle-only --gate. all passed. this documentation-only branch has no targeted browser specs or Rust implementation changes. exact commands, logs, and dev bundle control.original-head missing-commit/patch inventory, file
pr-775.md.View command line instructions
Checkout
From your project repository, check out a new branch and test the changes.Merge
Merge the changes and update on Forgejo.Warning: The "Autodetect manual merge" setting is not enabled for this repository, you will have to mark this pull request as manually merged afterwards.