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: 95d0e4245fd14bcc90983a9d998a1a0b
Branch: dev/2-p280-diagnostics-test-strength
Base: f87fceb
At: 2026-10-31T10:39:37Z
Dedupe (checked before opening): open issues searched for diagnostics stack summary return only #1919 (the change that added this test) and #1918 (a different file); nothing covers the test's strength or the changelog sentence. No Implementation: marker from another team on any of them.
Problem
#1920 (#1919) replaced entry.text.slice(0, 80) with cut(entry.text, 80).text in the report's <details><summary>Stack: line, and added one case to core/test/diagnostics.test.js — "a stack summary cut at its bound never splits a surrogate pair (#1919)". That case pins only the upper bound:
shown.length <= 80shown.isWellFormed()is true and the output has no U+FFFD- dropping the tail leaves a byte-for-byte UTF-8 prefix of the input
None of these changes if the bound itself is wrong. Change cut(entry.text, 80) to cut(entry.text, 40) — or to cut(entry.text, 60) — and the case still passes: the output is still a well-formed byte prefix and is still <= 80. A mutation that silently halves the summary would ship green.
#1919's own Red-first section also asked for two things that were never asserted: that < is escaped (<, no bare <, escaping applied after the cut, as before) and that the whole entry.stack body below the summary stays byte-for-byte identical.
Separately, changelog.d/1919-stack-summary-cut.fixed.md says the report "shows the whole character instead of U+FFFD". That is not what happens: cut moves the bound back, so the code point that straddles it is dropped entirely and the summary ends with the complete prefix before it. #1916's note is the accurate phrasing to follow ("stopped … showing half of an emoji").
This is the accounting the team agreed to: whoever touches this bound next lands this first.
Expected
- The case pins the bound by content: for the input
'a'.repeat(79) + '\u{1F600}' + 'tail',cut(text, 80)retracts one unit, so the summary is exactly'a'.repeat(79)and the case asserts that. <escaping is asserted in the same case: the input carries a<, the summary contains<and no bare<, and the escaping still happens after the cut.- The
entry.stackbody printed under the summary is asserted byte-for-byte against the input's stack. changelog.d/1919-stack-summary-cut.fixed.mdstates the real behaviour: the code point that straddles the bound is dropped whole, so the summary ends on a complete character (aligned with core-host: the remaining code-unit cuts (claim cue, read_own_chat query/around, page title, diagnostics lines, peer name) #1916's wording).
Red first
With the strengthened assertions and the base f87fceb0 diagnostics.js:
# tests 16 # pass 15 # fail 1
not ok - a stack summary cut at its bound never splits a surrogate pair (#1919)
expected: 'a'×79
actual: 'a'×79 + '\ud83d'
Mutation check, which the current test does not catch and the strengthened one must: in the tip tree, change cut(entry.text, 80) to cut(entry.text, 40); with today's case the suite stays green, with the strengthened case it must fail. Record both runs.
Scope
core/test/diagnostics.test.js— the content assertions above.changelog.d/1919-stack-summary-cut.fixed.md— the corrected sentence.patches/ds-bot/0007-version-and-tooling.patch— regenerate (the test lives in the upstream mirror).- No source change:
core/src/host/diagnostics.jsstayscut(entry.text, 80).text.
Base
#1920 must merge first. Rebase onto that merge commit and re-run the gates there; the parent branch dev/2-diagnostics-stack-summary-cut already carries an unpushed variant of this change.
Gates
TZ=UTC ARCH_DOCS_BASE=<live main> npm run verify exits 0; check + canonical green and generate a no-op; PR body with Fixes #<this issue>, the mutation-check output, and a checkpoint whose head/tree/checks.at name the pushed tip.
References
- diagnostics: the stack summary still cuts entry.text on a UTF-16 unit, so the report can show U+FFFD #1919 / diagnostics: cut the report's stack summary on a code point boundary #1920 — the change that introduced the bound and the case.
- host: the memory-review prompt cuts on UTF-16 units, and a two-argument clip() prints the literal (cut; undefined) #1918 — the same boundary rule, with the red-first shape this test should follow.
Activity
diagnostics: the stack-summary test pins only the upper bound, so a w…