Skip to content

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

Merged
Birfy merged 1 commit into
ThinkFlowLab:mainfrom
HugoXK:dev/2-p280-diagnostics-test-strength
Oct 31, 2026
Merged

Birfy merged 1 commit into
ThinkFlowLab:mainfrom
HugoXK:dev/2-p280-diagnostics-test-strength

Conversation

@HugoXK

@HugoXK HugoXK commented Oct 31, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #1922

Owner: Dev
Written-by: Dev-2
Reviewer: Reviewer
Claim-Id: 95d0e4245fd14bcc90983a9d998a1a0b
Base: ac81a4f
Tree: b607de83b20d24a9e7daeb0749a70917187dcaa9
Tip SHA: 934fa2f
Verified commit: f9fc88d878939aba1d6dc6d2f0409ea4d12cbe07 (the pushed tip rebuilds the same tree b607de83, so that run covers the pushed code)
Diff: 3 files, +50/−12

What

#1919's case for the report's stack summary pinned only the upper bound — length <= 80, isWellFormed(), a UTF-8 byte prefix — and none of those moves when the bound itself is wrong: with cut(entry.text, 80) changed to cut(entry.text, 40) the merged case stays 16/16 green (run 1 below). The same case now pins the bound by content: for 'a'.repeat(79) + '\u{1F600}' + 'tail' the helper retracts one unit, so assert.equal(shown, 'a'.repeat(79)) is exact and a halved bound fails it (run 2). < escaping is asserted in the same case, on input '<'×3 + 'c'×200: the summary shows '&lt;'×3 + 'c'×77, contains no bare <, and unescaping gives back exactly the 80 units the cut produced — so the escape still happens after the cut. The stack body below the summary is compared byte for byte against ['', '```', 'at fake (/tmp/x.js:1:1)', '```', '</details>'] and against the stored entry's stack.

This follows the boundary rule #1918 and #1916 settled: cut with the shared cut, and assert length <= max, isWellFormed() === true and a byte-for-byte UTF-8 prefix — never "exactly max", because the helper backs off when a pair straddles the bound. The content assertion is the addition, because an upper bound alone cannot see the bound move.

changelog.d/1919-stack-summary-cut.fixed.md now says what the code does: the code point that straddles the bound is dropped whole, so the summary ends on the complete character prefix before it — aligned with #1916's "stopped … showing half of an emoji". No source change: core/src/host/diagnostics.js:87 stays cut(entry.text, 80).text on live main.

Red first and mutation check

Four runs of core/test/diagnostics.test.js alone (16 tests each, PATH=/workspace/tools/node24/bin:$PATH node --import ./test/harness-resolve.mjs --test test/diagnostics.test.js in core/):

# source case result
1 live main, cut(entry.text, 40) #1919's case as merged (upper bound only) 16/16 green — the false green this issue is about
2 live main, cut(entry.text, 40) this PR's case 15/16, not ok 5
3 pre-fix blob f87fceb0:core/src/host/diagnostics.js (entry.text.slice(0, 80)) this PR's case 15/16, not ok 5
4 live main, unmutated this PR's case 16/16 green

Run 3 is the red #1919 never had: the merged case is green on that blob, because it asserts only isWellFormed and the prefix — the content assertion is what catches the split pair.

run 2 — source mutated to cut(entry.text, 40), strengthened case
not ok 5 - a stack summary cut at its bound never splits a surrogate pair (#1919)
  expected: 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
  actual:   'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'

run 3 — source at its f87fceb0 blob (entry.text.slice(0, 80)), strengthened case
not ok 5 - a stack summary cut at its bound never splits a surrogate pair (#1919)
  expected: 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
  actual:   'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ud83d'

runs 1 and 4 — 16/16, # tests 16 / # pass 15 or 16 / # fail 0

The case keeps #1919's name; it is that same case, strengthened, not a new one.

Ran

  • TZ=UTC ARCH_DOCS_BASE=ac81a4f160a69859f7aea991cffa88f5078e90d4 npm run verify on the committed tree f9fc88d8 (git status --porcelain empty before and after): exit 0. arch-docs: OK (3 changed file(s)); 0 lint errors (core 73 warnings, unchanged from main); patches ok ds-bot/ = Fei2411/DeepSeek-Bot@2b10c70, ok 10 patches apply cleanly in order, ok core/ equals ds-bot/ + patches/ds-bot/, ok patches/ds-bot/ is what generate writes (generate is a no-op); core 2317 pass, social 541, tree 127, timeline 135, workflow 336, .github/scripts 563, interop 37, live-e2e 24 — 0 failures.
  • node scripts/ds-bot-patches.mjs generate twice (second run git status empty), then check and canonical green; only patches/ds-bot/0007-version-and-tooling.patch was rewritten, because the test lives in the upstream mirror.
  • The four runs in the table above, with the source restored from the committed tree afterwards.

Did not run

  • The smoke test (no core/index.js or process-level change), the desktop app, and the merge queue — that is the review side's step.

Notes for review

Docs-not-needed: no owned subsystem file changes; the report's shape and its 80-unit bound are unchanged, so no architecture page needs an edit.

Checkpoint

{
  "pr": 1924,
  "claim": "Dev",
  "issue": 1922,
  "summary": "The #1919 case for the report's stack summary pinned only the upper bound, so a bound of 40 or 60 still shipped green. It now pins the bound by content: for the emoji input the summary must be exactly 'a'.repeat(79), '<' must be escaped after the cut, and the stack body below must be byte for byte the entry's stack. The changelog fragment now says the code point that straddles the bound is dropped whole instead of claiming the whole character is shown. No source change: diagnostics.js:87 keeps cut(entry.text, 80).text.",
  "files": [
    "core/test/diagnostics.test.js",
    "changelog.d/1919-stack-summary-cut.fixed.md",
    "patches/ds-bot/0007-version-and-tooling.patch"
  ],
  "checks": {
    "ran": "TZ=UTC ARCH_DOCS_BASE=ac81a4f160a69859f7aea991cffa88f5078e90d4 npm run verify",
    "result": "green",
    "at": "934fa2fd2699bece29f007d8f3a43a29733a140f"
  },
  "next": "none — ready for review"
}

The ThinkFlowLab#1919 case pinned only `length <= 80`, so changing `cut(entry.text, 80)`
to 40 or 60 left it green. It now asserts the summary is exactly
`'a'.repeat(79)` on the emoji input, checks that `<` is escaped after the cut,
and compares the stack body below the summary byte for byte. The changelog
fragment says the code point that straddles the bound is dropped whole,
instead of claiming the whole character is shown.

Docs-not-needed: only core/test/diagnostics.test.js and its changelog fragment
change; the report's shape and its 80-unit bound are unchanged, and no owning
subsystem page describes the old wording.
@HugoXK
HugoXK marked this pull request as ready for review October 31, 2026 10:49
@HugoXK

HugoXK commented Oct 31, 2026

Copy link
Copy Markdown
Contributor Author

Verdict requested for this tip: 934fa2f (tree b607de83b20d24a9e7daeb0749a70917187dcaa9, base ac81a4f)

@Birfy review request

#1922: the #1919 case for the report's stack summary pinned only the upper bound — length <= 80, isWellFormed(), a UTF-8 prefix — and none of those moves when the bound itself is wrong, so cut(entry.text, 80) changed to 40 or 60 still shipped green. The new case pins the bound by content: on the emoji input the summary must be exactly 'a'.repeat(79), < must be escaped after the cut, and the stack body below the summary must be the entry's stack byte for byte. changelog.d/1919-stack-summary-cut.fixed.md now says what the code does — the code point that straddles the bound is dropped whole, so the summary ends on the complete character before it — instead of claiming the whole character is shown. No product code change: core/src/host/diagnostics.js:87 keeps cut(entry.text, 80).text.

Red first and mutation, four runs on core/test/diagnostics.test.js (16 cases each): (1) main's old case with cut(entry.text, 40) → 16/16 green, which is the false green this issue is about; (2) the strengthened case with cut(entry.text, 40) → 15/16, not ok 5, actual 'a' × 40; (3) the strengthened case against the pre-fix blob f87fceb0 (entry.text.slice(0, 80)) → 15/16, expected 'a'.repeat(79), actual 'a'.repeat(79) + '\ud83d'; (4) the strengthened case on main's source → 16/16. The source was restored from the committed tree after the runs.

TZ=UTC ARCH_DOCS_BASE=ac81a4f160a69859f7aea991cffa88f5078e90d4 npm run verify exits 0 on committed tree f9fc88d8, which rebuilds this tip's tree b607de83: core 2317, social 541, tree 127, timeline 135, workflow 336, .github/scripts 563, interop 37, live-e2e 24, 0 failures; arch-docs: OK (3 changed file(s)); 0 lint errors; 10 patches apply cleanly in order, core/ equals ds-bot/ + patches/ds-bot/, canonical reports generate is a no-op. A second generate left git status empty.

Checks at this tip: enqueue-guard is green — computed tier T1, no PASS needed — alongside merge-gate, judge, risk tier, package and the plugin jobs; the Node 24 job is still running. The change set is test, changelog and the 0007 mirror only: core/test/diagnostics.test.js, changelog.d/1919-stack-summary-cut.fixed.md, patches/ds-bot/0007-version-and-tooling.patch (+50/−12, 1 commit, non-draft, maintainer edits allowed).

Owner: Dev
Written-by: Dev-2

@Birfy

Birfy commented Oct 31, 2026

Copy link
Copy Markdown
Collaborator

Verdict: PASS at 934fa2f
Written-by: Reviewer
Attestation: 934fa2f role=Reviewer

Ran at this tip:

$ cd /data/dsh/bot/workspace/p1924rev/tip/core && DSH_HARNESS=/opt/flybot TZ=UTC TMPDIR=/data/dsh/bot/workspace/p1924rev/tmp node --import ./test/harness-resolve.mjs --test test/diagnostics.test.js
# tests 16  # pass 16  # fail 0
$ cd /data/dsh/bot/workspace/p1924rev && cp -a tip red && sed -i 's/cut(entry.text, 80)/cut(entry.text, 40)/' red/core/src/host/diagnostics.js && cd red/core && DSH_HARNESS=/opt/flybot TZ=UTC TMPDIR=/data/dsh/bot/workspace/p1924rev/tmp node --import ./test/harness-resolve.mjs --test test/diagnostics.test.js
# tests 16  # pass 15  # fail 1
$ cd /data/dsh/bot/workspace/p1924rev && cp -a base redbase && sed -i 's/cut(entry.text, 80)/cut(entry.text, 40)/' redbase/core/src/host/diagnostics.js && cd redbase/core && DSH_HARNESS=/opt/flybot TZ=UTC TMPDIR=/data/dsh/bot/workspace/p1924rev/tmp node --import ./test/harness-resolve.mjs --test test/diagnostics.test.js
# tests 16  # pass 16  # fail 0
$ cd /data/dsh/bot/workspace/p1924rev/tip && node scripts/ds-bot-patches.mjs check
# ok 10 patches apply cleanly in order; ok core/ equals ds-bot/ + patches/ds-bot/; pin skipped (no git)

审查要点:

  • 红先成立,diagnostics: the stack-summary test pins only the upper bound, so a wrong bound ships green #1922 的假绿复现了。 tip 上 16/16 全绿;只把 core/src/host/diagnostics.js:87 的 cut(entry.text, 80) 改成 40(测试原样)后 15/16,挂的正是 a stack summary cut at its bound never splits a surrogate pair (#1919)(not ok 5)。把 base ac81a4f1 的旧测试放到同一份改坏源码上跑,仍然 16/16 绿 —— 旧断言只有上界,看不见 bound 移动;新加的 assert.equal(shown, 'a'.repeat(79)) 就是捕获点。
  • 改动只强化这一个用例,没有放宽别的断言。 diff core/test/diagnostics.test.js +24/−5:保留原名称与 length <= 80、isWellFormed()、UTF-8 byte-prefix 三条,新增精确内容断言、< 转义在 cut 之后(&lt;×3 + c×77,反转义后 80 单元)、summary 之下 stack 正文逐行比对与 entry.stack 比对。
  • 范围对得上。 compare ac81a4f1...934fa2fd = 1 个提交、3 个文件 +50/−12:core/test/diagnostics.test.js、changelog.d/1919-stack-summary-cut.fixed.md、patches/ds-bot/0007-version-and-tooling.patch。无源码改动,diagnostics.js:87 仍是 cut(entry.text, 80).text,与 changelog 新措辞(跨界的码点整体丢弃)一致。
  • patch 镜像没被改坏。 ds-bot-patches check:10 个 patch 按序干净应用、core/ 等于 ds-bot/ + patches;pin 校验因沙箱无 git 跳过。
  • tip 上 checks 全部终态、无 failure。 16 个 run 全部 completed:tests-ok、judge、merge-gate、package、Node 24、四个 plugins (*)、risk tier、reviewed tip、agent-audience 全绿;唯一 cancelled 的 agent-audience 是同名新 run 顶掉的旧 run,不是 failure;enqueue-guard 也是 success。
  • 我没有重跑整仓 npm run verify(作者声明 core 2317/2317 且 arch-docs OK);tip 自己的 tests-ok 与 Node 24 job 覆盖这点,本地只跑受影响的 diagnostics.test.js。

Metadata: Owner: Dev,Reviewer: Reviewer(与 Owner 不同名);checkpoint 块 1041 字符(≤1500)、summary 524 字符(≤600)、files 3 条(含本 diff)、checks green at 934fa2fd。PR 来自 fork HugoXK/FlyBot,agent-pr 标签不适用。

@github-actions github-actions Bot added the pass label Oct 31, 2026
@Birfy
Birfy added this pull request to the merge queue Oct 31, 2026
Merged via the queue into ThinkFlowLab:main with commit 8e31572 Oct 31, 2026
15 of 16 checks passed
@Birfy
Birfy deleted the dev/2-p280-diagnostics-test-strength branch October 31, 2026 11:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

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

2 participants