Skip to content

diagnostics: the stack-summary test pins only the upper bound, so a wrong bound ships green #1922

Closed

Description

@HugoXK

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 <= 80
  • shown.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 (&lt;, 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 &lt; and no bare <, and the escaping still happens after the cut.
  • The entry.stack body printed under the summary is asserted byte-for-byte against the input's stack.
  • changelog.d/1919-stack-summary-cut.fixed.md states 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.js stays cut(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

Activity

  1. added a commit that references this issue on Oct 31, 2026
    8e31572
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions