Browse Source

fix(explore): a funded whole-file buy must also fit the render ceiling (CG-21)

Found reviewing the CG-21 fix rather than by a failing test, and it is the
same defect inverted. A whole render that overruns `renderCeiling` is
skipped ENTIRELY (the branch refuses to slice a file mid-method), so a buy
that is approved by the funding pool but refused by the ceiling trades a
clustered section for NO section.

Only reachable on the 24K tiers. The funding line is
`reservedTotal + 0.15 * envelope` — ~27.2K when a medium repo saturates —
while `renderCeiling` is `min(1.5 * envelope, 25000) - 600` = 24.4K, so
funding can approve ~2.8K the ceiling then refuses. At 13K the line is
~14.4K against an 18.9K ceiling and the two cannot cross, which is why the
small-tier fixtures cannot see it.

Failing the test in `buysWhole` drops through to the cluster path, which is
bounded by `headroom` and always renders something. The GRACE arm is left
alone deliberately: a file within a sliver of its reservation that still
does not fit is genuinely at the end of a full response, and that predates
this epic.

Verified inert on the three A/B repos, so the agent A/B measured the same
behaviour: excalidraw byte-identical on 3 queries, client-go byte-identical
on 3 queries, express reproducer unchanged at 15,984. Full suite green
(2,867 passed; one unrelated fs.watch timing flake that passes 30/30 in
isolation).
Colby McHenry 1 month ago
parent
commit
fca7d87047
1 changed files with 20 additions and 1 deletions
  1. 20 1
      src/mcp/tools.ts

+ 20 - 1
src/mcp/tools.ts

@@ -4110,9 +4110,28 @@ export class ToolHandler {
       // `payslip_builder.go`, and it is refused here. Self-limiting: each buy
       // grows `sourceSpent`, so the pool cannot be spent twice.
       const owedBelow = Math.max(0, reservedTotal - reservedSoFar);
+      // Third condition on the BUY arm only: it must also FIT. A whole render
+      // that overruns `renderCeiling` is skipped ENTIRELY a few lines below (the
+      // branch refuses to slice a file mid-method), so attempting a buy that
+      // cannot fit trades a clustered section for NO section — the same trade
+      // the funding pool exists to refuse, arriving by a different route.
+      // Failing the test here instead drops through to the cluster path, which
+      // is bounded by `headroom` and always renders something.
+      //
+      // Only reachable on the 24K tiers, which is why the small-tier fixtures
+      // cannot see it: the funding line is `reservedTotal + 0.15 * envelope`
+      // (~27.2K when a medium repo saturates) while `renderCeiling` is
+      // `min(1.5 * envelope, 25000) - 600` = 24.4K — so funding can approve
+      // ~2.8K that the ceiling then refuses. At 13K the line is ~14.4K against a
+      // ceiling of 18.9K and the two cannot cross.
+      //
+      // The GRACE arm is deliberately left alone: a file within a sliver of its
+      // reservation that still does not fit is genuinely at the end of a full
+      // response, and that behaviour predates this fix.
       const buysWhole = fileContent.length <= graceBound
         || (reserved >= fileContent.length * EXPLORE_ALLOCATION.WHOLE_FILE_BUY_FRACTION
-            && sourceSpent + fileContent.length + owedBelow <= sourceCeiling);
+            && sourceSpent + fileContent.length + owedBelow <= sourceCeiling
+            && totalChars + fileContent.length + EXPLORE_ALLOCATION.FILE_OVERHEAD <= renderCeiling);
       if (fileLines.length <= WHOLE_FILE_MAX_LINES && buysWhole) {
         const body = fileContent.replace(/\n+$/, '');
         let wholeSection = exploreLineNumbersEnabled() ? numberSourceLines(body, 1) : body;