Skip to content

fix: announce truncated block lists in status overview; per-tier block counts (#221) - #222

Open
ranxianglei wants to merge 1 commit into
masterfrom
2026-09-08_status-truncation-honesty
Open

fix: announce truncated block lists in status overview; per-tier block counts (#221)#222
ranxianglei wants to merge 1 commit into
masterfrom
2026-09-08_status-truncation-honesty

Conversation

@ranxianglei

Copy link
Copy Markdown
Owner

Root cause (verified against source)

The nudge and acp_status already share one data source: within a single processTurn, nudgeNode runs on the same io.state after syncBlocksNode (src/compress.ts:466-481), and decideNudge derives tierTargetBlocks from activeBlocks(state) — the exact same predicate buildStatusReport uses (src/state.ts:41-43, src/report.ts:125-127). There is no snapshot drift inside a turn.

The mismatch is a rendering asymmetry:

  • The tier-distillation nudge lists every active lower-tier block, uncapped (formatTierTargetBlocks, src/nudge-text.ts:39-49).
  • The acp_status overview caps its block list at 30 entries sorted by original size across all tiers (sorted.slice(0, limit), src/report.ts:201) and did so silently — no "N more" line, unlike the other two views. The header still showed the full count.

So once a session accumulates >30 active blocks — which is guaranteed exactly when T2/T3 distillation nudges fire (they fire because lower-tier blocks piled up past tier2Trigger) — some active target-tier blocks vanish from the status list while the nudge names them. In bcp#330 session 01a07b3c (41 blocks): the nudge named 11 T1 targets (b31..b41), the model's acp_status visibly contained only b31/b32 as T1 → "Nudge 列表再次与实际不符,跳过" → distillation skipped → T1s pile up further → nudge re-fires next turn. Repeating, self-reinforcing trust break.

The two fixes proposed in the issue are both no-ops against this cause: "unify data source" is already true; "filter targetBlocks by current active blocks" is already what pendingByTier does (src/compress.ts:1095-1126). The defect is on the status-rendering side, so that is where this PR acts.

Changes

  • renderOverview: explicit ... and N more blocks not shown (scope:"compressed", limit:M for full list) when the cap bites — parity with renderUncompressedRanges / renderCompressedDrilldown.
  • tierBreakdown: per-tier block counts alongside token totals (T1: 12.3K (35 blocks) | T2: 45K (6 blocks)) so the nudge's target count is checkable even when individual lines are hidden by the size sort.

Tests

New tests/report-truncation.test.ts (3 tests), fixture mirrors session 01a07b3c's shape (41 active = 35 T1 + 6 T2):

  1. overview announces the exact hidden count and points at scope:"compressed" (failed pre-fix — silent truncation reproduced);
  2. end-to-end symptom shape: nudge names all 35 T1 targets, overview hides some of them, and the announced numbers now reconcile with the nudge count (failed pre-fix);
  3. control: no announcement when the list fits.

Full suite: 583 pass / 0 fail. tsc --noEmit clean. Build OK.

…k counts (#221)

The tier-distillation nudge lists every active lower-tier block uncapped,
while buildStatusReport's overview silently capped the block list at 30
entries sorted by original size. Once a session accumulates >30 active
blocks — exactly the condition under which T2/T3 distillation nudges fire —
active target-tier blocks vanish from acp_status and the model reads the
two same-source views as contradictory (bcp#330 session 01a07b3c: nudge
named 11 T1 targets, status visibly showed only b31/b32), skipping the
distillation and re-triggering it on the next turn.

- renderOverview: explicit '... and N more blocks not shown' line with a
  pointer to scope:"compressed", parity with the other two views
- tierBreakdown: per-tier active block counts next to token totals so the
  nudge's target count is checkable even when individual lines are hidden
@github-actions

github-actions Bot commented Sep 8, 2026

Copy link
Copy Markdown

📦 Built Package Artifact

Branch: 2026-09-08_status-truncation-honesty (f2f91ad)

Option A — Install from npm PR tag (recommended)

In your adapter project:

npm install acp-kernel@pr-222

Each push to this PR publishes a new version under the pr-222 npm tag.

Option B — Download artifact

  1. Download the artifact from the Actions run
  2. Extract the tarball and install:
tar xzf acp-kernel-pr222.tgz
npm install ./package

This comment is automatically updated on each push.

@ranxianglei

Copy link
Copy Markdown
Owner Author

🤖 Powered by ework · qwen3.8-27b

[bot] 🏷 Review started. Fetching PR branch 2026-09-08_status-truncation-honesty (f2f91ad), verifying the root-cause claims against master source, then running typecheck/tests/build on the PR head. Will post full findings shortly.

@ranxianglei

Copy link
Copy Markdown
Owner Author

🤖 Powered by ework · qwen3.8-27b

[bot] 🏷 Review: LGTM — root cause verified against source, pre-fix failure reproduced, all checks green. Details below per triage rules.

1. Root-cause verification (all claims checked out true)

"Data source is already unified" — confirmed:

  • Pipeline order in buildNodes (src/compress.ts:466-481): syncBlocksNode (2nd) runs before nudgeNode (9th) on the same io.state; no snapshot drift within a turn.
  • pendingByTier (src/compress.ts:1095-1126) derives targetBlocks from activeBlocks(state) = state.blocks.filter(b => b.active) (src/state.ts:41-43) — byte-for-byte the same predicate buildStatusReport uses (src/report.ts:125-127).
  • So yes: "unify data source" and "filter targetBlocks by active blocks" are both no-ops against this cause. The defect is genuinely on the status-rendering side.

"Rendering asymmetry" — confirmed:

  • formatTierTargetBlocks (src/nudge-text.ts:39-49) lists every target uncapped.
  • renderOverview did sorted.slice(0, limit) (default 30, size-sorted across tiers) with no announcement. I checked the other views: renderUncompressedRanges says "... and N more ranges", renderCompressedDrilldown/renderMessageDrilldown say "N of M shown." — the overview was the only view that truncated silently while its header kept the full count. Exactly the trust break you describe.

2. Reproduction & verification (ran locally, Node v22)

Check Result
Pre-fix repro at merge base 04bd5ed + new test file tests 1–2 fail (not ok), test 3 passes — silent truncation reproduced
tsc --noEmit at PR head f2f91ad clean
Full suite at PR head 583/583 pass (matches your claim)
Build at PR head OK
Merge with current master (dd787e5, PR is behind) test-merge clean, no conflicts (master touched nothing in src/report.ts since base); post-merge suite 627/627, typecheck + build clean
Duplicate screening no existing issue/PR covers status-overview truncation or nudge/status mismatch

3. Fix assessment

Right layer, right shape. The announcement line gives both the exact hidden count and an actionable pointer (scope:"compressed" + the precise limit that shows everything) — so the model can self-correct in one follow-up call. Per-tier counts in tierBreakdown make the nudge's target count checkable even when individual lines fall below the size-sort cut. Edge cases checked:

  • Single-tier session with >30 blocks: tierBreakdown returns null (needs ≥2 tiers), but reconciliation still works via the "N active" header + announced hidden count. Fine.
  • Blocks grow between turns: the suggested limit:N may then show "N of M shown" in the drilldown — self-correcting, not misleading.

4. Minor observations (non-blocking)

  1. Parity gap remains one level down: renderCompressedDrilldown's "N of M shown." gives no pointer for how to see the rest (the overview now does). Small follow-up candidate: append limit:M there too.
  2. Test 2 constructs NudgeDecision by hand rather than via decideNudge — acceptable for a rendering-parity test; an end-to-end variant through the real nudge path would be stronger if you ever want it.
  3. Commit message carries a (#221) suffix referencing the origin number — harmless, just noting it breaks the pure fix: convention slightly.

Nothing here blocks merge.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant