A cold Note deep link can show the error state during sequential fixture navigation #1451

Closed
opened 2026-10-08 05:57:45 +00:00 by kayg · 5 comments
Owner

Found once during the #1440 browser regression on a real local production build, Chromium with macOS platform emulation.

The harness created and opened nine Notes in sequence. The first eight Copy link cases passed their API reads and reload checks. For the ninth Note, the direct uncached GET returned its body, then opening its stable /n/<id> route showed “This note could not be opened” and “Try again”. The editor remained absent for the 60-second wait. There were no page JavaScript errors. Copy link had not been clicked on that Note.

The Note contained a heading and a sole autolink. The same case passed on a fresh fixture. A later complete nine-case run also passed, with Notes HTTP error-status logging enabled and no error status recorded. No source-byte mismatch or data loss was observed in this load failure. The original run did not record the swallowed load exception or HTTP status, so its cause is unknown.

Trace for investigation: NoteView.svelte load() maps non-404/non-401 read errors to this state. getNote() uses the bounded revision cache. loadNoteViewForNavigation() already documents a pending-read-cap exception for creation navigation (#1128). These are investigation points, not a proven cause.

Evidence is retained in the linkdup-1440 worktree: artifacts/browser-final-passing.log contains the failed route state; artifacts/browser-standalone-final.log and artifacts/browser-all-verified.log contain successful fresh and full reruns. The #1440 fix does not change Note loading or cache admission. Investigate the load error separately.

Found once during the #1440 browser regression on a real local production build, Chromium with macOS platform emulation. The harness created and opened nine Notes in sequence. The first eight Copy link cases passed their API reads and reload checks. For the ninth Note, the direct uncached GET returned its body, then opening its stable `/n/<id>` route showed “This note could not be opened” and “Try again”. The editor remained absent for the 60-second wait. There were no page JavaScript errors. Copy link had not been clicked on that Note. The Note contained a heading and a sole autolink. The same case passed on a fresh fixture. A later complete nine-case run also passed, with Notes HTTP error-status logging enabled and no error status recorded. No source-byte mismatch or data loss was observed in this load failure. The original run did not record the swallowed load exception or HTTP status, so its cause is unknown. Trace for investigation: `NoteView.svelte` load() maps non-404/non-401 read errors to this state. `getNote()` uses the bounded revision cache. `loadNoteViewForNavigation()` already documents a pending-read-cap exception for creation navigation (#1128). These are investigation points, not a proven cause. Evidence is retained in the linkdup-1440 worktree: `artifacts/browser-final-passing.log` contains the failed route state; `artifacts/browser-standalone-final.log` and `artifacts/browser-all-verified.log` contain successful fresh and full reruns. The #1440 fix does not change Note loading or cache admission. Investigate the load error separately.
Author
Owner

Persistent evidence archive. verification/browser-final-passing.log contains the one load failure before Copy link on the ninth Note. verification/browser-standalone-final.log and verification/browser-all-verified.log contain the passing fresh and complete reruns. The final #1440 fix and all gates pass. The load failure remains separate; its original exception/status was not captured.

[Persistent evidence archive](https://git.kayg.org/attachments/a09961d3-5b79-4079-ab7c-cc3552f14982). `verification/browser-final-passing.log` contains the one load failure before Copy link on the ninth Note. `verification/browser-standalone-final.log` and `verification/browser-all-verified.log` contain the passing fresh and complete reruns. The final #1440 fix and all gates pass. The load failure remains separate; its original exception/status was not captured.
Author
Owner

Starting issue #1451 on branch job/coldnote-1451.

Base SHA: d395b6e25da20d8c67b8b9fc1a593b813939c8a7.

I am reading the Note loading path and will reproduce the cold /n/<id> failure with the real production web build and shared release server before changing the client.

Starting issue #1451 on branch `job/coldnote-1451`. Base SHA: `d395b6e25da20d8c67b8b9fc1a593b813939c8a7`. I am reading the Note loading path and will reproduce the cold `/n/<id>` failure with the real production web build and shared release server before changing the client.
Author
Owner

Production reproduction result: the local production web build was served with the release binary from /mnt/hdd/targets/shared-server/CURRENT and macOS platform emulation. The 50-Note sequence completed: every direct uncached read and stable /n/<id> route read returned HTTP 200, all 50 editors became ready, and no error state or client failure event appeared. The original intermittent failure did not reproduce, so its specific triggering response remains unproven.

Code inspection confirms the visible failure path: NoteView.load() treated any non-404/non-401 exception as terminal, with no retry and no diagnostic. The load now retries one transient read failure and records only a structured failure kind/status, without Note ID, title, body or server message. The added API regression test covers a transient 503 and confirms the log is content-free.

Production reproduction result: the local production web build was served with the release binary from `/mnt/hdd/targets/shared-server/CURRENT` and macOS platform emulation. The 50-Note sequence completed: every direct uncached read and stable `/n/<id>` route read returned HTTP 200, all 50 editors became ready, and no error state or client failure event appeared. The original intermittent failure did not reproduce, so its specific triggering response remains unproven. Code inspection confirms the visible failure path: `NoteView.load()` treated any non-404/non-401 exception as terminal, with no retry and no diagnostic. The load now retries one transient read failure and records only a structured failure kind/status, without Note ID, title, body or server message. The added API regression test covers a transient 503 and confirms the log is content-free.
Author
Owner

#1451 final report

Built

  • Note view reads retry one time after transient network, cache-capacity, superseded-read, HTTP 408/425/429, or 5xx failures. Authorization and missing-Note responses do not retry. A failed read emits the structured calternal.notes.note_load_failed event with only attempt, error kind, and HTTP status.
  • The permanent production regression creates 50 Notes through the API, verifies each uncached API read, then opens each stable /n/<id> route. It injects one client-side 503 and checks the automatic retry, editor readiness, zero error states, and sanitized log event. It also profiles a 16-read burst.

Findings

  • The reported spontaneous failure did not reproduce in the natural 50-open production run. All 50 routes opened with HTTP 200 and no client load-failure event.
  • The visible failure path was confirmed: NoteView.load converted any non-404/non-401 read exception directly into the terminal error state, without logging the exception or retrying. A synthetic one-time 503 on the first cold read now produces route statuses 503, 200; all 50 Notes open with zero error states. The structured event was {"attempt":1,"kind":"http","status":503}.
  • No real server 5xx or 429 occurred in the production run. The original initiating transient remains unknown; the new log will identify its kind and status if it recurs.

Verification

  • Production build: bun run build passed. Output included Compressed 914 static variants; saved 21512879 bytes. Existing Svelte CSS and vendor bundle warnings remain.
  • 50-note production regression: passed against the local production web build and the shared release server, with macOS platform emulation. Direct API reads returned 200; the injected first route read returned 503 and the retry returned 200; all 50 editors opened and no error state appeared. The 16 concurrent reads returned 200.
  • Full web gates:
perf-lint: PASS; 0 violations; 22544 scoped exceptions
svelte-check found 0 errors and 4 warnings in 2 files
 Test Files  297 passed (297)
      Tests  2124 passed (2124)
   Start at  15:37:05
   Duration  930.82s (transform 29%, environment 26%, import 22%, tests 17%, setup 5%)
  • Rust gates were not run because no Rust crate changed. Cleanup output: Removed 1 file, 356B total.

Performance

The first #1451 profile is in docs/perf/baseline.json. The normal case is one cold API read per Note. On the 50-Note run, open latency was p50 3550.98 ms and p95 6721.65 ms; server CPU was 4.31 s and RSS changed from 330.875 MiB to 378.637 MiB. One transient adds one read after 50 ms; a 429 uses its Retry-After delay with a one-second bound. The 16-read burst took 1557.67 ms, used 0.08 server CPU seconds, and changed RSS from 378.637 MiB to 379.035 MiB.

The perf VM was held by another calternal benchmark. This local run had load average 29.79–47.94, so treat these numbers as a first data point, not a controlled comparison.

UX gaps closed and left

  • Closed: a single transient cold-read failure retries automatically before the existing error state; diagnostics reveal failure kind and status without Note content.
  • Left: the spontaneous trigger was not reproduced. Persistent failures still use the existing calm error state and manual Try again action. No visual styling changed.

Decisions not covered by DESIGN

  • One view-level retry is allowed after 50 ms for transient network/cache errors and HTTP 408, 425, 429, or 5xx. For 429, the client honors Retry-After for up to one second. Authorization and missing-Note errors remain terminal.
  • The browser log omits Note ID, title, body, and server error message.

Commits

  • f88621582 fix(notes): retry transient cold note reads (#1451)
  • 56b15b2c3 test(notes): profile 50 cold deep-link opens (#1451)
  • a51eab9cb docs(notes): clarify cold read retry boundaries (#1451)
  • e5609d342 docs(test): clarify cold note profile helpers (#1451)
  • Head: e5609d342dfc87ac03221bb5730d008db8a37942
## #1451 final report ### Built - Note view reads retry one time after transient network, cache-capacity, superseded-read, HTTP 408/425/429, or 5xx failures. Authorization and missing-Note responses do not retry. A failed read emits the structured `calternal.notes.note_load_failed` event with only attempt, error kind, and HTTP status. - The permanent production regression creates 50 Notes through the API, verifies each uncached API read, then opens each stable `/n/<id>` route. It injects one client-side 503 and checks the automatic retry, editor readiness, zero error states, and sanitized log event. It also profiles a 16-read burst. ### Findings - The reported spontaneous failure did not reproduce in the natural 50-open production run. All 50 routes opened with HTTP 200 and no client load-failure event. - The visible failure path was confirmed: `NoteView.load` converted any non-404/non-401 read exception directly into the terminal error state, without logging the exception or retrying. A synthetic one-time 503 on the first cold read now produces route statuses `503, 200`; all 50 Notes open with zero error states. The structured event was `{"attempt":1,"kind":"http","status":503}`. - No real server 5xx or 429 occurred in the production run. The original initiating transient remains unknown; the new log will identify its kind and status if it recurs. ### Verification - Production build: `bun run build` passed. Output included `Compressed 914 static variants; saved 21512879 bytes.` Existing Svelte CSS and vendor bundle warnings remain. - 50-note production regression: passed against the local production web build and the shared release server, with macOS platform emulation. Direct API reads returned 200; the injected first route read returned 503 and the retry returned 200; all 50 editors opened and no error state appeared. The 16 concurrent reads returned 200. - Full web gates: ```text perf-lint: PASS; 0 violations; 22544 scoped exceptions svelte-check found 0 errors and 4 warnings in 2 files Test Files 297 passed (297) Tests 2124 passed (2124) Start at 15:37:05 Duration 930.82s (transform 29%, environment 26%, import 22%, tests 17%, setup 5%) ``` - Rust gates were not run because no Rust crate changed. Cleanup output: `Removed 1 file, 356B total`. ### Performance The first #1451 profile is in `docs/perf/baseline.json`. The normal case is one cold API read per Note. On the 50-Note run, open latency was p50 3550.98 ms and p95 6721.65 ms; server CPU was 4.31 s and RSS changed from 330.875 MiB to 378.637 MiB. One transient adds one read after 50 ms; a 429 uses its Retry-After delay with a one-second bound. The 16-read burst took 1557.67 ms, used 0.08 server CPU seconds, and changed RSS from 378.637 MiB to 379.035 MiB. The perf VM was held by another calternal benchmark. This local run had load average 29.79–47.94, so treat these numbers as a first data point, not a controlled comparison. ### UX gaps closed and left - Closed: a single transient cold-read failure retries automatically before the existing error state; diagnostics reveal failure kind and status without Note content. - Left: the spontaneous trigger was not reproduced. Persistent failures still use the existing calm error state and manual Try again action. No visual styling changed. ### Decisions not covered by DESIGN - One view-level retry is allowed after 50 ms for transient network/cache errors and HTTP 408, 425, 429, or 5xx. For 429, the client honors Retry-After for up to one second. Authorization and missing-Note errors remain terminal. - The browser log omits Note ID, title, body, and server error message. ### Commits - `f88621582` fix(notes): retry transient cold note reads (#1451) - `56b15b2c3` test(notes): profile 50 cold deep-link opens (#1451) - `a51eab9cb` docs(notes): clarify cold read retry boundaries (#1451) - `e5609d342` docs(test): clarify cold note profile helpers (#1451) - Head: `e5609d342dfc87ac03221bb5730d008db8a37942`
Author
Owner

Deployed to calternal.cloud in merge round 35b (build 9dc65437e, live 2026-10-09 ~11:07 IST). Closing.

Deployed to calternal.cloud in merge round 35b (build 9dc65437e, live 2026-10-09 ~11:07 IST). Closing.
kayg closed this issue 2026-10-09 05:36:41 +00:00
Commenting is not possible because the repository is archived.
No labels
No milestone
No project
No assignees
1 participant
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-v0#1451
No description provided.