* test(#3065): build the load-bearing contract gate ADR-1671 promised Epic #1671 Phase 7. A post-merge audit of every promise in ADR-1671 against the merged tree found one mitigation asserted-but-absent and two stale records. ADR-1671 names exactly one correctness risk — trimming a load-bearing fragment, with the recorded history of a paraphrased META.RULE causing agent violations — and #2931 amended its mitigation to a deterministic contract gate that proves no load-bearing fragment was omitted or shrunk, treats a floored fragment as a success, and asserts the isolate prefix survives byte-identical, with an explicit anti-vacuity rule. That gate did not exist. What existed was tests/context-composer.test.cjs: synthetic unit tests of the composeWithinBudget primitive over invented fragments, asserting nothing about real declared strategies. The ADR asserted a mitigation that was never built, which is the promised-but-not-built shape the epic's own coverage discipline exists to catch. The gate derives its load-bearing set from declared verbatim strategies rather than a hand-maintained list, so it cannot go stale as upstream changes. It sweeps budgets from 4x total down to a quarter of total and asserts at every step that no load-bearing id appears in omitted or shrunk, that isolatePrefix is byte-identical, and that hardFailed is surfaced rather than silently passed. Both anti-vacuity guards are EXECUTABLE, not comments. One proves the empty load-bearing set guard actually throws. The other proves a sweep that never applies pressure is rejected — because a gate that only ever runs unpressured is exactly how the original mitigation went missing without anyone noticing. Measured: underPressure true at 6 of 7 budgets, false only at 4x total. Three ADR records corrected in the same change, all doc-vs-reality drift: - Decision item 2 describes a composer that trims by priority to fit a measured per-runtime cap. composeWorkflow in fact passes MAX_SAFE_INTEGER with every fragment verbatim (both verified in source), so no trimming happens there; the emitted-byte cap is a separate measure-and-fail gate and Windsurf's limit a bespoke truncation. The wording described an option as shipped behavior. - flag:--converge never reached a terminal state. #2992 withheld six atoms; five were resolved explicitly. This one was resolved in code by reusing state:plan-strategy-converge but recorded nowhere — the same gap #2995 closed for flag:--verify-only, and I closed five of six. - The open-questions list enumerated three questions while two Resolved-by blocks resolved an unlisted Question 4. It is now listed. Refs #3065 * fix(#3065): make the gate assert over production, not a copy of it The isolated review found a blocker, and it was fatal to the gate's purpose: it hand-copied applyBudget's fragment array into the test, so flipping a strategy in src/prompt-budget.cts — say roadmap from verbatim to drop — would leave the gate computing from its own untouched copy and still passing. A guard built as an instance of the very divergence class it exists to prevent (DEFECT.GENERATIVE-FIX) is worse than no guard, because it reports green. Fixed by eliminating the duplicate rather than adding a parity assertion, the same resolution used for the FAMILIES table in #2996. applyBudget's inline construction is extracted to an exported buildBudgetFragments(), which both applyBudget and the gate now call; the 1024 plan floor is exported as PLAN_FLOOR_CHARS instead of being re-declared in the test. The extraction is pure — verified behavior-preserving at budget=2000: hardFailed false, omitted ['context'], projectMd shrunk, plan truncation ~27.8%, all headers present. There is no longer a second copy to diverge from. Also fixed a vacuous assertion the same review caught: isolatePrefix was pinned across the sweep, but no production fragment sets isolate:true, so the value is always '' and the check could never fail. The pinning assertion stays, with an honest comment that nothing in production sets it today, and a second test now constructs an isolate:true fragment set and proves the prefix is non-empty and byte-identical across a roomy and a severely tight budget — which is what makes the first assertion capable of detecting a real change. Refs #3065 * chore(#3065): backfill changeset pr number to 3068 --------- Co-authored-by: sim <sim@local>
This commit is contained in:
@@ -31,8 +31,13 @@ import contextComposer = require('./context-composer.cjs');
|
||||
|
||||
const NOTE_RESERVE_TOKENS = 80;
|
||||
|
||||
/** floor per plan when proportionally truncating and for the minimum-set check. */
|
||||
const MIN_PLAN_BYTES = 1024;
|
||||
/**
|
||||
* Floor per plan when proportionally truncating and for the minimum-set
|
||||
* check. Exported so consumers (notably the load-bearing contract gate,
|
||||
* issue #3065) never need to re-declare this value locally.
|
||||
*/
|
||||
export const PLAN_FLOOR_CHARS = 1024;
|
||||
const MIN_PLAN_BYTES = PLAN_FLOOR_CHARS;
|
||||
|
||||
const DEFAULT_NOTE_TEMPLATE = [
|
||||
'<note>',
|
||||
@@ -158,16 +163,22 @@ function assemblePrompt(parts: {
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply a token budget to a set of review prompt sections.
|
||||
* Returns the trimmed prompt and structured metadata.
|
||||
* Build the `composeWithinBudget` fragment array for a set of review prompt
|
||||
* sections, with each fragment's declared trim strategy attached.
|
||||
*
|
||||
* Extracted (issue #3065) so the load-bearing contract gate
|
||||
* (tests/load-bearing-contract-gate.test.cjs) can assert directly over the
|
||||
* REAL declared strategies used by `applyBudget`, rather than a hand-copied
|
||||
* duplicate array. A duplicate would let production silently diverge from
|
||||
* the gate (e.g. flipping `roadmap` from `verbatim` to `drop` would keep the
|
||||
* gate green if it read from a copy) — exactly the
|
||||
* `DEFECT.GENERATIVE-FIX` divergence class this extraction exists to
|
||||
* prevent. Pure; performs no I/O and has no side effects.
|
||||
*/
|
||||
export function applyBudget({ sections, budget, options = {} }: ApplyBudgetInput): BudgetResult {
|
||||
const {
|
||||
safetyMarginPct = 10,
|
||||
noteTemplate = DEFAULT_NOTE_TEMPLATE,
|
||||
projectMdHeadLines = 40,
|
||||
} = options;
|
||||
|
||||
export function buildBudgetFragments(
|
||||
sections: PromptSections,
|
||||
projectMdHeadLines: number
|
||||
): contextComposer.Fragment[] {
|
||||
const {
|
||||
instructions,
|
||||
roadmap,
|
||||
@@ -198,7 +209,7 @@ export function applyBudget({ sections, budget, options = {} }: ApplyBudgetInput
|
||||
required: true,
|
||||
}));
|
||||
|
||||
const fragments: contextComposer.Fragment[] = [
|
||||
return [
|
||||
{ id: 'instructions', content: instructions, wrapper: '', strategy: { kind: 'verbatim' }, required: true },
|
||||
{ id: 'roadmap', content: roadmap, wrapper: '## Roadmap\n\n', strategy: { kind: 'verbatim' }, required: true },
|
||||
{
|
||||
@@ -213,6 +224,27 @@ export function applyBudget({ sections, budget, options = {} }: ApplyBudgetInput
|
||||
{ id: 'research', content: researchRaw ?? '', wrapper: '## Research\n\n', strategy: { kind: 'drop' } },
|
||||
{ id: 'requirements', content: requirementsRaw ?? '', wrapper: '## Requirements\n\n', strategy: { kind: 'drop' } },
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply a token budget to a set of review prompt sections.
|
||||
* Returns the trimmed prompt and structured metadata.
|
||||
*/
|
||||
export function applyBudget({ sections, budget, options = {} }: ApplyBudgetInput): BudgetResult {
|
||||
const {
|
||||
safetyMarginPct = 10,
|
||||
noteTemplate = DEFAULT_NOTE_TEMPLATE,
|
||||
projectMdHeadLines = 40,
|
||||
} = options;
|
||||
|
||||
const { plans } = sections;
|
||||
|
||||
const fragments: contextComposer.Fragment[] = buildBudgetFragments(sections, projectMdHeadLines);
|
||||
|
||||
// Recover the per-plan fragment ids buildBudgetFragments assigned (in
|
||||
// `plans` declaration order) rather than re-deriving the id-collision
|
||||
// logic here — a single source of truth for id assignment.
|
||||
const planIds: string[] = fragments.filter((f) => f.group === 'plans').map((f) => f.id);
|
||||
|
||||
const composed = contextComposer.composeWithinBudget({
|
||||
fragments,
|
||||
|
||||
Reference in New Issue
Block a user