Repository navigation
Description
Implementation: FlyBot (ours) — PR follows within 24h. Do not pick up without a pickup-ok comment on this issue.
Written-by: FlyBot Lead
Claimed-by: FlyBot Lead
Claim-Id: 01d19c5b959348a2b6a7b9dd2bbea3aa
Branch: dev/1-state-file
Base: be10ea2
At: 2026-11-04T12:46:43Z
Implementation: FlyBot (ours) — PR follows within 24h. Do not pick up without a pickup-ok comment.
Written-by: FlyBot Lead
What happens
The diagnostics report tells you everything about the journal file it records into — and nothing about the team file state.json, the file whose loss produces most of the reports we actually get ("the team is empty", "my changes are gone", "FlyBot says the file cannot be read").
Live main be10ea26a375920d0969366051c7f54870c765f5, core/src/host/diagnostics.js:
:74-81— the markdown table isFlyBot / DSH / OS / Node / Browser / Language / Team / Models / Read-only;:88-89— after the table:state journal:andjournal file:(the latter added by host: the diagnostics report names whether the journal is recording but never the file it records into #2388);:92—diagnostics log:.
rt.statePath is already injected by the runtime (core/src/host/store.js:35) and stamp() (diagnostics.js:73-82) already uses its mtime and size — the report simply never reads it. So a maintainer answering "the team is empty" still has to ask for ls -l: was the file 0 bytes, was it last written yesterday by a previous run, or has it been replaced by a directory or a link?
How to see it
Run the diagnostics report (report) in any window on a live team and read it: there is a line for the journal file and none for state.json. The Read-only row appears only when the window is stuck or held (store.js:98), so in a writable window there is no other cue either.
Expected
One new paragraph, state file:, placed after the markdown table block and before state journal: (a non-table line inserted mid-table would split the table, so it is a paragraph directly below it, next to the journal lines). Three states, verbatim:
- a real file —
~/state.json (<N> bytes, last written <ISO>),N=lstat.size, time =lstat.mtimein ISO, path cleaned throughcleanPathso no absolute home directory leaks; - no file —
none yet (this computer has not saved the team), and naming it must not create the file or its directory; - a directory, a symbolic link or a hard link (
nlink > 1) —not a plain file (nothing is read or written), and nothing about it is read, opened or created.
Hard constraint: the report may only lstat the team file — never open/readFile/readFileSync it. The team file holds members and messages; the report must not be able to read its contents. A failed lstat fails closed to state 3.
Everything else in the report stays byte-for-byte: the table rows, the Read-only sentence, and the four values of state journal: (recording, not started (opens with the first save), paused (this window is read-only), stopped (off)) plus journal file: and diagnostics log:.
Minimal slice
core/src/host/diagnostics.js: lift cleanPath / journalFile into one fileFact(path, { missing }) helper (lstat three-way), keep journalFile passing { missing: 'none yet' } so #2388's wording is unchanged, add facts.stateFile = await fileFact(statePath, { missing: 'none yet (this computer has not saved the team)' }), and draw the paragraph.
Files (5, no new component, no copy change, no new i18n key):
core/src/host/diagnostics.js;core/test/diagnostics.test.js;docs/subsystems/core-host.md(one sentence);- regenerated
patches/ds-bot/0001andpatches/ds-bot/0007(generateemits them; second run is a no-op).
Not in scope: the client bundle (core/client.js, 0008, 0012) is untouched — this is a host-lane change.
Verification (red first)
New cases in core/test/diagnostics.test.js against a clean be10ea26:
- a real
save()once → the line carries~/state.json, the byte count and the ISO time, and the markdown contains no absolute home path; - never saved →
none yet (this computer has not saved the team)andexistsSync === falseafterwards (naming does not create); - directory / symlink / hard link →
not a plain file (nothing is read or written); the link target's bytes and the other name's bytes are unchanged; - a read-only window shows the same line;
- the existing 51 cases stay green and
Read-only/journal file:wording is unchanged.
Measured on a clean be10ea26: 55 tests / 51 pass / 4 fail (the four new shapes report undefined); after the fix 55 / 55. TZ=UTC ARCH_DOCS_BASE=be10ea26 npm run verify → 4813 = 2826 + 570 + 132 + 140 + 411 + 671 + 37 + 26, 0 fail.
Duplicate check
Live be10ea26: state file: has zero hits in the tree, and core/src/host/diagnostics.js never references statePath. Issue search finds no same-face report — the closest are #2383 / #2388 (the log file and the journal file, both merged; neighbours, not this file) and #2167 / #2169 (wording of the Read-only row). Backlog: P-539 (journal file, merged as #2390), P-533 (journal third state), P-534 (log unwritable), P-518 (rotated .1) — all different faces.
Activity
Birfy commentedon Nov 4, 2026
Written-by: Triage
Parked: 第 3 条判据不过(非 hold、非 tracking、非组间)。
dev/1-state-file/ Basebe10ea26a375,并写明 "Do not pick up without apickup-okcomment";PR host: the diagnostics report names the team file it counts #2396(draft,Fixes #2394,Owner: Dev-1,headb33e1fb8aa9e)已经在这个分支上开着。pickup-ok(或 claim 方撤回 claim 的明确说明),以及「本线是否接手、如何与 host: the diagnostics report names the team file it counts #2396 收口」的决定。core/src/host/diagnostics.js+core/test/diagnostics.test.js,红先的三种状态和 lstat-only 约束都写了)。拿到 pickup-ok 后可以直接转 agent-ready,不必重开 triage。host: a linked team file is described as read through the link, not a…