HOTFIX: /draw shows No blocks; selecting a block reloads; Not live status line is back #1132

Open
opened 2026-10-05 08:56:23 +00:00 by kayg · 10 comments
Owner

Owner report (2026-10-05, production 570e084c8, desktop)

  1. /draw shows "No blocks": typing /draw in a Note/Journal entry card opens the slash menu with "No blocks". Regression from the Sketch → Draw rename (0949ee4a7, batch 5). /draw (and the hidden /sketch alias) must offer Draw in every editor where Sketch was offered.
  2. Selecting a block reloads: selecting a block makes the view reload (owner: "if I select a block now it reloads"). Find what navigation or invalidation block selection triggers (URL update for the block deep link causing a full load? a store reset?) and fix it; block selection must never reload or remount the editor.
  3. "Not live: changes save when you pause" is back: a collaboration status line above the Note card, removed long ago at the owner's request, has returned (likely 7c collaboration/history merges). Remove it again; status may only appear as a quiet indicator if DESIGN asks for one, never as a line of text above the content.

Add regression tests for all three (slash menu lists Draw; block selection keeps the same editor instance and no navigation; no status line rendered).

## Owner report (2026-10-05, production 570e084c8, desktop) 1. **/draw shows "No blocks"**: typing /draw in a Note/Journal entry card opens the slash menu with "No blocks". Regression from the Sketch → Draw rename (0949ee4a7, batch 5). /draw (and the hidden /sketch alias) must offer Draw in every editor where Sketch was offered. 2. **Selecting a block reloads**: selecting a block makes the view reload (owner: "if I select a block now it reloads"). Find what navigation or invalidation block selection triggers (URL update for the block deep link causing a full load? a store reset?) and fix it; block selection must never reload or remount the editor. 3. **"Not live: changes save when you pause" is back**: a collaboration status line above the Note card, removed long ago at the owner's request, has returned (likely 7c collaboration/history merges). Remove it again; status may only appear as a quiet indicator if DESIGN asks for one, never as a line of text above the content. Add regression tests for all three (slash menu lists Draw; block selection keeps the same editor instance and no navigation; no status line rendered).
Author
Owner

Starting #1132 on job/editreg-1132, based on production/dev SHA 570e084c8691a76b9bec904f47151f4ff5701298. The three owner screenshots are present in the worktree. I am reproducing all reported behavior against a production build in Chromium and WebKit before editing.

Starting #1132 on `job/editreg-1132`, based on production/dev SHA `570e084c8691a76b9bec904f47151f4ff5701298`. The three owner screenshots are present in the worktree. I am reproducing all reported behavior against a production build in Chromium and WebKit before editing.
Author
Owner

Finding: the reported Note route can use the standalone Markdown editor after its collaboration room is refused. NoteView.svelte injects noteSlashItems({ draw: ... }) only through liveNoteExtensions; Editor.svelte builds only the default calternalExtensions list. That fallback list cannot match /draw or /sketch, so the menu says “No blocks.” I am adding a host-provided action path to the standalone editor and will keep the slash action functional there.

History finding: git log -S'Not live: changes save when you pause' finds only the original addition in ceb70c6f6. c7dc7e408 hid the steady “Live” label but explicitly kept “not live” visible; 73aa4af2c moved the status into a fixed 40 px slot. The exact fallback label was not removed, so I will remove that visible fallback line without describing it as newly introduced by the 7c merges.

Finding: the reported Note route can use the standalone Markdown editor after its collaboration room is refused. `NoteView.svelte` injects `noteSlashItems({ draw: ... })` only through `liveNoteExtensions`; `Editor.svelte` builds only the default `calternalExtensions` list. That fallback list cannot match `/draw` or `/sketch`, so the menu says “No blocks.” I am adding a host-provided action path to the standalone editor and will keep the slash action functional there. History finding: `git log -S'Not live: changes save when you pause'` finds only the original addition in `ceb70c6f6`. `c7dc7e408` hid the steady “Live” label but explicitly kept “not live” visible; `73aa4af2c` moved the status into a fixed 40 px slot. The exact fallback label was not removed, so I will remove that visible fallback line without describing it as newly introduced by the 7c merges.
Author
Owner

Baseline reproduction on the local production build from 570e084c8, with macOS-rendered Chromium and WebKit:

  • The refused-room Note fallback opens the slash list for both /draw and /sketch, but the list has no options in either engine.
  • The visible “Not live: changes save when you pause” line appears in both engines.
  • Journal Composer /draw and /sketch each open Draw in both engines.
  • A single block selection on a live Note keeps the same editor DOM and URL in both engines. I have not reproduced the reported reload on this clean Note yet; the focused e2e guard checks the editor identity, document token, URL, and history.

Root cause found for Draw: commit 0949ee4a7 renamed the injected live Note action to draw and the Composer command handles both aliases, but the standalone Markdown editor API has no host-owned slash-item input. NoteView’s refused-room fallback mounts that editor with the default menu, so it has no Draw action. I am adding the smallest optional editor API field and wiring this fallback to the existing DrawSheet.

Root cause found for the status line: git log -S'Not live: changes save when you pause' finds the original addition and no later removal. The later status change hid only Live and kept the fallback label; a later layout change moved the status row. The text was not newly reintroduced by those merges.

Baseline reproduction on the local production build from 570e084c8, with macOS-rendered Chromium and WebKit: - The refused-room Note fallback opens the slash list for both `/draw` and `/sketch`, but the list has no options in either engine. - The visible “Not live: changes save when you pause” line appears in both engines. - Journal Composer `/draw` and `/sketch` each open Draw in both engines. - A single block selection on a live Note keeps the same editor DOM and URL in both engines. I have not reproduced the reported reload on this clean Note yet; the focused e2e guard checks the editor identity, document token, URL, and history. Root cause found for Draw: commit 0949ee4a7 renamed the injected live Note action to `draw` and the Composer command handles both aliases, but the standalone Markdown editor API has no host-owned slash-item input. NoteView’s refused-room fallback mounts that editor with the default menu, so it has no Draw action. I am adding the smallest optional editor API field and wiring this fallback to the existing DrawSheet. Root cause found for the status line: `git log -S'Not live: changes save when you pause'` finds the original addition and no later removal. The later status change hid only `Live` and kept the fallback label; a later layout change moved the status row. The text was not newly reintroduced by those merges.
Author
Owner

Draw fallback fix committed on job/editreg-1132: c2896ef73.

The standalone editor now accepts extra host slash actions and appends them to its shared command list. The refused-room Note fallback uses the existing DrawSheet and inserts a stable Drawing link through its ETag-backed save path, with Undo. The API change is additive: existing editor callers keep the shared default list.

Verification: packages/editor check passed with 0 errors and 0 warnings; full editor tests passed (21 files, 435 tests); the production-build e2e passed for /draw and /sketch in Chromium and WebKit. Screenshots are in artifacts/editreg-1132/ and are not committed.

Draw fallback fix committed on `job/editreg-1132`: `c2896ef73`. The standalone editor now accepts extra host slash actions and appends them to its shared command list. The refused-room Note fallback uses the existing DrawSheet and inserts a stable Drawing link through its ETag-backed save path, with Undo. The API change is additive: existing editor callers keep the shared default list. Verification: `packages/editor` check passed with 0 errors and 0 warnings; full editor tests passed (21 files, 435 tests); the production-build e2e passed for `/draw` and `/sketch` in Chromium and WebKit. Screenshots are in `artifacts/editreg-1132/` and are not committed.
Author
Owner

Orchestrator note: c2896ef73 and c894baaef ship to production now. Item 2 (block selection reloads) is still open. Also investigate WHY the owner's Notes and Journal entries land in the refused-room Markdown fallback at all (that is why /draw broke and why "Not live" appeared). Read production-shaped notes: which construct makes the Markdown bridge refuse the live room? Report the refusal reasons with counts (read-only aggregate, no note content) and fix the bridge so ordinary notes get the live room.

Orchestrator note: c2896ef73 and c894baaef ship to production now. Item 2 (block selection reloads) is still open. Also investigate WHY the owner's Notes and Journal entries land in the refused-room Markdown fallback at all (that is why /draw broke and why "Not live" appeared). Read production-shaped notes: which construct makes the Markdown bridge refuse the live room? Report the refusal reasons with counts (read-only aggregate, no note content) and fix the bridge so ordinary notes get the live room.
Author
Owner

Block-selection check: the production repro now selects the /draw paragraph shown in the owner screenshots. In Chromium and WebKit, the block enters selection state while the same .ProseMirror node remains mounted; the document token, URL, and History API count are unchanged after two animation frames and the settling interval. Source tracing found selection updates local Svelte state and a metadata-only ProseMirror decoration; the desktop callback does not navigate. I added this exact paragraph as the e2e regression target in 5138735b5.

Block-selection check: the production repro now selects the `/draw` paragraph shown in the owner screenshots. In Chromium and WebKit, the block enters selection state while the same `.ProseMirror` node remains mounted; the document token, URL, and History API count are unchanged after two animation frames and the settling interval. Source tracing found selection updates local Svelte state and a metadata-only ProseMirror decoration; the desktop callback does not navigate. I added this exact paragraph as the e2e regression target in 5138735b5.
Author
Owner

Follow-up for #1132: I also opened the same /draw Note through the refused-room fallback shown in the screenshots, clicked its block, then waited 750 ms plus two animation frames. Chromium and WebKit kept the same .ProseMirror node, document token, URL, and History API count. I added this fallback stability check in d7681c739. The reported reload is still not reproducible from the owner-shaped Note state, so I have no source-level navigation/invalidation to remove without guessing.

Follow-up for #1132: I also opened the same `/draw` Note through the refused-room fallback shown in the screenshots, clicked its block, then waited 750 ms plus two animation frames. Chromium and WebKit kept the same `.ProseMirror` node, document token, URL, and History API count. I added this fallback stability check in d7681c739. The reported reload is still not reproducible from the owner-shaped Note state, so I have no source-level navigation/invalidation to remove without guessing.
Author
Owner

#1132 hotfix report

READY FOR HOTFIX: no. The Draw regression and fallback status line are fixed. The reported block-selection reload remains unresolved because it does not reproduce in the production build described below.

Root causes and changes

  • Draw in the refused-room Note fallback: the shared editor had no way for a host to append slash actions. The live Note and Composer had their host action; standalone Markdown did not. EditorProps.slashItems now appends host actions to the shared list, and NoteView supplies the same Draw action and hidden /sketch alias. Choosing Draw opens the existing Draw sheet and keeps its saved path, fallback save, and Undo flow.
  • “Not live: changes save when you pause”: the fallback branch still returned this label, and the status row rendered it. git log -S finds the text in the original NoteView implementation (ceb70c6f6); it was not added by a recent merge. The fallback branch now returns no label. Read-only and offline states remain visible.
  • Block selection reload: I could not find a navigation or invalidation call in the selection path. In production Chromium and WebKit, selecting the owner-shaped /draw paragraph in a live Note keeps the same .ProseMirror node, document token, URL, and History API count. Clicking that block in the refused-room fallback also keeps the same editor node and URL. Both checks wait 750 ms and two animation frames. No speculative navigation guard was added. The owner's reported reload still needs a trigger that reproduces it.

Verification

Production build: Compressed 883 static variants; saved 20852528 bytes.

cargo fmt --check exited 0 with no output. No Rust files changed, so Rust clippy and tests were not run.

perf-lint: PASS; 0 violations; 21977 scoped exceptions
svelte-check found 0 errors and 4 warnings in 3 files
svelte-check found 0 errors and 0 warnings
Test Files  21 passed (21)
      Tests  435 passed (435)
 Test Files  1 passed (1)
      Tests  21 passed (21)
PASS #1132 production regressions in Chromium and WebKit; screenshots: /home/kayg/Developer/calternal-wt/editreg-1132/artifacts/editreg-1132
Removed 8626 files, 7.2GiB total

The four web warnings are in AttachmentDeck.svelte, AgendaList.svelte, and routes/notes/+page.svelte; there are no Svelte errors. The full E2E passes /draw and /sketch in fallback Notes and Composer, checks block stability in live and fallback Notes, and checks the removed status line in both engines. Mac-rendered screenshots cover 1440 dark for both engines and 390/820/1440 in light and dark. They are attached to this issue comment.

Files and commits

Changed for #1132: packages/editor/src/source.ts, packages/editor/src/Editor.svelte, packages/editor/src/Editor.svelte.test.ts, apps/web/src/lib/notes/NoteView.svelte, apps/web/e2e/editreg-1132.mjs, and contracts/perf/exceptions.json (12 exact NoteView exception hashes refreshed after the Svelte source change).

The required origin/dev merge is included. Final branch: job/editreg-1132; HEAD: bc1244f8ae3ba90801bfccbf72ca9ea638874e32. No push or deploy was done. Web build output was removed and cargo clean completed.

Decisions and remaining UX gap

The host slash-action API is optional and additive, so existing editor callers keep the shared command list unchanged. I left block-selection production code unchanged because the reported reload did not reproduce and the traced selection path does not navigate. UX gap left: the owner's block-selection reload remains unverified and is why this branch is not marked ready for the hotfix.

#1132 hotfix report **READY FOR HOTFIX: no.** The Draw regression and fallback status line are fixed. The reported block-selection reload remains unresolved because it does not reproduce in the production build described below. ## Root causes and changes - **Draw in the refused-room Note fallback:** the shared editor had no way for a host to append slash actions. The live Note and Composer had their host action; standalone Markdown did not. `EditorProps.slashItems` now appends host actions to the shared list, and NoteView supplies the same Draw action and hidden `/sketch` alias. Choosing Draw opens the existing Draw sheet and keeps its saved path, fallback save, and Undo flow. - **“Not live: changes save when you pause”:** the fallback branch still returned this label, and the status row rendered it. `git log -S` finds the text in the original NoteView implementation (`ceb70c6f6`); it was not added by a recent merge. The fallback branch now returns no label. Read-only and offline states remain visible. - **Block selection reload:** I could not find a navigation or invalidation call in the selection path. In production Chromium and WebKit, selecting the owner-shaped `/draw` paragraph in a live Note keeps the same `.ProseMirror` node, document token, URL, and History API count. Clicking that block in the refused-room fallback also keeps the same editor node and URL. Both checks wait 750 ms and two animation frames. No speculative navigation guard was added. The owner's reported reload still needs a trigger that reproduces it. ## Verification Production build: `Compressed 883 static variants; saved 20852528 bytes.` `cargo fmt --check` exited 0 with no output. No Rust files changed, so Rust clippy and tests were not run. ```text perf-lint: PASS; 0 violations; 21977 scoped exceptions svelte-check found 0 errors and 4 warnings in 3 files svelte-check found 0 errors and 0 warnings Test Files 21 passed (21) Tests 435 passed (435) Test Files 1 passed (1) Tests 21 passed (21) PASS #1132 production regressions in Chromium and WebKit; screenshots: /home/kayg/Developer/calternal-wt/editreg-1132/artifacts/editreg-1132 Removed 8626 files, 7.2GiB total ``` The four web warnings are in `AttachmentDeck.svelte`, `AgendaList.svelte`, and `routes/notes/+page.svelte`; there are no Svelte errors. The full E2E passes `/draw` and `/sketch` in fallback Notes and Composer, checks block stability in live and fallback Notes, and checks the removed status line in both engines. Mac-rendered screenshots cover 1440 dark for both engines and 390/820/1440 in light and dark. They are attached to this issue comment. ## Files and commits Changed for #1132: `packages/editor/src/source.ts`, `packages/editor/src/Editor.svelte`, `packages/editor/src/Editor.svelte.test.ts`, `apps/web/src/lib/notes/NoteView.svelte`, `apps/web/e2e/editreg-1132.mjs`, and `contracts/perf/exceptions.json` (12 exact NoteView exception hashes refreshed after the Svelte source change). The required `origin/dev` merge is included. Final branch: `job/editreg-1132`; HEAD: `bc1244f8ae3ba90801bfccbf72ca9ea638874e32`. No push or deploy was done. Web build output was removed and `cargo clean` completed. ## Decisions and remaining UX gap The host slash-action API is optional and additive, so existing editor callers keep the shared command list unchanged. I left block-selection production code unchanged because the reported reload did not reproduce and the traced selection path does not navigate. **UX gap left:** the owner's block-selection reload remains unverified and is why this branch is not marked ready for the hotfix.
Author
Owner

#1132 investigation finding: the refused-room case is identity-based. Notes indexing assigns path:<Home-relative path> when Markdown has no calternal-id; durable room history returns 409 for path: IDs because they do not survive moves (DESIGN §§17, 33, 61). The Markdown bridge’s tolerant parser does not reject unsupported constructs; it retains them as literal text.

I added a per-User backfill for legacy Notes. It assigns UUID identities with the checked writer, preserves frontmatter and Markdown, reindexes the Note, covers both .md and .markdown, and keeps old path: links resolving to the current indexed path. The regression fixture had 2 path-keyed Notes before the backfill and 2 stable IDs after it; both open through the live-room read path. The migration logs only aggregate counts, with no Note paths or content.

This worktree has no production Home mounted, so I cannot read the owner’s production refusal counts. The code evidence establishes 0 parser-level Markdown refusals and the path: identity refusal reason; it does not establish which exact Journal cards in the owner screenshots hit that path.

#1132 investigation finding: the refused-room case is identity-based. Notes indexing assigns `path:<Home-relative path>` when Markdown has no `calternal-id`; durable room history returns 409 for `path:` IDs because they do not survive moves (DESIGN §§17, 33, 61). The Markdown bridge’s tolerant parser does not reject unsupported constructs; it retains them as literal text. I added a per-User backfill for legacy Notes. It assigns UUID identities with the checked writer, preserves frontmatter and Markdown, reindexes the Note, covers both `.md` and `.markdown`, and keeps old `path:` links resolving to the current indexed path. The regression fixture had 2 path-keyed Notes before the backfill and 2 stable IDs after it; both open through the live-room read path. The migration logs only aggregate counts, with no Note paths or content. This worktree has no production Home mounted, so I cannot read the owner’s production refusal counts. The code evidence establishes 0 parser-level Markdown refusals and the `path:` identity refusal reason; it does not establish which exact Journal cards in the owner screenshots hit that path.
Author
Owner

#1132 hotfix report

READY FOR HOTFIX: no. Draw is available in the refused-room Note editor and Composer. The fallback status line is removed. The reported block-selection reload still does not reproduce in the real production build, so that reported failure remains open.

Root causes and changes

  • The standalone shared editor could not accept host slash actions. EditorProps.slashItems is now optional and additive. NoteView passes the existing Draw action in the refused-room editor, including the hidden /sketch alias. The existing Draw sheet saves to Home and keeps Undo. The production E2E opens Draw in the Notes fallback and Log-mode Composer in Chromium and WebKit.
  • The fallback branch returned the “Not live: changes save when you pause” status. git log -S traces it to the original NoteView implementation (ceb70c6f6), not a recent merge. The fallback branch now returns no status. Read-only and offline states remain visible.
  • Production Chromium and WebKit checks selected the reported /draw block in both live and refused-room Notes. The .ProseMirror node, document token, URL and History API count stayed unchanged after 750 ms and two animation frames. No navigation or invalidation call appeared in the selection path. I did not add a speculative selection guard.
  • The live-room refusal is identity-based. store::index_note_projection uses path:<Home-relative path> when a Markdown Note has no calternal-id; durable room history rejects path: identities because they change on rename. The tolerant Markdown bridge does not reject unsupported constructs; it retains them as literal text. The new per-User backfill gives legacy Notes/ files permanent UUID IDs, reindexes them, and preserves their frontmatter and body. It covers .md and .markdown, repairs explicit path: frontmatter IDs, continues past a damaged file, and leaves that file byte-identical for repair. The User lock is held for one checked file write and its Index commit, then released. Aggregate logs do not include Note paths or content. Legacy path: links still resolve to the current indexed path.
  • The owner’s production Home is not mounted in this worktree. Production refusal counts are therefore unavailable. The regression fixtures had 2 path-keyed Notes before migration and 2 live-room IDs after it. Code inspection found 0 parser-level Markdown refusals.

UX gaps closed

  • Draw opens from /draw and /sketch in Notes fallback and Composer. The fallback status row no longer implies a save delay.
  • Backfilled Notes preserve their Markdown body, existing YAML properties and stable room identity. Old path links resolve while the Note remains at that path.
  • E2E checks editor and route stability for block selection in Chromium and WebKit. Screenshot evidence is attached to the original report comment (26348), including macOS rendering, 390/820/1440 widths, light/dark, and 1440 dark in both engines.

UX gaps left

  • The owner-reported block-selection reload remains unverified. A production trigger is needed before a safe code fix can be made.
  • Exact owner production refusal counts cannot be read without the production Home. The migration logs aggregate scanned, missing, assigned, repaired and unresolved counts when it runs.
  • The 656-Note local profile measured a one-time migration p95 of 178.0 s before lock scoping. The lock now releases between files, but the 656-Note quick rerun hit the shared Index busy limit during fixture setup, so it produced no post-change worst-case timing.

Verification

Production build: Compressed 883 static variants; saved 20852528 bytes.

apps/web bun run check
perf-lint: PASS; 0 violations; 21977 scoped exceptions
svelte-check found 0 errors and 4 warnings in 3 files

packages/editor bun run check
svelte-check found 0 errors and 0 warnings

packages/editor bun run test -- --maxWorkers=2
Test Files  21 passed (21)
      Tests  435 passed (435)

bunx vitest run src/Editor.svelte.test.ts --maxWorkers=2
 Test Files  1 passed (1)
      Tests  21 passed (21)

PASS #1132 production regressions in Chromium and WebKit; screenshots: /home/kayg/Developer/calternal-wt/editreg-1132/artifacts/editreg-1132

cargo fmt --check
(no output; exit 0)

cargo clippy -p calternal-plugin-notes --all-targets -- -D warnings
Finished `dev` profile [unoptimized + debuginfo] target(s) in 41.03s

cargo test -p calternal-plugin-notes
thread 'tests::seven_hundred_notes_reconcile_without_feedback' (1549246) panicked at crates/plugins/notes/src/lib.rs:9129:59:
called `Result::unwrap()` on an `Err` value: ApiError(503, ErrorEnvelope { error: ApiError { code: ServiceUnavailable, message: "Index is busy; retry shortly", details: None } }, true)
test result: FAILED. 284 passed; 1 failed; 3 ignored; 0 measured; 0 filtered out; finished in 326.68s
error: test failed, to rerun pass `-p calternal-plugin-notes --lib`

cargo clean
Removed 9720 files, 6.5GiB total

The full Rust crate suite passed once earlier in this job. Its final rerun hit the Index busy limit in the 700-Note reconciliation stress test while the host load was high. I did not repeat the full suite.

The local pre-lock-scope profile had no prior baseline in docs/perf/baseline.json. Host load was [15.01, 20.85, 24.62] before and [24.01, 22.78, 21.33] after.

Home size Migration latency p50 / p95 Cargo/test process-tree CPU p50 / p95 Peak RSS p50 / p95
100 Notes, 5 runs 16.4 / 23.3 s 2.63 / 2.74 s 183.3 / 184.1 MB
656 Notes, 3 runs 122.5 / 178.0 s 12.93 / 14.65 s 183.3 / 183.5 MB

The final one-run 100-Note profile measured 30.2 s. The 656-Note profile stopped during fixture setup with the same Index is busy; retry shortly error. These are local first measurements, not a comparison with an existing baseline.

Files and commits

UI and E2E: packages/editor/src/source.ts, packages/editor/src/Editor.svelte, packages/editor/src/Editor.svelte.test.ts, apps/web/src/lib/notes/NoteView.svelte, apps/web/e2e/editreg-1132.mjs, and contracts/perf/exceptions.json.

Identity backfill and profile: crates/plugins/notes/src/lib.rs, crates/plugins/notes/src/store.rs, and bench/notes-stable-id-1132.py.

Branch: job/editreg-1132. Final HEAD: 6bf7074e3e53f4e6a943bb273dd4834d2becc4e4. The required origin/dev merge (8db65896e) is included. No push or deploy was done. Build output was removed and cargo clean was run after verification.

Decisions not specified in DESIGN.md

  • Reuse the existing per-User migration ledger, whose table name refers to Daily Notes, to avoid adding a new schema migration for this Note metadata backfill.
  • Treat .markdown as a migration input because note_path already accepts that Markdown extension.
  • Keep legacy path: selectors resolving the current exact indexed path for compatibility. New links use permanent calternal-id values.
  • Release the User lock between Notes and write the per-User completion marker only after the Index contains no Notes/ path IDs. This keeps normal writes available during the background pass.

For the merge round

  • bash tests/adversarial/run.sh must attack a real local server for hostile paths, cross-User access, authorization and Notes path lookup.
  • cargo test -p calternal-plugin-notes must pass on the combined branch. The last run here hit the host Index busy limit in the 700-Note stress test.
#1132 hotfix report **READY FOR HOTFIX: no.** Draw is available in the refused-room Note editor and Composer. The fallback status line is removed. The reported block-selection reload still does not reproduce in the real production build, so that reported failure remains open. ## Root causes and changes - The standalone shared editor could not accept host slash actions. `EditorProps.slashItems` is now optional and additive. NoteView passes the existing Draw action in the refused-room editor, including the hidden `/sketch` alias. The existing Draw sheet saves to Home and keeps Undo. The production E2E opens Draw in the Notes fallback and Log-mode Composer in Chromium and WebKit. - The fallback branch returned the “Not live: changes save when you pause” status. `git log -S` traces it to the original NoteView implementation (`ceb70c6f6`), not a recent merge. The fallback branch now returns no status. Read-only and offline states remain visible. - Production Chromium and WebKit checks selected the reported `/draw` block in both live and refused-room Notes. The `.ProseMirror` node, document token, URL and History API count stayed unchanged after 750 ms and two animation frames. No navigation or invalidation call appeared in the selection path. I did not add a speculative selection guard. - The live-room refusal is identity-based. `store::index_note_projection` uses `path:<Home-relative path>` when a Markdown Note has no `calternal-id`; durable room history rejects `path:` identities because they change on rename. The tolerant Markdown bridge does not reject unsupported constructs; it retains them as literal text. The new per-User backfill gives legacy `Notes/` files permanent UUID IDs, reindexes them, and preserves their frontmatter and body. It covers `.md` and `.markdown`, repairs explicit `path:` frontmatter IDs, continues past a damaged file, and leaves that file byte-identical for repair. The User lock is held for one checked file write and its Index commit, then released. Aggregate logs do not include Note paths or content. Legacy `path:` links still resolve to the current indexed path. - The owner’s production Home is not mounted in this worktree. Production refusal counts are therefore unavailable. The regression fixtures had 2 path-keyed Notes before migration and 2 live-room IDs after it. Code inspection found 0 parser-level Markdown refusals. ## UX gaps closed - Draw opens from `/draw` and `/sketch` in Notes fallback and Composer. The fallback status row no longer implies a save delay. - Backfilled Notes preserve their Markdown body, existing YAML properties and stable room identity. Old path links resolve while the Note remains at that path. - E2E checks editor and route stability for block selection in Chromium and WebKit. Screenshot evidence is attached to the original report comment (26348), including macOS rendering, 390/820/1440 widths, light/dark, and 1440 dark in both engines. ## UX gaps left - The owner-reported block-selection reload remains unverified. A production trigger is needed before a safe code fix can be made. - Exact owner production refusal counts cannot be read without the production Home. The migration logs aggregate scanned, missing, assigned, repaired and unresolved counts when it runs. - The 656-Note local profile measured a one-time migration p95 of 178.0 s before lock scoping. The lock now releases between files, but the 656-Note quick rerun hit the shared Index busy limit during fixture setup, so it produced no post-change worst-case timing. ## Verification Production build: `Compressed 883 static variants; saved 20852528 bytes.` ```text apps/web bun run check perf-lint: PASS; 0 violations; 21977 scoped exceptions svelte-check found 0 errors and 4 warnings in 3 files packages/editor bun run check svelte-check found 0 errors and 0 warnings packages/editor bun run test -- --maxWorkers=2 Test Files 21 passed (21) Tests 435 passed (435) bunx vitest run src/Editor.svelte.test.ts --maxWorkers=2 Test Files 1 passed (1) Tests 21 passed (21) PASS #1132 production regressions in Chromium and WebKit; screenshots: /home/kayg/Developer/calternal-wt/editreg-1132/artifacts/editreg-1132 cargo fmt --check (no output; exit 0) cargo clippy -p calternal-plugin-notes --all-targets -- -D warnings Finished `dev` profile [unoptimized + debuginfo] target(s) in 41.03s cargo test -p calternal-plugin-notes thread 'tests::seven_hundred_notes_reconcile_without_feedback' (1549246) panicked at crates/plugins/notes/src/lib.rs:9129:59: called `Result::unwrap()` on an `Err` value: ApiError(503, ErrorEnvelope { error: ApiError { code: ServiceUnavailable, message: "Index is busy; retry shortly", details: None } }, true) test result: FAILED. 284 passed; 1 failed; 3 ignored; 0 measured; 0 filtered out; finished in 326.68s error: test failed, to rerun pass `-p calternal-plugin-notes --lib` cargo clean Removed 9720 files, 6.5GiB total ``` The full Rust crate suite passed once earlier in this job. Its final rerun hit the Index busy limit in the 700-Note reconciliation stress test while the host load was high. I did not repeat the full suite. The local pre-lock-scope profile had no prior baseline in `docs/perf/baseline.json`. Host load was `[15.01, 20.85, 24.62]` before and `[24.01, 22.78, 21.33]` after. | Home size | Migration latency p50 / p95 | Cargo/test process-tree CPU p50 / p95 | Peak RSS p50 / p95 | | --- | ---: | ---: | ---: | | 100 Notes, 5 runs | 16.4 / 23.3 s | 2.63 / 2.74 s | 183.3 / 184.1 MB | | 656 Notes, 3 runs | 122.5 / 178.0 s | 12.93 / 14.65 s | 183.3 / 183.5 MB | The final one-run 100-Note profile measured 30.2 s. The 656-Note profile stopped during fixture setup with the same `Index is busy; retry shortly` error. These are local first measurements, not a comparison with an existing baseline. ## Files and commits UI and E2E: `packages/editor/src/source.ts`, `packages/editor/src/Editor.svelte`, `packages/editor/src/Editor.svelte.test.ts`, `apps/web/src/lib/notes/NoteView.svelte`, `apps/web/e2e/editreg-1132.mjs`, and `contracts/perf/exceptions.json`. Identity backfill and profile: `crates/plugins/notes/src/lib.rs`, `crates/plugins/notes/src/store.rs`, and `bench/notes-stable-id-1132.py`. Branch: `job/editreg-1132`. Final HEAD: `6bf7074e3e53f4e6a943bb273dd4834d2becc4e4`. The required `origin/dev` merge (`8db65896e`) is included. No push or deploy was done. Build output was removed and `cargo clean` was run after verification. ## Decisions not specified in DESIGN.md - Reuse the existing per-User migration ledger, whose table name refers to Daily Notes, to avoid adding a new schema migration for this Note metadata backfill. - Treat `.markdown` as a migration input because `note_path` already accepts that Markdown extension. - Keep legacy `path:` selectors resolving the current exact indexed path for compatibility. New links use permanent `calternal-id` values. - Release the User lock between Notes and write the per-User completion marker only after the Index contains no `Notes/` path IDs. This keeps normal writes available during the background pass. ## For the merge round - `bash tests/adversarial/run.sh` must attack a real local server for hostile paths, cross-User access, authorization and Notes path lookup. - `cargo test -p calternal-plugin-notes` must pass on the combined branch. The last run here hit the host Index busy limit in the 700-Note stress test.
Sign in to join this conversation.
No labels
No milestone
No project
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#1132
No description provided.