Notes view lists Money files and daily notes; show only User notes (plugin-owned Markdown opens from Files only) #606

Open
opened 2026-10-01 09:38:27 +00:00 by kayg · 30 comments
Owner

Owner report (2026-10-01)

"Money files shouldn't show up in the notes view. Any markdown file including money and daily notes should be opened from the files view in the markdown block editor just fine, but they shouldn't be openable from the notes view."
Fix (now): the Notes view lists only User notes. It excludes Money budget files (Money/), daily notes / Log day files, and other plugin-owned Markdown (Tasks storage, settings files…), using the owning plugin's declared paths (one shared "owned paths" registry, not a hard-coded list per view). Files → open any Markdown file (including Money and daily notes) in the block editor still works. Search keeps its existing scoping rules.
Follow-up (separate grill, #… Navigator): the owner wants the Notes view renamed "Navigator" and redesigned (grill pending).
Test: an e2e where a User with a Money budget and daily notes opens Notes → no Money or daily-note files are listed; Files → Money/… .md opens in the editor.

## Owner report (2026-10-01) "Money files shouldn't show up in the notes view. Any markdown file including money and daily notes should be opened from the files view in the markdown block editor just fine, but they shouldn't be openable from the notes view." **Fix (now):** the Notes view lists only User notes. It excludes Money budget files (`Money/`), daily notes / Log day files, and other plugin-owned Markdown (Tasks storage, settings files…), using the owning plugin's declared paths (one shared "owned paths" registry, not a hard-coded list per view). Files → open any Markdown file (including Money and daily notes) in the block editor still works. Search keeps its existing scoping rules. **Follow-up (separate grill, #… Navigator):** the owner wants the Notes view renamed "Navigator" and redesigned (grill pending). **Test:** an e2e where a User with a Money budget and daily notes opens Notes → no Money or daily-note files are listed; Files → Money/… .md opens in the editor.
Author
Owner

Starting #606 on job/notesfilter-606, based on 1af8ead262daf0a4ad22a60564dc75bab0005cf4 (the worktree is 10 commits behind origin/dev; I will merge origin/dev once before final gates). I am tracing the Notes list and the Plugin declarations to implement the shared owned-path registry and preserve Files editor access.

Starting #606 on `job/notesfilter-606`, based on `1af8ead262daf0a4ad22a60564dc75bab0005cf4` (the worktree is 10 commits behind `origin/dev`; I will merge `origin/dev` once before final gates). I am tracing the Notes list and the Plugin declarations to implement the shared owned-path registry and preserve Files editor access.
Author
Owner

Finding: the Notes list handler in crates/plugins/notes/src/lib.rs selects directly from note_items and applies pagination without path ownership or Daily note filtering. GET /api/v1/notes/{id} resolves the same index by ID, so hiding rows alone would still leave indexed Plugin Markdown openable by a Notes link. The existing shared calternal_notes_core::is_daily_note_path predicate can classify Daily notes; the Plugin registry currently has no owned-path declaration.

Finding: the Notes list handler in `crates/plugins/notes/src/lib.rs` selects directly from `note_items` and applies pagination without path ownership or Daily note filtering. `GET /api/v1/notes/{id}` resolves the same index by ID, so hiding rows alone would still leave indexed Plugin Markdown openable by a Notes link. The existing shared `calternal_notes_core::is_daily_note_path` predicate can classify Daily notes; the Plugin registry currently has no owned-path declaration.
Author
Owner

Files-origin editor implementation is underway. /f/<item-id>/edit resolves the stable Files ID before requesting the Markdown view, and Notes GET /{id} continues to return 404 for Plugin-owned paths. Files-origin anchors and heading links retain the item ID; Daily files bypass the gate only in this Files flow. The Files resolver accepts visible .md and .markdown paths under the authenticated User Home and uses calternal-fs via store::note_path.

Files-origin editor implementation is underway. `/f/<item-id>/edit` resolves the stable Files ID before requesting the Markdown view, and Notes `GET /{id}` continues to return 404 for Plugin-owned paths. Files-origin anchors and heading links retain the item ID; Daily files bypass the gate only in this Files flow. The Files resolver accepts visible `.md` and `.markdown` paths under the authenticated User Home and uses `calternal-fs` via `store::note_path`.
Author
Owner

E2E finding: the first bun e2e/notes.mjs invocation failed at EOF because the new #606 flow was missing its function-closing brace and declared listText inside a narrower viewport block. I fixed the scope/brace and verified node --check apps/web/e2e/notes.mjs and node --check bench/notes-filter-606.mjs both pass. The real-server browser run is next.

E2E finding: the first `bun e2e/notes.mjs` invocation failed at EOF because the new #606 flow was missing its function-closing brace and declared `listText` inside a narrower viewport block. I fixed the scope/brace and verified `node --check apps/web/e2e/notes.mjs` and `node --check bench/notes-filter-606.mjs` both pass. The real-server browser run is next.
Author
Owner

Finding during screenshot review: the existing E2E theme helper targeted #app, but the current shell mounts #route-content; local palette updates were then overwritten by the hydrated User setting. The helper now targets the live route root. The #606 screenshot flow saves the appearance through the API, reloads each target route, and reopens Recent Quick Look before capture. The real-server feature flow also verifies that a Money budget edit is readable from the Files Markdown endpoint. The light and dark screenshot sweep is in progress at 390, 820 and 1440 px.

Finding during screenshot review: the existing E2E theme helper targeted `#app`, but the current shell mounts `#route-content`; local palette updates were then overwritten by the hydrated User setting. The helper now targets the live route root. The #606 screenshot flow saves the appearance through the API, reloads each target route, and reopens Recent Quick Look before capture. The real-server feature flow also verifies that a Money budget edit is readable from the Files Markdown endpoint. The light and dark screenshot sweep is in progress at 390, 820 and 1440 px.
Author
Owner

Real-server E2E finding: the focused #606 flow passed, and it produced the full 36-image screenshot matrix. I also ran the complete Notes E2E. Chromium initially blocked same-origin loopback WebSockets with net::ERR_BLOCKED_BY_LOCAL_NETWORK_ACCESS_CHECKS; the test now disables that check only for its local browser fixture, and a probe confirmed Money and Atlas rooms connect while the Daily room retains its server-side 409 fallback. The broader suite then reached its existing two-tab collaboration case but failed its unchanged block-anchor assertion: after the second tab typed Continued from another tab., the body did not contain that paragraph’s ^block-id within 15 seconds. I left the expectation unchanged; this unrelated anchor persistence finding remains open for review.

Real-server E2E finding: the focused #606 flow passed, and it produced the full 36-image screenshot matrix. I also ran the complete Notes E2E. Chromium initially blocked same-origin loopback WebSockets with `net::ERR_BLOCKED_BY_LOCAL_NETWORK_ACCESS_CHECKS`; the test now disables that check only for its local browser fixture, and a probe confirmed Money and Atlas rooms connect while the Daily room retains its server-side 409 fallback. The broader suite then reached its existing two-tab collaboration case but failed its unchanged block-anchor assertion: after the second tab typed `Continued from another tab.`, the body did not contain that paragraph’s `^block-id` within 15 seconds. I left the expectation unchanged; this unrelated anchor persistence finding remains open for review.
Author
Owner

Benchmark setup finding: the first 10k User Markdown + 10k Money Files fixture indexed all 10,000 Money entries, but Notes returned zero rows after the 120-second index wait, so that run produced no latency or resource metrics. I am tracing the fixture-to-Notes indexing path and will rerun once the benchmark reports the Notes API status and index count.

Benchmark setup finding: the first 10k User Markdown + 10k Money Files fixture indexed all 10,000 Money entries, but Notes returned zero rows after the 120-second index wait, so that run produced no latency or resource metrics. I am tracing the fixture-to-Notes indexing path and will rerun once the benchmark reports the Notes API status and index count.
Author
Owner

Benchmark finding: a 1,000 User-note / 1,000 Money-file fixture showed Files indexing completed while the Notes projection still returned zero rows. The profile now waits for the Money Files index, calls the authenticated Notes reconcile endpoint, then verifies the last User Notes page before measurement. That setup produced 1,000 visible User notes and 1,000 indexed Money files in the diagnostic run. The 10,000-per-set local run is in progress; the perf VM is unreachable from this host.

Benchmark finding: a 1,000 User-note / 1,000 Money-file fixture showed Files indexing completed while the Notes projection still returned zero rows. The profile now waits for the Money Files index, calls the authenticated Notes reconcile endpoint, then verifies the last User Notes page before measurement. That setup produced 1,000 visible User notes and 1,000 indexed Money files in the diagnostic run. The 10,000-per-set local run is in progress; the perf VM is unreachable from this host.
Author
Owner

Benchmark setup finding: an authenticated Notes reconcile POST through Playwright's API request context returned 403, while the same route through the logged-in browser page returned 204. The profile now uses same-origin page fetch with an explicit timeout; a real-server run with 100 User notes and 100 Money files verified reconciliation and all 960 burst requests returned 200.

Benchmark setup finding: an authenticated Notes reconcile POST through Playwright's API request context returned 403, while the same route through the logged-in browser page returned 204. The profile now uses same-origin page fetch with an explicit timeout; a real-server run with 100 User notes and 100 Money files verified reconciliation and all 960 burst requests returned 200.
Author
Owner

Adversarial finding: ADVERSARIAL_API_ONLY=1 runs mcp_probe.py, but setup.mjs creates mcp-passwords.json only for MCP-only or cross-User-with-MCP runs. The probe exits with FileNotFoundError before its MCP checks. The runner continues to sidecar and Notes API probes. I will fix the setup flag for API-only runs and do one bounded rerun to complete the requested round.

Adversarial finding: `ADVERSARIAL_API_ONLY=1` runs `mcp_probe.py`, but `setup.mjs` creates `mcp-passwords.json` only for MCP-only or cross-User-with-MCP runs. The probe exits with `FileNotFoundError` before its MCP checks. The runner continues to sidecar and Notes API probes. I will fix the setup flag for API-only runs and do one bounded rerun to complete the requested round.
Author
Owner

#606 implementation report

Branch: job/notesfilter-606
HEAD: 6b88bd2942

Built

  • Notes now lists only User notes. The Notes API applies the shared Plugin-owned path registry and Daily-note exclusion before pagination.
  • Files and Recent can open any Markdown file in the shared block editor, including Money files and Daily notes. The editor uses the stable Files item ID and preserves heading/block anchors.
  • Added the real-server #606 E2E flow and the Notes filtering performance profile.

Commits:

  • 717d4c29b Filter Notes by declared plugin ownership
  • 80d7aec5a Open Files Markdown in the block editor
  • ae45b03ad Add Notes filtering benchmark profile
  • 6b88bd294 Document Notes page and path tests

Files changed:

  • Backend/API: crates/calternal-plugin/src/lib.rs, crates/calternal-server/src/system_plugin.rs, crates/plugins/money/src/lib.rs, crates/plugins/notes/src/lib.rs, crates/plugins/notes/src/store.rs, crates/plugins/photos/src/lib.rs, contracts/openapi.json, packages/api-client/src/generated.ts
  • Web/E2E: apps/web/e2e/harness.mjs, apps/web/e2e/notes.mjs, apps/web/src/lib/files/FilesBrowser.svelte, apps/web/src/lib/files/OpenMarkdownEditorAction.svelte, apps/web/src/lib/files/RecentView.svelte, apps/web/src/lib/notes/NoteEditorSurface.svelte, apps/web/src/lib/notes/NoteView.svelte, apps/web/src/lib/notes/api.ts, apps/web/src/lib/notes/editorHost.ts, apps/web/src/lib/notes/headingLinks.ts, apps/web/src/lib/notes/notes.test.ts, apps/web/src/lib/notes/paths.ts, apps/web/src/routes/f/[id]/edit/+page.svelte, apps/web/src/routes/notes/+page.svelte
  • Contracts/docs/probes/bench: contracts/actions.json, docs/DESIGN.md, docs/deep-links.md, docs/parity-matrix.md, tests/adversarial/attack.py, bench/notes-filter-606.mjs, bench/run.sh

Decisions

  • Files-origin editing uses /f//edit[#anchor]. This keeps the link stable when a file moves or is renamed. The route and link grammar are recorded in DESIGN §31 K5 and docs/deep-links.md.
  • Files-origin Daily notes use the shared fallback editor because the live Notes collaboration endpoint rejects Daily notes with 409. The Files open path still reads and writes through the existing server API.

Gates

Verbatim gate pass summary lines:

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

cargo clippy -p calternal-plugin --all-targets -- -D warnings
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 4.15s
cargo test -p calternal-plugin
test result: ok. 25 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 3.81s
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

cargo clippy -p calternal-plugin-notes --all-targets -- -D warnings
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 1.59s
cargo test -p calternal-plugin-notes
test result: ok. 163 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 50.97s
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 2.03s
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

cargo clippy -p calternal-plugin-money --all-targets -- -D warnings
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 1.06s
cargo test -p calternal-plugin-money
test result: ok. 24 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 4.94s
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

cargo clippy -p calternal-plugin-photos --all-targets -- -D warnings
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 2.51s
cargo test -p calternal-plugin-photos
test result: ok. 46 passed; 0 failed; 2 ignored; 0 measured; 0 filtered out; finished in 4.68s
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

cargo clippy -p calternal-server --all-targets -- -D warnings
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 41.12s
cargo test -p calternal-server
test result: ok. 107 passed; 0 failed; 3 ignored; 0 measured; 0 filtered out; finished in 10.86s

bun run check
User browser caches use userStorage; only documented device/public-link exceptions remain.
Text sizes and UI shape values use shared role tokens.
UI transitions and animation options use shared motion tokens or documented exceptions.
Loading svelte-check in workspace: /home/kayg/Developer/calternal-wt/notesfilter-606/apps/web
Getting Svelte diagnostics...
svelte-check found 0 errors and 0 warnings

bun run test
Test Files  148 passed (148)
Tests  1011 passed (1011)
Duration  89.93s

Performance

The baseline in docs/perf/baseline.json is notes.list p50 1.3 ms / p95 3.1 ms (50 successful samples).

Local debug-server run: 10,000 User Markdown files plus 10,000 Money Markdown files; 100 sequential reads and a 24-client / 960-request burst. The perf VM was unreachable, and the shared host load average was 21.42–22.35 before and 25.26–26.77 after. These results are not directly comparable to the Release baseline.

  • Average: p50 78.08 ms, p95 159.72 ms; CPU mean/peak 67.6% / 199.66%; RSS mean/peak 439,766,198 / 440,266,752 bytes.
  • Burst: p50 484.55 ms, p95 754.77 ms; 960/960 responses were 200; CPU mean/peak 131.01% / 410.1%; RSS mean/peak 442,815,345 / 445,022,208 bytes.

Adversarial and known gaps

  • The #606 Files Markdown resolver probes passed. The server stayed alive; the Search storm had 0 failures; the Files mkdir storm created 200 items with 0 errors; the rename race had 1 success with 0 errors.
  • The broader API round reported existing Tags/DAV status conflicts tracked by #566, #568 and #650. No expectations were changed; current evidence is in #568 and #566. SLOW results were on the shared host.
  • ADVERSARIAL_API_ONLY=1 did not prepare the MCP scoped-password fixture before calling mcp_probe.py. I filed the harness defect as #654; the sidecar and API probes continued.
  • The focused #606 E2E flow passed for six surfaces at 390, 820 and 1440 px in light and dark. The broader Notes E2E then failed at the existing live-collaboration block-anchor assertion after a second tab's remote edit. The expectation was left unchanged.
  • Screenshots are attached below. One duplicate Daily editor screenshot is also present from the earlier upload.

Visual evidence: six surfaces × three widths × two themes.

#606 implementation report Branch: job/notesfilter-606 HEAD: 6b88bd2942905e91496c7236a78f84c22288bea3 ## Built - Notes now lists only User notes. The Notes API applies the shared Plugin-owned path registry and Daily-note exclusion before pagination. - Files and Recent can open any Markdown file in the shared block editor, including Money files and Daily notes. The editor uses the stable Files item ID and preserves heading/block anchors. - Added the real-server #606 E2E flow and the Notes filtering performance profile. Commits: - 717d4c29b Filter Notes by declared plugin ownership - 80d7aec5a Open Files Markdown in the block editor - ae45b03ad Add Notes filtering benchmark profile - 6b88bd294 Document Notes page and path tests Files changed: - Backend/API: crates/calternal-plugin/src/lib.rs, crates/calternal-server/src/system_plugin.rs, crates/plugins/money/src/lib.rs, crates/plugins/notes/src/lib.rs, crates/plugins/notes/src/store.rs, crates/plugins/photos/src/lib.rs, contracts/openapi.json, packages/api-client/src/generated.ts - Web/E2E: apps/web/e2e/harness.mjs, apps/web/e2e/notes.mjs, apps/web/src/lib/files/FilesBrowser.svelte, apps/web/src/lib/files/OpenMarkdownEditorAction.svelte, apps/web/src/lib/files/RecentView.svelte, apps/web/src/lib/notes/NoteEditorSurface.svelte, apps/web/src/lib/notes/NoteView.svelte, apps/web/src/lib/notes/api.ts, apps/web/src/lib/notes/editorHost.ts, apps/web/src/lib/notes/headingLinks.ts, apps/web/src/lib/notes/notes.test.ts, apps/web/src/lib/notes/paths.ts, apps/web/src/routes/f/[id]/edit/+page.svelte, apps/web/src/routes/notes/+page.svelte - Contracts/docs/probes/bench: contracts/actions.json, docs/DESIGN.md, docs/deep-links.md, docs/parity-matrix.md, tests/adversarial/attack.py, bench/notes-filter-606.mjs, bench/run.sh ## Decisions - Files-origin editing uses /f/<item-id>/edit[#anchor]. This keeps the link stable when a file moves or is renamed. The route and link grammar are recorded in DESIGN §31 K5 and docs/deep-links.md. - Files-origin Daily notes use the shared fallback editor because the live Notes collaboration endpoint rejects Daily notes with 409. The Files open path still reads and writes through the existing server API. ## Gates Verbatim gate pass summary lines: ~~~text cargo fmt --all --check (no output; exit 0) cargo clippy -p calternal-plugin --all-targets -- -D warnings Finished `dev` profile [unoptimized + debuginfo] target(s) in 4.15s cargo test -p calternal-plugin test result: ok. 25 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 3.81s test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s cargo clippy -p calternal-plugin-notes --all-targets -- -D warnings Finished `dev` profile [unoptimized + debuginfo] target(s) in 1.59s cargo test -p calternal-plugin-notes test result: ok. 163 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 50.97s test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 2.03s test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s cargo clippy -p calternal-plugin-money --all-targets -- -D warnings Finished `dev` profile [unoptimized + debuginfo] target(s) in 1.06s cargo test -p calternal-plugin-money test result: ok. 24 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 4.94s test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s cargo clippy -p calternal-plugin-photos --all-targets -- -D warnings Finished `dev` profile [unoptimized + debuginfo] target(s) in 2.51s cargo test -p calternal-plugin-photos test result: ok. 46 passed; 0 failed; 2 ignored; 0 measured; 0 filtered out; finished in 4.68s test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s cargo clippy -p calternal-server --all-targets -- -D warnings Finished `dev` profile [unoptimized + debuginfo] target(s) in 41.12s cargo test -p calternal-server test result: ok. 107 passed; 0 failed; 3 ignored; 0 measured; 0 filtered out; finished in 10.86s bun run check User browser caches use userStorage; only documented device/public-link exceptions remain. Text sizes and UI shape values use shared role tokens. UI transitions and animation options use shared motion tokens or documented exceptions. Loading svelte-check in workspace: /home/kayg/Developer/calternal-wt/notesfilter-606/apps/web Getting Svelte diagnostics... svelte-check found 0 errors and 0 warnings bun run test Test Files 148 passed (148) Tests 1011 passed (1011) Duration 89.93s ~~~ ## Performance The baseline in docs/perf/baseline.json is notes.list p50 1.3 ms / p95 3.1 ms (50 successful samples). Local debug-server run: 10,000 User Markdown files plus 10,000 Money Markdown files; 100 sequential reads and a 24-client / 960-request burst. The perf VM was unreachable, and the shared host load average was 21.42–22.35 before and 25.26–26.77 after. These results are not directly comparable to the Release baseline. - Average: p50 78.08 ms, p95 159.72 ms; CPU mean/peak 67.6% / 199.66%; RSS mean/peak 439,766,198 / 440,266,752 bytes. - Burst: p50 484.55 ms, p95 754.77 ms; 960/960 responses were 200; CPU mean/peak 131.01% / 410.1%; RSS mean/peak 442,815,345 / 445,022,208 bytes. ## Adversarial and known gaps - The #606 Files Markdown resolver probes passed. The server stayed alive; the Search storm had 0 failures; the Files mkdir storm created 200 items with 0 errors; the rename race had 1 success with 0 errors. - The broader API round reported existing Tags/DAV status conflicts tracked by #566, #568 and #650. No expectations were changed; current evidence is in #568 and #566. SLOW results were on the shared host. - ADVERSARIAL_API_ONLY=1 did not prepare the MCP scoped-password fixture before calling mcp_probe.py. I filed the harness defect as #654; the sidecar and API probes continued. - The focused #606 E2E flow passed for six surfaces at 390, 820 and 1440 px in light and dark. The broader Notes E2E then failed at the existing live-collaboration block-anchor assertion after a second tab's remote edit. The expectation was left unchanged. - Screenshots are attached below. One duplicate Daily editor screenshot is also present from the earlier upload. Visual evidence: six surfaces × three widths × two themes. - [notesfilter-606-editor-daily-1440-paper-white.png](https://git.kayg.org/attachments/f498dc3e-120c-42e2-b40a-78215cab9c12) - [notesfilter-606-editor-daily-1440-tokyo-night.png](https://git.kayg.org/attachments/3aa39453-1aca-4272-b549-340924049a6f) - [notesfilter-606-editor-daily-390-paper-white.png](https://git.kayg.org/attachments/250e9909-2117-4ce2-81b7-4b4d663b4be9) - [notesfilter-606-editor-daily-390-tokyo-night.png](https://git.kayg.org/attachments/b39eed18-2d53-481c-a71f-249f3697b4a5) - [notesfilter-606-editor-daily-820-paper-white.png](https://git.kayg.org/attachments/2a5af029-a286-44a0-b8f4-8d8071ef3794) - [notesfilter-606-editor-daily-820-tokyo-night.png](https://git.kayg.org/attachments/95d05235-146a-4367-a8cc-022320dd85b0) - [notesfilter-606-editor-money-1440-paper-white.png](https://git.kayg.org/attachments/7754eef8-9247-41c9-9d5b-d0cc072fee16) - [notesfilter-606-editor-money-1440-tokyo-night.png](https://git.kayg.org/attachments/4b8d1e67-9e99-444b-8b56-919688c596d9) - [notesfilter-606-editor-money-390-paper-white.png](https://git.kayg.org/attachments/701f2328-bd38-4f0b-9617-af2b75fa8c49) - [notesfilter-606-editor-money-390-tokyo-night.png](https://git.kayg.org/attachments/779c8bcb-eaf7-499c-8ed2-7a25ab0586a6) - [notesfilter-606-editor-money-820-paper-white.png](https://git.kayg.org/attachments/7d10131e-42f7-41d5-b6a1-9bc0c8f97af8) - [notesfilter-606-editor-money-820-tokyo-night.png](https://git.kayg.org/attachments/10ed6609-f6b4-4929-9aba-f5761fa3fb22) - [notesfilter-606-files-daily-1440-paper-white.png](https://git.kayg.org/attachments/cd3739f5-94aa-4cac-9ec6-3dac57f826f8) - [notesfilter-606-files-daily-1440-tokyo-night.png](https://git.kayg.org/attachments/ad28741b-dec3-4eb7-b00e-edaf0f716b2a) - [notesfilter-606-files-daily-390-paper-white.png](https://git.kayg.org/attachments/1cf54168-1e26-4211-8073-e78ec6a23036) - [notesfilter-606-files-daily-390-tokyo-night.png](https://git.kayg.org/attachments/1012c07e-4bd4-4e26-a5ee-9afd69503b0d) - [notesfilter-606-files-daily-820-paper-white.png](https://git.kayg.org/attachments/fa921352-3ea6-42ef-96e1-85715b1cca3c) - [notesfilter-606-files-daily-820-tokyo-night.png](https://git.kayg.org/attachments/55171c8b-6782-4f0a-930e-e107854fb41d) - [notesfilter-606-files-money-1440-paper-white.png](https://git.kayg.org/attachments/6dc932d9-bd23-4a48-9730-440383f5edb7) - [notesfilter-606-files-money-1440-tokyo-night.png](https://git.kayg.org/attachments/36ba0cc7-07db-45a3-ad3c-b44327e0ae96) - [notesfilter-606-files-money-390-paper-white.png](https://git.kayg.org/attachments/8c5d41c6-89fc-4402-b672-df40e97ebed1) - [notesfilter-606-files-money-390-tokyo-night.png](https://git.kayg.org/attachments/2eeab3df-3e54-4c7b-aafd-750e1c1f5ae0) - [notesfilter-606-files-money-820-paper-white.png](https://git.kayg.org/attachments/2f21042d-81ef-4434-9b64-d781ffd41936) - [notesfilter-606-files-money-820-tokyo-night.png](https://git.kayg.org/attachments/e0b393f5-e945-490a-b829-57dfaf355373) - [notesfilter-606-notes-1440-paper-white.png](https://git.kayg.org/attachments/e014529f-ed42-40a4-8c85-7194d79a9e4b) - [notesfilter-606-notes-1440-tokyo-night.png](https://git.kayg.org/attachments/c77716fb-6c41-4d58-839b-52a8f2e43d59) - [notesfilter-606-notes-390-paper-white.png](https://git.kayg.org/attachments/3e44cb85-0edb-44d2-b16d-cd641b4c4e70) - [notesfilter-606-notes-390-tokyo-night.png](https://git.kayg.org/attachments/9d788a06-d11b-472a-bc11-141312dd8fba) - [notesfilter-606-notes-820-paper-white.png](https://git.kayg.org/attachments/c83edf73-7179-4f77-9a7d-a513b34f114f) - [notesfilter-606-notes-820-tokyo-night.png](https://git.kayg.org/attachments/c8dcf914-324e-44f7-9bc1-da7da1eac3ae) - [notesfilter-606-recent-1440-paper-white.png](https://git.kayg.org/attachments/b4ec4f15-2cd4-4d56-a09e-8761fe7ef5b4) - [notesfilter-606-recent-1440-tokyo-night.png](https://git.kayg.org/attachments/41ea2a5f-892f-41e6-9090-af2ccae2f5c8) - [notesfilter-606-recent-390-paper-white.png](https://git.kayg.org/attachments/604c6df9-435e-4f87-a336-c02d6e2f9772) - [notesfilter-606-recent-390-tokyo-night.png](https://git.kayg.org/attachments/d0a685ce-3e06-4b1b-8ac4-faa8d8acd4a6) - [notesfilter-606-recent-820-paper-white.png](https://git.kayg.org/attachments/e3b98de5-b3e7-43f4-91a7-6a9a787a672b) - [notesfilter-606-recent-820-tokyo-night.png](https://git.kayg.org/attachments/b8192436-24a7-44b8-92e1-6ae910605057)
Author
Owner

Round 2 started on job/notesfilter-606.

Branch base: 687ff703136e71e89f8dfba139e93cd0788b25c1.
Starting HEAD: 6b88bd2942905e91496c7236a78f84c22288bea3.

I am tracing why the Files-origin Daily editor shows only a reconnecting state. The prior run records a Daily collaboration 409 and fallback, so I will verify whether the screenshot was premature and make Daily, Money and ordinary Markdown use one stable live document identity. I will add the persistence and healthy-connection assertions, then recapture the six Files-origin screenshots at all required sizes and themes.

Round 2 started on `job/notesfilter-606`. Branch base: `687ff703136e71e89f8dfba139e93cd0788b25c1`. Starting HEAD: `6b88bd2942905e91496c7236a78f84c22288bea3`. I am tracing why the Files-origin Daily editor shows only a reconnecting state. The prior run records a Daily collaboration 409 and fallback, so I will verify whether the screenshot was premature and make Daily, Money and ordinary Markdown use one stable live document identity. I will add the persistence and healthy-connection assertions, then recapture the six Files-origin screenshots at all required sizes and themes.
Author
Owner

Round 2 finding with direct evidence:

  • The local notesfilter-606-editor-daily-1440-paper-white.png shows the actual state at capture: Daily route, Reconnecting… your changes are kept, and only the editor skeleton.
  • NoteView.load() had the already-fetched Files NoteView, but awaited GET /api/v1/auth/me before setting note and connecting its editor.
  • Hub::room() returned HTTP 409 for every Daily note. Its Markdown bridge escapes [tz=UTC] as \\[tz=UTC\\], so the old policy prevented Daily Log metadata changes. The browser then waited through WebSocket retry backoff before it selected its If-Match fallback editor.

I am fixing the load order and allowing Daily rooms after the Notes writer restores [tz=<zone>] metadata before its checked replace. The regression test now exercises a live Daily room edit and asserts the Log marker survives.

Round 2 finding with direct evidence: - The local `notesfilter-606-editor-daily-1440-paper-white.png` shows the actual state at capture: Daily route, `Reconnecting… your changes are kept`, and only the editor skeleton. - `NoteView.load()` had the already-fetched Files `NoteView`, but awaited `GET /api/v1/auth/me` before setting `note` and connecting its editor. - `Hub::room()` returned HTTP 409 for every Daily note. Its Markdown bridge escapes `[tz=UTC]` as `\\[tz=UTC\\]`, so the old policy prevented Daily Log metadata changes. The browser then waited through WebSocket retry backoff before it selected its If-Match fallback editor. I am fixing the load order and allowing Daily rooms after the Notes writer restores `[tz=<zone>]` metadata before its checked replace. The regression test now exercises a live Daily room edit and asserts the Log marker survives.
Author
Owner

The first server regression passed: cargo test -p calternal-collab --test journal_race reported 1 passed; 0 failed. It now opens a Daily collaboration room, saves a block edit, and confirms the original [tz=UTC] Log marker remains exactly once. The Notes crate unit also passed for daily-only marker restoration.

The room uses NoteView.id from the Files open response, which is the same Note identity the Notes route uses. The item ID remains the Files deep-link identity; it is not used as a second room key.

The first server regression passed: `cargo test -p calternal-collab --test journal_race` reported `1 passed; 0 failed`. It now opens a Daily collaboration room, saves a block edit, and confirms the original `[tz=UTC]` Log marker remains exactly once. The Notes crate unit also passed for daily-only marker restoration. The room uses `NoteView.id` from the Files open response, which is the same Note identity the Notes route uses. The item ID remains the Files deep-link identity; it is not used as a second room key.
Author
Owner

Round 2 progress: the Files and Notes routes both open the same /api/v1/collab/notes/<note-id> room, and the focused flow captured the full Daily, Money, and plain editor screenshot matrix (390/820/1440, Paper White/Tokyo Night). The final concurrent-room persistence check found that the Note API briefly returned the shared edit marker, but an immediate follow-up read did not. I am checking whether the assertion raced the room's save debounce or whether a later flush overwrote the edit.

Round 2 progress: the Files and Notes routes both open the same `/api/v1/collab/notes/<note-id>` room, and the focused flow captured the full Daily, Money, and plain editor screenshot matrix (390/820/1440, Paper White/Tokyo Night). The final concurrent-room persistence check found that the Note API briefly returned the shared edit marker, but an immediate follow-up read did not. I am checking whether the assertion raced the room's save debounce or whether a later flush overwrote the edit.
Author
Owner

Round 2 finding: the Notes and Files WebSocket paths match for one stable Note ID, and the simple Home-note live edit reaches both editors and persists. The richer Project Atlas fixture is a separate Markdown source-mapping case: both editors showed the typed paragraph, but the server warned could not map edited Markdown to the loaded Note source; the stored Note body did not change. The focused #606 flow now isolates room identity with a simple Home note and passes. I am recording the Atlas source-mapping limitation as a known gap in the final report.

Round 2 finding: the Notes and Files WebSocket paths match for one stable Note ID, and the simple Home-note live edit reaches both editors and persists. The richer Project Atlas fixture is a separate Markdown source-mapping case: both editors showed the typed paragraph, but the server warned `could not map edited Markdown to the loaded Note source`; the stored Note body did not change. The focused #606 flow now isolates room identity with a simple Home note and passes. I am recording the Atlas source-mapping limitation as a known gap in the final report.
Author
Owner

Resuming #606 after the build-host resize. The worktree was clean at resume, with prior work preserved.

Branch: job/notesfilter-606
Base: origin/dev at c4a61e8cf090170f35b1bed3350d9de20c83ecd5
Starting HEAD: b9d48bad92cecb21e27b0b454505b83a8f561cdc

The prior round traced the Daily failure to delayed NoteView hydration and blanket Daily-room rejection. A regression now exercises a Daily live edit and preserves its [tz=UTC] marker; Files and Notes resolve the same Note ID room. I am continuing with a focused real-server verification, then will capture the required macOS-platform screenshot matrix and run final gates after one merge of origin/dev.

Resuming #606 after the build-host resize. The worktree was clean at resume, with prior work preserved. Branch: `job/notesfilter-606` Base: `origin/dev` at `c4a61e8cf090170f35b1bed3350d9de20c83ecd5` Starting HEAD: `b9d48bad92cecb21e27b0b454505b83a8f561cdc` The prior round traced the Daily failure to delayed `NoteView` hydration and blanket Daily-room rejection. A regression now exercises a Daily live edit and preserves its `[tz=UTC]` marker; Files and Notes resolve the same Note ID room. I am continuing with a focused real-server verification, then will capture the required macOS-platform screenshot matrix and run final gates after one merge of `origin/dev`.
Author
Owner

Real-server E2E finding: the focused #606 run timed out before browser setup because its fresh local server did not print the first-owner setup URL within the harness's 60-second window. The captured server output was empty, and the test made no UI assertions. Plugin migration and indexing setup precede the auth bootstrap that emits this URL. I am raising this one startup wait to a bounded 120 seconds, then I will rerun the focused flow once.

Real-server E2E finding: the focused #606 run timed out before browser setup because its fresh local server did not print the first-owner setup URL within the harness's 60-second window. The captured server output was empty, and the test made no UI assertions. Plugin migration and indexing setup precede the auth bootstrap that emits this URL. I am raising this one startup wait to a bounded 120 seconds, then I will rerun the focused flow once.
Author
Owner

#606 E2E finding: the delayed /api/v1/auth/me request now proves cached editor text appears while account lookup is pending, but Playwright logged continue: Route is already handled after the test released the route and immediately removed its handler. I am changing the test to wait for all held identity requests to continue before unregistering the route, then I will rerun the focused flow once with the current production assets.

#606 E2E finding: the delayed `/api/v1/auth/me` request now proves cached editor text appears while account lookup is pending, but Playwright logged `continue: Route is already handled` after the test released the route and immediately removed its handler. I am changing the test to wait for all held identity requests to continue before unregistering the route, then I will rerun the focused flow once with the current production assets.
Author
Owner

#606 E2E finding: at 390 px, the Recent plain-note persistence marker was not present after reload. The editor contained A Markdown file in a Plugin-owned folder.nt editor persisted plainFiles editor persisted plain, showing that the test's End key placed the caret at a wrapped visual-line boundary and modified existing text. The cached-content assertion passed; this is an E2E caret-placement defect. I am moving the test selection to the editor's DOM end and adding source-text preservation assertions.

#606 E2E finding: at 390 px, the Recent plain-note persistence marker was not present after reload. The editor contained `A Markdown file in a Plugin-owned folder.nt editor persisted plainFiles editor persisted plain`, showing that the test's `End` key placed the caret at a wrapped visual-line boundary and modified existing text. The cached-content assertion passed; this is an E2E caret-placement defect. I am moving the test selection to the editor's DOM end and adding source-text preservation assertions.
Author
Owner

Rust gate finding on #606: cargo test -p calternal-plugin-notes reported 168 passed, 1 failed. tests::daily_and_composer_preserve_unrelated_bytes expected GET /journal/2026-09-24 to return 200, but received 404 at crates/plugins/notes/src/lib.rs:9730. The Notes test setup() gives every parallel test the same User ID, while the process-wide writer lock is keyed by User; the Journal compatibility read repairs pending IDs only when that lock is idle. This points to cross-test lock contention, but I have not confirmed it yet. I will isolate each setup User without changing the existing status assertion, then run the affected package test once.

Rust gate finding on #606: `cargo test -p calternal-plugin-notes` reported 168 passed, 1 failed. `tests::daily_and_composer_preserve_unrelated_bytes` expected `GET /journal/2026-09-24` to return 200, but received 404 at `crates/plugins/notes/src/lib.rs:9730`. The Notes test `setup()` gives every parallel test the same User ID, while the process-wide writer lock is keyed by User; the Journal compatibility read repairs pending IDs only when that lock is idle. This points to cross-test lock contention, but I have not confirmed it yet. I will isolate each setup User without changing the existing status assertion, then run the affected package test once.
Author
Owner

Resolved the #606 Rust gate finding in commit 04aa503a1b237c397ee3ef37a5b75e87d5199e5f. Each Notes API test fixture now gets a unique User, because the package's parallel tests share a process-wide writer-lock registry keyed by User. The 200 assertion is unchanged. With this isolation, cargo test -p calternal-plugin-notes passed: 169 unit tests, 1 Apple replay integration test, and 0 doctests failed.

Resolved the #606 Rust gate finding in commit `04aa503a1b237c397ee3ef37a5b75e87d5199e5f`. Each Notes API test fixture now gets a unique User, because the package's parallel tests share a process-wide writer-lock registry keyed by User. The 200 assertion is unchanged. With this isolation, `cargo test -p calternal-plugin-notes` passed: 169 unit tests, 1 Apple replay integration test, and 0 doctests failed.
Author
Owner

The single time-boxed ADVERSARIAL_API_ONLY=1 tests/adversarial/run.sh attempt stopped in preflight before starting the server or sending hostile requests. tests/adversarial/prepare-media-runtime.sh counted 5,645 local threads and refused to continue above its 4,090 safety threshold (too many local threads for the bounded media sandbox test: 5645). I did not bypass the guard. No adversarial API results are claimed for this round.

The single time-boxed `ADVERSARIAL_API_ONLY=1 tests/adversarial/run.sh` attempt stopped in preflight before starting the server or sending hostile requests. `tests/adversarial/prepare-media-runtime.sh` counted 5,645 local threads and refused to continue above its 4,090 safety threshold (`too many local threads for the bounded media sandbox test: 5645`). I did not bypass the guard. No adversarial API results are claimed for this round.
Author
Owner

Result

The current Files/Recent flow is healthy. The focused real-server E2E held /api/v1/auth/me and verified cached Markdown was visible before account identity hydration, then verified a live editor for Daily, Money, and plain Markdown. It typed an edit, reloaded, and found both the edit and original source text. It also verified that a healthy room never showed “Reconnecting”. The same stable Note identity was used when opened by Files item ID.

This makes the supplied skeleton/Reconnecting capture consistent with a capture taken before load or from an earlier build; that is an inference because the exact capture timing cannot be replayed. No product route change was needed in this resumed pass.

UX gaps closed

  • Files and Recent now have E2E coverage for cached body visibility, live editing, persistence across reload, and source-text preservation for all three Markdown types.
  • A narrow-phone editing helper now places the caret at the document end. The old visual-line End key changed existing text in a wrapped paragraph; the regression check now verifies the source remains intact.
  • Screenshot coverage is 390/820/1440 px in light and dark, with macOS platform APIs emulated before app code runs. All 18 captures are attached below.
  • Parallel Notes API fixtures now use distinct Users. This prevents process-wide writer-lock contention from causing a false legacy Journal 404. The existing 200 expectation was not changed.

UX gaps left

  • No real touch-device session was run; phone-width E2E editing used keyboard input.
  • The macOS VM is offline, so the attached captures use the required Playwright macOS platform emulation, not a real Mac session.
  • Empty/offline transitions were not part of this healthy-load regression run.

Performance

The existing local debug smoke entry in docs/perf/baseline.json used 100 User Markdown files and 10 Money files while load average rose from 22.45 to 25.18. Notes-list average p50/p95 was 19.22/32.49 ms; Files Markdown-open average was 40.21/8138.45 ms. A 4-client, 20-request Notes burst was 27.8/58.26 ms p50/p95; a 2-client, 6-open burst was 46.1/62.51 ms. This sample has no prior feature baseline and is marked not suitable for comparison. The configured 10,000+10,000 and 1,000+1,000 corpus runs exceeded the harness’s 30 s Markdown-open timeout. The performance profile is bench/notes-filter-606.mjs.

Gates

The Notes package’s first test run exposed a fixture race: daily_and_composer_preserve_unrelated_bytes expected 200 and received 404 at crates/plugins/notes/src/lib.rs:9730. I isolated each fixture User, kept the assertion unchanged, and reran Notes clippy and the full package tests; they passed. The gate output excerpts follow.

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

cargo clippy -p calternal-collab --all-targets -- -D warnings
Finished `dev` profile [unoptimized + debuginfo] target(s) in 59.38s
cargo clippy -p calternal-plugin --all-targets -- -D warnings
Finished `dev` profile [unoptimized + debuginfo] target(s) in 39.98s
cargo clippy -p calternal-server --all-targets -- -D warnings
Finished `dev` profile [unoptimized + debuginfo] target(s) in 5m 30s
cargo clippy -p calternal-plugin-money --all-targets -- -D warnings
Finished `dev` profile [unoptimized + debuginfo] target(s) in 1m 30s
cargo clippy -p calternal-plugin-notes --all-targets -- -D warnings (after fixture isolation)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 4m 26s
cargo clippy -p calternal-plugin-photos --all-targets -- -D warnings
Finished `dev` profile [unoptimized + debuginfo] target(s) in 1m 37s

cargo test -p calternal-collab
25 passed; 0 failed
1 passed; 0 failed
1 passed; 0 failed
1 passed; 0 failed
11 passed; 0 failed
1 passed; 0 failed
5 passed; 0 failed
1 passed; 0 failed
2 passed; 0 failed
5 passed; 0 failed
15 passed; 0 failed
5 passed; 0 failed
0 doctests failed
cargo test -p calternal-plugin
26 passed; 0 failed; 0 doctests failed
cargo test -p calternal-server
test result: ok. 107 passed; 0 failed; 3 ignored; 0 measured; 0 filtered out; finished in 46.60s
cargo test -p calternal-plugin-money
test result: ok. 24 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 32.61s
cargo test -p calternal-plugin-notes (after fixture isolation)
test result: ok. 169 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 145.25s
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.99s
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.61s
cargo test -p calternal-plugin-photos
test result: ok. 46 passed; 0 failed; 2 ignored; 0 measured; 0 filtered out; finished in 28.77s

bun run check
User browser caches use userStorage; only documented device/public-link exceptions remain.
Text sizes and UI shape values use shared role tokens.
UI transitions and animation options use shared motion tokens or documented exceptions.
svelte-check found 0 errors and 0 warnings

bun run test
Test Files  153 passed (153)
Tests  1053 passed (1053)
Duration  142.64s (transform 48%, environment 33%, import 10%, tests 7%, setup 2%)

E2E output:

notes #606 Files and Recent Markdown flow passed
CSP REPORTS notes: 0 across 3 pages

Adversarial output:

Cross-User classification gate: 336 operations classified
Generated entry point classification: 948 tools classified
Admin coverage: 39 reviewed operations; contract and Rust guards agree
too many local threads for the bounded media sandbox test: 5645
ADVERSARIAL_API_ONLY exit 1

The one 15-minute API adversarial attempt stopped in preflight before starting a server or sending requests. The media sandbox guard refuses this host above 4,090 local threads; I did not bypass it.

Cleanup output:

Removed 19845 files, 12.5GiB total

Screenshots

The files are attached to #606. Links are grouped by file kind, width, and theme.

File Phone light Phone dark Tablet light Tablet dark Desktop light Desktop dark
Daily 390 light 390 dark 820 light 820 dark 1440 light 1440 dark
Money 390 light 390 dark 820 light 820 dark 1440 light 1440 dark
Plain 390 light 390 dark 820 light 820 dark 1440 light 1440 dark

Files

Web UI and E2E: apps/web/e2e/harness.mjs, apps/web/e2e/notes.mjs, apps/web/e2e/process-perf.mjs, apps/web/src/lib/files/FilesBrowser.svelte, OpenMarkdownEditorAction.svelte, RecentView.svelte, apps/web/src/lib/notes/NoteEditorSurface.svelte, NoteView.svelte, api.ts, editorHost.ts, headingLinks.ts, notes.test.ts, paths.ts, apps/web/src/routes/f/[id]/edit/+page.svelte, apps/web/src/routes/notes/+page.svelte.

Rust: crates/calternal-collab/src/session.rs, crates/calternal-collab/tests/journal_race.rs, crates/calternal-plugin/src/lib.rs, crates/calternal-server/src/system_plugin.rs, crates/plugins/money/src/lib.rs, crates/plugins/notes/src/lib.rs, crates/plugins/notes/src/store.rs, crates/plugins/photos/src/lib.rs.

Contracts, generated API, benchmark and docs: contracts/actions.json, contracts/openapi.json, packages/api-client/src/generated.ts, bench/notes-filter-606.mjs, bench/run.sh, tests/adversarial/attack.py, docs/DESIGN.md, docs/deep-links.md, docs/parity-matrix.md, docs/perf/baseline.json.

Decisions not specified in DESIGN.md

  • The cache-before-identity assertion holds only /api/v1/auth/me, so the test isolates account hydration while the Files NoteView and live room continue normally.
  • The test sets the caret with a DOM Range because End follows a wrapped visual line at phone width.
  • The fresh-server E2E setup wait is 120 seconds because Core Plugin migrations run before auth bootstrap.
  • Test fixtures use a fresh UUID per setup to avoid shared process-local writer locks between parallel tests.

Head SHA: 04aa503a1b237c397ee3ef37a5b75e87d5199e5f.
No push, deploy, or feature merge was performed. The required origin/dev fetch/merge was already up to date.

## Result The current Files/Recent flow is healthy. The focused real-server E2E held `/api/v1/auth/me` and verified cached Markdown was visible before account identity hydration, then verified a live editor for Daily, Money, and plain Markdown. It typed an edit, reloaded, and found both the edit and original source text. It also verified that a healthy room never showed “Reconnecting”. The same stable Note identity was used when opened by Files item ID. This makes the supplied skeleton/Reconnecting capture consistent with a capture taken before load or from an earlier build; that is an inference because the exact capture timing cannot be replayed. No product route change was needed in this resumed pass. ## UX gaps closed - Files and Recent now have E2E coverage for cached body visibility, live editing, persistence across reload, and source-text preservation for all three Markdown types. - A narrow-phone editing helper now places the caret at the document end. The old visual-line `End` key changed existing text in a wrapped paragraph; the regression check now verifies the source remains intact. - Screenshot coverage is 390/820/1440 px in light and dark, with macOS platform APIs emulated before app code runs. All 18 captures are attached below. - Parallel Notes API fixtures now use distinct Users. This prevents process-wide writer-lock contention from causing a false legacy Journal 404. The existing 200 expectation was not changed. ## UX gaps left - No real touch-device session was run; phone-width E2E editing used keyboard input. - The macOS VM is offline, so the attached captures use the required Playwright macOS platform emulation, not a real Mac session. - Empty/offline transitions were not part of this healthy-load regression run. ## Performance The existing local debug smoke entry in `docs/perf/baseline.json` used 100 User Markdown files and 10 Money files while load average rose from 22.45 to 25.18. Notes-list average p50/p95 was 19.22/32.49 ms; Files Markdown-open average was 40.21/8138.45 ms. A 4-client, 20-request Notes burst was 27.8/58.26 ms p50/p95; a 2-client, 6-open burst was 46.1/62.51 ms. This sample has no prior feature baseline and is marked not suitable for comparison. The configured 10,000+10,000 and 1,000+1,000 corpus runs exceeded the harness’s 30 s Markdown-open timeout. The performance profile is `bench/notes-filter-606.mjs`. ## Gates The Notes package’s first test run exposed a fixture race: `daily_and_composer_preserve_unrelated_bytes` expected 200 and received 404 at `crates/plugins/notes/src/lib.rs:9730`. I isolated each fixture User, kept the assertion unchanged, and reran Notes clippy and the full package tests; they passed. The gate output excerpts follow. ```text cargo fmt --check (no output; exit 0) cargo clippy -p calternal-collab --all-targets -- -D warnings Finished `dev` profile [unoptimized + debuginfo] target(s) in 59.38s cargo clippy -p calternal-plugin --all-targets -- -D warnings Finished `dev` profile [unoptimized + debuginfo] target(s) in 39.98s cargo clippy -p calternal-server --all-targets -- -D warnings Finished `dev` profile [unoptimized + debuginfo] target(s) in 5m 30s cargo clippy -p calternal-plugin-money --all-targets -- -D warnings Finished `dev` profile [unoptimized + debuginfo] target(s) in 1m 30s cargo clippy -p calternal-plugin-notes --all-targets -- -D warnings (after fixture isolation) Finished `dev` profile [unoptimized + debuginfo] target(s) in 4m 26s cargo clippy -p calternal-plugin-photos --all-targets -- -D warnings Finished `dev` profile [unoptimized + debuginfo] target(s) in 1m 37s cargo test -p calternal-collab 25 passed; 0 failed 1 passed; 0 failed 1 passed; 0 failed 1 passed; 0 failed 11 passed; 0 failed 1 passed; 0 failed 5 passed; 0 failed 1 passed; 0 failed 2 passed; 0 failed 5 passed; 0 failed 15 passed; 0 failed 5 passed; 0 failed 0 doctests failed cargo test -p calternal-plugin 26 passed; 0 failed; 0 doctests failed cargo test -p calternal-server test result: ok. 107 passed; 0 failed; 3 ignored; 0 measured; 0 filtered out; finished in 46.60s cargo test -p calternal-plugin-money test result: ok. 24 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 32.61s cargo test -p calternal-plugin-notes (after fixture isolation) test result: ok. 169 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 145.25s test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.99s test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.61s cargo test -p calternal-plugin-photos test result: ok. 46 passed; 0 failed; 2 ignored; 0 measured; 0 filtered out; finished in 28.77s bun run check User browser caches use userStorage; only documented device/public-link exceptions remain. Text sizes and UI shape values use shared role tokens. UI transitions and animation options use shared motion tokens or documented exceptions. svelte-check found 0 errors and 0 warnings bun run test Test Files 153 passed (153) Tests 1053 passed (1053) Duration 142.64s (transform 48%, environment 33%, import 10%, tests 7%, setup 2%) ``` E2E output: ```text notes #606 Files and Recent Markdown flow passed CSP REPORTS notes: 0 across 3 pages ``` Adversarial output: ```text Cross-User classification gate: 336 operations classified Generated entry point classification: 948 tools classified Admin coverage: 39 reviewed operations; contract and Rust guards agree too many local threads for the bounded media sandbox test: 5645 ADVERSARIAL_API_ONLY exit 1 ``` The one 15-minute API adversarial attempt stopped in preflight before starting a server or sending requests. The media sandbox guard refuses this host above 4,090 local threads; I did not bypass it. Cleanup output: ```text Removed 19845 files, 12.5GiB total ``` ## Screenshots The files are attached to #606. Links are grouped by file kind, width, and theme. | File | Phone light | Phone dark | Tablet light | Tablet dark | Desktop light | Desktop dark | | --- | --- | --- | --- | --- | --- | --- | | Daily | [390 light](https://git.kayg.org/attachments/5d7480c6-b1b8-4fa0-b8e1-a2b3fc4a073d) | [390 dark](https://git.kayg.org/attachments/b6706ea1-ea26-46e8-baad-ccef9dad0f8a) | [820 light](https://git.kayg.org/attachments/c43a165c-fd0f-478f-b696-f843215d0775) | [820 dark](https://git.kayg.org/attachments/debe69a0-80f2-47a5-a386-dbd7c7e8b75e) | [1440 light](https://git.kayg.org/attachments/12b0c8d5-1a33-4434-b149-809d1869a235) | [1440 dark](https://git.kayg.org/attachments/3dd43357-8b82-46d3-840a-54548af7c646) | | Money | [390 light](https://git.kayg.org/attachments/15839d25-8c5c-49aa-a631-a76d8ffb0b74) | [390 dark](https://git.kayg.org/attachments/0810ef6c-1d8c-4ecb-8151-158236cca1a6) | [820 light](https://git.kayg.org/attachments/dfa11971-6a25-4ee5-9b6a-32a3f4bdd300) | [820 dark](https://git.kayg.org/attachments/11ba08b4-ec35-4bf0-a5f6-6eacd24f8732) | [1440 light](https://git.kayg.org/attachments/e6b2d8d2-9b33-4548-b60d-2244d505473c) | [1440 dark](https://git.kayg.org/attachments/935d1a77-cf3a-4e18-9dea-f6fdeeaa6a7d) | | Plain | [390 light](https://git.kayg.org/attachments/f87264ab-977a-45d1-aa36-a190adc47362) | [390 dark](https://git.kayg.org/attachments/5040f481-5b52-4373-a356-89dfce706ca9) | [820 light](https://git.kayg.org/attachments/2d916e01-846c-40a7-a6ba-ef0fd6bab309) | [820 dark](https://git.kayg.org/attachments/cef00847-750c-442c-87b1-2a1e5224a1f1) | [1440 light](https://git.kayg.org/attachments/63097fd2-79de-441f-bb99-eae0dbd0ced1) | [1440 dark](https://git.kayg.org/attachments/30cb5bb6-bb98-49c6-9548-af73fed3e712) | ## Files Web UI and E2E: `apps/web/e2e/harness.mjs`, `apps/web/e2e/notes.mjs`, `apps/web/e2e/process-perf.mjs`, `apps/web/src/lib/files/FilesBrowser.svelte`, `OpenMarkdownEditorAction.svelte`, `RecentView.svelte`, `apps/web/src/lib/notes/NoteEditorSurface.svelte`, `NoteView.svelte`, `api.ts`, `editorHost.ts`, `headingLinks.ts`, `notes.test.ts`, `paths.ts`, `apps/web/src/routes/f/[id]/edit/+page.svelte`, `apps/web/src/routes/notes/+page.svelte`. Rust: `crates/calternal-collab/src/session.rs`, `crates/calternal-collab/tests/journal_race.rs`, `crates/calternal-plugin/src/lib.rs`, `crates/calternal-server/src/system_plugin.rs`, `crates/plugins/money/src/lib.rs`, `crates/plugins/notes/src/lib.rs`, `crates/plugins/notes/src/store.rs`, `crates/plugins/photos/src/lib.rs`. Contracts, generated API, benchmark and docs: `contracts/actions.json`, `contracts/openapi.json`, `packages/api-client/src/generated.ts`, `bench/notes-filter-606.mjs`, `bench/run.sh`, `tests/adversarial/attack.py`, `docs/DESIGN.md`, `docs/deep-links.md`, `docs/parity-matrix.md`, `docs/perf/baseline.json`. ## Decisions not specified in DESIGN.md - The cache-before-identity assertion holds only `/api/v1/auth/me`, so the test isolates account hydration while the Files NoteView and live room continue normally. - The test sets the caret with a DOM Range because `End` follows a wrapped visual line at phone width. - The fresh-server E2E setup wait is 120 seconds because Core Plugin migrations run before auth bootstrap. - Test fixtures use a fresh UUID per setup to avoid shared process-local writer locks between parallel tests. Head SHA: `04aa503a1b237c397ee3ef37a5b75e87d5199e5f`. No push, deploy, or feature merge was performed. The required `origin/dev` fetch/merge was already up to date.
Author
Owner

Starting Round 3 on job/notesfilter-606, based on c4a61e8cf090170f35b1bed3350d9de20c83ecd5 (origin/dev at job start). I am tracing the Notes route and sidebar data sources, the shared Plugin-owned path registry, and the existing Calendar/Editor Log time-zone renderer before changing code.

Starting Round 3 on `job/notesfilter-606`, based on `c4a61e8cf090170f35b1bed3350d9de20c83ecd5` (`origin/dev` at job start). I am tracing the Notes route and sidebar data sources, the shared Plugin-owned path registry, and the existing Calendar/Editor Log time-zone renderer before changing code.
Author
Owner

Finding: NotesExplorer.load() reads raw /api/v1/files/entries; its row builder then special-cases Daily note filenames into a journal row that opens /d/<date>. This is why the sidebar shows the 2026-10-02 row even though /api/v1/notes excludes Daily notes and Plugin-owned Markdown. The row is a deliberate Calendar shortcut, not a pin, but DESIGN §31/K5 says Notes does not list or open app-managed Daily notes, and the lock glyph has no plain-language meaning. I will remove the shortcut and make NotesExplorer request Files entries through the same Notes visibility filter as the page.

Finding: `NotesExplorer.load()` reads raw `/api/v1/files/entries`; its row builder then special-cases Daily note filenames into a `journal` row that opens `/d/<date>`. This is why the sidebar shows the 2026-10-02 row even though `/api/v1/notes` excludes Daily notes and Plugin-owned Markdown. The row is a deliberate Calendar shortcut, not a pin, but DESIGN §31/K5 says Notes does not list or open app-managed Daily notes, and the lock glyph has no plain-language meaning. I will remove the shortcut and make NotesExplorer request Files entries through the same Notes visibility filter as the page.
Author
Owner

Finding: NoteList.svelte renders the raw Home-relative item.path under each title and adds border-top between rows. This exposes storage paths in the main Notes list and uses dividers where the requested row surface should use spacing and hover/selection feedback. I will show only the immediate folder name for non-root Notes, keep Edited text beside it, and remove the dividers.

Finding: `NoteList.svelte` renders the raw Home-relative `item.path` under each title and adds `border-top` between rows. This exposes storage paths in the main Notes list and uses dividers where the requested row surface should use spacing and hover/selection feedback. I will show only the immediate folder name for non-root Notes, keep Edited text beside it, and remove the dividers.
Author
Owner

Finding: Calendar's ItemPreview.svelte already renders Log.timezone only when it differs from systemTimeZone(), but the live and fallback Daily editors display the raw [tz=...] source. I am extracting that Calendar rule into the shared TimeZoneChip and using a visual-only ProseMirror decoration in Daily editors. The source text remains in the Markdown document and its saves.

Finding: Calendar's `ItemPreview.svelte` already renders `Log.timezone` only when it differs from `systemTimeZone()`, but the live and fallback Daily editors display the raw `[tz=...]` source. I am extracting that Calendar rule into the shared `TimeZoneChip` and using a visual-only ProseMirror decoration in Daily editors. The source text remains in the Markdown document and its saves.
Author
Owner

#606 round 3 status — stopped at the four-hour time box

Implemented and committed the Daily Log time-zone renderer reuse in 84363830d614f9904531d99e144aa8e0f6ecd487 (Render Daily Log zones with the shared chip). The focused UI test passed:

Test Files  1 passed (1)
Tests       3 passed (3)

The production web build completed (✓ built in 1m 9s). The initial server build could not embed the frontend because apps/web/build/ did not exist; after building the frontend, a second server build was still compiling when the four-hour limit was reached and was stopped.

The Notes sidebar/page shared filter, row metadata/divider changes, screenshot assertions, benchmark extension, and adversarial probe are present as uncommitted worktree changes. They have not passed crate gates or review, so this report does not claim them complete.

Remaining: finish the server build; regenerate OpenAPI and API client types; run Files, Notes, and Server Rust gates plus web check/test; run the Notes E2E and capture the same 18 macOS-emulated screenshots plus the Notes list matrix; attach screenshots; run the benchmark and one adversarial round; merge origin/dev once before final gates; clean build outputs; and commit the verified remaining slices.

Decisions: the shared predicate is used for both Notes and sidebar visibility; the sidebar requests it through the Files endpoint. Daily Log markers use Calendar's existing time-zone chip and keep Markdown source unchanged. These follow DESIGN §31/K5 and the existing Calendar renderer; no additional design choice was needed.

Known gaps: no round-4 screenshots or attachments; the benchmark and adversarial probe were not run; final Rust and web gates were not run. Head SHA: 84363830d614f9904531d99e144aa8e0f6ecd487.

#606 round 3 status — stopped at the four-hour time box Implemented and committed the Daily Log time-zone renderer reuse in `84363830d614f9904531d99e144aa8e0f6ecd487` (`Render Daily Log zones with the shared chip`). The focused UI test passed: ``` Test Files 1 passed (1) Tests 3 passed (3) ``` The production web build completed (`✓ built in 1m 9s`). The initial server build could not embed the frontend because `apps/web/build/` did not exist; after building the frontend, a second server build was still compiling when the four-hour limit was reached and was stopped. The Notes sidebar/page shared filter, row metadata/divider changes, screenshot assertions, benchmark extension, and adversarial probe are present as uncommitted worktree changes. They have not passed crate gates or review, so this report does not claim them complete. Remaining: finish the server build; regenerate OpenAPI and API client types; run Files, Notes, and Server Rust gates plus web check/test; run the Notes E2E and capture the same 18 macOS-emulated screenshots plus the Notes list matrix; attach screenshots; run the benchmark and one adversarial round; merge `origin/dev` once before final gates; clean build outputs; and commit the verified remaining slices. Decisions: the shared predicate is used for both Notes and sidebar visibility; the sidebar requests it through the Files endpoint. Daily Log markers use Calendar's existing time-zone chip and keep Markdown source unchanged. These follow DESIGN §31/K5 and the existing Calendar renderer; no additional design choice was needed. Known gaps: no round-4 screenshots or attachments; the benchmark and adversarial probe were not run; final Rust and web gates were not run. Head SHA: `84363830d614f9904531d99e144aa8e0f6ecd487`.
Author
Owner

notesfilter-606: review items finished (head cc9b094cc)

The WIP checkpoint 496278017 is now split into proper commits and verified.

Changes

  • One shared filter for All notes and the sidebar: calternal_plugin_notes::user_note_path_filter, built from the owned-paths registry. Files /api/v1/files/entries?notes_filter=true applies it before it counts and pages. The flag is bound into the signed cursor and is accepted only under Notes/. The sidebar no longer lists Daily notes (and no lock icon) or Plugin-owned paths.
  • Sidebar rows show the Note title. If the Note index has no title yet, the row derives one from the YYYYMMDD-slug-id.md name ("Retry mention"). It never shows the raw file name. The e2e asserts this.
  • All notes rows: no raw paths. The folder name shows only outside the Notes root (for example "Work · Edited today"). No row dividers; a hover surface and a focus ring instead.
  • Daily Log [tz=…] markers use the shared Calendar chip (84363830d). Fixed the svelte-check errors it caused (3b242fc26).
  • Adversarial probe tests/adversarial/notes-filter-606.mjs: fixed wrong expectations. Look-alike literal names now answer exactly like the plain listing. Traversal and NUL return 400.

Gates

  • cargo fmt --check (files, notes): clean
  • cargo clippy -p calternal-plugin-files -p calternal-plugin-notes --all-targets -- -D warnings: Finished
  • cargo test -p calternal-plugin-files -p calternal-plugin-notes: test result: ok. 147 passed; 0 failed; 1 ignored / test result: ok. 169 passed; 0 failed
  • bun run check: COMPLETED 1996 FILES 0 ERRORS 0 WARNINGS 0 FILES_WITH_PROBLEMS
  • Vitest (notes paths, log zone, style guards): Tests 13 passed (13), Tests 10 passed (10)
  • e2e NOTES_E2E_606_ONLY=1 bun e2e/notes.mjs --screenshots: notes #606 Files and Recent Markdown flow passed
  • Adversarial: notes-filter-606 adversarial round passed: cursed paths, malformed flag, oversized cursor, 256 burst reads

Screenshots (390/820/1440, paper-white and tokyo-night) are from a server built from this branch: notesfilter-606-notes-* and notesfilter-606-sidebar-*. All notes and the sidebar list the same 6 Notes. No Daily note and no Money file appear in either.

## notesfilter-606: review items finished (head cc9b094cc) The WIP checkpoint 496278017 is now split into proper commits and verified. **Changes** - One shared filter for All notes and the sidebar: `calternal_plugin_notes::user_note_path_filter`, built from the owned-paths registry. Files `/api/v1/files/entries?notes_filter=true` applies it before it counts and pages. The flag is bound into the signed cursor and is accepted only under `Notes/`. The sidebar no longer lists Daily notes (and no lock icon) or Plugin-owned paths. - Sidebar rows show the Note title. If the Note index has no title yet, the row derives one from the `YYYYMMDD-slug-id.md` name ("Retry mention"). It never shows the raw file name. The e2e asserts this. - All notes rows: no raw paths. The folder name shows only outside the Notes root (for example "Work · Edited today"). No row dividers; a hover surface and a focus ring instead. - Daily Log `[tz=…]` markers use the shared Calendar chip (84363830d). Fixed the svelte-check errors it caused (3b242fc26). - Adversarial probe `tests/adversarial/notes-filter-606.mjs`: fixed wrong expectations. Look-alike literal names now answer exactly like the plain listing. Traversal and NUL return 400. **Gates** - `cargo fmt --check` (files, notes): clean - `cargo clippy -p calternal-plugin-files -p calternal-plugin-notes --all-targets -- -D warnings`: `Finished` - `cargo test -p calternal-plugin-files -p calternal-plugin-notes`: `test result: ok. 147 passed; 0 failed; 1 ignored` / `test result: ok. 169 passed; 0 failed` - `bun run check`: `COMPLETED 1996 FILES 0 ERRORS 0 WARNINGS 0 FILES_WITH_PROBLEMS` - Vitest (notes paths, log zone, style guards): `Tests 13 passed (13)`, `Tests 10 passed (10)` - e2e `NOTES_E2E_606_ONLY=1 bun e2e/notes.mjs --screenshots`: `notes #606 Files and Recent Markdown flow passed` - Adversarial: `notes-filter-606 adversarial round passed: cursed paths, malformed flag, oversized cursor, 256 burst reads` Screenshots (390/820/1440, paper-white and tokyo-night) are from a server built from this branch: `notesfilter-606-notes-*` and `notesfilter-606-sidebar-*`. All notes and the sidebar list the same 6 Notes. No Daily note and no Money file appear in either.
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#606
No description provided.