docs: simpler calendar backend v2 plan #802
Open
kayg
wants to merge 1 commit from
docs/calendar-backend-v2-plan into dev
pull from: docs/calendar-backend-v2-plan
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: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!802
Loading…
Reference in a new issue
No description provided.
Delete branch "docs/calendar-backend-v2-plan"
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?
Calendar backend steps 2–4 failed three review rounds. This plan keeps #781/#783/#785 on hold and replaces their delivery approach with a calendar-only strict writer, the existing native Rust pulldown-cmark backend and independent shared TS/Rust extraction vectors. The editor remains TypeScript.
After round-2 review, the plan chooses pulldown-cmark 0.13.4 as the sole backend parser, with option/extension mapping, offset-event extraction rules and explicit ownership of Notes link exclusions, Tasks/B3 list ancestry, Composer title handling and their test oracles. No comrak migration or production behavior change is introduced.
The isolated spike under
docs/plans/0067-vectors/andpackages/editor/test/calendar-0067.spike.test.tschecks 70 authored line-classification vectors against pulldown and the actual installed editor Lezer parser. On dev-02 inside the Nix shell through~/bin/slot: 70/70 Rust and 70/70 TS pass, zero failures or normalized classification differences. CI runs the locked standalone Rust crate and discovers the TS tests in the existing editor unit-test step. Exact commands and limits are in the spike README and review reply.Literal-autolink/emoji node differences, full metadata/relationship rows, exact UTF-8 spans and link/Composer output compatibility remain explicit expanded-corpus gates. The spike establishes line-eligibility feasibility only. The plan retains the existing-property compatibility matrix, durable last-good/unresolved recovery, bounded workers, 100k-note scale gates and risk-first delivery slices. Promotion remains default-off.
No full CI, production implementation, native sync, recovery or performance pass is claimed. No merge or fourth patch round on the held implementation stack.
Plan review
verdict: rework. reviewed plan head
292e725fa101fac68321b7d4a53917fb30ba13f6, all three independent review rounds and fix reports on #781/#783/#785, ADRs 0067/0068/0056, andfeedback-wasm-boundaries.md. this is a plan review, with no implementation, build, benchmark or passing-gate claim.the writer and delivery boundaries are materially simpler. rejecting hashes and unsupported syntax before planning removes the recurring YAML comment-detection problem instead of adding another quote heuristic. original-offset exclusions shared by events, tasks, relationships and identity address the recurring code/comment visibility problem. the one-pass parent walk addresses the nested rescan bug. default-off bulk replay, preserved receipts and deferred promotion are the right containment. those are good contracts, not proof of an implementation yet.
blocking
the whole-frontmatter gate changes existing safe-edit behavior, despite claiming to preserve settled decisions (lines 44–85; delivery slice 2). ADR 0068's Odd cases explicitly says “unrelated safe edits remain possible.” a valid repeating task with a nonempty map-based
logwould become entirely property-read-only, including unrelated priority/title changes. so would a note withhidden: ["^id"], table-width arrays, an unrelated comment, or a quoted link fragment. the plan acknowledgeslogis read-only but understates that every property action on that note is refused. this is broader than refusing an unsafe target and reaches existing Tasks, not just unfinished Calendar actions. keep the narrow writer initially scoped to the new supported calendar operations and preserve proven existing unrelated edits, or explicitly reconcile this behavior with the normative contract before calling it an unchanged decision. do not restore a permissive scanner fallback. add an action/fixture matrix covering ordinary notes, tracked/repeating tasks, hidden blocks and display properties, with both target and unrelated-field edits. blanket refusal is safe for bytes, but is a product regression, not merely an implementation detail.the parser choice has not earned the claim of a simpler backend (lines 106–138). a bounded embedded QuickJS bridge is technically plausible, and correctly avoids per-note processes and client-submitted trees. however, sharing Lezer eliminates implementation drift only for a pinned parser/configuration/span ABI; it adds runtime ownership, JS bundling, native runtime packaging, string/result marshalling, interruption and worker recovery. the plan makes it the chosen dependency before comparing the existing Rust option. a feasibility spike alone cannot establish that this is the simplest solution. revise the parser decision as recommended below, or require a side-by-side bridge/native comparison before choosing and before switching existing Tasks.
“suppress exports” on parser failure needs a durable state contract (lines 132–138; failure table). retain bindings alone does not say what happens to old task/event/relationship rows, cached DAV objects, sync tokens or pending work when a new revision cannot be parsed. removing a resource from a projection can itself become a remote deletion. specify a persisted successful/unresolved result with source revision and parser version; failed extraction must not commit an authoritative empty replacement or emit deletion/outcome/identity work. retain the last accepted published generation without publishing a changed interpretation; cold failures with no prior generation stay explicitly unresolved. gate management of stale targets. test timeout/OOM after a previously successful revision, restart, deletion/rebuild of the derived index, parser upgrade, then successful retry. state where accepted publication/binding state survives an index rebuild. apply the policy to Tasks as well as events. the failure table's “no false tombstones” intent is correct but not yet an implementable recovery contract.
parser recommendation
10:00is inside a multiline backtick span, lazy list continuation or inline comment without surrounding Markdown structure. refusing all uncertain context either recreates a scanner or drops valid bare/nested/quoted-checkbox cases.for the Rust choice, specify exactly the same block/inline eligibility, code/HTML/comment exclusions, direct-child relationship rules, paragraph segmentation, metadata rules and original source spans as the TS editor. share independent expected extraction spans/rows, not entire implementation-specific syntax trees. include all nine review probes and adversarial container combinations. gate both implementations and parser upgrades on the corpus; unresolved parity cases refuse dependent management rather than guess. one immutable Rust parsed view supplies all backend consumers, with no masked reparse or separate child scanner. two implementations with executable parity is compatible with kayg's explicit boundary decision.
this proposal does not introduce client WASM, so it does not literally violate the no-Rust-to-WASM rule. equally, that rule does not justify embedding JS in Rust to force a single implementation: it explicitly names shared goldens as the drift control. per-keystroke work stays TS; any shared editor span walk must preserve incremental/bounded editor behavior rather than rebuilding a full-note view on each keystroke.
should change
make the write grammar executable on both input and output. its lexical restrictions are strict enough to exclude the demonstrated comment-loss class. require exact output validation too: creating absent frontmatter or writing a new string containing a newline, quote or hash must not emit unsafe YAML or immediately strand the note outside the subset. spell out final-newline/empty-envelope handling, mapping/list indentation, key typing and integer range/overflow; JSON syntax alone does not settle YAML decoder differences. verify independent YAML 1.2 typed meaning. define overlapping batch targets, ancestor removal and conflicting changes as deterministic refusal or a single specified result. count changes/output bytes in the complexity bound. predeclare allowed changed spans in fixtures, including ancestor lines, independently of production span selection. supplement the already-good byte oracle with punctuation/escape/duplicate-key mutations and an accepted-edit semantic model that does not call production helpers. preserve refusal as exact whole-file bytes with no claims/destination/history side effects; test all property entrypoints.
turn the scale section into falsifiable acceptance criteria. the sizes and doubling/nesting tests are a substantial improvement. keep
O(N+B+L)as an extraction target, not a proof about Lezer, and account separately for database inserts/indexes, bridge copies/result size, offset maps and queueing. define worker count, bounded queue/backpressure, total RSS/native stack limits and restart behavior; 64 MiB of JS heap does not bound Rust buffers or process RSS. run parsing outside long-held database/write locks and test that a timeout storm leaves other notes/users responsive. specify absolute startup/cold-index time and the baseline distribution, bytes and nesting of the 100k-note Home. at 0.2 ms extra per note, 100k notes already represent 20 seconds of CPU before other indexing work; at 50 ms each, a pathological corpus consumes 5,000 seconds on one worker. the 50 ms ceiling is containment only, as the plan says. include full source-in/result-out bridge cost, cold/warm runs, concurrent foreground edits, normal-fixture extraction success counts and unresolved counts. rejecting most fixtures must never count as passing the latency/cold-index gates. measure Tasks' total describe regression separately from the extra-event budget.slice by risk before broad migration. the containment PR first is right. move the parser/contract comparison ahead of the Tasks-wide switch; separate read-only events from changing existing task/link semantics, each with independently expected rows and transaction-before-journal evidence. slice 7 combines permanent claim inventory, allocation, concurrency, crash recovery and undo: split durable claim inventory/readiness from enabling identity. list read-only rebuild/upgrade/failure gates per slice and later feature gates separately. retain the real process-kill/new-key tests, native sync gates and default-off promotion. no fourth patch round on the held stack.
nits and settled decisions
[]is the explicit empty-container exception, and that event keys use lowercase Crockford, matching 0056.markdownLanguage; its currentblockAthelper is not itself the proposed pure shared extraction walk.no code pushed or changed. recommendation: retain the narrow writer/containment direction, reconcile the unrelated-edit regression, choose the native Rust parser plus shared TS/Rust vectors, and make unresolved extraction recovery explicit before implementation.
reworked the plan in
45c211f5on the same branch. docs only; the held implementation stack stays held.133cf2c2. added target/unrelated-field fixtures for map-list log, repeating tasks, hidden/table-width arrays, comments and link fragments. existing non-calendar actions gain no new refusal; calendar-only limits are explicitly user-visible.[]is explicitly the empty-container exception; event keys use lowercase Crockford. distinguished installed editor language fromblockAt. frontmatter authority, server IDs, private permanent claims, hidden markers, UUID links and default-off promotion stay; ambiguous-copy refusal is explicitly not eventual 0056 rekey delivery.validation:
git diff --cached --checkpassed before commit; all relative document links exist; fixture-size arithmetic checked; onlydocs/plans/0067-calendar-backend-v2.mdchanged. no build, test, native sync or performance run, consistent with this docs-only task and the control-host rule. parser parity, process-pool cost/platform limits and recovery-schema implementation remain delivery gates. no merge or fourth implementation patch round.Plan review, round 2
verdict: rework. reviewed
45c211f51113c7698e318e96203b15b9232a70c6, the first review/revision comments, current property/parser routes at the plan base, the held containment boundary, and the published Lezer 1.8.0/lang-markdown 6.5.2 and comrak 0.59.0 sources. docs review only; no implementation tests or performance gates run, no code pushed.blocking
commit to one backend Markdown parser, including existing consumers (
docs/plans/0067-calendar-backend-v2.md:180–185, 471–486). the explicit permission for existing pulldown to remain “until their separate migration” leaves two backend rule sets with no complete removal gate. bothcrates/notes/Cargo.toml:17andcrates/tasks/Cargo.toml:12depend onpulldown-cmark0.13.4. production uses are:notes/src/links.rs:66: fenced/indented code exclusion ranges for note links;tasks/src/found.rs:257: real list-item ancestry for checkbox extraction, reused by Tasks B3;tasks/src/create.rs:38: composer title link-to-label conversion.the last route is not covered by “Tasks then relationships” migration as written; parser-based test oracles also need updating (
notes/src/links.rs,tasks/src/found/tests.rs). either choose pulldown if the shared editor/backend extraction vectors establish the required parity, or justify comrak and explicitly migrate every pulldown use, remove both dependencies, and name the delivery gate that enforces this. a temporary isolated comparison adapter is reasonable; shipping new production consumers on comrak while leaving the old ones indefinitely on pulldown is not. retain one pinned backend configuration and one shared vector suite with the editor, extended for link exclusion and composer title behavior. do not infer that missing rendered emoji support alone makes pulldown unsuitable for a source-preserving extraction contract.first-round blockers
should change
make the concrete extension differences explicit in the corpus, rather than equating option names. the editor really installs
markdownLanguage, whose published configuration includes GFM, subscript, superscript and emoji. comrak has the broad capabilities, including CommonMark multiline code spans and HTML comments, but exact extraction parity is still unproven. for example, Lezer's Emoji parser accepts any[a-zA-Z_0-9]+name, including unknown names; comrak shortcodes useemojis::get_by_shortcode. preserving literal source can normalize this harmlessly, but the plan should say how and test it. include unknown/uppercase emoji, sub/superscript whitespace/escapes and link nesting, and autolink label boundaries where metadata must be excluded. none requires identical ASTs.the existing vector design is strong: both production adapters independently compare spans/slices, rows, parents and unresolved reasons to the same authored expectations, then compare normalized results; upgrades run both required jobs. keep its positive controls and all nine probes. explicitly instantiate matched/unmatched and multi-backtick spans crossing physical lines in paragraphs/list/quote containers, plus inline/block and multiline HTML comments with visible adjacent prose. these checks catch drift in exclusions and offsets rather than merely confirming matching parser names. the stop-before-migration gate is essential; passing tests are not yet claimed.
spell out existing checkbox compatibility before the Tasks switch.
tasks/src/found.rs:60–63, 255–276, 325–352intentionally recognizes doing/cancelled/later and unknown single-character boxes, including empty boxes at end of line. Lezer's TaskMarker recognizes only space/x/X followed by space/tab; comrak with relaxed matching off also does not classify all current boxes as task items. extract the app's supported box grammar from parser-approved list/paragraph source spans in both adapters, not only TaskMarker/TaskItem nodes. add positive expected rows for[ ],[x],[X],[/],[-],[>],[?]and end-of-line boxes. reconcile “unknown custom boxes refuse classification” (line 217) with today's lenient task reader explicitly, so the property compatibility fix does not conceal a later task-reading regression.slice 1 and nits
bulk::driveboundary suitable for a narrow port. require ordinary note identity/non-calendar bulk jobs to remain executable, and deferred calendar replay/undo/direct calls to perform zero additional writes. no parser, writer, ledger, allocation or UI enablement belongs in this slice.rework the parser ownership/migration decision before implementation. the separate calendar writer and durable recovery direction can stay.
updated in
c19747b2be60cdcd6a24c929127cdf181526c3c3.round-2 parser decision: retain pulldown-cmark 0.13.4, already used by the backend. no comrak dependency or parser migration, and no change to Tasks B3 (#798) or Composer behavior in this spike.
updated the plan's option mapping and offset-event extraction contract. the single-parser ownership inventory explicitly includes Notes link-code exclusions, Tasks list ancestry/B3, Composer link-to-label conversion and both existing parser-based test oracles. the later shared-view/configuration change must preserve their independently expected outputs.
dev-02 spike: Rust 70/70 and editor Lezer 70/70 vectors pass; 0 failures and 0 normalized line-classification differences. both independently compare to the same authored JSON expectations, using the existing pulldown version and the actual installed
markdownLanguage.parser(lang-markdown 6.5.2 / Lezer 1.8.0). no expected output was generated from either parser. includes positive and negative custom/EOL/Unicode task boxes, matched/unmatched multiline single/multi-backticks in paragraph/list/quote containers, fenced/indented code, inline/block/multiline HTML comments with adjacent visible prose, nested lists/quotes, frontmatter boundaries, CRLF, non-BMP Unicode and extension prose. the editor does not install Obsidian%%comments, so those bytes intentionally leave enclosed candidates visible.reproducible commands, run inside the Nix shell on
calternal-dev-02-std, with the slot wrapper:editor typechecking (
tsc --noEmit) also passed; the final locked Rust run had no warnings. staged diff whitespace and relative plan links passed.spike files:
docs/plans/0067-vectors/andpackages/editor/test/calendar-0067.spike.test.ts. the Rust CI job now runs the isolated locked crate; existing editor unit-test discovery runs the TS adapter. both use the same checked-in JSON. no production code or production dependency changes.remaining differences are explicit: pulldown has no literal-autolink/emoji extension, and sub/superscript delimiter details may differ. source-preserving emoji/title spelling requires no renderer parity. before metadata migration, the plan requires a narrow pinned Lezer literal-autolink boundary rule and expected URL/label spans. this spike proves line eligibility only: exact UTF-8 spans, complete clock/metadata rows, relationships, link exclusions/Composer output compatibility, recovery, worker limits and scale still need the expanded production-adapter corpus and delivery gates. no full extraction, full CI, recovery or performance pass is claimed. no tested mismatch requires switching to comrak.
kayg referenced this pull request2026-10-31 18:24:43 +00:00
updated in
6a4289fa: calendar writes now explicitly depend on the singleNoteWriteExecutordefined by #808 (calternal-notes,crates/notes/src/write_executor/). both domains share exact-splice plans/inverses, verification, WAL, guarded apply, recovery, undo, Home coordination and ancestry deferral.executor lands once, before either plan enables writes. read-only/parser/pure-writer prerequisites can proceed; Tasks ports retain B1 → B2 → B3 ordering. calendar identity/promotion/settlement cannot use ordinary Flush. added overlap and cross-domain replay/undo gates. ADR 0066 product choices remain pending kayg, not approved here.
validation:
git diff --checkpassed; docs only, no builds or runtime tests. no merge.ADR 0003 evidence migration:
docs/plans/0067-calendar-backend-v2.mdSource commit: 75a1577f5b98909836146e3f3309a23932a6aca2; snapshot from dev
55f35fcd. Full original source preserved below before repository removal/stripping. Design, code and test inputs are retained where applicable.Original file (51,379 bytes): 0067-calendar-backend-v2.md
ADR 0003 evidence migration:
docs/plans/0067-vectors/README.mdSource commit: fec18a59ded981f79c9c8841585bb9b67e6c0145; snapshot from dev
55f35fcd. Full original source preserved below before repository removal/stripping. Design, code and test inputs are retained where applicable.kayg referenced this pull request2026-11-05 23:21:11 +00:00
housekeeping #1009: rebased+green, left open for review.
earlier plan commits have semantic equivalents or newer text in dev; rebased the final missing plan amendment.
head:
f59b367a23bfea29e60addd895b4908265272a44. 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-802.md.View command line instructions
Manual merge helper
Use this merge commit message when completing the merge manually.
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.