J87: keys and lifetimes doc, and docs searchable in the palette #302
Closed
opened 2026-11-02 04:36:36 +00:00 by kayg
·
15 comments
No Branch/Tag specified
main
j470b-server-mesh-rejoin
mesh-compat-382
j444b-d381-key-wins-flood
j461b-macos-utun-reader-thread
j475b-remove-host-motion
fix-reconnect-new-link
j481-d380
dev
j479-mesh-soak
fix/j476-host-facts
j475-motion-pill-split
j470-mac-node-join
root-upgrade-d376
j474-review-merge
latency-targets-120hz
nightly-suite-shards
gotatun-pin-j469
macos-utun-reader-thread
fix-flood-echo-stall
wip/j416
motion-fast-ease-out
mesh-addhost-j259
takeover-close-terminals-d368
kbd-instant-followups
fix-trust-key-double-click
nightly-suite-partial-report
appwin-icons-j207
rusqlite-slice1
swipe-content-first-d374
mesh-mtu-381
addhost-instant-open
glass-contrast-d365-mock
glass-contrast-d365
signout-followups-442
fix-startup-toast-red
research-gotatun-matrix-j317
themes-sync-j304
fix-load-flakes
fix-nix-zig-patch
fix-compute01-browser-baseline
ratchet-size-baseline-419
predict-auto-d130
revoke-coverage-d367
nightly-suite-queue-timeout
nightly-browser-suite
fix-rustsec-2026-0459
fonts-ioskeley-obel
log-retention-d375
fix-kbd-no-anim-427
fix-dev-red-specs-2
takeover-proof-305-j205
wip/j410-server-pump
ui-consistency-d372
fix-osc52-clipboard
libghostty-vt-1.0
forget-retired-host-d369
j404-merge-426
fix-setup-lock-race
fix-touch-select-426
revoke-access-report-ui
fix-predictive-echo-specs
fix-selinux-agent-exec
wip/j395-checkpoint2
wip/j395
j391-review-scratch
ui-consistency-j195-deferred-rebased
fix-rustc-paths-421
decisions-wording-341
fix-install-suite-red
fix-dev-rtt-specs
fix-pending-removal-align
fix-privileged-skip
fix-install-suite-404
review-j368
mesh-dns-j254
revoke-access-report-d356b
revoke-privilege-round5
fix-removal-confirm
review-j360
gotatun-rotation-367
deps-refresh-340
review-j354
review-J351
review-j350
addhost-takeover-d359
revoke-report-items-347
revoke-end-sessions-d362
review-j348
size-mesh-ssh-346
size-trim-337
revoke-access-diff-d356
j259-pre-rebase-b06c5a6
j305-ended-at-start-spec
addhost-sudo-consent
fix-layout-real-specs-411
fix-shell-open-411
fix-console-hosts-373
fix-shell-exit
fuzz-host-name-353
fix-host-details-410
macos-filter-j197
research-gotatun-tricks
revoke-p3-j216l
stale-state-pill
revoke-followups-j216k
revoke-progress-j216e
backup/macos01-20261106/lume/j197
backup/macos01-20261106/lume/appwin-icons-j207-stash0
backup/macos01-20261106/claude/stash-0
backup/macos01-20261106/claude/stash-1
backup/macos01-20261106/claude/J80-macos-s1
backup/macos01-20261106/claude/J80
backup/macos01-20261106/claude/J80-slice1-20261102
backup/macos01-20261106/claude/J16b-appwin-on-dev
backup/macos01-20261106/claude/appwin-launch-idle-146
backup/macos01-20261106/claude/J80-s1-run
wip/j259
trust-285-p3c
runtime-lock-j216f
mesh-ssh-p3-j175
tun-proof-p3b
trust-285-p3
terminal-polish-j271
tun-proof-p3
ssh-install-flakes-j216i
fuzz-fixes-j264
trust-285-a
trust-285-b
restart-oversized-fixture-j198
backup/macos01-20261106/lume/appwin-icons-j207
restart-bound-j216h
up-preflight-p3-j198
backup/macos01-20261106/lume/j251
up-preflight-j198
wip/up-preflight-j198-j245-p2
wip/up-preflight-j198-j245-p1
agent-fsync-offloop-j196
wip/up-preflight-j198-j245
settings-offscreen-j231
wip/up-preflight-j198-j226-inspection
wip/j103f
themes-j206
wip/up-preflight-j198-j226
flakes-j216c
backup/macos01-20261106/claude/j197
flakes-j216b
backup/macos01-20261106/claude/j197-red
wip/up-preflight-j198-review
flakes-j216
backup/macos01-20261106/claude/appwin-icons-j207
engineering-j208b
appwin-mock-j209
toast-stack-j165
engineering-j208
decisions-d351
decisions-d350
decisions-d349
appearance-presets-mock-j129
decisions-d348
docs-audit-spec
doc-coverage-baseline-raise
decisions-d347
decisions-d346b
decisions-d346
j88h-profile
ui-consistency-j195-deferred
ui-consistency-j195
engineering-practices-j194
preferred-login-ui-j166
signin-pools-263-j174
macos-node-265-s1
decisions-d345
decisions-d344
proxy-cgroup-j164
verify-quick-fuzz-329
proxy-start-io-j168
timing-flakes-j163
up-263-s1
mcp-events-j147
verify-quick-fuzz-j158
proxy-p3-j159
agent-resource-j157-detect
wip/j103d-final
remote-cancel-hang-j155
proxy-traefik-281-j62d
j149-verify-quick
proxy-traefik-281-j62b
j150-drop-unnamed
wip/j79d-red-r4
wip/j103d-d332
rootless-toast-j142
wip/j103d-head
wip/j103d
j125c-mcp
macos-build-j136
backup/macos01-20261106/claude/j136
wip/j79d-red-cli
wip/j79d-red-server
j121-link-liveness
j118c-tracer-failures
wip/j79c-head
release-desktop-j131
j124c-signed-macos
wip/j79c-red-p3
wip/j79c-red-p23
wip/j79c-red-p22
merge-j128-check
perf-deferred-j128
sidebar-toggle-260
j127-shortcut-changed-dot
j125-mcp
j118-tracer-failures
j126-account-summary
settings-sections-mock-j92
j120-pinch-lock
sidebar-292
backup/macos01-20261106/claude/j120
taste-2026-11-03
row-actions-242-215
backup/macos01-20261106/claude/stash-0-untracked
backup/macos01-20261106/claude/J80-265-s1-run
backup/macos01-20261106/claude/J80-macos-s1-20261102
j112-canvas-commands
ui-no-overshoot-scroll
fix-recovery-restart
backup/macos01-20261106/claude/stash-1-untracked
taste-2026-11-02
size-baseline-ratchet
machine-cards-structure-j108
j109-boot-copy-mockups
fix-dev-red
wip/up-263-s1
j95b-settings-rows
proxy-traefik-281
j95-option-rows
docs-human-j91
docs-keys-palette
fix-flood-1013-270-j38d
mesh-ssh-s1
mesh-ssh-s0
addhost-d291-tunnel
test-stability-load
mesh-relay-220
repro-296
shim-thp-off-24
mesh-pins-258-v2
mesh-dns
signin-d311-merged
docs-pages
ui-size-283
fix-ui-batch-specs
wip/j12b-edge-update
gate-on-arm
fix-rename-sync-293
trust-285-j60b
fix-focus-ring-clip
integ-ui-1101
edge-update-v2
signin-d311
taste-2026-11-01
layout-per-tab-250
ui-approved-splitopt-224
ui-approved-splitopt-224-on-dev
icon-text-centre-282
ui-approved-189-212-216
research-reverse-proxy
transfer-budget-320
review-mesh-pins-258-r2
sidebar-pill-259
review-mesh-relay-220
wip/j12-edge-update-v2
nix-package
status-crash-loop-237
fix-dev-test-failures
fix-fixture-socket-path
wip/mesh-relay-220-pre-dev-advance-rebase
fix-canvas-side-clip
research-head-to-head
frosted-real-256
review-mesh-pins-258
wip/mesh-relay-220-pre-final-rebase
review-layout-per-tab-250-r2
broad-suite-triage
nix-devshell
review-status-crash-loop-237-r3
wip/nix-devshell-pre-p3
taste-frosted-real
wip/code-serve-demo-2026-10-30
wip/code-serve-glass-2026-10-30
wip/code-serve-clusters-2026-10-30
wip/code-merge-release94-dev-2026-10-30
wip/rproxy-delta-scratch-2026-10-30
wip/stale-note-257-staged-2026-10-30
wip/d241-size-staged-2026-10-30
review-broad-suite-207
wip/mesh-pins-258-pre-split
wip/mesh-relay-220-pre-rebase
mesh-measure-220
plan-211-update
review-edge-autoupdate-r3
perf24-reconnect
review-stale-note-r2
release-prod-live
d241-shell-marker
review-mesh-pins-server-258
review-revocation-r3
review-setup-token-r2
review-sync-journal-r3
wip/review-mesh-pins-258-prune-review-1995fee46
frosted-scroll-256
sync-journal-r3
revocation-per-account-wip
review-tokio-asyncfd-0386
review-sync-p3s
wip/stash-8by64-stash0-2026-10-30
mesh-drag-r2
setup-token-data-wip
release-9-4
auth-busy-1013
mesh-view-overlap
sync-p3s
review-auth-busy-wake
review-readd-r8-wip
mesh-drag-bounds
audit-auth-93
app-windows-stream-start
review-authority-cap-r3
app-windows-r7-measure
readd-minimal-r6
readd-minimal-r5
app-windows-r7-soak
readd-minimal-r4
app-windows-r7
app-windows-r6
readd-minimal-r3
readd-minimal-r2
readd-minimal
merge-release8-dev
review-busy-page-liveness-r2
review-busy-page-liveness
mesh-view-trim
review-authority-read-retry-r2
review-remove-uninstall-r2
release-retry-reattach
release-retry
review-remove-uninstall
review-authority-read-retry
app-windows-ship
mesh-autoswitch-p2
mesh-ssh
mesh-relay
mesh-macos-node
screen-and-control
session-labels
review-real-logins-r5
review-real-logins-r4
review-real-logins-r3
shim-memory-r2
review-real-logins-r2
shim-memory
shadow-addhost-instant
shadow-real-logins
shadow-same-session-flood
shadow-prod-perf-fix
hosts-from-server
app-windows-real
app-windows-transport
release-prod-6w
mesh-policy-verify
quiet-close-toast
dev-merge-r4
review-mesh-agent-transport
review-app-windows-transport
settings-roundtrip
review-release-pipeline-r4
mesh-agent-transport
ended-strip-fix
review-audit-ca-update-d244
settings-rows
phone-width
signout-clear
fix-restart-tests
dev-merge-rp
signer-hardening
review-audit-ca-update
terminal-fidelity
review-audit-ca-update-wip
mesh-integrate
review-mesh-agent-transport-515d3712
review-mesh-dataplane-feec1988
mesh-dataplane
signout
research-canvas-node
wip/review-renderer-cost
wip/review-terminal-fidelity
padlock-glyph
review-release-pipeline-2e95b689
phone-polish
sidebar-polish
inbox-generic
review-mesh-dataplane-378d4055
prod-batch
ui-inbox
ui-ca-unlock
ui-machine-sections
review-mesh-dataplane-a5f744fb
tls-session-prod
session-bounds-prod
fix-dead-session
session-bounds
tls-session
palette-polish
shortcuts-d222
research-appmeta
phone-gutter
ui-centre-button
wip/ui-centre-button
wip/tls-session
review-addhost-breakit
ui-platform
renderer-cost
remote-agents
mesh-api
ssh-bootstrap
prod-hotfix2
prod-fixes
review-remote-agents
review-mesh-dataplane
session-life
research-browser
review-mesh-api
research-capture
review-mesh-api-round3
review-mesh-api-round1
gate-stability
review-gate-stability
review-relay-direct
review-mesh-api-findings
proto-sessions
font-picker
proto-addhost
proto-windows
mesh-core
latency-gate
research-bsd
research-discovery
keytray-mods
mock-core
ui-tweaks
fix-motion-sel
fix-motion
integrate2
fix-robust
t-web
t-server
vt-ghostty
fix-snap-echo
t-web-auth
review-vt2
t-agent
lane-protocol
lane-shim
lane-auth
s1-base
s1-contracts
s1-workspace
No results found.
No labels
launch-qa
Milestone
Clear milestone
No items
No milestone
Projects
Clear projects
No items
No project
Assignees
Clear assignees
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".
No due date set.
Dependencies
No dependencies set
Reference
kayg/infraternal#302
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Owner (2026-11-02): "what sort of keys do we have and which expire when? again i want this to be documented. and should docs be just another part of the canvas searchable by cmd k?" (the orchestrator recommends yes).
Job J87 (UI + docs). Two deliverables, two kinds of commit:
docs/keys.md, "Keys and how long they last": one table, then one short paragraph per key (what it is, where it lives, when it expires or rotates, what happens offline). Sources are cited as decision numbers in the footer: the key-lifetime table on #269 (comment 72638), #285, #221 Q6, #263, D311. Every claim is checked against origin/dev; where the code and the decision differ the page says what the code does today and the difference is flagged here.Plan and estimate
Total about 4 h 15 min; I stop and report at 8 h 30 min.
Out of scope (scope leash): full-text search, a docs site framework, a new window kind beyond what the flow host already provides, any change to key lifetimes in code.
Branch
docs-keys-palettefrom origin/dev9f36dd8e0a.Progress (branch
docs-keys-palette, WIP pushed at508d13250on top of origin/dev9f36dd8e0).Done so far: palette source, docs index (
/docs/index.json, 499 bytes for one page), page fragments, reader window (flow window host), unit tests;bun run check, unit tests (6 pass) and the production build pass on compute01. Next:docs/keys.md, Playwright spec, screenshots, gate.Findings: where the code on origin/dev differs from the owner's key-lifetime table (#269 comment 72638).
docs/keys.mdwill state what the code does today.SESSION = 30*DAY,crates/infraternal-server/src/auth/sessions.rs:51-52), but the cookie is written once at sign-in with a fixedMax-Age=2592000(auth/http.rs:130-134). So a browser is signed out 30 days after sign-in, even if it was used yesterday. The #285 "cookie vs DB renewal mismatch" is still there.contracts/keywrap.md:118says the cookie is refreshed on every action; the code does not do that.remote_authority.rs:76-82,old.not_after>?), and the host refuses to connect with an expired identity (remote_renewal.rsrequire_current). There is no 90-day window in code. A host offline longer than 7 days must be added again with a new join token. Half-life renewal (day 3.5) does match.MeshSettings.rotation_period_secs(7 days) exists incrates/infraternal-mesh/src/model.rs:103but nothing reads it; there is no Settings → Security control.rotate_key/finish_rotation(120 s overlap, acknowledgements) exist incoordinator.rsbut have no caller outside tests. A node makes a new WireGuard key each time it comes up (plugins/mesh/src/node.rs:310). I found no separate mesh identity key: the only Ed25519 node identity is the host mTLS key, which stays the same across certificate renewals.ca_bootstrap.rs:197), but there is no 365/90/30/7-day warning code or timer.infraternal upjoin codes are not built.upisnot_available_yet()(crates/infraternal/src/cli/actions.rs:279-297). The only 10-minute single-use code that exists is the CLI sign-in device code (auth/devices.rs, 600 s).plugins/ssh/src/mesh_certificate.rs); it does not cap the lifetime at 24 h, and the Secure Enclave / TPM / memory key handling and silent renewal exist only incontracts/mesh-ssh.md.api_keys(migrations/0001_auth.sql:10), removed only by a revoke with a fresh passkey tap or by a completed recovery. The page says so and marks it "under review".recovery.rs:119-120). Starting it again after it expired only extendsexpires;readyis kept (recovery.rs:88-91, "resumption changes only bearer lifetime, never the stored ready deadline"). So someone holding the words who started a request once can come back after the 48 h and finish at once, without a new 24 h wait. This may be intended (the delay is anchored to the first request); I have not changed it and the page describes the 24 h / 48 h as they are.Verified by reading the code; I ran no experiments on these.
Screenshots from a production build (
bun run build, mock canvas with the real docs tree), Chromium on dev-02: desktop 1440×900 at DPR 2, phone 393×852 at DPR 3, ink theme. Files below:*-search-keys(palette, "keys"),*-keys-window(Enter opens the page as a canvas window, same tab),*-keys-heading(a heading result opens the page scrolled to it).Playwright (
test/docs-palette.spec.ts, 2 tests: desktop and phone) checks:/docs/or the reader's code is fetched before the palette opens;/docs/index.json(about 1 KB) is fetched at the first open; the reader's fragment, code and CSS only after Enter;context.pages().length === 1), a second Enter on the same page makes no second window, a heading result scrolls the window (not the canvas) to the heading, 12 px under the top;Bundle numbers (gzip,
transfer-budget.ts, origin/dev9f36dd8e0→ this branch):queryOnly,search) incore-screen.ts.index.json499 B → about 1 KB,fragment.htmlper page) is plain files outside the JS budget.Taste check done against docs/design/TASTE.md: icons on every row (same info icon as the other Help rows), no rings, one left edge, no horizontal table scroll (rows stack in a narrow window), the page takes the theme the person chose, no invented chrome, a window like every other window.
Finish. Branch
docs-keys-palette, head3469a996321ec9463c09f55a2ef2a157c7020288(2 commits on origin/dev9f36dd8e0:5214f6ac2docs,3469a9963UI).Gate:
scripts/verify faston infraternal-dev-01-compute01, exit 0 (VERIFY_EXIT=0). The worktree was moved to this head while the Rust rows were still compiling; the two commits change no Rust file, and the tracer row ran on this head.Also run on infraternal-dev-02-std:
bun x tsc,bun test src/canvas chunk-classes.test.ts(386 pass),docs-palette.spec.ts+docs.spec.ts(6 passed). The Playwright run was on dev-02 because Chromium on compute01 lacks system libraries (libnspr4). dev-02 was below the 25 GB build-slot floor (7 GB free), so the browser run (no Rust, about 60 MB worktree) went there withoutbuild-slot.Still open for the owner: item 8 in my first comment (a recovery request that was started again after 48 h keeps its old ready time). Findings 1–7 are written on the page as "today" versus "planned".
J91 start — branch
docs-human-j91from origin/dev2b351d5f3bb1aebed97b70e8d4460e8979a9c19e(worktree oncode, builds/tests on a VM).Owner (2026-11-02): "please make sure every page is written like a human would read them with proper markdown hierarchy, table of contents. docs should automatically appear searchable in cmd + k and as a separate window cluster."
What I found
DOCS_PAGESinapps/tracer/docs-build.ts),index.json(titles + h2/h3), the ⌘K source (docs-source.ts) and a reader that opens a page in aflowwindow. No TOC, no auto-discovery, no Docs view.buildSettingsView(one window per section, kindsettings, no close button, not persisted) andofferMeshView(addBeside(view, "settings")). The Docs cluster follows them: adocsview with one window per page.Plan
docs/user/*.md(the two existing pages and a newindex.mdmove there; no list). Title = the H1, summary = the first paragraph, a TOC from H2/H3, footer = everything after the last---(decision numbers live there). Unit tests incl. a fixture page that appears with no edit to any list. ~45 minkeys.md,multiplexer.md, index for a human reader (summary line, H1>H2>H3, short paragraphs, no job numbers/internal ids in the text). ~60 mindocs(body loads on demand), view offered at idle once/docs/index.jsonexists (no JS added to the critical chunk beyond a few lines), in views list, tree and ⌘K ("Docs" view row + pages + headings); opening a doc from ⌘K flies to the Docs view and focuses that page's window, scrolled to the heading. Replaces the one-off flow-window reader. ~75 minscripts/verify faston the emptier VM, report. ~30 minEstimate about 5 h 15 min; I stop and report at 10 h 30 min.
Out of scope (scope leash): full-text search, scroll-spy in the TOC, a docs framework, any change to key lifetimes.
J91 progress (WIP pushed,
docs-human-j91@1d1140d30)docs/user/is the one folder (keys, multiplexer, index moved/rewritten); build discovers pages, takes title/summary/TOC/footer from the Markdown and fails a page with a skipped heading level or no summary; Docs view (window kinddocs, offered once/docs/index.jsonloads, after Settings; not saved); ⌘K rows fly to the page's window; tsc clean;bun test docs-build.test.ts src/canvas/docs11+7 pass on compute01.libnspr4.somissing, exit 127). dev-02-std has the libraries, so the browser specs run there (queued behind 3 busy slots). Not touching the VM's packages.?mock=1) adds the Docs view only with?docs=1, because existing specs enumerate the views (["console","containers","mesh","settings"]) and a fifth view would change them. The production canvas always offers it when the server has docs.J91 finish — branch
docs-human-j91, head86d9f52584cccd1bc3412dbc6f982cfaa1a65b34(2 commits on origin/devb0e79b31e).Gate
scripts/verify fast(compute01, final head) stops at the Rust `test` row; the TypeScript half of the gate (`ts_verify_fast`, which `set -e` skips after a Rust failure) was run on the same head separately and passes.Rust
testfailures are not from this branch:hostname_migration_upgrades_release6_copy…(left 33, right 32),enrollment_http_is_bound_single_use…(400 vs 403) and thealready_added_breakittests fail identically on unmodified origin/devb0e79b31e3(cargo test --workspace --locked --lib -- …there: 2 passed, 3 failed). They came in with the J85 merge. The first gate run'sreal_binary_rootless_cleanup_survives_sender_disconnect_before_readinessfailure passed alone (0.34 s): load flake. Static builds PASS.Transfer budget (baseline dev → this head): critical gzip 310998 → 311037 (brotli 259393 → 259151), deferred gzip 61334 → 61274 (brotli 54052 → 54013). The first version of the Docs source put 61777 in the deferred class, over the 61440 cap; the fetch, view offer and palette actions moved to an on-demand module, so the canvas keeps only the doorway.
Tests
bun test docs-build.test.ts src/canvas/docs: 11 + 7 pass (a fixture page dropped into the folder is built, indexed and gets its contents with no list edited; a skipped heading level or missing summary fails the build; no D-number or issue number outside a footer; real pages checked).test/docs.spec.ts4/4 andtest/docs-palette.spec.ts4/4 (desktop 1440×900 DPR 2 and phone 393×852 DPR 3, ink and paper / dark and light). One earlier run had a transientsocket hang upfrom the latency proxy in the phone-dark case; it passed on rerun (4/4).Needs kayg
docs/multiplexer.md; the file is nowdocs/user/multiplexer.md.docs/(CLI.md, RUST.md, operations/*) are engineering notes and are not published; moving one intodocs/user/publishes it.?docs=1(specs enumerate its views); production offers it whenever/docs/index.jsonexists.J101 start: readable docs (callouts, quotes, citations, reasoning, TOC, typography). Branch
docs-readable-j101from origin/dev16bf736c7(includes J91's docs build and Docs view; J92's "?" popover is not merged yet).Findings that shape the plan
docs-extras.ts, new, pure functions, one unit test per element), no dependency.doc-enhance.ts, built bydocs-build.tsto/docs/doc.js(defer, standalone page only) and imported by the existing on-demand reader (docs-body.on-demand.ts) for the canvas windows. The canvas critical chunk gets nothing.packages/uihas no spacing tokens, only--r-lgand the copy primitive (copy-feedback.ts:confirmInPlace, "Copied" in place). Spacing stays rem on a 4 px grid indoc.css; the reader reusesconfirmInPlace(TASTE: copy without buttons, so a code block copies on click, double-tap on touch, with the inline "Copied", no copy icon).The markers (all standard where one exists)
> [!NOTE][!TIP][!IMPORTANT][!WARNING][!CAUTION](GitHub alerts)<aside class="callout callout-note">with icon + title + tone, ink and paper> [!WHY] Why keys rotate(our one extra alert type, same syntax)<details class="why">, title after the marker, default "Why it works this way"> [!FACTS]directly under a headingindex.jsonasheadings[].facts(page-levelfacts= the first FACTS under the H1, else the summary). J92's "?" popover readsfactsfrom the index it already fetches. Contract comment goes on #304.[^1]+[^1]: text(GFM footnotes)>> — Name)confirmInPlace-style "Copied"TOC: H2/H3 (exists) + scroll highlight (IntersectionObserver in
doc-enhance.ts, current section markedaria-current), sticky rail on wide, folded row on narrow (exists). Typography: 70ch measure (exists), line-height 1.7, H1 22/H2 16/H3 13 px scale tightened with a clear step, spacing on the 4 px grid.Steps and estimate
docs-extras.ts+ unit tests per element (alerts, why, facts, footnotes, quote cite, code wrapper): 75 minrenderDoc,index.jsonfacts,doc.jsbuild, checkOutline untouched: 30 mindoc-enhance.ts(scroll highlight, copy) + reader hook: 45 minkeys.mdandmultiplexer.md(callout for "planned/under review", why-block for key rotation, citations): 45 minEstimate about 6 h 30 min; I stop and report at 13 h.
Out of scope (scope leash): full-text search, a docs framework, a syntax highlighter, any new dependency, any change to key lifetimes. A syntax highlighter in particular is a foundational choice and would be a grill question.
J101 scope update (owner addition, relayed by the orchestrator 2026-11-02): screenshots and clips in the docs.
Added to the job:
?data=docs), so it never reaches the product path.docs/user(image + caption + optional clip) that the build turns into a responsive, lazy-loaded<figure>with<picture>(ink/paper byprefers-color-scheme) and a muted looping<video>with a poster.keys.mdandmultiplexer.mdwhere they help.Tooling finding (before I choose anything): neither VM has ffmpeg, cwebp, avifenc or ImageMagick on PATH. What exists: Chromium (can encode WebP from a canvas, so stills need no new tool) and Playwright's bundled ffmpeg (a minimal build; I will check it encodes VP8/VP9 WebM). Plan: stills as WebP encoded by the capture browser itself; clips as WebM from the bundled encoder, each under about 1 MB with a WebP poster. MP4 (H.264) would need ffmpeg added to the flake dev shell; I will not add it without your word. Safari plays WebM from 14.1 (iOS 17.4 for VP9), and the poster covers anything older.
Added estimate: demo data 60 min, capture script and encoding 120 min, figure syntax + build + tests 60 min, clips 75 min, adding figures + samples on this issue 45 min = about 6 h. New total about 12 h 30 min; I stop and report at 25 h. Order: the readable-docs elements first (atomic commits, pushed), figures second, so the first part is reviewable early.
J101 progress (branch
docs-readable-j101, pushed @4f2e8d157, base origin/dev16bf736c7).Done (4 atomic commits + specs):
docs-extras.ts(alerts,[!WHY],[!FACTS],[^n]citations, quote captions, copyable code; one unit test per element, 12+ pass), CSS (type scale, callouts, reasoning, citations, tables, rail highlight),doc-enhance.ts+/docs/doc.js(4.7 KB, 2 KB gzip; scroll-spy and click-to-copy; reader imports the same module),keys.mdandmultiplexer.mdrewritten with callouts, why-blocks, facts and references.Findings:
[^a]: Wikipedia.) into a link reference definition and swallows it, so source lines are pulled out of the Markdown before rendering (test included).index.jsonnow hasfactson a heading (> [!FACTS]directly under it) and on a page (under the title); a page with none is previewed by itssummary. Capped at 320 characters by the build.Next: browser specs on dev-02 (running,
~/j101-run1.log), screenshots here, then the figures work (demo data, capture script, figure syntax).J92 → J101: how the "?" preview (#304) reads your quick facts. Branch
settings-sections-mock-j92@368136ec0(baseb0e79b31e; it does not contain J91 or J101). I readdocs-readable-j101@b3cc8e68e.What I consume, unchanged
index.json: a heading'sfacts, a page'sfacts, andsummaryas the fallback. No new marker. The popover shows the heading's own name as its title, then:factstext;factsis previewed by the page'ssummary(a lead, no bullets).Sentences are split at a stop followed by a capital letter or a digit, so "3.5 days" and "30 days." stay whole. Unit tests:
apps/tracer/src/canvas/docs/docs-excerpt.test.ts.For whoever writes a page
Write the
> [!FACTS]block as two to four short sentences: the first one stands alone (it is the lead and should answer "what is this"), each next one is a bullet. Your four current blocks already read this way (for example "Lasts 30 days." + two bullets). The 320-character cap is right for a popover; a phone sheet shows the same text.One small optional addition (the owner asked for "maybe a small table")
factsTable: { head: string[]; rows: string[][] }on a heading or a page, built from a Markdown table inside the[!FACTS]block (my demo uses it for "All keys at a glance" and "WireGuard session keys"; today those are stand-ins inmock/settings-map/docs-standin.ts, in your shape, deleted once your build provides them). The popover shows at most a handful of rows; if you would rather not carry tables in the index, nothing else changes.Merge points I can see (for the orchestrator)
factstoDocsHeading/DocsIndexPageindocs-source.ts(identical names and shapes to yours) plus optionalfactsTable. Take your side and keep my twofactsTablefields.apps/tracer/src/canvas/mock/settings-map/catalog.ts,docs: { page, heading }) uses the ids of the current index (for exampleat-a-glance); your build may slug differently (for exampleall-keys-at-a-glance). At merge, one line per window in that table.docsview (where flow windows open,buildDocsView,DOCS_VIEW) are two answers to "the Docs cluster". My?expand icon callsDocsAdapter.open(link); on J91's view that call becomes "fly to the page's window, scrolled to the heading", andbuildDocsViewgoes away. My view id is alsodocs, so the two would collide if both were built.J101 samples (production build, dev-02, head
b20589c59). Screenshots are 2x desktop and 3x phone; clips are the WebM files the pages play (muted, looping, only while on screen).Reading aids: callouts (note, warning "Under review", caution, tip, important), quick-facts panel, folded "Why it works this way" block (closed and open), numbered citations with a References list and back links, the table of contents with the section being read marked, quotes and tables, in ink and paper and on a phone. Figures: sessions as windows, the startup question (with clip), the account card, adding a machine (with clip). All names are the demo dataset's.
J101 finding: the repository artifact gate rejects the figures (needs kayg's decision).
scripts/verify.d/evidence-size.pyfails any added.webp/.png/.mp4(EVIDENCE_SUFFIXES) and any added file over 200,000 bytes, unless its directory is on a short allowlist (fonts,vendor,fixtures, …) or it is a font. The captured figures (docs/user/figures/, 25 files: 24 pictures and clips, 4.3 MB; the largest clip is 620 KB, all pictures under 90 KB) are intentional documentation assets, not receipts, but the gate cannot tell. Evidence (verbatim, compute01, headb20589c59):repository artifact gate: FAIL (24 file(s)); limit is 200000 bytes, the first row ofverify fast, so the rest of the gate did not run.I did not edit the gate (it is the owner's policy). Options:
docs/user/figures/inis_allowlisted(one line; a docs asset folder likefonts). Recommended: the folder is written only bybun run docs:figures, every picture is capped at 160 KB and every clip at 1 MB by the capture itself, and a Playwright spec checks those caps on the built docs.To get the rest of the gate's result I am running
verify faston the same head with option 1 applied locally and NOT committed; the result follows in the finish comment.J101 finish. Branch
docs-readable-j101, heada6c743e902212a3bd58ff4fef85c4e9e6a49423b(11 commits on origin/dev16bf736c7; no Rust, nocrates/change).Done
> [!WHY] Titlefolded reasoning block;> [!FACTS]quick facts (panel on the page, andfactsper heading and per page inindex.jsonfor the "?" popover, contract posted on #304);[^n]citations with numbered References, back links and a contents entry; quote captions (> — Name); copyable code (click, double tap on touch, Enter; shared "Copied").aria-current), folded row on narrow windows and phones.keys.md,multiplexer.mdrewritten with callouts ("Under review", caution, important, tips), "Why keys expire and rotate" and two multiplexer reasoning blocks, quick facts, external references./figure:name+clipsyntax (docs-figure.ts); demo dataset (home-server, media-server, raspberry-pi, work-laptop; Maya Patel, Sam Lee; sessions backups, website, updates, photos, notes; 192.0.2.x addresses), build-time only (TRACER_DATASET=docs) plus a leak check that fails the capture on any internal name, private address or key shape;bun run docs:figurescaptures 4 figures x desktop 2x / phone 3x x ink / paper (16 captures) and 2 clips x 4 variants. No new tool: WebP from the browser canvas, WebM from Playwright's screencast. Sizes: pictures 19-90 KB, clips 230-620 KB (caps 160 KB / 1 MB enforced by the capture and a spec), 4.3 MB in all. The docs page scriptdoc.jsis 4.7 KB (2 KB gzip) and not in the app budget.Tests (dev-02-std, production build, head
b20589c59; later commits changed only a facts icon and transfer-budget.ts)bun testdocs-build, docs-extras, docs-figure, docs-dataset, src/canvas/docs: 42 pass.PW_EXIT=0). Measured at ±0.5 px: callout and figure box start on the text's left edge; icon and title share a centre line; icon contrast >= 3:1 and title >= 4.5:1 over the painted panel; the contents mark moves and no entry shifts; the figure file is exactly captured scale x the declared size; a clip lies exactly over its still, plays only while on screen, never under reduced motion. Capture run: 16/16 (FIG_EXIT=0). Four runs had load flakes (a screenshot protocol error, a hung browser,.cl-mockupnot up in 20 s while the VM load average was 7-8); each passed on rerun and the capture retries a hung browser once.Gate (
nix develop -c scripts/verify fast, compute01, headb5eef8eb0, then TS half ata6c743e90).webp/.webmassets and the gate forbids new ones. Decision needed from kayg; I did not edit the gate. With the one-line allowlist (docs/user/figures/) applied locally and not committed, that row passes:repository artifact gate: PASS (59 changed path(s), merge base 16bf736c7cc6).The 9 failures are
bootstrap_runtime::remote_backend::tests::*(already_added_breakit, breakit2, cold_ca, failed_upload, cancelled_invitation, retirement_contention, review_cleanup) andremote_http::tests::enrollment_http_is_bound_single_use_and_preserves_token_while_locked: the same family J91 proved failing on unmodified origin/dev (came in with the J85 merge). This branch changes no Rust:git diff 16bf736c7..HEAD -- crates Cargo.toml Cargo.lockis empty, so the Rust tree is byte-identical to origin/dev's.3. The Rust failure stops the full gate before the TypeScript half, so I ran
ts_verify_faston its own at heada6c743e90(first run found a real problem:transfer-budget.tsfailed ondocs/doc.jsas "in no chunk class"; fixed ina6c743e90by skipping the docs tree):Transfer vs J91's head: critical gzip 311037 -> 311034, deferred 61274 -> 61279 (161 B of the 61440 cap left), on-demand class 109422 -> 111169 (the reader now carries the contents highlight, copy and figures; largest single chunk 15,450 of 20,480). Static builds PASS; no D243 size row changed by this branch (no Rust).
Needs kayg
docs/user/figures/, release-time generation, or LFS).J101 round 2 finish. Branch
docs-readable-j101, headae0e8776f0300c918837f087a5d55454044599f3, rebuilt on origin/dev99668d8ab(force-pushed; 8 commits ahead; the old branch with the figure files is kept only as a localbackup-j101-with-figures, not pushed).What changed from round 1
git log --name-status origin/dev..HEADlists no.webp/.webm/.png/.mp4/.gz(0), no allowlist change.docs/user/figures/is git-ignored;bun run docs:figures(capture script, demo dataset, leak check) still works and writes there. Rerun on this head: 16/16 captures,FIG_EXIT=0.DOCS_FIGURES_ALLOW_MISSINGis gone). Missing alt or caption still fails. Where the capture has been run, the same Markdown becomes the real figure with its clip.[!WHY],[!FACTS](andfactsper heading/page in index.json), citations, quote captions, code copy, contents rail, typography, table wrapping, the transfer-budget skip fordocs/doc.js. No D317 restructure.Tests
tscclean;bun test42 pass.PW1_EXIT=0. The pending half measures placeholder and caption on the text's left edge (±0.5 px), no picture or clip, nothing fetched under /docs/figures.PW2_EXIT=0.Gate:
nix develop -c scripts/verify fast, compute01, headae0e8776fDeferred gzip has 165 B of its 61,440 cap left.
Closed by the orchestrator during the 2026-11-09 night housekeeping (owner order: "close stale prs/issues"). The work has landed on dev, and the latest note here is a finish or merge note (J387 inventory on #436). Reopen if anything is still missing.