fix(explore): hold back what is still owed below a clustered render (CG-31)
Carry-forward slack let a file spend what the files ABOVE it left on the
table. Nothing held back what was promised BELOW it. The whole-file BUY arm
has always refused that trade (`owedBelow`); the cluster path read `headroom`
— what is left before the hard ceiling — instead of what is still owed, so
`fileBudget` and `SPINE_CEILING` could pay a 1.5x overshoot out of another
file's reservation.
`fundedHeadroom` is the same inequality in the units the cluster path spends
in: source PLUS the per-section overhead each unreached file will charge.
Floored at the file's own reservation — a kept promise is not a displacement —
and it is <= `headroom` by construction, so it is the only bound the three
render sites need. The skeleton path's `bodyCap` takes it too.
Measured on `__tests__/fixtures/displacement-ts` (a 4-stage pipeline padded
past 500 files, where the 24K envelope genuinely saturates the 24.4K render
ceiling):
before ingest.ts emitted 9,301 on a 6,289 spendable, then lost the whole
section to the final ceiling — 0 delivered. types.ts and sink.ts
skipped `budget-whole-file`. 3 of 6 admitted files delivered.
after ingest.ts bounded to the 4,913 actually free. 6 of 6 delivered,
envelope 14,908 -> 22,066.
The self-query allocation fixture flips back to PASS with it, on a clean full
rebuild of this repo's index (CG-33). Its `afterCG30` verdict blamed an
over-RESERVED incidental file; the reservation was identical in both arms —
the file was over-SPENDING. Recorded honestly in `afterCG31`.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
0d014a6582
commit
089dcc276f
@@ -103,6 +103,15 @@ interface FileRecord extends ExploreCandidateMeta {
|
||||
* a file spending over its reservation.
|
||||
*/
|
||||
spendable: number | null;
|
||||
/**
|
||||
* The DISPLACEMENT-GUARDED bound (CG-31): how much this file may render
|
||||
* without spending a reservation still owed to a file the loop has not
|
||||
* reached. `spendable` is what the file was promised, this is what is
|
||||
* actually still there to pay it with — when it sits below `spendable`, the
|
||||
* difference is the overshoot the guard refused, and the files below this one
|
||||
* in the table are the reason. `null` until the render loop reaches the file.
|
||||
*/
|
||||
funded: number | null;
|
||||
render?: ExploreRenderMode;
|
||||
/**
|
||||
* Source chars this call did NOT re-send because an earlier call in the
|
||||
@@ -152,6 +161,8 @@ export interface ExploreDiagnosticFile extends ExploreCandidateMeta {
|
||||
allowance: number | null;
|
||||
/** Reservation + inherited slack — the bound the render paths actually use. */
|
||||
spendable: number | null;
|
||||
/** Same bound after holding back what is still owed to unreached files. */
|
||||
funded: number | null;
|
||||
render: ExploreRenderMode | null;
|
||||
skipped: ExploreSkipReason | null;
|
||||
clipped: boolean;
|
||||
@@ -375,7 +386,7 @@ export class ExploreDiagnostics {
|
||||
/** Record one ranked candidate's scoring inputs, in final sort order. */
|
||||
noteCandidate(path: string, meta: ExploreCandidateMeta): void {
|
||||
this.files.set(path, {
|
||||
path, ...meta, allowance: null, spendable: null,
|
||||
path, ...meta, allowance: null, spendable: null, funded: null,
|
||||
dedupSavedChars: 0, dedupCovered: [],
|
||||
emittedChars: 0, finalChars: 0, share: 0, allocatedShare: 0, clipped: false,
|
||||
});
|
||||
@@ -413,6 +424,15 @@ export class ExploreDiagnostics {
|
||||
if (rec) rec.spendable = chars;
|
||||
}
|
||||
|
||||
/**
|
||||
* What the render loop will let this file spend once the reservations still
|
||||
* owed BELOW it are held back (CG-31). Called alongside `recordSpendable`.
|
||||
*/
|
||||
recordFunded(path: string, chars: number): void {
|
||||
const rec = this.files.get(path);
|
||||
if (rec) rec.funded = chars;
|
||||
}
|
||||
|
||||
/** A candidate rendered source into the response. */
|
||||
recordRender(path: string, render: ExploreRenderMode, sourceChars: number, clipped: boolean): void {
|
||||
const rec = this.files.get(path);
|
||||
@@ -561,6 +581,7 @@ export class ExploreDiagnostics {
|
||||
kinds: r.kinds,
|
||||
allowance: r.allowance,
|
||||
spendable: r.spendable,
|
||||
funded: r.funded,
|
||||
render: r.render ?? null,
|
||||
skipped: r.skipped ?? null,
|
||||
clipped: r.clipped,
|
||||
@@ -732,6 +753,11 @@ export function renderTable(report: ExploreDiagnosticReport): string {
|
||||
if (f.spendable !== null && f.allowance !== null && f.spendable !== f.allowance) {
|
||||
out.push(` spendable: ${num(f.spendable)} (reservation + inherited slack)`);
|
||||
}
|
||||
// Only when the displacement guard actually bit: the gap is what this file
|
||||
// was refused so the files below it could still be paid.
|
||||
if (f.funded !== null && f.spendable !== null && f.funded < f.spendable) {
|
||||
out.push(` funded: ${num(f.funded)} (capped — ${num(f.spendable - f.funded)} held back for files not yet rendered)`);
|
||||
}
|
||||
if (f.dedupSavedChars > 0) {
|
||||
const spans = f.dedupCovered.slice(0, 6).map(([a, b]) => (a === b ? `${a}` : `${a}-${b}`)).join(',');
|
||||
const more = f.dedupCovered.length > 6 ? `,+${f.dedupCovered.length - 6}` : '';
|
||||
|
||||
Reference in New Issue
Block a user