* refactor(#720): lazy-load MVP-only reference bodies (eager @-import → gated Read) Convert eager @-imports of MVP-only reference bodies into lazy "Read" instructions gated on MVP_MODE / WALKING_SKELETON / MVP+TDD, so non-MVP planning/execution runs no longer pull MVP guidance into context. Covers both the workflow files and the planner/executor agent definitions (the dominant context-cost path): - workflows/plan-phase.md: planner-mvp-mode.md + skeleton-template.md (L146/936/937/941) - workflows/execute-phase.md: execute-mvp-tdd.md halt-report ref, now gated on gate-trip (L191) - agents/gsd-planner.md: planner-mvp-mode.md, user-story-template.md, skeleton-template.md - agents/gsd-executor.md: execute-mvp-tdd.md The dedicated always-MVP mvp-phase workflow keeps its eager imports (intentional). Behaviour is unchanged; non-MVP runs simply carry less loaded context. Adds a regression guard mirroring the discuss-phase lazy-load test, and documents the conformance in docs/ARCHITECTURE.md. Refs #720 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * docs(#720): add changeset fragment (pr #746) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -402,3 +402,150 @@ describe('SIZE: discuss-phase progressive disclosure (issue #2551)', () => {
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
const AGENTS_DIR = path.join(__dirname, '..', 'agents');
|
||||
|
||||
describe('workflow progressive disclosure — MVP bodies lazy-loaded (#720)', () => {
|
||||
// MVP-only reference bodies (planner-mvp-mode.md, skeleton-template.md,
|
||||
// execute-mvp-tdd.md) must NOT be eagerly @-imported at the top level of the
|
||||
// always-loaded workflow files or agent definitions. An @-prefixed path is
|
||||
// expanded into context the moment the file loads — regardless of whether
|
||||
// MVP_MODE is true — inflating every session's token cost. Use a plain
|
||||
// backtick path or a conditional "Read ..." instruction instead. See issue #720.
|
||||
|
||||
test('plan-phase.md does not eagerly @-import planner-mvp-mode.md', () => {
|
||||
const planPhaseContent = fs.readFileSync(path.join(WORKFLOWS_DIR, 'plan-phase.md'), 'utf-8');
|
||||
assert.ok(
|
||||
!/@[~./\w-]*planner-mvp-mode\.md/.test(planPhaseContent),
|
||||
'plan-phase.md contains an eager @-import of planner-mvp-mode.md — ' +
|
||||
'this loads the MVP body into context for every session, even when MVP_MODE is false. ' +
|
||||
'Replace with a conditional Read instruction or a plain backtick path. See #720.'
|
||||
);
|
||||
});
|
||||
|
||||
test('plan-phase.md does not eagerly @-import skeleton-template.md', () => {
|
||||
const planPhaseContent = fs.readFileSync(path.join(WORKFLOWS_DIR, 'plan-phase.md'), 'utf-8');
|
||||
assert.ok(
|
||||
!/@[~./\w-]*skeleton-template\.md/.test(planPhaseContent),
|
||||
'plan-phase.md contains an eager @-import of skeleton-template.md — ' +
|
||||
'this loads the template into context on every plan-phase invocation. ' +
|
||||
'Replace with a conditional Read instruction or a plain backtick path. See #720.'
|
||||
);
|
||||
});
|
||||
|
||||
test('plan-phase.md still references both MVP bodies (lazy reference preserved)', () => {
|
||||
const planPhaseContent = fs.readFileSync(path.join(WORKFLOWS_DIR, 'plan-phase.md'), 'utf-8');
|
||||
assert.ok(
|
||||
/planner-mvp-mode\.md/.test(planPhaseContent) && /skeleton-template\.md/.test(planPhaseContent),
|
||||
'plan-phase.md must still reference planner-mvp-mode.md and skeleton-template.md ' +
|
||||
'(as lazy backtick paths or Read instructions) so agents know where to find them. ' +
|
||||
'Do not delete the references — only remove the leading @ sigil. See #720.'
|
||||
);
|
||||
});
|
||||
|
||||
test('plan-phase.md does not list MVP bodies in <required_reading>', () => {
|
||||
const planPhaseContent = fs.readFileSync(path.join(WORKFLOWS_DIR, 'plan-phase.md'), 'utf-8');
|
||||
const requiredReadingMatch = planPhaseContent.match(/<required_reading>([\s\S]*?)<\/required_reading>/);
|
||||
if (requiredReadingMatch) {
|
||||
const block = requiredReadingMatch[1];
|
||||
assert.ok(
|
||||
!/planner-mvp-mode\.md/.test(block),
|
||||
'planner-mvp-mode.md must NOT appear in plan-phase.md <required_reading> — ' +
|
||||
'that block is always loaded regardless of MVP_MODE. See #720.'
|
||||
);
|
||||
assert.ok(
|
||||
!/skeleton-template\.md/.test(block),
|
||||
'skeleton-template.md must NOT appear in plan-phase.md <required_reading> — ' +
|
||||
'that block is always loaded regardless of MVP_MODE. See #720.'
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
test('execute-phase.md does not eagerly @-import execute-mvp-tdd.md', () => {
|
||||
const executePhaseContent = fs.readFileSync(path.join(WORKFLOWS_DIR, 'execute-phase.md'), 'utf-8');
|
||||
assert.ok(
|
||||
!/@[~./\w-]*execute-mvp-tdd\.md/.test(executePhaseContent),
|
||||
'execute-phase.md contains an eager @-import of execute-mvp-tdd.md — ' +
|
||||
'this loads the MVP TDD body into context for every session. ' +
|
||||
'Replace with a conditional Read instruction or a plain backtick path. See #720.'
|
||||
);
|
||||
});
|
||||
|
||||
test('execute-phase.md still references execute-mvp-tdd.md (lazy reference preserved)', () => {
|
||||
const executePhaseContent = fs.readFileSync(path.join(WORKFLOWS_DIR, 'execute-phase.md'), 'utf-8');
|
||||
assert.ok(
|
||||
/execute-mvp-tdd\.md/.test(executePhaseContent),
|
||||
'execute-phase.md must still reference execute-mvp-tdd.md (as a lazy backtick path ' +
|
||||
'or Read instruction) so agents know where to find it. ' +
|
||||
'Do not delete the reference — only ensure there is no leading @ sigil. See #720.'
|
||||
);
|
||||
});
|
||||
|
||||
test('gsd-planner.md does not eagerly @-import planner-mvp-mode.md', () => {
|
||||
const content = fs.readFileSync(path.join(AGENTS_DIR, 'gsd-planner.md'), 'utf-8');
|
||||
assert.ok(
|
||||
!/@[~./\w-]*planner-mvp-mode\.md/.test(content),
|
||||
'gsd-planner.md contains an eager @-import of planner-mvp-mode.md — ' +
|
||||
'this loads the MVP body into context for every session, even when MVP_MODE is false. ' +
|
||||
'Replace with a conditional Read instruction or a plain backtick path. See #720.'
|
||||
);
|
||||
});
|
||||
|
||||
test('gsd-planner.md does not eagerly @-import skeleton-template.md', () => {
|
||||
const content = fs.readFileSync(path.join(AGENTS_DIR, 'gsd-planner.md'), 'utf-8');
|
||||
assert.ok(
|
||||
!/@[~./\w-]*skeleton-template\.md/.test(content),
|
||||
'gsd-planner.md contains an eager @-import of skeleton-template.md — ' +
|
||||
'this loads the template into context on every planner invocation. ' +
|
||||
'Replace with a conditional Read instruction or a plain backtick path. See #720.'
|
||||
);
|
||||
});
|
||||
|
||||
test('gsd-planner.md does not eagerly @-import user-story-template.md', () => {
|
||||
const content = fs.readFileSync(path.join(AGENTS_DIR, 'gsd-planner.md'), 'utf-8');
|
||||
assert.ok(
|
||||
!/@[~./\w-]*user-story-template\.md/.test(content),
|
||||
'gsd-planner.md contains an eager @-import of user-story-template.md — ' +
|
||||
'this loads the template into context on every planner invocation. ' +
|
||||
'Replace with a conditional Read instruction or a plain backtick path. See #720.'
|
||||
);
|
||||
});
|
||||
|
||||
test('gsd-planner.md still references the three MVP bodies', () => {
|
||||
const content = fs.readFileSync(path.join(AGENTS_DIR, 'gsd-planner.md'), 'utf-8');
|
||||
assert.ok(
|
||||
/planner-mvp-mode\.md/.test(content),
|
||||
'gsd-planner.md must still reference planner-mvp-mode.md (as a lazy path or Read instruction). ' +
|
||||
'Do not delete the reference — only remove the leading @ sigil. See #720.'
|
||||
);
|
||||
assert.ok(
|
||||
/skeleton-template\.md/.test(content),
|
||||
'gsd-planner.md must still reference skeleton-template.md (as a lazy path or Read instruction). ' +
|
||||
'Do not delete the reference — only remove the leading @ sigil. See #720.'
|
||||
);
|
||||
assert.ok(
|
||||
/user-story-template\.md/.test(content),
|
||||
'gsd-planner.md must still reference user-story-template.md (as a lazy path or Read instruction). ' +
|
||||
'Do not delete the reference — only remove the leading @ sigil. See #720.'
|
||||
);
|
||||
});
|
||||
|
||||
test('gsd-executor.md does not eagerly @-import execute-mvp-tdd.md', () => {
|
||||
const content = fs.readFileSync(path.join(AGENTS_DIR, 'gsd-executor.md'), 'utf-8');
|
||||
assert.ok(
|
||||
!/@[~./\w-]*execute-mvp-tdd\.md/.test(content),
|
||||
'gsd-executor.md contains an eager @-import of execute-mvp-tdd.md — ' +
|
||||
'this loads the MVP TDD body into context for every session. ' +
|
||||
'Replace with a conditional Read instruction or a plain backtick path. See #720.'
|
||||
);
|
||||
});
|
||||
|
||||
test('gsd-executor.md still references execute-mvp-tdd.md', () => {
|
||||
const content = fs.readFileSync(path.join(AGENTS_DIR, 'gsd-executor.md'), 'utf-8');
|
||||
assert.ok(
|
||||
/execute-mvp-tdd\.md/.test(content),
|
||||
'gsd-executor.md must still reference execute-mvp-tdd.md (as a lazy path or Read instruction). ' +
|
||||
'Do not delete the reference — only remove the leading @ sigil. See #720.'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user