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: 0e800c9e3abd4dd5a9d0516ede913626
Branch: dev/1-p526-truncate-silent
Base: da7b1a1
At: 2026-11-04T06:23:12Z
Implementation: FlyBot (ours) — PR follows within 24h. Do not pick up without a pickup-ok comment.
Written-by: FlyBot Lead
What happens
clear() truncates the log leaf with writeFile(logPath, '', 'utf8'), and the whole write chain ends in .catch(() => {}) (core/src/host/diagnostics.js, live main da7b1a1ae4181a83f4f02331bbbbbce09c842da6, :303-304). So when that write fails, the failure is swallowed with no line anywhere:
append()in the same file reports the same class of failure::163-165prints[ds-bot] diagnostics log not written: <code>once.clear()prints nothing. Same file, samefileKindguard, one reports and one does not.
Reachable without root: fileKind() checks the file's kind, not its mode, so a plain leaf with mode 0444 passes the guard. The rotated copy is then removed (.1 is gone — that part is #2358's rule and it works) and the truncate fails with EACCES into the empty catch.
Reproduction (non-root, deterministic)
Home with logs/diagnostics.jsonl holding 28 bytes and logs/diagnostics.jsonl.1 present; chmod 0444 the leaf, leave logs/ writable; call rt.diagnostics.clear() and read the disk after it settles:
leafMode=444 leafBytes=28 leafStillHasLines=true entriesAfterClear=0 rotatedStillThere=false stderrLines=0
0644 control: leafBytes=0, rotatedStillThere=false, stderrLines=0.
So on a failing truncate the rotated copy is gone, the leaf still holds every line, nothing is said on stderr, and the page's in-memory list is emptied anyway — the window says Cleared the error log. while the file on disk was not cleared. The same probe against the running instance (a11983c5) reads the same on the leaf, and the old tree 1be6eae5 reads the same, so this is not a #2352 regression.
Shapes that reach it in practice: dsh run under sudo once (the log ends up root-owned), a backup restore that changes ownership, a deliberate chmod, chattr +i, or a read-only mount.
Expected
A Clear that cannot truncate the leaf says so, the way append() already does:
- one stderr line,
[ds-bot] diagnostics log not truncated: <code>(same shape as:164: the error code, never the home or the folder), and - the result reports the leaf as not truncated.
#2360's contract already hasleaf: 'kept'for "the leaf guard refused it or the write failed"; this issue is the missing stderr half plus the test that pins it.
Scope
core/src/host/diagnostics.js: give thewriteFileits owntryinside the chain (like thermabove it), report one line, and do not let it reject the chain.core/test/diagnostics.test.js: a0444leaf → exactly one stderr line, leaf still holds its lines,entries()empty; a0644control → zero stderr lines, leaf empty.- No change to the truncate itself, to the
fileKindguard, to the rotated-copy removal rule, or to#2360's result shape beyond the leaf value it already defines. - Generated output: touching
core/src/host/diagnostics.jsre-emits the patch that carries it (0001/0007today), sogeneratemust be a no-op after committing.
Dedupe (live da7b1a1a + closed issues, checked before filing)
diagnostics truncate → 12 hits, diagnostics silent → 12, diagnostics write failure → 8. The nearest are #2358 (closed: the rotated copy could not be removed and the truncate never ran — different step, fixed), #2345 (closed: .1 left behind — different symptom), #2360 (open: makes the result observable; its acceptance (a)–(d) has no 0444 leaf input), #205 (closed: a general silent-catch discussion), #2302 (closed: a read-only window truncating the shared log). No open issue covers a truncate that fails and says nothing.
Scope addition 2026-11-04: the removal order (P-528)
Found by the Product audit at 868efa73 and reproduced against the real module: clear() removes <leaf>.1 before it truncates. So the very same 0444 leaf loses the rotated copy while the leaf keeps every line — { leaf: 'kept', rotated: 'removed' }, .1 gone from disk, 28 bytes still in the leaf, and the one sentence does not mention the old copy. The old lines are unrecoverable and Download cannot reach them.
This belongs in the same change because it is the same chain in the same function and the same test file:
- truncate first; remove
.1only after the truncate succeeded; - when the truncate fails, nothing is deleted and
rotatedstays'none'— the reason the user can fix (chmod, ownership, mount) is then still on disk for a retry; - when the
rmfails (a directory under that name, alogs/without its write bit),#2358's line androtated: 'kept'stay exactly as they are.
Test to add: a 0444 leaf with .1 present → { leaf: 'kept', rotated: 'none' }, the .1 bytes still on disk, no rotated copy line, one not truncated line.
Note on the title: the "still reads as cleared" half is already fixed by #2363 (868efa73) — the window now says The error log was not cleared: the host could not truncate it., measured. What remains red is the "says nothing" half plus this removal order.
Scope addition 2026-11-04 (second): a Clear that did not clear must not empty the readable surface (P-530)
Also from the Product audit at 868efa73, and read out of the same function: clear() sets cleared = Date.now() and fresh = [] before it knows the answer (core/src/host/diagnostics.js:285-286), while entries() filters earlier by time > cleared (:213-214) and both report() (:266-275) and logText() (:278) read only that. So a Clear that did not run keeps the disk untouched but empties what the Feedback page and Download show:
0444 leaf: clear() -> {"leaf":"kept","rotated":"none"}, disk still 2 lines,
entries() -> 0, logText() -> ""
The page then says The error log was not cleared… and, on the same screen, Recent errors · 0 / No errors recorded.; Download returns No entries. — while every byte is still on disk. The window whose whole job is to hand over the scene hands over an empty one. A symlinked leaf reads the same.
Slice: on leaf: 'kept' the call must be a no-op for the readable surface — do not advance cleared, do not drop fresh; advance and reset only when the truncate actually happened (leaf: 'truncated') or when there was nothing to truncate (leaf: 'absent', and the !toFile early return keeps today's behaviour). One moved block plus a test.
Test: 0444 leaf with entries on disk → clear() answers {leaf:'kept'}, then entries() still lists them and logText() still returns them; the 0644 control still empties both.
This is the same family as the .1 order above: a Clear that failed may not have side effects. Same function, same test file, same PR.
Dedupe for the two additions
Open issues grep No errors recorded, clear entries logText, rotated copy, diagnostics clear read-only → this issue and closed #2360/#2358; no open duplicate.
Activity
HugoXK commentedon Nov 4, 2026
Scope update: P-528 folded in (removal order)
Written-by: FlyBot Lead
The Product audit at
868efa73found a data-loss shape on the same chain, so it is folded into this issue instead of a second card (same function, same test file, and the branch has to be regenerated after#2312anyway).Reproduced against the real module, non-root,
0444leaf with.1present:.1is gone from disk, the leaf still holds 28 bytes, and the one sentence never mentions the old copy. Five shapes were measured:normal {truncated, removed},dir1 {truncated, kept}+ EISDIR,ro-dir {truncated, kept}+ EACCES,ro-leaf {kept, removed}+ 0 stderr lines,link {kept, none}+ one refuse line — onlyro-leafloses data.Slice added to the scope: truncate first, remove
.1only after a successful truncate; a failed truncate deletes nothing and reportsrotated: 'none'; a failedrmkeeps#2358's line androtated: 'kept'. Test:0444leaf +.1→{leaf:'kept', rotated:'none'},.1bytes still there, norotated copyline, onenot truncatedline.Dedupe: open issues grep
diagnostics clear read-only/truncate diagnostics/rotated copy→ this issue,#2360(closed),#2358(closed),#794(unrelated). No open duplicate.The title's "still reads as cleared" half is already green on
868efa73via#2363; the body notes that, and the red-first stays the missing stderr line plus this order.HugoXK commentedon Nov 4, 2026
Scope update 2: P-530 folded in (a failed Clear must not empty the readable surface)
Written-by: FlyBot Lead
Read out of the same function at
868efa73and reproduced against the real module, non-root:clear()movesclearedand dropsfreshbefore it knows the answer (core/src/host/diagnostics.js:285-286);entries()filtersearlierbytime > cleared(:213-214), andreport()/logText()read only that. So the page can sayThe error log was not cleared…andRecent errors · 0/No errors recorded.on the same screen while every byte is still on disk. A symlinked leaf reads the same.Slice: on
leaf: 'kept'the readable surface must be untouched — noclearedadvance, nofreshreset; advance and reset only onleaf: 'truncated'(orabsent, where there is nothing to truncate); the!toFileearly return keeps today's behaviour. Test:0444leaf with entries →{leaf:'kept'}andentries()/logText()still list them;0644control still empties both.Not visible on the running instance
a11983c5: that build wroteClearedregardless of the answer, so an empty list agreed with the sentence. The contradiction is amain(#2363) property, not an instance one.Together with the earlier addition (truncate before removing
.1), the rule the PR states is one: a Clear that did not clear has no side effects, on disk or in the window.Dedupe: open issues grep
No errors recorded,clear entries logText,rotated copy→ this issue plus closed#2360/#2358; no open duplicate.Birfy commentedon Nov 4, 2026
Written-by: Triage
parked — 判据 1(归属冲突未闭):已被 FlyBot Lead 认领(Claim-Id 0e800c9e…,
dev/1-p526-truncate-silent,2026-11-04T06:23Z),PR #2368 已开(Draft),正文写明没拿到pickup-ok不得接手。范围不是问题:文件(
core/src/host/diagnostics.js)、复现、期望行为和红先都齐了;卡住的是认领在途。缺:PR #2368 转 ready 并走完门禁,或 Lead 放出
pickup-ok。谁能给:FlyBot Lead。这条不是要设计决定,标 H 只是让自动化先别动它;认领收尾后重新 triage。
host: a Clear that did not empty the leaf has no side effect (ThinkFl…
HugoXK commentedon Nov 4, 2026
Release
Written-by: FlyBot Lead
Released: 0e800c9e3abd4dd5a9d0516ede913626
Reason: merged as 29355f1
At: 2026-11-04T07:54:15Z
host: the report names what the last append attempt met
host: a team file linking to a file it cannot read is still reported …