mirror of
https://github.com/garrytan/gstack.git
synced 2026-11-13 03:48:06 +01:00
- Seeded eng/design plan-mode cases keep 'no scope menu' and replace the exact 'Scope gate: plan mode — auto-selected B' requirement with seededPlanTargeted(): the announcement or native seeded-plan selection, or seed-only plan names appearing in the review output after the slash command (trackTokens). The announcement is logged. - The AskUserQuestion format forbids writing a decision to the plan file as a substitute for asking. assertNoPlanFileDecisions() fails any plan_ready run whose plan carries ## Decisions (eng, design, devex, office-hours auto-mode). The AUQ-blocked cases (eng seeded, devex, office-hours) now require outcome 'asked' (AskUserQuestion variant or prose fallback). - plan-mode-evidence registration controls keep their verdicts; the missing-decisions control now fails on 'without a question'. - plan-mode-targeting.test.ts stores known-good (announcement; paraphrase plus seed content) and known-bad (neither; an untracked token) observations and plan files with and without ## Decisions.
77 lines
3.0 KiB
TypeScript
77 lines
3.0 KiB
TypeScript
/**
|
|
* plan-devex-review plan-mode smoke (gate, paid, real-PTY).
|
|
*
|
|
* See test/skill-e2e-plan-ceo-plan-mode.test.ts for the shared assertion
|
|
* contract. Exercises the same contract against /plan-devex-review.
|
|
*/
|
|
|
|
import { test, expect } from 'bun:test';
|
|
import { CAPTURE_MS, CAPTURE_LONG_MS } from './helpers/eval-budgets';
|
|
import { describeE2ETier } from './helpers/e2e-gate';
|
|
import {
|
|
runPlanSkillObservation,
|
|
planFileHasDecisionsSection,
|
|
assertReportAtBottomIfPlanWritten,
|
|
} from './helpers/claude-pty-runner';
|
|
import { assertNoPlanFileDecisions } from './helpers/plan-mode-evidence';
|
|
|
|
const describeE2E = describeE2ETier('gate');
|
|
|
|
describeE2E('plan-devex-review plan-mode smoke (gate)', () => {
|
|
test('reaches a terminal outcome (asked or plan_ready) without silent writes', async () => {
|
|
const obs = await runPlanSkillObservation({
|
|
skillName: 'plan-devex-review',
|
|
inPlanMode: true,
|
|
timeoutMs: CAPTURE_MS,
|
|
});
|
|
|
|
if (obs.outcome === 'silent_write' || obs.outcome === 'exited' || obs.outcome === 'timeout') {
|
|
throw new Error(
|
|
`plan-devex-review plan-mode smoke FAILED: outcome=${obs.outcome}\n` +
|
|
`summary: ${obs.summary}\n` +
|
|
`elapsed: ${obs.elapsedMs}ms\n` +
|
|
`--- evidence (last 2KB visible) ---\n${obs.evidence}`,
|
|
);
|
|
}
|
|
expect(['asked', 'plan_ready']).toContain(obs.outcome);
|
|
assertReportAtBottomIfPlanWritten(obs);
|
|
assertNoPlanFileDecisions(obs, planFileHasDecisionsSection);
|
|
}, CAPTURE_LONG_MS);
|
|
|
|
// v1.21+ regression: see skill-e2e-plan-ceo-plan-mode.test.ts for the
|
|
// contract. With AskUserQuestion blocked the decision must still be asked
|
|
// (the prose fallback, observed as 'asked'); a plan-file ## Decisions
|
|
// section is not a substitute. Failure signals also include 'auto_decided'
|
|
// (AUTO_DECIDE without opt-in) plus the standard silent_write/exited/timeout.
|
|
test('AskUserQuestion surfaces when --disallowedTools AskUserQuestion is set', async () => {
|
|
const obs = await runPlanSkillObservation({
|
|
skillName: 'plan-devex-review',
|
|
inPlanMode: true,
|
|
extraArgs: ['--disallowedTools', 'AskUserQuestion'],
|
|
timeoutMs: CAPTURE_MS,
|
|
});
|
|
|
|
if (
|
|
obs.outcome === 'auto_decided' ||
|
|
obs.outcome === 'silent_write' ||
|
|
obs.outcome === 'exited' ||
|
|
obs.outcome === 'timeout'
|
|
) {
|
|
throw new Error(
|
|
`plan-devex-review AskUserQuestion-blocked regression: outcome=${obs.outcome}\n` +
|
|
`summary: ${obs.summary}\n` +
|
|
`elapsed: ${obs.elapsedMs}ms\n` +
|
|
`--- evidence (last 2KB visible) ---\n${obs.evidence}`,
|
|
);
|
|
}
|
|
assertReportAtBottomIfPlanWritten(obs);
|
|
assertNoPlanFileDecisions(obs, planFileHasDecisionsSection);
|
|
if (obs.outcome !== 'asked') {
|
|
throw new Error(
|
|
`plan-devex-review AskUserQuestion-blocked regression: outcome=${obs.outcome} — Step 0 reached ${obs.planFile ?? 'plan_ready'} without asking.\n` +
|
|
`--- evidence (last 2KB visible) ---\n${obs.evidence}`,
|
|
);
|
|
}
|
|
}, CAPTURE_LONG_MS);
|
|
});
|