fix(explore): fund the guard from room that exists, and cut the epilogue first (CG-31)
Two corrections found by measuring the first cut of the guard against the 6-repo suite. The first version held back the FULL sum of the reservations below a file. On django that took 2,319 chars off a file the agent receives and handed them to a section the hard ceiling then threw away — the guard's own failure mode, one layer down. tokio lost 1,298 the same way. 1. `owedPayableBelow` — hold back only the prefix of what is owed below that the response can still PAY, in rank order. A promise the ceiling cannot reach is not a claim on this file's bytes. 2. The final truncation now spends the EPILOGUE before it spends a rendered file section. It used to cut at the last section header, dropping that section AND the trailing notes; dropping the notes alone is almost always enough. A section is source the agent otherwise has to Read; the epilogue is a pointer list and two reminders, and the note that replaces it carries the "explore these names" instruction forward. Also count `flow.text` in `totalChars`. It is prepended to `lines` to make the final output, so the render loop always spent against a ceiling it was ~2K under on symbol-bag queries. Deterministic, same clean-rebuilt indexes, both builds (baseline = CG-30 tip): repo base source new source files django 20,033 20,791 5 trunc -> 6 excalidraw 18,776 20,204 7 trunc -> 8 okhttp 15,628 19,034 4 trunc -> 5 tokio 20,340 21,521 4 trunc -> 5 gin 10,776 10,776 4 -> 4 (byte-identical) alamofire 11,662 11,662 2 -> 2 (byte-identical) No repo delivers less; four stop truncating. `funded` in the diagnostic now reports the render CEILING the guard allows, which is what every render path is actually bounded by. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
089dcc276f
commit
f1fecb8232
@@ -151,9 +151,11 @@ describe('CG-31 — the cluster path holds back what is still owed below it', ()
|
||||
// shape that makes the bounded overshoot fire at all.
|
||||
const source = fs.readFileSync(path.join(testDir, GIANT), 'utf-8');
|
||||
expect(source.length).toBeGreaterThan((rec.spendable ?? 0) * 2);
|
||||
// And the guard actually bit — a vacuous pass here would hide a regression.
|
||||
// And the guard actually bit — a vacuous pass here would hide a
|
||||
// regression. Measured against the bounded overshoot a cluster's top
|
||||
// member may otherwise take (1.5x, CG-30), which is what it refused.
|
||||
expect(rec.funded).not.toBeNull();
|
||||
expect(rec.funded!).toBeLessThan(rec.spendable!);
|
||||
expect(rec.funded!).toBeLessThan(Math.round(rec.spendable! * 1.5));
|
||||
});
|
||||
});
|
||||
|
||||
@@ -203,6 +205,15 @@ describe('CG-31 — the cluster path holds back what is still owed below it', ()
|
||||
}
|
||||
});
|
||||
|
||||
it('nothing is lost to the hard ceiling — the epilogue is cut before a section', () => {
|
||||
// A section thrown away by the final truncation is the same starvation
|
||||
// arriving after the guard has done its work: the bytes were held back
|
||||
// for that file and then nobody received them.
|
||||
for (const probe of [spread, precise]) {
|
||||
expect(probe.report.files.filter((f) => f.render === 'dropped')).toEqual([]);
|
||||
}
|
||||
});
|
||||
|
||||
it('keeps the response inside the hard ceiling', () => {
|
||||
for (const probe of [spread, precise]) {
|
||||
expect(probe.report.envelope.chars).toBeLessThanOrEqual(probe.report.budget.hardCeiling);
|
||||
|
||||
Reference in New Issue
Block a user