test(pty): fake PTY session driver with an injectable clock through the runner launch seam

The three plan-skill runners take an optional PtyDriver (launch, now,
monotonic, sleep); omitted, they use the real launcher and clocks exactly as
before. test/helpers/pty/fake-session.ts feeds scripted frames through that
seam, and claude-pty-runner.runners.unit.test.ts runs observation, counting
and floor for success, deadline timeout, permission prompt and plan-ready
outcomes with no CLI or real timers. These cases must stay green unchanged
through the W4 split and the runPtySession extraction.

Touchfiles: every entry that lists claude-pty-runner.ts or pty-screen.ts now
also lists test/helpers/pty/**.
This commit is contained in:
garrytan committed 2026-09-30 05:55:32 +00:00
1 parent 96764e80a6
commit a9a1e98e84
5 files changed
+451 -88

No files matched your search

@@ -0,0 +1,186 @@
/**
* The three plan-skill runners driven through the fake PTY session driver
* (scripted frames, injectable clock, no CLI or model). Each runner is run
* for success, deadline timeout, a permission prompt and plan-ready, and its
* launch request is checked for the model pin and skill seeding.
*
* Value: protects=runner outcomes across the runPtySession extraction; fails_when=the session loop reorders poll, permission, deadline or terminal handling; why_new=the runner loops had no deterministic driver; seam=PtyDriver
*/
import { describe, expect, test } from 'bun:test';
import * as fs from 'node:fs';
import * as os from 'node:os';
import * as path from 'node:path';
import { runPlanSkillObservation, runPlanSkillCounting, runPlanSkillFloorCheck } from './claude-pty-runner';
import { createFakePtyDriver, type FakeFrame, type FakeSessionContext } from './pty/fake-session';
import { FORCING_FLOOR_DEVEX } from '../fixtures/forcing-finding-seeds';
const IDLE = 'Claude Code\n> ';
const PLAN_READY = 'Here is the plan.\nReady to execute?\n❯ 1. Yes, and auto-accept edits\n 2. Yes, and manually approve edits\n 3. No, keep planning';
const PERMISSION = 'Create file\n/tmp/unowned-report.md\n────────────────\n 1 # Report\n────────────────\n' +
'Do you want to create unowned-report.md?\n❯ 1. Yes\n 2. Yes, and switch to accept edits (auto-approve file edits and common file commands) for this session\n 3. No\nEsc to cancel · Tab to amend';
const QUESTION = { header: 'Architecture', question: 'The plan repeats a custom generator in each service. Should we use the built-in generator?',
multiSelect: false, options: [{ label: 'Use built-in', description: 'Remove the custom generator.' }, { label: 'Keep custom', description: 'Keep the maintenance burden.' }] };
const TTHW = { header: 'TTHW target', question: 'D2 — Which TTHW target should this journey be measured against?\nThe SDK quickstart has eight steps and an unbounded wait for an emailed API key.',
multiSelect: false, options: [{ label: 'A) Champion (< 2 min)', description: 'Puts key and database questions on the table; not reachable via docs alone.' },
{ label: 'B) Competitive (2-5 min) (recommended)', description: 'Shows which gaps docs polish closes; still blocked by emailed key and local Postgres.' }] };
const render = (q: typeof QUESTION) => ['☐ ' + q.header, q.question,
...q.options.flatMap((o, i) => [`${i ? ' ' : '❯'} ${i + 1}. ${o.label}`, o.description]),
'Enter to select · ↑/↓ to navigate · Esc to cancel'].join('\n');
/** Native JSONL writer for the fake session's isolated config dir. */
function journal(ctx: FakeSessionContext, sessionId: string, role: 'user' | 'assistant', content: unknown, extra: object = {}) {
const file = path.join(ctx.configDir!, 'projects', 'owned', `${sessionId}.jsonl`);
fs.mkdirSync(path.dirname(file), { recursive: true });
fs.appendFileSync(file, JSON.stringify({ type: role, cwd: ctx.launch.cwd, sessionId, isSidechain: false,
timestamp: new Date(ctx.now).toISOString(), message: { role, content }, ...extra }) + '\n');
}
const floorSession = (ctx: FakeSessionContext) => ctx.launch.extraArgs![ctx.launch.extraArgs!.indexOf('--session-id') + 1]!;
async function withConfigDir<T>(run: (configDir: string) => Promise<T>): Promise<T> {
const configDir = fs.mkdtempSync(path.join(os.tmpdir(), 'pty-fake-config-'));
const saved = { run: process.env.EVALS_RUN_ID, dir: process.env.GSTACK_EVAL_DIR };
delete process.env.EVALS_RUN_ID; delete process.env.GSTACK_EVAL_DIR;
try { return await run(configDir); } finally {
if (saved.run !== undefined) process.env.EVALS_RUN_ID = saved.run;
if (saved.dir !== undefined) process.env.GSTACK_EVAL_DIR = saved.dir;
fs.rmSync(configDir, { recursive: true, force: true });
}
}
describe('runPlanSkillObservation through the fake driver', () => {
const observe = (frames: FakeFrame[]) => withConfigDir(async () => {
const fake = createFakePtyDriver({ frames: [{ screen: IDLE }, ...frames] });
const obs = await runPlanSkillObservation({ skillName: 'plan-eng-review', timeoutMs: 20_000, model: 'fake-model', driver: fake.driver });
return { obs, fake };
});
test('success: a rendered question is asked', async () => {
const { obs, fake } = await observe([{ onInput: '/plan-eng-review\r', screen: render(QUESTION) }]);
expect(obs.outcome).toBe('asked');
expect(fake.sent).toEqual(['/plan-eng-review\r']);
expect(fake.closes()).toBe(1);
expect(fake.launches).toHaveLength(1);
expect(fake.launches[0]).toMatchObject({ permissionMode: 'plan', seedSkills: true, model: 'fake-model', env: { GSTACK_PLAN_MODE: 'active' } });
});
test('deadline: no terminal frame times out on the injected clock', async () => {
const { obs, fake } = await observe([{ onInput: '/plan-eng-review\r', screen: 'Thinking…' }]);
expect(obs.outcome).toBe('timeout');
expect(obs.summary).toBe('no terminal outcome within 20000ms');
expect(obs.elapsedMs).toBe(20_000);
expect(fake.closes()).toBe(1);
});
test('permission prompt: never answered and never counted as a question', async () => {
const { obs, fake } = await observe([{ onInput: '/plan-eng-review\r', screen: PERMISSION }]);
expect(obs.outcome).toBe('timeout');
expect(obs.proseAUQEverObserved).toBe(false);
expect(fake.sent).toEqual(['/plan-eng-review\r']);
});
test('plan-ready: the native confirmation ends the observation', async () => {
const { obs } = await observe([{ onInput: '/plan-eng-review\r', screen: PERMISSION }, { afterMs: 4000, screen: PLAN_READY }]);
expect(obs.outcome).toBe('plan_ready');
});
});
describe('runPlanSkillCounting through the fake driver', () => {
const count = (frames: FakeFrame[], seedTranscript = true) => withConfigDir(async configDir => {
const fake = createFakePtyDriver({ configDir, frames: [
{ screen: IDLE, effect: ctx => { if (seedTranscript) journal(ctx, 'count', 'assistant', [{ type: 'text', text: 'Ready.' }]); } },
...frames] });
const obs = await runPlanSkillCounting({ skillName: 'plan-eng-review', slashCommand: '/plan-eng-review',
followUpPrompt: '# Plan: fake counting fixture', isLastStep0AUQ: () => false, isReviewAUQ: () => true,
reviewCountCeiling: 8, timeoutMs: 60_000, model: 'fake-model', driver: fake.driver });
return { obs, fake };
});
const asked = (ctx: FakeSessionContext) => journal(ctx, 'count', 'assistant', [{ type: 'tool_use', id: 'finding', name: 'AskUserQuestion', input: { questions: [QUESTION] } }]);
const answered = (ctx: FakeSessionContext) => journal(ctx, 'count', 'user', [{ type: 'tool_result', tool_use_id: 'finding', content: 'Answered.' }],
{ toolUseResult: { answers: { [QUESTION.question]: 'Use built-in' } } });
test('success: one answered native review question, then the completion summary', async () => {
const { obs, fake } = await count([
{ onInput: '/plan-eng-review\r', screen: render(QUESTION), effect: asked },
{ onInput: '1', screen: '## Completion Summary\nOne finding resolved.\n> ', effect: answered },
]);
expect(obs.outcome).toBe('completion_summary');
expect(obs.reviewCount).toBe(1);
expect(fake.sent).toEqual(['/plan-eng-review\r', '1']);
expect(fake.closes()).toBe(1);
expect(fake.launches[0]).toMatchObject({ permissionMode: 'plan', seedSkills: true, model: 'fake-model', observeScreen: true, observePlanReady: true });
});
test('deadline: the work window closes with the cleanup reserve kept', async () => {
const { obs, fake } = await count([{ onInput: '/plan-eng-review\r', screen: 'Thinking…' }]);
expect(obs.outcome).toBe('timeout');
expect(obs.summary).toContain('no terminal outcome within 60000ms total budget');
expect(obs.elapsedMs).toBeLessThanOrEqual(55_000);
});
test('permission prompt: granted with the default pick, then plan-ready', async () => {
const { obs, fake } = await count([
{ onInput: '/plan-eng-review\r', screen: PERMISSION },
{ onInput: '1\r', screen: PLAN_READY },
]);
expect(obs.outcome).toBe('plan_ready');
expect(fake.sent).toEqual(['/plan-eng-review\r', '1\r']);
});
test('plan-ready: needs a complete native transcript', async () => {
const ready = await count([{ onInput: '/plan-eng-review\r', screen: PLAN_READY }]);
expect(ready.obs.outcome).toBe('plan_ready');
expect(ready.obs.reviewCount).toBe(0);
const missing = await count([{ onInput: '/plan-eng-review\r', screen: PLAN_READY }], false);
expect(missing.obs.outcome).toBe('transcript_unavailable');
});
});
describe('runPlanSkillFloorCheck through the fake driver', () => {
const delivered = (ctx: FakeSessionContext) => journal(ctx, floorSession(ctx), 'user',
'<command-message>plan-devex-review</command-message>\n<command-name>/plan-devex-review</command-name>\n<command-args>PLAN.md</command-args>');
const floor = (frames: FakeFrame[]) => withConfigDir(async configDir => {
const fake = createFakePtyDriver({ configDir, frames: [{ screen: IDLE }, ...frames] });
const obs = await runPlanSkillFloorCheck({ skillName: 'plan-devex-review', slashCommand: '/plan-devex-review',
followUpPrompt: FORCING_FLOOR_DEVEX, timeoutMs: 30_000, model: 'fake-model', driver: fake.driver });
return { obs, fake };
});
test('success: the deterministic seeded finding is observed without an answer', async () => {
const { obs, fake } = await floor([
{ onInput: '/plan-devex-review PLAN.md\r', screen: 'Reviewing PLAN.md', effect: delivered },
{ afterMs: 2000, screen: render(TTHW), effect: ctx => journal(ctx, floorSession(ctx), 'assistant',
[{ type: 'tool_use', id: 'tthw', name: 'AskUserQuestion', input: { questions: [TTHW] } }]) },
]);
expect(obs.outcome).toBe('auq_observed');
expect(obs.auqObserved).toBe(true);
expect(obs.targetDelivery?.status).toBe('ready');
expect(fake.sent).toEqual(['/plan-devex-review PLAN.md\r']);
expect(fake.closes()).toBe(1);
expect(fake.launches[0]).toMatchObject({ permissionMode: 'plan', seedSkills: true, model: 'fake-model', observeScreen: true, observeSetupQuestions: true });
});
test('deadline: a delivered target with no question times out', async () => {
const { obs } = await floor([{ onInput: '/plan-devex-review PLAN.md\r', screen: 'Thinking…', effect: delivered }]);
expect(obs.outcome).toBe('timeout');
expect(obs.summary).toBe('no qualifying finding question within 30000ms');
});
test('permission prompt: an unowned permission is neither granted nor counted', async () => {
const { obs, fake } = await floor([
{ onInput: '/plan-devex-review PLAN.md\r', screen: PERMISSION, effect: delivered },
{ afterMs: 6000, screen: PLAN_READY },
]);
expect(obs.outcome).toBe('plan_ready');
expect(obs.auqObserved).toBe(false);
expect(fake.sent).toEqual(['/plan-devex-review PLAN.md\r']);
});
test('plan-ready: reaching approval without a finding is the regression outcome', async () => {
const { obs } = await floor([
{ onInput: '/plan-devex-review PLAN.md\r', screen: 'Reviewing PLAN.md', effect: delivered },
{ afterMs: 2000, screen: PLAN_READY },
]);
expect(obs.outcome).toBe('plan_ready');
expect(obs.summary).toBe('agent reached plan_ready without a qualifying finding question');
});
});
+95 -68
View File
@@ -216,6 +216,21 @@ export interface ClaudePtySession {
close(): Promise<void>;
}
/**
* The runners' launch seam: how a session starts, and the clock the runner
* loop reads. Omitted in production (real launcher, Date.now,
* performance.now, Bun.sleep); tests pass the fake driver from
* test/helpers/pty/fake-session.ts.
*/
export interface PtyDriver {
launch(opts: ClaudePtyOptions): Promise<ClaudePtySession>;
/** Wall clock, Date.now() semantics. */
now(): number;
/** Monotonic clock, performance.now() semantics. */
monotonic(): number;
sleep(ms: number): Promise<void>;
}
/** Let a numbered menu apply its selection before confirming it. */
export async function selectPtyNumberedOption(
session: Pick<ClaudePtySession, 'send'>,
@@ -3688,11 +3703,15 @@ export async function runPlanSkillObservation(opts: {
* buffer (case-sensitive). Results land in obs.tokensObserved. Use for
* consumption asserts that must survive the 2KB evidence tail. */
trackTokens?: string[];
/** Launch seam and clock; tests pass the fake driver. Default: real launcher and clocks. */
driver?: PtyDriver;
}): Promise<PlanSkillObservation> {
const startedAt = Date.now();
const driver = opts.driver ?? { launch: launchClaudePty, now: () => Date.now(),
monotonic: () => performance.now(), sleep: (ms: number) => Bun.sleep(ms) };
const startedAt = driver.now();
const budgetMs = opts.timeoutMs ?? 180_000;
const deadlineAt = startedAt + budgetMs;
const screenDeadlineAt = performance.now() + budgetMs;
const screenDeadlineAt = driver.monotonic() + budgetMs;
// Explicitly identify only a new seeded plan-mode session. Caller-owned
// resume/session arguments retain their existing behavior.
const scopeSessionId = opts.initialPlanContent && opts.inPlanMode !== false &&
@@ -3701,7 +3720,7 @@ export async function runPlanSkillObservation(opts: {
const readAutoDecisionState = opts.autoDecisionState
? bindAutoDecisionState(opts.autoDecisionState, opts.env, opts.skillName) : undefined;
const saveSnapshot = createPlanCountSnapshotWriter();
const session = await launchClaudePty({
const session = await driver.launch({
permissionMode: opts.inPlanMode === false ? null : 'plan',
cwd: opts.cwd,
timeoutMs: (opts.timeoutMs ?? 180_000) + 30_000,
@@ -3727,7 +3746,7 @@ export async function runPlanSkillObservation(opts: {
observation: { state: 'plan_skill_preflight_timeout', summary, scopeSessionId, startedAt, deadlineAt, viewportError } });
return {
outcome: 'timeout', summary, evidence: session.visibleText().slice(-2000),
elapsedMs: Date.now() - startedAt,
elapsedMs: driver.now() - startedAt,
proseAUQEverObserved: false, waitingEverObserved: false,
scopeGateQuestionObserved: false, scopeGateAutoSelectObserved: false,
...(opts.trackTokens?.length ? { tokensObserved: Object.fromEntries(opts.trackTokens.map(t => [t, false])) } : {}),
@@ -3736,7 +3755,7 @@ export async function runPlanSkillObservation(opts: {
};
// Entry deadline → boot → owned paste/receipt/ack → slash → observation.
// Setup consumes the existing case budget; cleanup has its separate grace.
if (!opts.initialPlanContent) await Bun.sleep(Math.min(8000, Math.max(0, deadlineAt - Date.now())));
if (!opts.initialPlanContent) await driver.sleep(Math.min(8000, Math.max(0, deadlineAt - driver.now())));
if (opts.initialPlanContent) {
const seed = `Keep this draft plan as context. Briefly acknowledge receipt, then wait for my next message containing a slash command. Do not start the review or call tools yet.\n\n${opts.initialPlanContent}`;
try {
@@ -3749,12 +3768,12 @@ export async function runPlanSkillObservation(opts: {
return await preflightTimeout(`Plan seed submission failed: ${error.message}`);
}
}
if (Date.now() >= deadlineAt) return await preflightTimeout('Boot or seed preflight exhausted the existing case budget');
const commandStartedAt = Date.now();
if (driver.now() >= deadlineAt) return await preflightTimeout('Boot or seed preflight exhausted the existing case budget');
const commandStartedAt = driver.now();
const since = session.mark();
session.send(`/${opts.skillName}\r`);
const start = Date.now();
const start = driver.now();
let lastJudgeAt = 0;
let lastJudgeVerdict: PtyStateVerdict | null = null;
// High-water marks: did we EVER see a prose-AUQ surface or a judge
@@ -3793,8 +3812,8 @@ export async function runPlanSkillObservation(opts: {
};
const JUDGE_AFTER_MS = 60_000;
const JUDGE_INTERVAL_MS = 30_000;
while (Date.now() < deadlineAt) {
await Bun.sleep(Math.min(2000, Math.max(0, deadlineAt - Date.now())));
while (driver.now() < deadlineAt) {
await driver.sleep(Math.min(2000, Math.max(0, deadlineAt - driver.now())));
const visible = session.visibleSince(since);
if (session.exited()) {
@@ -3802,7 +3821,7 @@ export async function runPlanSkillObservation(opts: {
outcome: 'exited',
summary: `claude exited (code=${session.exitCode()}) before reaching a terminal outcome`,
evidence: visible.slice(-2000),
elapsedMs: Date.now() - startedAt,
elapsedMs: driver.now() - startedAt,
...highWaterFlags(),
};
}
@@ -3811,7 +3830,7 @@ export async function runPlanSkillObservation(opts: {
outcome: 'exited',
summary: `claude rejected /${opts.skillName} as unknown command (skill not registered in this cwd)`,
evidence: visible.slice(-2000),
elapsedMs: Date.now() - startedAt,
elapsedMs: driver.now() - startedAt,
...highWaterFlags(),
};
}
@@ -3829,7 +3848,7 @@ export async function runPlanSkillObservation(opts: {
proseAUQEverObserved = true;
logPtySnapshot(visible, {
testName: opts.skillName,
elapsedMs: Date.now() - start,
elapsedMs: driver.now() - start,
tag: 'prose-auq-surfaced',
});
}
@@ -3848,7 +3867,7 @@ export async function runPlanSkillObservation(opts: {
scopeTools = [];
scopeTranscript = readPlanCountTranscript(session.hermeticConfigDir,
path.resolve(opts.cwd ?? process.cwd()), event => scopeTools.push(event));
nativePolledAt = Date.now();
nativePolledAt = driver.now();
if (!scopeGateAutoSelectObserved) scopeGateAutoSelectObserved = nativeSeededPlanSelection(scopeTranscript, scopeTools, {
seed: opts.initialPlanContent, skillName: opts.skillName, sessionId: scopeSessionId, commandStartedAt,
});
@@ -3861,7 +3880,7 @@ export async function runPlanSkillObservation(opts: {
const obs: PlanSkillObservation = {
...classified,
evidence: visible.slice(-2000),
elapsedMs: Date.now() - startedAt,
elapsedMs: driver.now() - startedAt,
...highWaterFlags(),
};
// Capture the plan file path on any outcome where one may have been
@@ -3880,13 +3899,13 @@ export async function runPlanSkillObservation(opts: {
// and writes). Only an unclassified frame may use owned native auto-decision evidence.
if (scopeSessionId) {
nativeAutoDecide = findNativeAutoDecision(scopeTranscript, scopeTools, {
skillName: opts.skillName, sessionId: scopeSessionId, commandStartedAt, now: Date.now(), proseQuestionObserved: proseAUQEverObserved,
skillName: opts.skillName, sessionId: scopeSessionId, commandStartedAt, now: driver.now(), proseQuestionObserved: proseAUQEverObserved,
stateEvidence: readAutoDecisionState?.(),
});
if (nativeAutoDecide) return {
outcome: 'auto_decided',
summary: 'owned native session completed the saved-preference auto-decision',
evidence: visible.slice(-2000), elapsedMs: Date.now() - startedAt,
evidence: visible.slice(-2000), elapsedMs: driver.now() - startedAt,
...highWaterFlags(),
};
}
@@ -3896,9 +3915,9 @@ export async function runPlanSkillObservation(opts: {
// working, or hung?" Treat 'waiting' as 'asked' (model surfaced a
// question via prose the regex couldn't reassemble). Snapshot the
// visible buffer at each judge call when GSTACK_PTY_LOG=1.
const elapsed = Date.now() - start;
if (elapsed > JUDGE_AFTER_MS && Date.now() - lastJudgeAt > JUDGE_INTERVAL_MS) {
lastJudgeAt = Date.now();
const elapsed = driver.now() - start;
if (elapsed > JUDGE_AFTER_MS && driver.now() - lastJudgeAt > JUDGE_INTERVAL_MS) {
lastJudgeAt = driver.now();
logPtySnapshot(visible, { testName: opts.skillName, elapsedMs: elapsed, tag: 'judge-tick' });
lastJudgeVerdict = judgePtyState(visible, { testName: opts.skillName });
if (lastJudgeVerdict.state === 'waiting' && !pendingSeededCompletion) {
@@ -3908,7 +3927,7 @@ export async function runPlanSkillObservation(opts: {
outcome: 'asked',
summary: `LLM judge: ${lastJudgeVerdict.reasoning} (state=waiting after ${Math.round(elapsed / 1000)}s)`,
evidence: visible.slice(-2000),
elapsedMs: Date.now() - startedAt,
elapsedMs: driver.now() - startedAt,
...highWaterFlags(),
};
}
@@ -3930,7 +3949,7 @@ export async function runPlanSkillObservation(opts: {
? ` (last LLM judge: ${lastJudgeVerdict.state} — ${lastJudgeVerdict.reasoning})`
: ''),
evidence: finalVisible.slice(-2000),
elapsedMs: Date.now() - startedAt,
elapsedMs: driver.now() - startedAt,
...highWaterFlags(),
};
}
@@ -3942,7 +3961,7 @@ export async function runPlanSkillObservation(opts: {
? ` (last LLM judge: state=${lastJudgeVerdict.state} — ${lastJudgeVerdict.reasoning})`
: ''),
evidence: finalVisible.slice(-2000),
elapsedMs: Date.now() - startedAt,
elapsedMs: driver.now() - startedAt,
...highWaterFlags(),
};
} catch (error) {
@@ -4125,7 +4144,11 @@ export async function runPlanSkillCounting(opts: {
env?: Record<string, string>;
/** Override the spawned model. Defaults via launchClaudePty's chain. */
model?: string;
/** Launch seam and clock; tests pass the fake driver. Default: real launcher and clocks. */
driver?: PtyDriver;
}): Promise<PlanSkillCountObservation> {
const driver = opts.driver ?? { launch: launchClaudePty, now: () => Date.now(),
monotonic: () => performance.now(), sleep: (ms: number) => Bun.sleep(ms) };
if (opts.requireNativePicker && !opts.pickAUQ)
throw Error('Native picker binding requires a declared picker');
if (opts.bindDesignBoardState && (opts.skillName !== 'plan-design-review' || !opts.pickAUQ))
@@ -4134,8 +4157,8 @@ export async function runPlanSkillCounting(opts: {
throw Error('Eng test-plan approval requires the Eng caller and its explicit report');
if (opts.isCollectionComplete && opts.expectedPlanPath)
throw Error('Collection-only completion cannot replace the final report contract');
const budgetStarted = performance.now();
const startedAt = Date.now();
const budgetStarted = driver.monotonic();
const startedAt = driver.now();
const defaultPick = opts.defaultPick ?? 1;
const timeoutMs = opts.timeoutMs ?? 1_500_000;
if (opts.startupReadyMarker !== undefined && !opts.startupReadyMarker.length) {
@@ -4149,12 +4172,12 @@ export async function runPlanSkillCounting(opts: {
throw new RangeError('Plan counting timeout must exceed the 5000ms cleanup reserve');
}
const workDeadline = budgetStarted + timeoutMs - cleanupReserveMs;
const remainingWork = () => Math.max(0, workDeadline - performance.now());
const remainingWork = () => Math.max(0, workDeadline - driver.monotonic());
async function waitForWork(ms: number): Promise<boolean> {
const remaining = remainingWork();
if (remaining <= 0) return false;
const clipped = ms >= remaining;
await Bun.sleep(Math.min(ms, remaining));
await driver.sleep(Math.min(ms, remaining));
// A clipped wait cannot finish the requested interval. Timers may wake
// just before the fractional deadline; that is no license to advance.
return !clipped && remainingWork() > 0;
@@ -4169,7 +4192,7 @@ export async function runPlanSkillCounting(opts: {
];
let session: ClaudePtySession;
try {
session = await launchClaudePty({
session = await driver.launch({
permissionMode: 'plan',
cwd: fixture.cwd,
// Stop new output at the work cutoff so screen drain cannot consume
@@ -4210,7 +4233,7 @@ export async function runPlanSkillCounting(opts: {
let administrativeCount = 0;
let isFirstAUQ = true;
const saveSnapshot = createPlanCountSnapshotWriter();
let lastCheckpointAt = Date.now();
let lastCheckpointAt = driver.now();
let viewport = '';
const capture = (observation: object) => {
@@ -4243,7 +4266,7 @@ export async function runPlanSkillCounting(opts: {
? `exitCode=${session.exitCode()}\n--- post-command evidence (last 3KB) ---\n${clean(visible).slice(-3000)}` +
`\n--- full-session evidence, including startup (last 6KB) ---\n${clean(session.visibleText()).slice(-6000)}`
: visible.slice(-3000),
elapsedMs: Date.now() - startedAt,
elapsedMs: driver.now() - startedAt,
fingerprints,
transcript,
step0Count,
@@ -4272,7 +4295,7 @@ export async function runPlanSkillCounting(opts: {
observedOutput = session.mark();
if (opts.approveEngTestPlanEdits) {
if (!session.startAutoplanArtifactEditApproval) throw Error('Owned Eng test-plan approval hook unavailable');
session.startAutoplanArtifactEditApproval(Date.now());
session.startAutoplanArtifactEditApproval(driver.now());
}
session.send(`${opts.slashCommand}\r`);
}
@@ -4281,10 +4304,10 @@ export async function runPlanSkillCounting(opts: {
await session.waitForOutput(observedOutput, Math.min(2000, remainingWork()));
if (remainingWork() <= 0) break;
const coalesceMs = session.rawOutput().length > observedOutput
? 250 : 250 - (performance.now() - lastObservationAt);
? 250 : 250 - (driver.monotonic() - lastObservationAt);
if (coalesceMs > 0 && !await waitForWork(coalesceMs)) break;
observedOutput = session.mark();
lastObservationAt = performance.now();
lastObservationAt = driver.monotonic();
const visible = viewport = await session.currentScreen();
if (remainingWork() <= 0) break;
transcript = session.hermeticConfigDir
@@ -4301,9 +4324,9 @@ export async function runPlanSkillCounting(opts: {
// Native approval owns this Edit. Never answer its repaint or count a
// metadata-only pending request; resume only after its actual result.
if (boundary === 'pending') {
if (Date.now() - lastCheckpointAt >= 30_000) {
lastCheckpointAt = Date.now();
const saved = capture({ state: 'artifact_pending', elapsedMs: Date.now() - startedAt,
if (driver.now() - lastCheckpointAt >= 30_000) {
lastCheckpointAt = driver.now();
const saved = capture({ state: 'artifact_pending', elapsedMs: driver.now() - startedAt,
fingerprints, step0Count, reviewCount, administrativeCount, transcript, artifactStatus: status });
if (saved.artifactError) console.error(`PTY artifact write failed: ${saved.artifactError}`);
}
@@ -4316,7 +4339,7 @@ export async function runPlanSkillCounting(opts: {
for (const [callIndex, call] of transcript.calls.entries()) {
const signature = `${call.sessionId}:${call.toolUseId}`;
if (!call.answered || countedCalls.has(signature)) continue;
const fp = nativePlanCallFingerprint(call, Date.now() - startedAt, !boundaryFired);
const fp = nativePlanCallFingerprint(call, driver.now() - startedAt, !boundaryFired);
const phase = planCountQuestionPhase(fp, boundaryFired, opts.isLastStep0AUQ, opts.isFirstReviewAUQ, opts.isSetupAUQ, opts.isCompletionHandoffAUQ, opts.isArtifactGenerationAUQ);
if (phase.administrative) {
fp.preReview = false;
@@ -4340,9 +4363,9 @@ export async function runPlanSkillCounting(opts: {
}
// An outer test timeout/cancellation may prevent a terminal snapshot.
// Keep bounded-cadence evidence without adding a timer to clean up.
if (Date.now() - lastCheckpointAt >= 30_000) {
lastCheckpointAt = Date.now();
const saved = capture({ state: 'in_progress', elapsedMs: Date.now() - startedAt,
if (driver.now() - lastCheckpointAt >= 30_000) {
lastCheckpointAt = driver.now();
const saved = capture({ state: 'in_progress', elapsedMs: driver.now() - startedAt,
fingerprints, step0Count, reviewCount, administrativeCount, transcript });
if (saved.artifactError) console.error(`PTY artifact write failed: ${saved.artifactError}`);
}
@@ -4520,7 +4543,7 @@ export async function runPlanSkillCounting(opts: {
// findings often reuse the same Add to plan / Defer / Skip menu.
if (opts.requireNativePicker && !newlyMatched) continue;
const capturedSeen = opts.requireNativePicker ? new Set(seen) : seen;
const fp = capturePlanCountQuestion(visible, capturedSeen, Date.now() - startedAt, !boundaryFired, pending, planningDirectory);
const fp = capturePlanCountQuestion(visible, capturedSeen, driver.now() - startedAt, !boundaryFired, pending, planningDirectory);
if (!fp) continue;
const boundNativeTab = pending && fp.nativeCall === pending && fp.nativeQuestionIndex !== undefined;
if (opts.requireNativePicker && !boundNativeTab) continue;
@@ -4572,7 +4595,7 @@ export async function runPlanSkillCounting(opts: {
// Keep the exact frame/transcript that the throwing caller observed;
// awaiting a redraw here would erase that ordering evidence.
const saved = capture({ state: 'threw', error: error instanceof Error ? error.message : String(error),
elapsedMs: Date.now() - startedAt, fingerprints, step0Count, reviewCount, administrativeCount, transcript,
elapsedMs: driver.now() - startedAt, fingerprints, step0Count, reviewCount, administrativeCount, transcript,
pendingQuestion: readPendingQuestion(session.pendingQuestionFile, fixture.cwd,
session.hermeticConfigDir, startedAt, transcript) });
if (saved.artifactDir) console.error(`Full PTY artifacts: ${saved.artifactDir}`);
@@ -4721,8 +4744,12 @@ export async function runPlanSkillFloorCheck(opts: {
env?: Record<string, string>;
/** Override the spawned model. Defaults via launchClaudePty's chain. */
model?: string;
/** Launch seam and clock; tests pass the fake driver. Default: real launcher and clocks. */
driver?: PtyDriver;
}): Promise<PlanSkillFloorObservation> {
const startedAt = Date.now();
const driver = opts.driver ?? { launch: launchClaudePty, now: () => Date.now(),
monotonic: () => performance.now(), sleep: (ms: number) => Bun.sleep(ms) };
const startedAt = driver.now();
const timeoutMs = opts.timeoutMs ?? 600_000;
const dxContext = opts.devexSetupContext;
if (dxContext !== undefined && (opts.skillName !== 'plan-devex-review' || opts.productType !== 'sdk-documentation' ||
@@ -4745,7 +4772,7 @@ export async function runPlanSkillFloorCheck(opts: {
const sessionId = randomUUID();
let session: ClaudePtySession;
try {
session = await launchClaudePty({
session = await driver.launch({
permissionMode: 'plan',
cwd: fixture.cwd,
timeoutMs: timeoutMs + 60_000,
@@ -4780,14 +4807,14 @@ export async function runPlanSkillFloorCheck(opts: {
let floorFailed = false;
let floorError: unknown;
try {
await Bun.sleep(8000); // boot grace + auto-trust handler window
await driver.sleep(8000); // boot grace + auto-trust handler window
const since = session.mark();
const commandStartedAt = Date.now();
const commandStartedAt = driver.now();
session.send(`${opts.slashCommand} PLAN.md\r`);
const deliveryOptions = { seed: fixture.seed, sessionId,
slashCommand: opts.slashCommand, startedAt: commandStartedAt };
let targetDelivery = readPlanFloorTarget(session.hermeticConfigDir, fixture.cwd,
{ ...deliveryOptions, now: Date.now() });
{ ...deliveryOptions, now: driver.now() });
const saveSnapshot = createPlanCountSnapshotWriter();
let nativeCandidates: NativePlanQuestionCall[] = [];
let validatedPendingQuestion: ReturnType<typeof readPendingQuestion>;
@@ -4805,7 +4832,7 @@ export async function runPlanSkillFloorCheck(opts: {
const input = readPendingWriteInput(binding.file, binding.expected, fixture.cwd, session.hermeticConfigDir, startedAt);
return input ? [input] : [];
}),
questionDiagnostics: { sampledAt, parentSessionId: sessionId, recorderStatus, recorderStatusAt: Date.now(), nativeCandidates, validatedPendingQuestion },
questionDiagnostics: { sampledAt, parentSessionId: sessionId, recorderStatus, recorderStatusAt: driver.now(), nativeCandidates, validatedPendingQuestion },
...(dxContext ? { setupContextReplies: [...dxReplies.values()] } : {}), artifactError } });
if (artifacts.artifactError) {
artifactError ??= artifacts.artifactError;
@@ -4816,9 +4843,9 @@ export async function runPlanSkillFloorCheck(opts: {
const checkpoint = () => {
const state = JSON.stringify([pendingQuestionRecorderStatus(session.pendingQuestionFile, fixture.cwd, session.hermeticConfigDir),
targetDelivery.status, nativeCandidates, validatedPendingQuestion, pendingQuestion, [...dxReplies.values()]]);
if (state === lastCheckpointState && Date.now() - lastCheckpointAt < 15_000) return;
lastCheckpointState = state; lastCheckpointAt = Date.now();
capture({ state: 'in_progress', elapsedMs: Date.now() - startedAt });
if (state === lastCheckpointState && driver.now() - lastCheckpointAt < 15_000) return;
lastCheckpointState = state; lastCheckpointAt = driver.now();
capture({ state: 'in_progress', elapsedMs: driver.now() - startedAt });
};
captureBeforeClose = (error) => {
if (floorFailed && session.hermeticConfigDir) {
@@ -4826,7 +4853,7 @@ export async function runPlanSkillFloorCheck(opts: {
transcript = readPlanCountTranscript(session.hermeticConfigDir, fixture.cwd, event => publicTools.push(event));
}
if (!finished) capture({ state: floorFailed ? 'threw' : 'in_progress', error: floorFailed ? String(error) : undefined,
captureReason: 'before_cleanup', elapsedMs: Date.now() - startedAt });
captureReason: 'before_cleanup', elapsedMs: driver.now() - startedAt });
};
const finish = (observation: PlanSkillFloorObservation): PlanSkillFloorObservation => {
const artifacts = capture(observation);
@@ -4834,11 +4861,11 @@ export async function runPlanSkillFloorCheck(opts: {
return { ...observation, targetDelivery, ...artifacts };
};
const start = Date.now();
const start = driver.now();
const deadlineAt = start + timeoutMs;
const screenDeadlineAt = performance.now() + timeoutMs;
while (Date.now() - start < timeoutMs) {
await Bun.sleep(2000);
const screenDeadlineAt = driver.monotonic() + timeoutMs;
while (driver.now() - start < timeoutMs) {
await driver.sleep(2000);
const visible = session.visibleSince(since);
if (session.exited()) {
@@ -4847,7 +4874,7 @@ export async function runPlanSkillFloorCheck(opts: {
outcome: 'exited',
summary: `claude exited (code=${session.exitCode()}) before a qualifying finding`,
evidence: visible.slice(-3000),
elapsedMs: Date.now() - startedAt,
elapsedMs: driver.now() - startedAt,
});
}
if (isRejectedSlashCommand(visible, opts.slashCommand)) {
@@ -4856,13 +4883,13 @@ export async function runPlanSkillFloorCheck(opts: {
outcome: 'exited',
summary: `claude rejected ${opts.slashCommand} as unknown command`,
evidence: visible.slice(-3000),
elapsedMs: Date.now() - startedAt,
elapsedMs: driver.now() - startedAt,
});
}
if (targetDelivery.status !== 'ready') {
targetDelivery = readPlanFloorTarget(session.hermeticConfigDir, fixture.cwd,
{ ...deliveryOptions, now: Date.now() });
{ ...deliveryOptions, now: driver.now() });
if (targetDelivery.status !== 'ready') {
viewport = await session.currentScreen(screenDeadlineAt);
checkpoint();
@@ -4883,10 +4910,10 @@ export async function runPlanSkillFloorCheck(opts: {
call.sessionId === sessionId && !call.answered && !call.failed && publicTools.filter(event =>
event.sessionId === sessionId && event.kind === 'use' && event.name === 'AskUserQuestion' &&
event.toolUseId === call.toolUseId && Date.parse(event.timestamp) >= commandStartedAt &&
Date.parse(event.timestamp) <= Date.now() && isDeepStrictEqual(event.input?.questions, call.questions)).length === 1) : [];
Date.parse(event.timestamp) <= driver.now() && isDeepStrictEqual(event.input?.questions, call.questions)).length === 1) : [];
nativeCandidates = currentCalls.slice();
validatedPendingQuestion = hook;
sampledAt = Date.now();
sampledAt = driver.now();
if (hook?.sessionId === sessionId && !transcript.calls.some(call => call.toolUseId === hook.toolUseId)) currentCalls.push(hook);
const activeReply = currentCalls.length === 1 && dxReplies.get(`${currentCalls[0]!.sessionId}:${currentCalls[0]!.toolUseId}`);
if (activeReply) {
@@ -4922,7 +4949,7 @@ export async function runPlanSkillFloorCheck(opts: {
if (permissionIsActiveRender) continue;
const questionViewport = dxContext && pendingQuestion ? planFloorDXPane(viewport, pendingQuestion)! : viewport;
const fp = pendingQuestion && capturePlanCountQuestion(questionViewport, new Set(), Date.now() - start, true, pendingQuestion, planningDirectory);
const fp = pendingQuestion && capturePlanCountQuestion(questionViewport, new Set(), driver.now() - start, true, pendingQuestion, planningDirectory);
if (fp && pendingQuestion) {
const index = fp.nativeQuestionIndex ?? 0;
const question = pendingQuestion.questions[index]!;
@@ -4947,7 +4974,7 @@ export async function runPlanSkillFloorCheck(opts: {
// a generic idle prompt, permission, tool result or quoted example.
floorReview = undefined;
const message = transcript.assistantMessages.filter(m => m.sessionId === sessionId &&
Date.parse(m.timestamp) >= commandStartedAt && Date.parse(m.timestamp) <= Date.now()).at(-1);
Date.parse(m.timestamp) >= commandStartedAt && Date.parse(m.timestamp) <= driver.now()).at(-1);
const compact = (text: string) => text.replace(/\s+/g, '');
if (!currentCalls.length && message && isProseAUQVisible(viewport) && isProseAUQVisible(message.text) &&
!/^\s*(?:>|`{3,}|~{3,})/m.test(message.text) && compact(viewport).includes(compact(message.text)))
@@ -4971,7 +4998,7 @@ export async function runPlanSkillFloorCheck(opts: {
} catch (error) {
return finish({ auqObserved: false, outcome: 'assessment_error',
summary: `Finding assessment failed: ${error instanceof Error ? error.message : String(error)}`,
evidence: viewport, elapsedMs: Date.now() - startedAt });
evidence: viewport, elapsedMs: driver.now() - startedAt });
}
assessed.set(key, floorAssessment);
}
@@ -4983,7 +5010,7 @@ export async function runPlanSkillFloorCheck(opts: {
if (floorAssessment.kind === 'finding') return finish({
auqObserved: true, outcome: 'auq_observed',
summary: `Current ${floorReview.candidate.transport} question addresses the owned seeded finding: ${floorAssessment.reason}`,
evidence: viewport, elapsedMs: Date.now() - startedAt,
evidence: viewport, elapsedMs: driver.now() - startedAt,
});
}
@@ -4999,7 +5026,7 @@ export async function runPlanSkillFloorCheck(opts: {
outcome: 'silent_write',
summary: `Write/Edit to ${target} fired before any AskUserQuestion`,
evidence: visible.slice(-3000),
elapsedMs: Date.now() - startedAt,
elapsedMs: driver.now() - startedAt,
});
}
}
@@ -5017,7 +5044,7 @@ export async function runPlanSkillFloorCheck(opts: {
outcome: 'plan_ready',
summary: 'agent reached plan_ready without a qualifying finding question',
evidence: visible.slice(-3000),
elapsedMs: Date.now() - startedAt,
elapsedMs: driver.now() - startedAt,
});
}
}
@@ -5029,7 +5056,7 @@ export async function runPlanSkillFloorCheck(opts: {
? `no qualifying finding question within ${timeoutMs}ms`
: `seeded target delivery unavailable within ${timeoutMs}ms: ${targetDelivery.reason ?? targetDelivery.status}`,
evidence: session.visibleSince(since).slice(-3000),
elapsedMs: Date.now() - startedAt,
elapsedMs: driver.now() - startedAt,
});
} catch (error) {
floorFailed = true;
+149
View File
@@ -0,0 +1,149 @@
/**
* Test-only fake PTY session driver. Feeds scripted frames on an injectable
* clock through the runners' launch seam (`PtyDriver`), so the plan-skill
* runners can be exercised without a CLI, a PTY, a model or real timers.
*
* A frame is shown when its trigger fires: `onInput` (the runner sent a
* matching input) or `afterMs` of fake time since the previous frame. Shown
* frames accumulate in the raw/visible history; the latest one is the
* current viewport. Never import this from production helpers.
*/
import type { ClaudePtyOptions, ClaudePtySession, PtyDriver } from '../claude-pty-runner';
export interface FakeSessionContext {
/** Options the runner passed to `driver.launch`. */
launch: ClaudePtyOptions;
/** Current fake wall clock (ms since epoch). */
now: number;
/** Isolated CLAUDE_CONFIG_DIR stand-in, or null. */
configDir: string | null;
sent: readonly string[];
}
export interface FakeFrame {
/** Viewport text shown by this frame; also appended to the session history. */
screen: string;
/** Show when the runner sends this exact input (string) or a matching one (RegExp). */
onInput?: string | RegExp;
/** Otherwise show after this much fake time since the previous frame. Default 0. */
afterMs?: number;
/** Side effect when shown, e.g. appending native transcript records. */
effect?: (ctx: FakeSessionContext) => void;
/** End the fake process with this exit code when shown. */
exit?: number;
}
export interface FakePtyScript {
frames: FakeFrame[];
/** Directory exposed as `session.hermeticConfigDir`. Default null. */
configDir?: string | null;
/** Fake wall-clock start. Default: the real clock when the driver is created. */
startAt?: number;
/** Extra session fields (e.g. pending hook files) merged into the fake session. */
session?: Partial<ClaudePtySession>;
}
export interface FakePtyDriver {
driver: PtyDriver;
/** Every input the runner sent, in order. */
sent: string[];
/** Every launch request, in order. */
launches: ClaudePtyOptions[];
/** Number of `close()` calls. */
closes(): number;
now(): number;
}
export function createFakePtyDriver(script: FakePtyScript): FakePtyDriver {
const startAt = script.startAt ?? Date.now();
const configDir = script.configDir ?? null;
const sent: string[] = [];
const launches: ClaudePtyOptions[] = [];
let now = startAt;
let closes = 0;
let next = 0;
let lastShownAt = startAt;
let history = '';
let screen = '';
let lastMark = 0;
let exitCode: number | null = null;
let launched: ClaudePtyOptions | undefined;
const context = (): FakeSessionContext => ({ launch: launched!, now, configDir, sent });
const show = (frame: FakeFrame) => {
next++;
lastShownAt = now;
screen = frame.screen;
history += (history ? '\n' : '') + frame.screen;
frame.effect?.(context());
if (frame.exit !== undefined) exitCode = frame.exit;
};
const dueAt = (frame: FakeFrame | undefined) =>
!launched || !frame || frame.onInput !== undefined || exitCode !== null ? Infinity : lastShownAt + (frame.afterMs ?? 0);
const showDue = () => { while (dueAt(script.frames[next]) <= now) show(script.frames[next]!); };
const advance = (ms: number) => {
const target = now + Math.max(0, ms);
while (dueAt(script.frames[next]) <= target) { now = Math.max(now, dueAt(script.frames[next])); show(script.frames[next]!); }
now = target;
};
const session: ClaudePtySession = {
send(data: string) {
if (exitCode !== null) return;
sent.push(data);
const frame = script.frames[next];
const trigger = frame?.onInput;
if (trigger !== undefined && (typeof trigger === 'string' ? trigger === data : trigger.test(data))) show(frame!);
showDue();
},
sendKey(key) {
const keys = { Enter: '\r', Up: '\x1b[A', Down: '\x1b[B', Esc: '\x1b', Tab: '\t', ShiftTab: '\x1b[Z', CtrlC: '\x03' };
session.send(keys[key]);
},
rawOutput: () => history,
visibleText: () => history,
currentScreen: async () => screen,
currentScreenFrame: async () => ({ text: screen, rawEnd: history.length, styledText: [] }),
mark: () => (lastMark = history.length),
visibleSince: (marker?: number) => history.slice(marker ?? lastMark),
async waitForOutput(since: number, timeoutMs: number) {
if (history.length > since || exitCode !== null) return;
const until = now + timeoutMs;
while (history.length <= since && exitCode === null && now < until) advance(Math.min(until, dueAt(script.frames[next])) - now);
},
async waitForAny(patterns, opts) {
const until = now + (opts?.timeoutMs ?? 60_000);
for (;;) {
if (exitCode !== null) throw new Error(`claude exited (code=${exitCode}) before any pattern matched.`);
const visible = opts?.since !== undefined ? history.slice(opts.since) : history;
for (const matched of patterns) {
const index = typeof matched === 'string' ? visible.indexOf(matched) : visible.search(matched);
if (index >= 0) return { matched, index };
}
if (now >= until) throw new Error(`Timed out after ${opts?.timeoutMs ?? 60_000}ms waiting for fake output`);
advance(Math.min(opts?.pollMs ?? 250, until - now));
}
},
async waitFor(pattern, opts) { await session.waitForAny([pattern], opts); },
pid: () => undefined,
exited: () => exitCode !== null,
exitCode: () => exitCode,
hermeticConfigDir: configDir,
async close() { closes++; },
...script.session,
};
const driver: PtyDriver = {
async launch(opts) {
launches.push(opts);
launched = opts;
lastShownAt = now;
showDue();
return session;
},
now: () => now,
monotonic: () => now - startAt,
async sleep(ms: number) { advance(ms); },
};
return { driver, sent, launches, closes: () => closes, now: () => now };
}
+20 -20
View File
@@ -196,7 +196,7 @@ export const E2E_TOUCHFILES: Record<string, string[]> = {
"test/fixtures/plan-scope-target-aw.json",
'test/fixtures/auto-decide-saved-ai.json', 'test/fixtures/auto-decide-retry-ai.json','bin/gstack-skill-start', 'bin/gstack-skill-end', 'plan-ceo-review/**', 'scripts/resolvers/preamble/generate-completion-status.ts', 'scripts/resolvers/question-tuning.ts', 'scripts/resolvers/preamble/generate-ask-user-format.ts', 'scripts/resolvers/preamble.ts', 'scripts/resolvers/review.ts', 'test/helpers/claude-pty-runner.ts', 'test/fixtures/design-ui-boxed-question.json', 'test/helpers/hermetic-skill-runtime.ts', 'test/helpers/pty-trust-dialog.ts', 'test/skill-e2e-plan-ceo-plan-mode.test.ts', 'test/fixtures/eng-d2-truncated-border-0bcd.json', 'test/fixtures/eng-d1-clipped-elision-1579.json', 'test/fixtures/eng-d2-planning-prelude-4d.json', 'test/fixtures/ceo-approach-z-call.json', 'test/fixtures/ceo-approach-z-screen.txt', 'test/helpers/plan-scope-selection.ts', 'test/helpers/native-auto-decide.ts', 'test/fixtures/auto-decide-current-declaration-6aef.json', 'test/fixtures/auto-decide-explanatory-mode-043a.json', 'test/fixtures/auto-decide-explanatory-mode-749df.json', 'test/fixtures/auto-decide-structured-77.json', 'test/helpers/auto-decision-state.ts', 'test/fixtures/auto-decide-state-cab3.json', 'bin/gstack-question-log', 'bin/gstack-question-preference', 'test/helpers/fake-plan-seed.ts', 'test/helpers/plan-seed-submission.ts', 'test/fixtures/plan-seed-cli.ts', 'test/fixtures/native-auto-decide-ag.json', 'test/fixtures/eng-seeded-completion-ai.json', 'test/helpers/plan-count-pending-exit.ts', 'test/helpers/pty-screen.ts', 'test/fixtures/pty-screen/**',
'test/fixtures/auto-decide-saved-ai.json', 'test/fixtures/auto-decide-retry-ai.json','bin/gstack-skill-start', 'bin/gstack-skill-end', 'plan-ceo-review/**', 'scripts/resolvers/preamble/generate-completion-status.ts', 'scripts/resolvers/question-tuning.ts', 'scripts/resolvers/preamble/generate-ask-user-format.ts', 'scripts/resolvers/preamble.ts', 'scripts/resolvers/review.ts', 'test/helpers/claude-pty-runner.ts', 'test/helpers/pty/**', 'test/fixtures/design-ui-boxed-question.json', 'test/helpers/hermetic-skill-runtime.ts', 'test/helpers/pty-trust-dialog.ts', 'test/skill-e2e-plan-ceo-plan-mode.test.ts', 'test/fixtures/eng-d2-truncated-border-0bcd.json', 'test/fixtures/eng-d1-clipped-elision-1579.json', 'test/fixtures/eng-d2-planning-prelude-4d.json', 'test/fixtures/ceo-approach-z-call.json', 'test/fixtures/ceo-approach-z-screen.txt', 'test/helpers/plan-scope-selection.ts', 'test/helpers/native-auto-decide.ts', 'test/fixtures/auto-decide-current-declaration-6aef.json', 'test/fixtures/auto-decide-explanatory-mode-043a.json', 'test/fixtures/auto-decide-explanatory-mode-749df.json', 'test/fixtures/auto-decide-structured-77.json', 'test/helpers/auto-decision-state.ts', 'test/fixtures/auto-decide-state-cab3.json', 'bin/gstack-question-log', 'bin/gstack-question-preference', 'test/helpers/fake-plan-seed.ts', 'test/helpers/plan-seed-submission.ts', 'test/fixtures/plan-seed-cli.ts', 'test/fixtures/native-auto-decide-ag.json', 'test/fixtures/eng-seeded-completion-ai.json', 'test/helpers/plan-count-pending-exit.ts', 'test/helpers/pty-screen.ts', 'test/fixtures/pty-screen/**',
'test/fixtures/design-scope-announcement-ao.json',
'test/fixtures/design-scope-declaration-ak.json',
@@ -217,7 +217,7 @@ export const E2E_TOUCHFILES: Record<string, string[]> = {
"test/fixtures/plan-scope-recovery-av.json",
'test/fixtures/auto-decide-saved-ai.json', 'test/fixtures/auto-decide-retry-ai.json','bin/gstack-skill-start', 'bin/gstack-skill-end', 'plan-eng-review/**', 'scripts/resolvers/preamble/generate-completion-status.ts', 'scripts/resolvers/question-tuning.ts', 'scripts/resolvers/preamble/generate-ask-user-format.ts', 'scripts/resolvers/preamble.ts', 'scripts/resolvers/review.ts', 'test/helpers/claude-pty-runner.ts', 'test/fixtures/design-ui-boxed-question.json', 'test/helpers/hermetic-skill-runtime.ts', 'test/helpers/pty-trust-dialog.ts', 'test/skill-e2e-plan-eng-plan-mode.test.ts', 'test/fixtures/eng-d2-truncated-border-0bcd.json', 'test/fixtures/eng-d1-clipped-elision-1579.json', 'test/fixtures/eng-d2-planning-prelude-4d.json', 'test/fixtures/ceo-approach-z-call.json', 'test/fixtures/ceo-approach-z-screen.txt', 'test/helpers/plan-scope-selection.ts', 'test/fixtures/design-plan-scope-ag.json', 'test/fixtures/design-scope-selection-aj.json', 'test/helpers/native-auto-decide.ts', 'test/fixtures/auto-decide-current-declaration-6aef.json', 'test/fixtures/auto-decide-explanatory-mode-043a.json', 'test/fixtures/auto-decide-explanatory-mode-749df.json', 'test/fixtures/auto-decide-structured-77.json', 'test/helpers/auto-decision-state.ts', 'test/fixtures/auto-decide-state-cab3.json', 'bin/gstack-question-log', 'bin/gstack-question-preference', 'test/helpers/fake-plan-seed.ts', 'test/fixtures/native-auto-decide-ag.json', 'test/fixtures/eng-seeded-completion-ai.json', 'test/helpers/plan-count-pending-exit.ts', 'test/helpers/pty-screen.ts', 'test/fixtures/pty-screen/**',
'test/fixtures/auto-decide-saved-ai.json', 'test/fixtures/auto-decide-retry-ai.json','bin/gstack-skill-start', 'bin/gstack-skill-end', 'plan-eng-review/**', 'scripts/resolvers/preamble/generate-completion-status.ts', 'scripts/resolvers/question-tuning.ts', 'scripts/resolvers/preamble/generate-ask-user-format.ts', 'scripts/resolvers/preamble.ts', 'scripts/resolvers/review.ts', 'test/helpers/claude-pty-runner.ts', 'test/helpers/pty/**', 'test/fixtures/design-ui-boxed-question.json', 'test/helpers/hermetic-skill-runtime.ts', 'test/helpers/pty-trust-dialog.ts', 'test/skill-e2e-plan-eng-plan-mode.test.ts', 'test/fixtures/eng-d2-truncated-border-0bcd.json', 'test/fixtures/eng-d1-clipped-elision-1579.json', 'test/fixtures/eng-d2-planning-prelude-4d.json', 'test/fixtures/ceo-approach-z-call.json', 'test/fixtures/ceo-approach-z-screen.txt', 'test/helpers/plan-scope-selection.ts', 'test/fixtures/design-plan-scope-ag.json', 'test/fixtures/design-scope-selection-aj.json', 'test/helpers/native-auto-decide.ts', 'test/fixtures/auto-decide-current-declaration-6aef.json', 'test/fixtures/auto-decide-explanatory-mode-043a.json', 'test/fixtures/auto-decide-explanatory-mode-749df.json', 'test/fixtures/auto-decide-structured-77.json', 'test/helpers/auto-decision-state.ts', 'test/fixtures/auto-decide-state-cab3.json', 'bin/gstack-question-log', 'bin/gstack-question-preference', 'test/helpers/fake-plan-seed.ts', 'test/fixtures/native-auto-decide-ag.json', 'test/fixtures/eng-seeded-completion-ai.json', 'test/helpers/plan-count-pending-exit.ts', 'test/helpers/pty-screen.ts', 'test/fixtures/pty-screen/**',
'test/fixtures/design-scope-announcement-ao.json',
'test/fixtures/design-scope-declaration-ak.json',
@@ -242,7 +242,7 @@ export const E2E_TOUCHFILES: Record<string, string[]> = {
"test/fixtures/plan-scope-recovery-av.json",
"test/fixtures/design-scope-checkpoint-at.json",
'test/fixtures/auto-decide-saved-ai.json', 'test/fixtures/auto-decide-retry-ai.json','bin/gstack-skill-start', 'bin/gstack-skill-end', 'plan-design-review/**', 'scripts/resolvers/preamble/generate-completion-status.ts', 'scripts/resolvers/question-tuning.ts', 'scripts/resolvers/preamble/generate-ask-user-format.ts', 'scripts/resolvers/preamble.ts', 'scripts/resolvers/review.ts', 'test/helpers/claude-pty-runner.ts', 'test/fixtures/design-ui-boxed-question.json', 'test/helpers/hermetic-skill-runtime.ts', 'test/helpers/pty-trust-dialog.ts', 'test/skill-e2e-plan-design-plan-mode.test.ts', 'test/skill-e2e-design.test.ts', 'test/fixtures/eng-d2-truncated-border-0bcd.json', 'test/fixtures/eng-d1-clipped-elision-1579.json', 'test/fixtures/eng-d2-planning-prelude-4d.json', 'test/fixtures/ceo-approach-z-call.json', 'test/fixtures/ceo-approach-z-screen.txt', 'test/helpers/plan-scope-selection.ts', 'test/fixtures/design-plan-scope-ag.json', 'test/fixtures/design-scope-selection-aj.json', 'test/helpers/native-auto-decide.ts', 'test/fixtures/auto-decide-current-declaration-6aef.json', 'test/fixtures/auto-decide-explanatory-mode-043a.json', 'test/fixtures/auto-decide-explanatory-mode-749df.json', 'test/fixtures/auto-decide-structured-77.json', 'test/helpers/auto-decision-state.ts', 'test/fixtures/auto-decide-state-cab3.json', 'bin/gstack-question-log', 'bin/gstack-question-preference', 'test/helpers/fake-plan-seed.ts', 'test/fixtures/native-auto-decide-ag.json', 'test/fixtures/eng-seeded-completion-ai.json', 'test/helpers/plan-count-pending-exit.ts', 'test/helpers/pty-screen.ts', 'test/fixtures/pty-screen/**',
'test/fixtures/auto-decide-saved-ai.json', 'test/fixtures/auto-decide-retry-ai.json','bin/gstack-skill-start', 'bin/gstack-skill-end', 'plan-design-review/**', 'scripts/resolvers/preamble/generate-completion-status.ts', 'scripts/resolvers/question-tuning.ts', 'scripts/resolvers/preamble/generate-ask-user-format.ts', 'scripts/resolvers/preamble.ts', 'scripts/resolvers/review.ts', 'test/helpers/claude-pty-runner.ts', 'test/helpers/pty/**', 'test/fixtures/design-ui-boxed-question.json', 'test/helpers/hermetic-skill-runtime.ts', 'test/helpers/pty-trust-dialog.ts', 'test/skill-e2e-plan-design-plan-mode.test.ts', 'test/skill-e2e-design.test.ts', 'test/fixtures/eng-d2-truncated-border-0bcd.json', 'test/fixtures/eng-d1-clipped-elision-1579.json', 'test/fixtures/eng-d2-planning-prelude-4d.json', 'test/fixtures/ceo-approach-z-call.json', 'test/fixtures/ceo-approach-z-screen.txt', 'test/helpers/plan-scope-selection.ts', 'test/fixtures/design-plan-scope-ag.json', 'test/fixtures/design-scope-selection-aj.json', 'test/helpers/native-auto-decide.ts', 'test/fixtures/auto-decide-current-declaration-6aef.json', 'test/fixtures/auto-decide-explanatory-mode-043a.json', 'test/fixtures/auto-decide-explanatory-mode-749df.json', 'test/fixtures/auto-decide-structured-77.json', 'test/helpers/auto-decision-state.ts', 'test/fixtures/auto-decide-state-cab3.json', 'bin/gstack-question-log', 'bin/gstack-question-preference', 'test/helpers/fake-plan-seed.ts', 'test/fixtures/native-auto-decide-ag.json', 'test/fixtures/eng-seeded-completion-ai.json', 'test/helpers/plan-count-pending-exit.ts', 'test/helpers/pty-screen.ts', 'test/fixtures/pty-screen/**',
'test/fixtures/design-scope-announcement-ao.json',
'test/fixtures/design-scope-declaration-ak.json',
@@ -260,7 +260,7 @@ export const E2E_TOUCHFILES: Record<string, string[]> = {
"test/fixtures/plan-scope-target-aw.json",
'test/fixtures/auto-decide-saved-ai.json', 'test/fixtures/auto-decide-retry-ai.json','bin/gstack-skill-start', 'bin/gstack-skill-end', 'plan-devex-review/**', 'scripts/resolvers/preamble/generate-completion-status.ts', 'scripts/resolvers/question-tuning.ts', 'scripts/resolvers/preamble/generate-ask-user-format.ts', 'scripts/resolvers/preamble.ts', 'scripts/resolvers/review.ts', 'test/helpers/claude-pty-runner.ts', 'test/fixtures/design-ui-boxed-question.json', 'test/helpers/hermetic-skill-runtime.ts', 'test/helpers/pty-trust-dialog.ts', 'test/skill-e2e-plan-devex-plan-mode.test.ts', 'test/fixtures/eng-d2-truncated-border-0bcd.json', 'test/fixtures/eng-d1-clipped-elision-1579.json', 'test/fixtures/eng-d2-planning-prelude-4d.json', 'test/fixtures/ceo-approach-z-call.json', 'test/fixtures/ceo-approach-z-screen.txt', 'test/helpers/plan-scope-selection.ts', 'test/helpers/native-auto-decide.ts', 'test/fixtures/auto-decide-current-declaration-6aef.json', 'test/fixtures/auto-decide-explanatory-mode-043a.json', 'test/fixtures/auto-decide-explanatory-mode-749df.json', 'test/fixtures/auto-decide-structured-77.json', 'test/helpers/auto-decision-state.ts', 'test/fixtures/auto-decide-state-cab3.json', 'bin/gstack-question-log', 'bin/gstack-question-preference', 'test/helpers/fake-plan-seed.ts', 'test/helpers/plan-seed-submission.ts', 'test/fixtures/plan-seed-cli.ts', 'test/fixtures/native-auto-decide-ag.json', 'test/fixtures/eng-seeded-completion-ai.json', 'test/helpers/plan-count-pending-exit.ts', 'test/helpers/pty-screen.ts', 'test/fixtures/pty-screen/**',
'test/fixtures/auto-decide-saved-ai.json', 'test/fixtures/auto-decide-retry-ai.json','bin/gstack-skill-start', 'bin/gstack-skill-end', 'plan-devex-review/**', 'scripts/resolvers/preamble/generate-completion-status.ts', 'scripts/resolvers/question-tuning.ts', 'scripts/resolvers/preamble/generate-ask-user-format.ts', 'scripts/resolvers/preamble.ts', 'scripts/resolvers/review.ts', 'test/helpers/claude-pty-runner.ts', 'test/helpers/pty/**', 'test/fixtures/design-ui-boxed-question.json', 'test/helpers/hermetic-skill-runtime.ts', 'test/helpers/pty-trust-dialog.ts', 'test/skill-e2e-plan-devex-plan-mode.test.ts', 'test/fixtures/eng-d2-truncated-border-0bcd.json', 'test/fixtures/eng-d1-clipped-elision-1579.json', 'test/fixtures/eng-d2-planning-prelude-4d.json', 'test/fixtures/ceo-approach-z-call.json', 'test/fixtures/ceo-approach-z-screen.txt', 'test/helpers/plan-scope-selection.ts', 'test/helpers/native-auto-decide.ts', 'test/fixtures/auto-decide-current-declaration-6aef.json', 'test/fixtures/auto-decide-explanatory-mode-043a.json', 'test/fixtures/auto-decide-explanatory-mode-749df.json', 'test/fixtures/auto-decide-structured-77.json', 'test/helpers/auto-decision-state.ts', 'test/fixtures/auto-decide-state-cab3.json', 'bin/gstack-question-log', 'bin/gstack-question-preference', 'test/helpers/fake-plan-seed.ts', 'test/helpers/plan-seed-submission.ts', 'test/fixtures/plan-seed-cli.ts', 'test/fixtures/native-auto-decide-ag.json', 'test/fixtures/eng-seeded-completion-ai.json', 'test/helpers/plan-count-pending-exit.ts', 'test/helpers/pty-screen.ts', 'test/fixtures/pty-screen/**',
'test/fixtures/design-scope-announcement-ao.json',
'test/fixtures/design-scope-declaration-ak.json',
@@ -285,7 +285,7 @@ export const E2E_TOUCHFILES: Record<string, string[]> = {
"test/fixtures/plan-scope-recovery-av.json",
"test/fixtures/design-scope-checkpoint-at.json",
'test/fixtures/auto-decide-saved-ai.json', 'test/fixtures/auto-decide-retry-ai.json','bin/gstack-skill-start', 'bin/gstack-skill-end', 'plan-ceo-review/**', 'plan-eng-review/**', 'plan-design-review/**', 'scripts/resolvers/preamble/generate-completion-status.ts', 'scripts/resolvers/preamble.ts', 'test/helpers/claude-pty-runner.ts', 'test/fixtures/design-ui-boxed-question.json', 'test/helpers/hermetic-skill-runtime.ts', 'test/helpers/pty-trust-dialog.ts', 'test/skill-e2e-plan-mode-no-op.test.ts', 'test/fixtures/eng-d2-truncated-border-0bcd.json', 'test/fixtures/eng-d1-clipped-elision-1579.json', 'test/fixtures/eng-d2-planning-prelude-4d.json', 'test/fixtures/ceo-approach-z-call.json', 'test/fixtures/ceo-approach-z-screen.txt', 'test/helpers/plan-scope-selection.ts', 'test/helpers/native-auto-decide.ts', 'test/fixtures/auto-decide-current-declaration-6aef.json', 'test/fixtures/auto-decide-explanatory-mode-043a.json', 'test/fixtures/auto-decide-explanatory-mode-749df.json', 'test/fixtures/auto-decide-structured-77.json', 'test/helpers/auto-decision-state.ts', 'test/fixtures/auto-decide-state-cab3.json', 'bin/gstack-question-log', 'bin/gstack-question-preference', 'test/helpers/fake-plan-seed.ts', 'test/fixtures/native-auto-decide-ag.json', 'test/fixtures/eng-seeded-completion-ai.json', 'test/helpers/plan-count-pending-exit.ts', 'test/helpers/pty-screen.ts', 'test/fixtures/pty-screen/**',
'test/fixtures/auto-decide-saved-ai.json', 'test/fixtures/auto-decide-retry-ai.json','bin/gstack-skill-start', 'bin/gstack-skill-end', 'plan-ceo-review/**', 'plan-eng-review/**', 'plan-design-review/**', 'scripts/resolvers/preamble/generate-completion-status.ts', 'scripts/resolvers/preamble.ts', 'test/helpers/claude-pty-runner.ts', 'test/helpers/pty/**', 'test/fixtures/design-ui-boxed-question.json', 'test/helpers/hermetic-skill-runtime.ts', 'test/helpers/pty-trust-dialog.ts', 'test/skill-e2e-plan-mode-no-op.test.ts', 'test/fixtures/eng-d2-truncated-border-0bcd.json', 'test/fixtures/eng-d1-clipped-elision-1579.json', 'test/fixtures/eng-d2-planning-prelude-4d.json', 'test/fixtures/ceo-approach-z-call.json', 'test/fixtures/ceo-approach-z-screen.txt', 'test/helpers/plan-scope-selection.ts', 'test/helpers/native-auto-decide.ts', 'test/fixtures/auto-decide-current-declaration-6aef.json', 'test/fixtures/auto-decide-explanatory-mode-043a.json', 'test/fixtures/auto-decide-explanatory-mode-749df.json', 'test/fixtures/auto-decide-structured-77.json', 'test/helpers/auto-decision-state.ts', 'test/fixtures/auto-decide-state-cab3.json', 'bin/gstack-question-log', 'bin/gstack-question-preference', 'test/helpers/fake-plan-seed.ts', 'test/fixtures/native-auto-decide-ag.json', 'test/fixtures/eng-seeded-completion-ai.json', 'test/helpers/plan-count-pending-exit.ts', 'test/helpers/pty-screen.ts', 'test/fixtures/pty-screen/**',
'test/fixtures/design-scope-announcement-ao.json',
'test/fixtures/design-scope-declaration-ak.json',
@@ -309,7 +309,7 @@ export const E2E_TOUCHFILES: Record<string, string[]> = {
'test/fixtures/auto-decide-recommendation-361c.json',
'test/fixtures/auto-decide-target-361c.json',
'test/fixtures/native-auto-decide-ag.json', 'test/helpers/native-auto-decide.ts', 'test/fixtures/auto-decide-current-declaration-6aef.json', 'test/fixtures/auto-decide-explanatory-mode-043a.json', 'test/fixtures/auto-decide-explanatory-mode-749df.json', 'bin/gstack-skill-start', 'bin/gstack-skill-end', 'office-hours/**', 'scripts/resolvers/preamble/generate-completion-status.ts', 'scripts/resolvers/question-tuning.ts', 'scripts/resolvers/preamble/generate-ask-user-format.ts', 'scripts/resolvers/preamble.ts', 'test/helpers/claude-pty-runner.ts', 'test/fixtures/design-ui-boxed-question.json', 'test/helpers/hermetic-skill-runtime.ts', 'test/helpers/pty-trust-dialog.ts', 'test/skill-e2e-office-hours-auto-mode.test.ts', 'test/fixtures/eng-d2-truncated-border-0bcd.json', 'test/fixtures/eng-d1-clipped-elision-1579.json', 'test/fixtures/eng-d2-planning-prelude-4d.json', 'test/fixtures/ceo-approach-z-call.json', 'test/fixtures/ceo-approach-z-screen.txt',
'test/fixtures/native-auto-decide-ag.json', 'test/helpers/native-auto-decide.ts', 'test/fixtures/auto-decide-current-declaration-6aef.json', 'test/fixtures/auto-decide-explanatory-mode-043a.json', 'test/fixtures/auto-decide-explanatory-mode-749df.json', 'bin/gstack-skill-start', 'bin/gstack-skill-end', 'office-hours/**', 'scripts/resolvers/preamble/generate-completion-status.ts', 'scripts/resolvers/question-tuning.ts', 'scripts/resolvers/preamble/generate-ask-user-format.ts', 'scripts/resolvers/preamble.ts', 'test/helpers/claude-pty-runner.ts', 'test/helpers/pty/**', 'test/fixtures/design-ui-boxed-question.json', 'test/helpers/hermetic-skill-runtime.ts', 'test/helpers/pty-trust-dialog.ts', 'test/skill-e2e-office-hours-auto-mode.test.ts', 'test/fixtures/eng-d2-truncated-border-0bcd.json', 'test/fixtures/eng-d1-clipped-elision-1579.json', 'test/fixtures/eng-d2-planning-prelude-4d.json', 'test/fixtures/ceo-approach-z-call.json', 'test/fixtures/ceo-approach-z-screen.txt',
'test/fixtures/pty-companion-cli.ts', 'lib/fs-atomic.ts', 'test/helpers/plan-skill-questions.ts', 'test/fixtures/eng-auq-validation-error.json', 'test/fixtures/bash-directory-permission.json', 'test/fixtures/design-tasks-bash-permission.json', 'test/fixtures/read-permission.json', 'test/fixtures/ceo-split-e5-numbered-description-491.json', 'test/helpers/plan-skill-question-events.ts', 'test/helpers/plan-skill-question-hook-scope.ts', 'test/helpers/skill-census.ts', 'test/helpers/auto-decision-state.ts', 'test/helpers/autoplan-artifact-digest.ts', 'test/helpers/autoplan-artifact-permission.ts', 'test/helpers/autoplan-artifact-recorder.ts', 'test/helpers/dx-selected-navigation.ts', 'test/helpers/e2e-gate.ts', 'test/helpers/eng-cache-writer-decision.ts', 'test/helpers/owned-claude-transcript.ts', 'test/helpers/plan-count-artifacts.ts', 'test/helpers/plan-count-file-permission.ts', 'test/helpers/plan-count-fixture.ts', 'test/helpers/plan-count-pending-exit.ts', 'test/helpers/plan-count-pending-question.ts', 'test/helpers/plan-count-transcript.ts', 'test/helpers/plan-floor-review.ts', 'test/helpers/plan-floor-target.ts', 'test/helpers/plan-scope-selection.ts', 'test/helpers/plan-seed-submission.ts', 'test/helpers/pty-screen.ts'],
'office-hours-phase4-fork': [ 'bin/gstack-skill-start', 'bin/gstack-skill-end', 'office-hours/**', 'scripts/resolvers/preamble/generate-ask-user-format.ts', 'scripts/resolvers/preamble/generate-completion-status.ts', 'scripts/resolvers/preamble.ts', 'scripts/resolvers/question-tuning.ts', 'test/helpers/llm-judge.ts', 'test/skill-e2e-office-hours-phase4.test.ts' ],
'llm-judge-recommendation': ['codex/**', 'test/helpers/llm-judge.ts', 'test/llm-judge-recommendation.test.ts', 'scripts/resolvers/preamble/generate-ask-user-format.ts', 'codex/SKILL.md.tmpl', 'scripts/resolvers/review.ts'],
@@ -328,7 +328,7 @@ export const E2E_TOUCHFILES: Record<string, string[]> = {
'test/fixtures/autoplan-public-narration-ad.json',
'test/fixtures/auto-decide-completed-mode-f359.json',
'test/helpers/plan-count-transcript.ts', 'test/fixtures/plan-count-cross-cwd-ancestry-0bcd.json',
'test/fixtures/auto-decide-saved-ai.json', 'test/fixtures/auto-decide-retry-ai.json','bin/gstack-skill-start', 'bin/gstack-skill-end', 'bin/gstack-session-kind', 'scripts/resolvers/question-tuning.ts', 'scripts/resolvers/preamble/generate-ask-user-format.ts', 'scripts/resolvers/preamble/generate-preamble-bash.ts', 'scripts/resolvers/preamble/generate-completion-status.ts', 'plan-ceo-review/**', 'bin/gstack-question-preference', 'bin/gstack-config', 'bin/gstack-slug', 'hosts/claude/hooks/question-preference-hook.ts', 'hosts/claude/hooks/spawned-directive.ts', 'lib/is-conductor.ts', 'test/helpers/claude-pty-runner.ts', 'test/fixtures/design-ui-boxed-question.json', 'test/helpers/hermetic-skill-runtime.ts', 'test/helpers/pty-trust-dialog.ts', 'test/skill-e2e-auto-decide-preserved.test.ts', 'test/fixtures/eng-d2-truncated-border-0bcd.json', 'test/fixtures/eng-d1-clipped-elision-1579.json', 'test/fixtures/eng-d2-planning-prelude-4d.json', 'test/fixtures/ceo-approach-z-call.json', 'test/fixtures/ceo-approach-z-screen.txt', 'test/helpers/native-auto-decide.ts', 'test/fixtures/auto-decide-current-declaration-6aef.json', 'test/fixtures/auto-decide-explanatory-mode-043a.json', 'test/fixtures/auto-decide-explanatory-mode-749df.json', 'test/fixtures/auto-decide-structured-77.json', 'test/helpers/auto-decision-state.ts', 'test/fixtures/auto-decide-state-cab3.json', 'bin/gstack-question-log', 'test/helpers/fake-plan-seed.ts', 'test/helpers/plan-seed-submission.ts', 'test/fixtures/plan-seed-cli.ts', 'test/fixtures/native-auto-decide-ag.json', 'test/fixtures/eng-seeded-completion-ai.json', 'test/helpers/plan-count-pending-exit.ts', 'test/helpers/pty-screen.ts', 'test/fixtures/pty-screen/**',
'test/fixtures/auto-decide-saved-ai.json', 'test/fixtures/auto-decide-retry-ai.json','bin/gstack-skill-start', 'bin/gstack-skill-end', 'bin/gstack-session-kind', 'scripts/resolvers/question-tuning.ts', 'scripts/resolvers/preamble/generate-ask-user-format.ts', 'scripts/resolvers/preamble/generate-preamble-bash.ts', 'scripts/resolvers/preamble/generate-completion-status.ts', 'plan-ceo-review/**', 'bin/gstack-question-preference', 'bin/gstack-config', 'bin/gstack-slug', 'hosts/claude/hooks/question-preference-hook.ts', 'hosts/claude/hooks/spawned-directive.ts', 'lib/is-conductor.ts', 'test/helpers/claude-pty-runner.ts', 'test/helpers/pty/**', 'test/fixtures/design-ui-boxed-question.json', 'test/helpers/hermetic-skill-runtime.ts', 'test/helpers/pty-trust-dialog.ts', 'test/skill-e2e-auto-decide-preserved.test.ts', 'test/fixtures/eng-d2-truncated-border-0bcd.json', 'test/fixtures/eng-d1-clipped-elision-1579.json', 'test/fixtures/eng-d2-planning-prelude-4d.json', 'test/fixtures/ceo-approach-z-call.json', 'test/fixtures/ceo-approach-z-screen.txt', 'test/helpers/native-auto-decide.ts', 'test/fixtures/auto-decide-current-declaration-6aef.json', 'test/fixtures/auto-decide-explanatory-mode-043a.json', 'test/fixtures/auto-decide-explanatory-mode-749df.json', 'test/fixtures/auto-decide-structured-77.json', 'test/helpers/auto-decision-state.ts', 'test/fixtures/auto-decide-state-cab3.json', 'bin/gstack-question-log', 'test/helpers/fake-plan-seed.ts', 'test/helpers/plan-seed-submission.ts', 'test/fixtures/plan-seed-cli.ts', 'test/fixtures/native-auto-decide-ag.json', 'test/fixtures/eng-seeded-completion-ai.json', 'test/helpers/plan-count-pending-exit.ts', 'test/helpers/pty-screen.ts', 'test/fixtures/pty-screen/**',
'test/helpers/plan-count-fixture.ts',
'test/fixtures/pty-companion-cli.ts', 'lib/fs-atomic.ts', 'test/fixtures/auto-decide-mode-selector-749df.json', 'lib/redact-engine.ts', 'lib/redact-patterns.ts', 'test/helpers/ceo-finding-fixture.ts', 'test/helpers/owned-claude-transcript.ts', 'test/helpers/plan-skill-questions.ts', 'test/fixtures/eng-auq-validation-error.json', 'test/fixtures/bash-directory-permission.json', 'test/fixtures/design-tasks-bash-permission.json', 'test/fixtures/read-permission.json', 'test/fixtures/ceo-split-e5-numbered-description-491.json', 'test/helpers/plan-skill-question-events.ts', 'test/helpers/plan-skill-question-hook-scope.ts', 'test/helpers/skill-census.ts', 'scripts/resolvers/tasks-section.ts', 'test/helpers/autoplan-artifact-digest.ts', 'test/helpers/autoplan-artifact-permission.ts', 'test/helpers/autoplan-artifact-recorder.ts', 'test/helpers/dx-selected-navigation.ts', 'test/helpers/e2e-gate.ts', 'test/helpers/eng-cache-writer-decision.ts', 'test/helpers/plan-count-artifacts.ts', 'test/helpers/plan-count-file-permission.ts', 'test/helpers/plan-count-pending-question.ts', 'test/helpers/plan-floor-review.ts', 'test/helpers/plan-floor-target.ts', 'test/helpers/plan-scope-selection.ts'],
@@ -344,7 +344,7 @@ export const E2E_TOUCHFILES: Record<string, string[]> = {
'test/helpers/auq-native-capture.ts', 'test/helpers/hermetic-env.ts',
'test/helpers/eval-store.ts', 'lib/claude-bin.ts', 'lib/eval-model.ts',
'scripts/resolvers/tasks-section.ts', 'test/helpers/auto-decision-state.ts', 'test/helpers/autoplan-artifact-digest.ts', 'test/helpers/autoplan-artifact-permission.ts', 'test/helpers/autoplan-artifact-recorder.ts', 'test/helpers/claude-pty-runner.ts', 'test/helpers/dx-selected-navigation.ts', 'test/helpers/e2e-gate.ts', 'test/helpers/eng-cache-writer-decision.ts', 'test/helpers/hermetic-skill-runtime.ts', 'test/helpers/native-auto-decide.ts', 'test/helpers/owned-claude-transcript.ts', 'test/helpers/plan-count-artifacts.ts', 'test/helpers/plan-count-file-permission.ts', 'test/helpers/plan-count-fixture.ts', 'test/helpers/plan-count-pending-exit.ts', 'test/helpers/plan-count-pending-question.ts', 'test/helpers/plan-count-transcript.ts', 'test/helpers/plan-floor-review.ts', 'test/helpers/plan-floor-target.ts', 'test/helpers/plan-scope-selection.ts', 'test/helpers/plan-seed-submission.ts', 'test/helpers/plan-skill-question-events.ts', 'test/helpers/plan-skill-question-hook-scope.ts', 'test/helpers/plan-skill-questions.ts', 'test/helpers/pty-screen.ts', 'test/helpers/pty-trust-dialog.ts', 'test/helpers/skill-census.ts'],
'scripts/resolvers/tasks-section.ts', 'test/helpers/auto-decision-state.ts', 'test/helpers/autoplan-artifact-digest.ts', 'test/helpers/autoplan-artifact-permission.ts', 'test/helpers/autoplan-artifact-recorder.ts', 'test/helpers/claude-pty-runner.ts', 'test/helpers/pty/**', 'test/helpers/dx-selected-navigation.ts', 'test/helpers/e2e-gate.ts', 'test/helpers/eng-cache-writer-decision.ts', 'test/helpers/hermetic-skill-runtime.ts', 'test/helpers/native-auto-decide.ts', 'test/helpers/owned-claude-transcript.ts', 'test/helpers/plan-count-artifacts.ts', 'test/helpers/plan-count-file-permission.ts', 'test/helpers/plan-count-fixture.ts', 'test/helpers/plan-count-pending-exit.ts', 'test/helpers/plan-count-pending-question.ts', 'test/helpers/plan-count-transcript.ts', 'test/helpers/plan-floor-review.ts', 'test/helpers/plan-floor-target.ts', 'test/helpers/plan-scope-selection.ts', 'test/helpers/plan-seed-submission.ts', 'test/helpers/plan-skill-question-events.ts', 'test/helpers/plan-skill-question-hook-scope.ts', 'test/helpers/plan-skill-questions.ts', 'test/helpers/pty-screen.ts', 'test/helpers/pty-trust-dialog.ts', 'test/helpers/skill-census.ts'],
'plan-ceo-mode-routing': [
'lib/claude-public-transcript.ts',
@@ -358,7 +358,7 @@ export const E2E_TOUCHFILES: Record<string, string[]> = {
'test/fixtures/ceo-mode-pending-submit.json',
"test/fixtures/plan-count-cross-cwd-ancestry-0bcd.json",
"test/fixtures/ceo-mode-colon-at.json", 'plan-ceo-review/**', 'scripts/resolvers/preamble/generate-ask-user-format.ts', 'scripts/resolvers/preamble.ts', 'test/helpers/claude-pty-runner.ts', 'test/fixtures/design-ui-boxed-question.json', 'test/helpers/pty-screen.ts', 'test/fixtures/pty-screen/**', 'test/helpers/hermetic-skill-runtime.ts', 'test/helpers/pty-trust-dialog.ts', 'test/helpers/ceo-mode-option.ts', 'test/fixtures/ceo-expansion-disposition-77.json', 'test/helpers/plan-count-transcript.ts', 'test/fixtures/autoplan-public-narration-ad.json', 'test/helpers/plan-count-fixture.ts', 'test/fixtures/ceo-prerequisite-n-call.json', 'test/fixtures/eng-prerequisite-77.json', 'test/skill-e2e-plan-ceo-mode-routing.test.ts', 'test/fixtures/ceo-hold-posture-l.json', 'test/fixtures/ceo-mode-labels-l.json', 'test/fixtures/ceo-checkbox-l.screen.txt', 'test/fixtures/ceo-mode-prerequisite-o-calls.json', 'test/fixtures/ceo-mode-prerequisite-q-call.json', 'test/fixtures/ceo-preview-u-call.json', 'test/fixtures/ceo-preview-u-screen.txt', 'test/fixtures/design-preview-v-screen.txt', 'test/fixtures/eng-d2-truncated-border-0bcd.json', 'test/fixtures/eng-d1-clipped-elision-1579.json', 'test/fixtures/eng-d2-planning-prelude-4d.json', 'test/fixtures/ceo-approach-z-call.json', 'test/fixtures/ceo-approach-z-screen.txt', 'test/fixtures/ceo-mode-preview-aa-screen.txt', 'test/fixtures/ceo-count-mode-preview-aa-screen.txt', 'test/fixtures/ceo-expansion-auq-ac.json', 'test/helpers/plan-count-pending-question.ts', 'test/fixtures/ceo-barless-submit-ac.json', 'test/fixtures/pending-question-completion-ad.json', 'test/fixtures/ceo-mode-posture-ad.json', 'test/fixtures/ceo-mode-full-ad.json', 'test/fixtures/ceo-prerequisite-ad-v2.json', 'test/fixtures/ceo-hold-posture-ag.json',
"test/fixtures/ceo-mode-colon-at.json", 'plan-ceo-review/**', 'scripts/resolvers/preamble/generate-ask-user-format.ts', 'scripts/resolvers/preamble.ts', 'test/helpers/claude-pty-runner.ts', 'test/helpers/pty/**', 'test/fixtures/design-ui-boxed-question.json', 'test/helpers/pty-screen.ts', 'test/fixtures/pty-screen/**', 'test/helpers/hermetic-skill-runtime.ts', 'test/helpers/pty-trust-dialog.ts', 'test/helpers/ceo-mode-option.ts', 'test/fixtures/ceo-expansion-disposition-77.json', 'test/helpers/plan-count-transcript.ts', 'test/fixtures/autoplan-public-narration-ad.json', 'test/helpers/plan-count-fixture.ts', 'test/fixtures/ceo-prerequisite-n-call.json', 'test/fixtures/eng-prerequisite-77.json', 'test/skill-e2e-plan-ceo-mode-routing.test.ts', 'test/fixtures/ceo-hold-posture-l.json', 'test/fixtures/ceo-mode-labels-l.json', 'test/fixtures/ceo-checkbox-l.screen.txt', 'test/fixtures/ceo-mode-prerequisite-o-calls.json', 'test/fixtures/ceo-mode-prerequisite-q-call.json', 'test/fixtures/ceo-preview-u-call.json', 'test/fixtures/ceo-preview-u-screen.txt', 'test/fixtures/design-preview-v-screen.txt', 'test/fixtures/eng-d2-truncated-border-0bcd.json', 'test/fixtures/eng-d1-clipped-elision-1579.json', 'test/fixtures/eng-d2-planning-prelude-4d.json', 'test/fixtures/ceo-approach-z-call.json', 'test/fixtures/ceo-approach-z-screen.txt', 'test/fixtures/ceo-mode-preview-aa-screen.txt', 'test/fixtures/ceo-count-mode-preview-aa-screen.txt', 'test/fixtures/ceo-expansion-auq-ac.json', 'test/helpers/plan-count-pending-question.ts', 'test/fixtures/ceo-barless-submit-ac.json', 'test/fixtures/pending-question-completion-ad.json', 'test/fixtures/ceo-mode-posture-ad.json', 'test/fixtures/ceo-mode-full-ad.json', 'test/fixtures/ceo-prerequisite-ad-v2.json', 'test/fixtures/ceo-hold-posture-ag.json',
"test/fixtures/ceo-hold-commitment-ar.json",
'test/fixtures/pty-companion-cli.ts', 'lib/fs-atomic.ts', 'test/helpers/ceo-finding-fixture.ts', 'test/helpers/plan-skill-questions.ts', 'test/fixtures/eng-auq-validation-error.json', 'test/fixtures/bash-directory-permission.json', 'test/fixtures/design-tasks-bash-permission.json', 'test/fixtures/read-permission.json', 'test/fixtures/ceo-split-e5-numbered-description-491.json', 'test/helpers/plan-skill-question-events.ts', 'test/helpers/plan-skill-question-hook-scope.ts', 'test/helpers/skill-census.ts', 'test/helpers/owned-claude-transcript.ts', 'scripts/resolvers/tasks-section.ts',
'test/fixtures/ceo-expansion-pacing-77.json', 'test/helpers/auto-decision-state.ts', 'test/helpers/autoplan-artifact-digest.ts', 'test/helpers/autoplan-artifact-permission.ts', 'test/helpers/autoplan-artifact-recorder.ts', 'test/helpers/dx-selected-navigation.ts', 'test/helpers/e2e-gate.ts', 'test/helpers/eng-cache-writer-decision.ts', 'test/helpers/native-auto-decide.ts', 'test/helpers/plan-count-artifacts.ts', 'test/helpers/plan-count-file-permission.ts', 'test/helpers/plan-count-pending-exit.ts', 'test/helpers/plan-floor-review.ts', 'test/helpers/plan-floor-target.ts', 'test/helpers/plan-scope-selection.ts', 'test/helpers/plan-seed-submission.ts'],
@@ -371,7 +371,7 @@ export const E2E_TOUCHFILES: Record<string, string[]> = {
"test/fixtures/plan-scope-recovery-av.json",
"test/fixtures/design-scope-checkpoint-at.json",'plan-design-review/**', 'test/fixtures/plans/ui-heavy-feature.md', 'test/helpers/claude-pty-runner.ts', 'test/fixtures/design-ui-boxed-question.json', 'test/helpers/hermetic-skill-runtime.ts', 'test/helpers/pty-trust-dialog.ts', 'test/skill-e2e-plan-design-with-ui.test.ts', 'test/fixtures/eng-d2-truncated-border-0bcd.json', 'test/fixtures/eng-d1-clipped-elision-1579.json', 'test/fixtures/eng-d2-planning-prelude-4d.json', 'test/fixtures/ceo-approach-z-call.json', 'test/fixtures/ceo-approach-z-screen.txt',
"test/fixtures/design-scope-checkpoint-at.json",'plan-design-review/**', 'test/fixtures/plans/ui-heavy-feature.md', 'test/helpers/claude-pty-runner.ts', 'test/helpers/pty/**', 'test/fixtures/design-ui-boxed-question.json', 'test/helpers/hermetic-skill-runtime.ts', 'test/helpers/pty-trust-dialog.ts', 'test/skill-e2e-plan-design-with-ui.test.ts', 'test/fixtures/eng-d2-truncated-border-0bcd.json', 'test/fixtures/eng-d1-clipped-elision-1579.json', 'test/fixtures/eng-d2-planning-prelude-4d.json', 'test/fixtures/ceo-approach-z-call.json', 'test/fixtures/ceo-approach-z-screen.txt',
"scripts/resolvers/preamble/generate-preamble-bash.ts", "scripts/resolvers/preamble/generate-completion-status.ts",
@@ -392,11 +392,11 @@ export const E2E_TOUCHFILES: Record<string, string[]> = {
'lib/eval-model.ts'
],
'ship-section-loading': [ 'ship/**', 'scripts/resolvers/sections.ts', 'scripts/gen-skill-docs.ts', 'test/helpers/auq-sdk-capture.ts', 'test/helpers/session-runner.ts', 'test/skill-e2e-ship-section-loading.test.ts',
'scripts/resolvers/testing.ts', 'test/helpers/agent-sdk-runner.ts', 'test/helpers/auq-native-capture.ts', 'test/helpers/auto-decision-state.ts', 'test/helpers/autoplan-artifact-digest.ts', 'test/helpers/autoplan-artifact-permission.ts', 'test/helpers/autoplan-artifact-recorder.ts', 'test/helpers/claude-pty-runner.ts', 'test/helpers/dx-selected-navigation.ts', 'test/helpers/e2e-gate.ts', 'test/helpers/eng-cache-writer-decision.ts', 'test/helpers/hermetic-skill-runtime.ts', 'test/helpers/llm-judge.ts', 'test/helpers/native-auto-decide.ts', 'test/helpers/owned-claude-transcript.ts', 'test/helpers/plan-count-artifacts.ts', 'test/helpers/plan-count-file-permission.ts', 'test/helpers/plan-count-fixture.ts', 'test/helpers/plan-count-pending-exit.ts', 'test/helpers/plan-count-pending-question.ts', 'test/helpers/plan-count-transcript.ts', 'test/helpers/plan-floor-review.ts', 'test/helpers/plan-floor-target.ts', 'test/helpers/plan-scope-selection.ts', 'test/helpers/plan-seed-submission.ts', 'test/helpers/plan-skill-question-events.ts', 'test/helpers/plan-skill-question-hook-scope.ts', 'test/helpers/plan-skill-questions.ts', 'test/helpers/pty-screen.ts', 'test/helpers/pty-trust-dialog.ts', 'test/helpers/skill-census.ts'],
'scripts/resolvers/testing.ts', 'test/helpers/agent-sdk-runner.ts', 'test/helpers/auq-native-capture.ts', 'test/helpers/auto-decision-state.ts', 'test/helpers/autoplan-artifact-digest.ts', 'test/helpers/autoplan-artifact-permission.ts', 'test/helpers/autoplan-artifact-recorder.ts', 'test/helpers/claude-pty-runner.ts', 'test/helpers/pty/**', 'test/helpers/dx-selected-navigation.ts', 'test/helpers/e2e-gate.ts', 'test/helpers/eng-cache-writer-decision.ts', 'test/helpers/hermetic-skill-runtime.ts', 'test/helpers/llm-judge.ts', 'test/helpers/native-auto-decide.ts', 'test/helpers/owned-claude-transcript.ts', 'test/helpers/plan-count-artifacts.ts', 'test/helpers/plan-count-file-permission.ts', 'test/helpers/plan-count-fixture.ts', 'test/helpers/plan-count-pending-exit.ts', 'test/helpers/plan-count-pending-question.ts', 'test/helpers/plan-count-transcript.ts', 'test/helpers/plan-floor-review.ts', 'test/helpers/plan-floor-target.ts', 'test/helpers/plan-scope-selection.ts', 'test/helpers/plan-seed-submission.ts', 'test/helpers/plan-skill-question-events.ts', 'test/helpers/plan-skill-question-hook-scope.ts', 'test/helpers/plan-skill-questions.ts', 'test/helpers/pty-screen.ts', 'test/helpers/pty-trust-dialog.ts', 'test/helpers/skill-census.ts'],
'plan-ceo-section-loading': [
'test/fixtures/ceo-fill-lifetime.json', 'plan-ceo-review/**', 'scripts/resolvers/sections.ts', 'scripts/gen-skill-docs.ts', 'test/helpers/auq-sdk-capture.ts', 'test/helpers/session-runner.ts', 'test/helpers/ceo-section-loading-fixture.ts', 'test/skill-e2e-plan-ceo-review-section-loading.test.ts', 'test/fixtures/ceo-section-loading-l-report.md', 'test/fixtures/ceo-section-loading-q-report.md', 'test/fixtures/ceo-section-r-rejected-report.md', 'test/fixtures/ceo-section-s-trace-report.md', 'test/fixtures/ceo-section-u-report.md', 'test/fixtures/ceo-section-y-report.md', 'test/fixtures/ceo-section-aa-report.md', 'test/fixtures/sdk-stale-table-ad-v3.json', 'test/fixtures/sdk-ordering-ae.json', 'test/fixtures/sdk-columnar-af.json', 'test/fixtures/sdk-order-b-ag.json', 'test/fixtures/sdk-schedule-continuation-ah.json', 'test/fixtures/sdk-original-order-ai.json', 'test/fixtures/sdk-compact-sequence-aj.json',
"test/fixtures/sdk-reported-coordination-ar.md", "test/fixtures/sdk-ordered-schedule-ar.md",
'scripts/resolvers/review.ts', 'scripts/resolvers/preamble/generate-ask-user-format.ts', 'scripts/resolvers/tasks-section.ts', 'test/helpers/agent-sdk-runner.ts', 'test/helpers/auq-native-capture.ts', 'test/helpers/auto-decision-state.ts', 'test/helpers/autoplan-artifact-digest.ts', 'test/helpers/autoplan-artifact-permission.ts', 'test/helpers/autoplan-artifact-recorder.ts', 'test/helpers/claude-pty-runner.ts', 'test/helpers/dx-selected-navigation.ts', 'test/helpers/e2e-gate.ts', 'test/helpers/eng-cache-writer-decision.ts', 'test/helpers/hermetic-skill-runtime.ts', 'test/helpers/llm-judge.ts', 'test/helpers/native-auto-decide.ts', 'test/helpers/owned-claude-transcript.ts', 'test/helpers/plan-count-artifacts.ts', 'test/helpers/plan-count-file-permission.ts', 'test/helpers/plan-count-fixture.ts', 'test/helpers/plan-count-pending-exit.ts', 'test/helpers/plan-count-pending-question.ts', 'test/helpers/plan-count-transcript.ts', 'test/helpers/plan-floor-review.ts', 'test/helpers/plan-floor-target.ts', 'test/helpers/plan-scope-selection.ts', 'test/helpers/plan-seed-submission.ts', 'test/helpers/plan-skill-question-events.ts', 'test/helpers/plan-skill-question-hook-scope.ts', 'test/helpers/plan-skill-questions.ts', 'test/helpers/pty-screen.ts', 'test/helpers/pty-trust-dialog.ts', 'test/helpers/skill-census.ts'],
'scripts/resolvers/review.ts', 'scripts/resolvers/preamble/generate-ask-user-format.ts', 'scripts/resolvers/tasks-section.ts', 'test/helpers/agent-sdk-runner.ts', 'test/helpers/auq-native-capture.ts', 'test/helpers/auto-decision-state.ts', 'test/helpers/autoplan-artifact-digest.ts', 'test/helpers/autoplan-artifact-permission.ts', 'test/helpers/autoplan-artifact-recorder.ts', 'test/helpers/claude-pty-runner.ts', 'test/helpers/pty/**', 'test/helpers/dx-selected-navigation.ts', 'test/helpers/e2e-gate.ts', 'test/helpers/eng-cache-writer-decision.ts', 'test/helpers/hermetic-skill-runtime.ts', 'test/helpers/llm-judge.ts', 'test/helpers/native-auto-decide.ts', 'test/helpers/owned-claude-transcript.ts', 'test/helpers/plan-count-artifacts.ts', 'test/helpers/plan-count-file-permission.ts', 'test/helpers/plan-count-fixture.ts', 'test/helpers/plan-count-pending-exit.ts', 'test/helpers/plan-count-pending-question.ts', 'test/helpers/plan-count-transcript.ts', 'test/helpers/plan-floor-review.ts', 'test/helpers/plan-floor-target.ts', 'test/helpers/plan-scope-selection.ts', 'test/helpers/plan-seed-submission.ts', 'test/helpers/plan-skill-question-events.ts', 'test/helpers/plan-skill-question-hook-scope.ts', 'test/helpers/plan-skill-questions.ts', 'test/helpers/pty-screen.ts', 'test/helpers/pty-trust-dialog.ts', 'test/helpers/skill-census.ts'],
// Data-driven behavioral guard for the 'plan'/'prompt' carves (eng, design,
// devex, office-hours + future PR2 carves). One file iterating CARVE_GUARDS;
// the selector sets GSTACK_CARVE_SKILL=<name> to scope cost to the changed
@@ -412,7 +412,7 @@ export const E2E_TOUCHFILES: Record<string, string[]> = {
"scripts/resolvers/preamble/generate-preamble-bash.ts", "scripts/resolvers/preamble/generate-completion-status.ts",
'test/carve-section-loading*.test.ts', 'test/helpers/carve-section-case.ts', 'test/carve-section-loading-browse.test.ts', 'test/carve-section-loading-codex.test.ts', 'test/carve-section-loading-design-consultation.test.ts', 'test/carve-section-loading-design-html.test.ts', 'test/carve-section-loading-design-shotgun.test.ts', 'test/carve-section-loading-document-release.test.ts', 'test/carve-section-loading-land-and-deploy.test.ts', 'test/carve-section-loading-plan-design-review.test.ts', 'test/carve-section-loading-plan-devex-review.test.ts', 'test/carve-section-loading-plan-eng-review.test.ts', 'test/carve-section-loading-qa.test.ts', 'test/carve-section-loading-retro.test.ts', 'test/carve-section-loading-review.test.ts', 'test/carve-section-loading-setup-gbrain.test.ts', 'test/carve-section-loading-spec.test.ts', 'test/fixtures/design-html-section-complete.md', 'scripts/resolvers/testing.ts', 'test/helpers/carve-plan-fixture.ts', 'test/fixtures/carve-existing-repository/**', 'scripts/resolvers/review.ts', 'scripts/resolvers/preamble/generate-ask-user-format.ts', 'test/helpers/agent-sdk-runner.ts', 'test/helpers/auq-native-capture.ts', 'test/helpers/auto-decision-state.ts', 'test/helpers/autoplan-artifact-digest.ts', 'test/helpers/autoplan-artifact-permission.ts', 'test/helpers/autoplan-artifact-recorder.ts', 'test/helpers/capture-parity-baseline.ts', 'test/helpers/claude-pty-runner.ts', 'test/helpers/dx-selected-navigation.ts', 'test/helpers/e2e-gate.ts', 'test/helpers/eng-cache-writer-decision.ts', 'test/helpers/hermetic-skill-runtime.ts', 'test/helpers/llm-judge.ts', 'test/helpers/native-auto-decide.ts', 'test/helpers/owned-claude-transcript.ts', 'test/helpers/parity-harness.ts', 'test/helpers/plan-count-artifacts.ts', 'test/helpers/plan-count-file-permission.ts', 'test/helpers/plan-count-fixture.ts', 'test/helpers/plan-count-pending-exit.ts', 'test/helpers/plan-count-pending-question.ts', 'test/helpers/plan-count-transcript.ts', 'test/helpers/plan-floor-review.ts', 'test/helpers/plan-floor-target.ts', 'test/helpers/plan-scope-selection.ts', 'test/helpers/plan-seed-submission.ts', 'test/helpers/plan-skill-question-events.ts', 'test/helpers/plan-skill-question-hook-scope.ts', 'test/helpers/plan-skill-questions.ts', 'test/helpers/pty-screen.ts', 'test/helpers/pty-trust-dialog.ts', 'test/helpers/skill-census.ts'],
'test/carve-section-loading*.test.ts', 'test/helpers/carve-section-case.ts', 'test/carve-section-loading-browse.test.ts', 'test/carve-section-loading-codex.test.ts', 'test/carve-section-loading-design-consultation.test.ts', 'test/carve-section-loading-design-html.test.ts', 'test/carve-section-loading-design-shotgun.test.ts', 'test/carve-section-loading-document-release.test.ts', 'test/carve-section-loading-land-and-deploy.test.ts', 'test/carve-section-loading-plan-design-review.test.ts', 'test/carve-section-loading-plan-devex-review.test.ts', 'test/carve-section-loading-plan-eng-review.test.ts', 'test/carve-section-loading-qa.test.ts', 'test/carve-section-loading-retro.test.ts', 'test/carve-section-loading-review.test.ts', 'test/carve-section-loading-setup-gbrain.test.ts', 'test/carve-section-loading-spec.test.ts', 'test/fixtures/design-html-section-complete.md', 'scripts/resolvers/testing.ts', 'test/helpers/carve-plan-fixture.ts', 'test/fixtures/carve-existing-repository/**', 'scripts/resolvers/review.ts', 'scripts/resolvers/preamble/generate-ask-user-format.ts', 'test/helpers/agent-sdk-runner.ts', 'test/helpers/auq-native-capture.ts', 'test/helpers/auto-decision-state.ts', 'test/helpers/autoplan-artifact-digest.ts', 'test/helpers/autoplan-artifact-permission.ts', 'test/helpers/autoplan-artifact-recorder.ts', 'test/helpers/capture-parity-baseline.ts', 'test/helpers/claude-pty-runner.ts', 'test/helpers/pty/**', 'test/helpers/dx-selected-navigation.ts', 'test/helpers/e2e-gate.ts', 'test/helpers/eng-cache-writer-decision.ts', 'test/helpers/hermetic-skill-runtime.ts', 'test/helpers/llm-judge.ts', 'test/helpers/native-auto-decide.ts', 'test/helpers/owned-claude-transcript.ts', 'test/helpers/parity-harness.ts', 'test/helpers/plan-count-artifacts.ts', 'test/helpers/plan-count-file-permission.ts', 'test/helpers/plan-count-fixture.ts', 'test/helpers/plan-count-pending-exit.ts', 'test/helpers/plan-count-pending-question.ts', 'test/helpers/plan-count-transcript.ts', 'test/helpers/plan-floor-review.ts', 'test/helpers/plan-floor-target.ts', 'test/helpers/plan-scope-selection.ts', 'test/helpers/plan-seed-submission.ts', 'test/helpers/plan-skill-question-events.ts', 'test/helpers/plan-skill-question-hook-scope.ts', 'test/helpers/plan-skill-questions.ts', 'test/helpers/pty-screen.ts', 'test/helpers/pty-trust-dialog.ts', 'test/helpers/skill-census.ts'],
// Per-finding AskUserQuestion count + review-report-at-bottom assertion.
// Each test drives its skill end-to-end; touchfiles include preamble +
@@ -435,7 +435,7 @@ export const E2E_TOUCHFILES: Record<string, string[]> = {
'test/fixtures/ceo-report-permission-fb10.json', 'test/fixtures/plan-floor-permission-fb10.json', 'test/helpers/plan-count-file-permission.ts', 'test/fixtures/plan-edit-cropped-permission-1579.json', 'test/fixtures/plan-count-permission-target-ad-v2.json', 'test/fixtures/design-crop-gutter-ap.json', 'test/fixtures/plan-count-crop-ak.json', 'test/fixtures/plan-count-long-edit-0bcd.json', 'test/fixtures/plan-count-cropped-wrap-6714.json',
'scripts/resolvers/learnings.ts',
"test/fixtures/plan-scope-recovery-av.json", 'bin/gstack-skill-start', 'bin/gstack-skill-end', 'plan-eng-review/**', 'scripts/resolvers/preamble.ts', 'scripts/resolvers/preamble/generate-ask-user-format.ts', 'scripts/resolvers/preamble/generate-completion-status.ts', 'scripts/resolvers/review.ts', 'test/helpers/claude-pty-runner.ts', 'test/fixtures/design-ui-boxed-question.json', 'test/helpers/hermetic-skill-runtime.ts', 'test/helpers/pty-trust-dialog.ts', 'test/fixtures/forcing-finding-seeds.ts', 'test/skill-e2e-plan-eng-finding-floor.test.ts', 'test/fixtures/eng-batching-t-calls.json', 'test/fixtures/eng-scope-y-calls.json', 'test/fixtures/eng-d2-truncated-border-0bcd.json', 'test/fixtures/eng-d1-clipped-elision-1579.json', 'test/fixtures/eng-d2-planning-prelude-4d.json', 'test/fixtures/ceo-approach-z-call.json', 'test/fixtures/ceo-approach-z-screen.txt', 'test/fixtures/eng-binding-z-calls.json', 'test/fixtures/eng-binding-retry-z-calls.json', 'test/helpers/plan-floor-target.ts', 'test/helpers/plan-count-fixture.ts', 'test/helpers/plan-count-artifacts.ts',
"test/fixtures/plan-scope-recovery-av.json", 'bin/gstack-skill-start', 'bin/gstack-skill-end', 'plan-eng-review/**', 'scripts/resolvers/preamble.ts', 'scripts/resolvers/preamble/generate-ask-user-format.ts', 'scripts/resolvers/preamble/generate-completion-status.ts', 'scripts/resolvers/review.ts', 'test/helpers/claude-pty-runner.ts', 'test/helpers/pty/**', 'test/fixtures/design-ui-boxed-question.json', 'test/helpers/hermetic-skill-runtime.ts', 'test/helpers/pty-trust-dialog.ts', 'test/fixtures/forcing-finding-seeds.ts', 'test/skill-e2e-plan-eng-finding-floor.test.ts', 'test/fixtures/eng-batching-t-calls.json', 'test/fixtures/eng-scope-y-calls.json', 'test/fixtures/eng-d2-truncated-border-0bcd.json', 'test/fixtures/eng-d1-clipped-elision-1579.json', 'test/fixtures/eng-d2-planning-prelude-4d.json', 'test/fixtures/ceo-approach-z-call.json', 'test/fixtures/ceo-approach-z-screen.txt', 'test/fixtures/eng-binding-z-calls.json', 'test/fixtures/eng-binding-retry-z-calls.json', 'test/helpers/plan-floor-target.ts', 'test/helpers/plan-count-fixture.ts', 'test/helpers/plan-count-artifacts.ts',
"test/fixtures/eng-injected-export-aq.json", "test/fixtures/eng-library-hooks-aq.json",
"scripts/resolvers/preamble/generate-preamble-bash.ts",
@@ -448,7 +448,7 @@ export const E2E_TOUCHFILES: Record<string, string[]> = {
'test/fixtures/plan-floor-routing-361c.json',
'test/fixtures/ceo-report-permission-fb10.json', 'test/fixtures/plan-floor-permission-fb10.json', 'test/helpers/plan-count-file-permission.ts', 'test/fixtures/plan-edit-cropped-permission-1579.json', 'test/fixtures/plan-count-permission-target-ad-v2.json', 'test/fixtures/design-crop-gutter-ap.json', 'test/fixtures/plan-count-crop-ak.json', 'test/fixtures/plan-count-long-edit-0bcd.json', 'test/fixtures/plan-count-cropped-wrap-6714.json', 'bin/gstack-skill-start', 'bin/gstack-skill-end', 'plan-ceo-review/**', 'scripts/resolvers/preamble.ts', 'scripts/resolvers/preamble/generate-ask-user-format.ts', 'scripts/resolvers/preamble/generate-completion-status.ts', 'scripts/resolvers/review.ts', 'test/helpers/claude-pty-runner.ts', 'test/fixtures/design-ui-boxed-question.json', 'test/helpers/hermetic-skill-runtime.ts', 'test/helpers/pty-trust-dialog.ts', 'test/fixtures/forcing-finding-seeds.ts', 'test/skill-e2e-plan-ceo-finding-floor.test.ts', 'test/fixtures/eng-d2-truncated-border-0bcd.json', 'test/fixtures/eng-d1-clipped-elision-1579.json', 'test/fixtures/eng-d2-planning-prelude-4d.json', 'test/fixtures/ceo-approach-z-call.json', 'test/fixtures/ceo-approach-z-screen.txt', 'test/helpers/plan-floor-target.ts', 'test/helpers/plan-count-fixture.ts', 'test/helpers/plan-count-artifacts.ts',
'test/fixtures/ceo-report-permission-fb10.json', 'test/fixtures/plan-floor-permission-fb10.json', 'test/helpers/plan-count-file-permission.ts', 'test/fixtures/plan-edit-cropped-permission-1579.json', 'test/fixtures/plan-count-permission-target-ad-v2.json', 'test/fixtures/design-crop-gutter-ap.json', 'test/fixtures/plan-count-crop-ak.json', 'test/fixtures/plan-count-long-edit-0bcd.json', 'test/fixtures/plan-count-cropped-wrap-6714.json', 'bin/gstack-skill-start', 'bin/gstack-skill-end', 'plan-ceo-review/**', 'scripts/resolvers/preamble.ts', 'scripts/resolvers/preamble/generate-ask-user-format.ts', 'scripts/resolvers/preamble/generate-completion-status.ts', 'scripts/resolvers/review.ts', 'test/helpers/claude-pty-runner.ts', 'test/helpers/pty/**', 'test/fixtures/design-ui-boxed-question.json', 'test/helpers/hermetic-skill-runtime.ts', 'test/helpers/pty-trust-dialog.ts', 'test/fixtures/forcing-finding-seeds.ts', 'test/skill-e2e-plan-ceo-finding-floor.test.ts', 'test/fixtures/eng-d2-truncated-border-0bcd.json', 'test/fixtures/eng-d1-clipped-elision-1579.json', 'test/fixtures/eng-d2-planning-prelude-4d.json', 'test/fixtures/ceo-approach-z-call.json', 'test/fixtures/ceo-approach-z-screen.txt', 'test/helpers/plan-floor-target.ts', 'test/helpers/plan-count-fixture.ts', 'test/helpers/plan-count-artifacts.ts',
'test/fixtures/pty-companion-cli.ts', 'lib/fs-atomic.ts', 'test/helpers/plan-skill-questions.ts', 'test/fixtures/eng-auq-validation-error.json', 'test/fixtures/bash-directory-permission.json', 'test/fixtures/design-tasks-bash-permission.json', 'test/fixtures/read-permission.json', 'test/fixtures/ceo-split-e5-numbered-description-491.json', 'test/helpers/plan-skill-question-events.ts', 'test/helpers/plan-skill-question-hook-scope.ts', 'test/helpers/skill-census.ts', 'scripts/resolvers/tasks-section.ts', 'test/helpers/auto-decision-state.ts', 'test/helpers/autoplan-artifact-digest.ts', 'test/helpers/autoplan-artifact-permission.ts', 'test/helpers/autoplan-artifact-recorder.ts', 'test/helpers/dx-selected-navigation.ts', 'test/helpers/e2e-gate.ts', 'test/helpers/eng-cache-writer-decision.ts', 'test/helpers/native-auto-decide.ts', 'test/helpers/owned-claude-transcript.ts', 'test/helpers/plan-count-pending-exit.ts', 'test/helpers/plan-count-pending-question.ts', 'test/helpers/plan-count-transcript.ts', 'test/helpers/plan-scope-selection.ts', 'test/helpers/plan-seed-submission.ts'],
@@ -464,7 +464,7 @@ export const E2E_TOUCHFILES: Record<string, string[]> = {
'test/fixtures/ceo-report-permission-fb10.json', 'test/fixtures/plan-floor-permission-fb10.json', 'test/helpers/plan-count-file-permission.ts', 'test/fixtures/plan-edit-cropped-permission-1579.json', 'test/fixtures/plan-count-permission-target-ad-v2.json', 'test/fixtures/design-crop-gutter-ap.json', 'test/fixtures/plan-count-crop-ak.json', 'test/fixtures/plan-count-long-edit-0bcd.json', 'test/fixtures/plan-count-cropped-wrap-6714.json',
"test/fixtures/plan-scope-recovery-av.json",
"test/fixtures/design-scope-checkpoint-at.json",'bin/gstack-skill-start', 'bin/gstack-skill-end', 'plan-design-review/**', 'scripts/resolvers/preamble.ts', 'scripts/resolvers/preamble/generate-ask-user-format.ts', 'scripts/resolvers/preamble/generate-completion-status.ts', 'scripts/resolvers/review.ts', 'test/helpers/claude-pty-runner.ts', 'test/fixtures/design-ui-boxed-question.json', 'test/helpers/hermetic-skill-runtime.ts', 'test/helpers/pty-trust-dialog.ts', 'test/fixtures/forcing-finding-seeds.ts', 'test/skill-e2e-plan-design-finding-floor.test.ts', 'test/fixtures/eng-d2-truncated-border-0bcd.json', 'test/fixtures/eng-d1-clipped-elision-1579.json', 'test/fixtures/eng-d2-planning-prelude-4d.json', 'test/fixtures/ceo-approach-z-call.json', 'test/fixtures/ceo-approach-z-screen.txt', 'test/helpers/plan-floor-target.ts', 'test/helpers/plan-count-fixture.ts', 'test/helpers/plan-count-artifacts.ts',
"test/fixtures/design-scope-checkpoint-at.json",'bin/gstack-skill-start', 'bin/gstack-skill-end', 'plan-design-review/**', 'scripts/resolvers/preamble.ts', 'scripts/resolvers/preamble/generate-ask-user-format.ts', 'scripts/resolvers/preamble/generate-completion-status.ts', 'scripts/resolvers/review.ts', 'test/helpers/claude-pty-runner.ts', 'test/helpers/pty/**', 'test/fixtures/design-ui-boxed-question.json', 'test/helpers/hermetic-skill-runtime.ts', 'test/helpers/pty-trust-dialog.ts', 'test/fixtures/forcing-finding-seeds.ts', 'test/skill-e2e-plan-design-finding-floor.test.ts', 'test/fixtures/eng-d2-truncated-border-0bcd.json', 'test/fixtures/eng-d1-clipped-elision-1579.json', 'test/fixtures/eng-d2-planning-prelude-4d.json', 'test/fixtures/ceo-approach-z-call.json', 'test/fixtures/ceo-approach-z-screen.txt', 'test/helpers/plan-floor-target.ts', 'test/helpers/plan-count-fixture.ts', 'test/helpers/plan-count-artifacts.ts',
"scripts/resolvers/preamble/generate-preamble-bash.ts",
@@ -479,7 +479,7 @@ export const E2E_TOUCHFILES: Record<string, string[]> = {
'test/fixtures/plan-floor-routing-361c.json',
'test/fixtures/ceo-report-permission-fb10.json', 'test/fixtures/plan-floor-permission-fb10.json', 'test/helpers/plan-count-file-permission.ts', 'test/fixtures/plan-edit-cropped-permission-1579.json', 'test/fixtures/plan-count-permission-target-ad-v2.json', 'test/fixtures/design-crop-gutter-ap.json', 'test/fixtures/plan-count-crop-ak.json', 'test/fixtures/plan-count-long-edit-0bcd.json', 'test/fixtures/plan-count-cropped-wrap-6714.json','bin/gstack-skill-start', 'bin/gstack-skill-end', 'plan-devex-review/**', 'scripts/resolvers/preamble.ts', 'scripts/resolvers/preamble/generate-ask-user-format.ts', 'scripts/resolvers/preamble/generate-completion-status.ts', 'scripts/resolvers/review.ts', 'test/helpers/claude-pty-runner.ts', 'test/fixtures/design-ui-boxed-question.json', 'test/helpers/hermetic-skill-runtime.ts', 'test/helpers/pty-trust-dialog.ts', 'test/fixtures/forcing-finding-seeds.ts', 'test/skill-e2e-plan-devex-finding-floor.test.ts', 'test/fixtures/eng-d2-truncated-border-0bcd.json', 'test/fixtures/eng-d1-clipped-elision-1579.json', 'test/fixtures/eng-d2-planning-prelude-4d.json', 'test/fixtures/ceo-approach-z-call.json', 'test/fixtures/ceo-approach-z-screen.txt', 'test/helpers/plan-floor-target.ts', 'test/helpers/plan-count-fixture.ts', 'test/helpers/plan-count-artifacts.ts',
'test/fixtures/ceo-report-permission-fb10.json', 'test/fixtures/plan-floor-permission-fb10.json', 'test/helpers/plan-count-file-permission.ts', 'test/fixtures/plan-edit-cropped-permission-1579.json', 'test/fixtures/plan-count-permission-target-ad-v2.json', 'test/fixtures/design-crop-gutter-ap.json', 'test/fixtures/plan-count-crop-ak.json', 'test/fixtures/plan-count-long-edit-0bcd.json', 'test/fixtures/plan-count-cropped-wrap-6714.json','bin/gstack-skill-start', 'bin/gstack-skill-end', 'plan-devex-review/**', 'scripts/resolvers/preamble.ts', 'scripts/resolvers/preamble/generate-ask-user-format.ts', 'scripts/resolvers/preamble/generate-completion-status.ts', 'scripts/resolvers/review.ts', 'test/helpers/claude-pty-runner.ts', 'test/helpers/pty/**', 'test/fixtures/design-ui-boxed-question.json', 'test/helpers/hermetic-skill-runtime.ts', 'test/helpers/pty-trust-dialog.ts', 'test/fixtures/forcing-finding-seeds.ts', 'test/skill-e2e-plan-devex-finding-floor.test.ts', 'test/fixtures/eng-d2-truncated-border-0bcd.json', 'test/fixtures/eng-d1-clipped-elision-1579.json', 'test/fixtures/eng-d2-planning-prelude-4d.json', 'test/fixtures/ceo-approach-z-call.json', 'test/fixtures/ceo-approach-z-screen.txt', 'test/helpers/plan-floor-target.ts', 'test/helpers/plan-count-fixture.ts', 'test/helpers/plan-count-artifacts.ts',
'test/fixtures/pty-companion-cli.ts', 'lib/fs-atomic.ts', 'test/helpers/plan-skill-questions.ts', 'test/fixtures/eng-auq-validation-error.json', 'test/fixtures/bash-directory-permission.json', 'test/fixtures/design-tasks-bash-permission.json', 'test/fixtures/read-permission.json', 'test/fixtures/ceo-split-e5-numbered-description-491.json', 'test/helpers/plan-skill-question-events.ts', 'test/helpers/plan-skill-question-hook-scope.ts', 'test/helpers/skill-census.ts', 'test/helpers/auto-decision-state.ts', 'test/helpers/autoplan-artifact-digest.ts', 'test/helpers/autoplan-artifact-permission.ts', 'test/helpers/autoplan-artifact-recorder.ts', 'test/helpers/dx-selected-navigation.ts', 'test/helpers/e2e-gate.ts', 'test/helpers/eng-cache-writer-decision.ts', 'test/helpers/native-auto-decide.ts', 'test/helpers/owned-claude-transcript.ts', 'test/helpers/plan-count-pending-exit.ts', 'test/helpers/plan-count-pending-question.ts', 'test/helpers/plan-count-transcript.ts', 'test/helpers/plan-scope-selection.ts', 'test/helpers/plan-seed-submission.ts'],
// Multi-finding batching regression — periodic tier complement to the
@@ -516,7 +516,7 @@ export const E2E_TOUCHFILES: Record<string, string[]> = {
"test/fixtures/plan-scope-recovery-av.json",
"test/fixtures/batching-permission-at.json",
"test/fixtures/eng-declared-retry-at.json", 'test/fixtures/design-crop-gutter-ap.json', 'bin/gstack-config', 'bin/gstack-skill-start', 'bin/gstack-skill-end', 'plan-eng-review/**', 'scripts/resolvers/preamble.ts', 'scripts/resolvers/preamble/generate-ask-user-format.ts', 'scripts/resolvers/preamble/generate-completion-status.ts', 'scripts/resolvers/review.ts', 'test/helpers/claude-pty-runner.ts', 'test/fixtures/design-ui-boxed-question.json', 'test/helpers/pty-screen.ts', 'test/fixtures/pty-screen/**', 'test/helpers/hermetic-skill-runtime.ts', 'test/helpers/pty-trust-dialog.ts', 'test/helpers/plan-count-transcript.ts', 'test/fixtures/autoplan-public-narration-ad.json', 'test/helpers/plan-count-pending-exit.ts', 'test/helpers/plan-count-artifacts.ts', 'test/helpers/eval-store.ts', 'test/helpers/plan-count-fixture.ts', 'test/fixtures/ceo-prerequisite-n-call.json', 'test/fixtures/eng-prerequisite-77.json', 'test/fixtures/forcing-finding-seeds.ts', 'test/skill-e2e-plan-eng-multi-finding-batching.test.ts', 'test/fixtures/ceo-checkbox-l.screen.txt', 'test/fixtures/eng-devex-s-first-calls.json', 'test/fixtures/eng-devex-s-retry-calls.json', 'test/helpers/plan-count-file-permission.ts', 'test/fixtures/plan-edit-cropped-permission-1579.json', 'test/fixtures/plan-count-edit-permission-t.json', 'test/fixtures/eng-batching-t-calls.json', 'test/fixtures/ceo-preview-u-call.json', 'test/fixtures/ceo-preview-u-screen.txt', 'test/fixtures/design-preview-v-screen.txt', 'test/fixtures/plan-count-owned-permission-v.json', 'test/fixtures/ceo-questionless-w-native.json', 'test/fixtures/eng-scope-y-calls.json', 'test/fixtures/eng-d2-truncated-border-0bcd.json', 'test/fixtures/eng-d1-clipped-elision-1579.json', 'test/fixtures/eng-d2-planning-prelude-4d.json', 'test/fixtures/ceo-approach-z-call.json', 'test/fixtures/ceo-approach-z-screen.txt', 'test/fixtures/eng-binding-z-calls.json', 'test/fixtures/eng-binding-retry-z-calls.json', 'test/fixtures/plan-count-permission-ac.json', 'test/fixtures/plan-count-permission-ad.json', 'test/fixtures/plan-count-permission-ae.json', 'test/fixtures/plan-count-permission-target-ad-v2.json', 'test/fixtures/eng-count-ad-v2.json', 'test/fixtures/eng-first-category-af.json', 'test/fixtures/plan-count-permission-ah.json',
"test/fixtures/eng-declared-retry-at.json", 'test/fixtures/design-crop-gutter-ap.json', 'bin/gstack-config', 'bin/gstack-skill-start', 'bin/gstack-skill-end', 'plan-eng-review/**', 'scripts/resolvers/preamble.ts', 'scripts/resolvers/preamble/generate-ask-user-format.ts', 'scripts/resolvers/preamble/generate-completion-status.ts', 'scripts/resolvers/review.ts', 'test/helpers/claude-pty-runner.ts', 'test/helpers/pty/**', 'test/fixtures/design-ui-boxed-question.json', 'test/helpers/pty-screen.ts', 'test/fixtures/pty-screen/**', 'test/helpers/hermetic-skill-runtime.ts', 'test/helpers/pty-trust-dialog.ts', 'test/helpers/plan-count-transcript.ts', 'test/fixtures/autoplan-public-narration-ad.json', 'test/helpers/plan-count-pending-exit.ts', 'test/helpers/plan-count-artifacts.ts', 'test/helpers/eval-store.ts', 'test/helpers/plan-count-fixture.ts', 'test/fixtures/ceo-prerequisite-n-call.json', 'test/fixtures/eng-prerequisite-77.json', 'test/fixtures/forcing-finding-seeds.ts', 'test/skill-e2e-plan-eng-multi-finding-batching.test.ts', 'test/fixtures/ceo-checkbox-l.screen.txt', 'test/fixtures/eng-devex-s-first-calls.json', 'test/fixtures/eng-devex-s-retry-calls.json', 'test/helpers/plan-count-file-permission.ts', 'test/fixtures/plan-edit-cropped-permission-1579.json', 'test/fixtures/plan-count-edit-permission-t.json', 'test/fixtures/eng-batching-t-calls.json', 'test/fixtures/ceo-preview-u-call.json', 'test/fixtures/ceo-preview-u-screen.txt', 'test/fixtures/design-preview-v-screen.txt', 'test/fixtures/plan-count-owned-permission-v.json', 'test/fixtures/ceo-questionless-w-native.json', 'test/fixtures/eng-scope-y-calls.json', 'test/fixtures/eng-d2-truncated-border-0bcd.json', 'test/fixtures/eng-d1-clipped-elision-1579.json', 'test/fixtures/eng-d2-planning-prelude-4d.json', 'test/fixtures/ceo-approach-z-call.json', 'test/fixtures/ceo-approach-z-screen.txt', 'test/fixtures/eng-binding-z-calls.json', 'test/fixtures/eng-binding-retry-z-calls.json', 'test/fixtures/plan-count-permission-ac.json', 'test/fixtures/plan-count-permission-ad.json', 'test/fixtures/plan-count-permission-ae.json', 'test/fixtures/plan-count-permission-target-ad-v2.json', 'test/fixtures/eng-count-ad-v2.json', 'test/fixtures/eng-first-category-af.json', 'test/fixtures/plan-count-permission-ah.json',
'test/fixtures/plan-count-crop-ak.json',
@@ -540,7 +540,7 @@ export const E2E_TOUCHFILES: Record<string, string[]> = {
'test/fixtures/plan-count-cropped-wrap-6714.json',
"test/fixtures/plan-count-cross-cwd-ancestry-0bcd.json",
'test/fixtures/design-crop-gutter-ap.json', 'bin/gstack-config', 'plan-ceo-review/**', 'scripts/resolvers/preamble.ts', 'scripts/resolvers/preamble/generate-ask-user-format.ts', 'bin/gstack-question-preference', 'test/helpers/claude-pty-runner.ts', 'test/fixtures/design-ui-boxed-question.json', 'test/helpers/pty-screen.ts', 'test/fixtures/pty-screen/**', 'test/helpers/hermetic-skill-runtime.ts', 'test/helpers/pty-trust-dialog.ts', 'test/helpers/plan-count-transcript.ts', 'test/fixtures/autoplan-public-narration-ad.json', 'test/helpers/plan-count-pending-exit.ts', 'test/helpers/plan-count-artifacts.ts', 'test/helpers/eval-store.ts', 'test/helpers/plan-count-fixture.ts', 'test/fixtures/ceo-prerequisite-n-call.json', 'test/fixtures/eng-prerequisite-77.json', 'test/fixtures/forcing-finding-seeds.ts', 'test/skill-e2e-plan-ceo-split-overflow.test.ts', 'test/fixtures/ceo-checkbox-l.screen.txt', 'test/helpers/plan-count-file-permission.ts', 'test/fixtures/plan-edit-cropped-permission-1579.json', 'test/fixtures/plan-count-edit-permission-t.json', 'test/fixtures/plan-count-owned-permission-v.json', 'test/fixtures/ceo-questionless-w-native.json', 'test/fixtures/eng-d2-truncated-border-0bcd.json', 'test/fixtures/eng-d1-clipped-elision-1579.json', 'test/fixtures/eng-d2-planning-prelude-4d.json', 'test/fixtures/ceo-approach-z-call.json', 'test/fixtures/ceo-approach-z-screen.txt', 'test/fixtures/plan-count-permission-ac.json', 'test/fixtures/plan-count-permission-ad.json', 'test/fixtures/plan-count-permission-ae.json', 'test/fixtures/plan-count-permission-target-ad-v2.json', 'test/fixtures/plan-count-permission-ah.json',
'test/fixtures/design-crop-gutter-ap.json', 'bin/gstack-config', 'plan-ceo-review/**', 'scripts/resolvers/preamble.ts', 'scripts/resolvers/preamble/generate-ask-user-format.ts', 'bin/gstack-question-preference', 'test/helpers/claude-pty-runner.ts', 'test/helpers/pty/**', 'test/fixtures/design-ui-boxed-question.json', 'test/helpers/pty-screen.ts', 'test/fixtures/pty-screen/**', 'test/helpers/hermetic-skill-runtime.ts', 'test/helpers/pty-trust-dialog.ts', 'test/helpers/plan-count-transcript.ts', 'test/fixtures/autoplan-public-narration-ad.json', 'test/helpers/plan-count-pending-exit.ts', 'test/helpers/plan-count-artifacts.ts', 'test/helpers/eval-store.ts', 'test/helpers/plan-count-fixture.ts', 'test/fixtures/ceo-prerequisite-n-call.json', 'test/fixtures/eng-prerequisite-77.json', 'test/fixtures/forcing-finding-seeds.ts', 'test/skill-e2e-plan-ceo-split-overflow.test.ts', 'test/fixtures/ceo-checkbox-l.screen.txt', 'test/helpers/plan-count-file-permission.ts', 'test/fixtures/plan-edit-cropped-permission-1579.json', 'test/fixtures/plan-count-edit-permission-t.json', 'test/fixtures/plan-count-owned-permission-v.json', 'test/fixtures/ceo-questionless-w-native.json', 'test/fixtures/eng-d2-truncated-border-0bcd.json', 'test/fixtures/eng-d1-clipped-elision-1579.json', 'test/fixtures/eng-d2-planning-prelude-4d.json', 'test/fixtures/ceo-approach-z-call.json', 'test/fixtures/ceo-approach-z-screen.txt', 'test/fixtures/plan-count-permission-ac.json', 'test/fixtures/plan-count-permission-ad.json', 'test/fixtures/plan-count-permission-ae.json', 'test/fixtures/plan-count-permission-target-ad-v2.json', 'test/fixtures/plan-count-permission-ah.json',
'test/fixtures/plan-count-crop-ak.json',
@@ -1096,7 +1096,7 @@ export const E2E_TOUCHFILES: Record<string, string[]> = {
'test/skill-e2e-arm-benchmark.test.ts',
'ship/SKILL.md', 'test/helpers/e2e-gate.ts'],
'office-hours-section-loading': [ 'office-hours/**', 'bin/gstack-office-hours-review', 'lib/office-hours-review.ts', 'lib/fs-atomic.ts', 'scripts/resolvers/review.ts', 'scripts/resolvers/sections.ts', 'scripts/gen-skill-docs.ts', 'test/helpers/carve-guards.ts', 'test/helpers/auq-sdk-capture.ts', 'test/helpers/office-hours-completion.ts', 'test/helpers/llm-judge.ts', 'test/helpers/session-runner.ts', 'test/skill-e2e-office-hours-section-loading.test.ts', 'test/helpers/agent-sdk-runner.ts', 'test/helpers/auq-native-capture.ts', 'test/helpers/auto-decision-state.ts', 'test/helpers/autoplan-artifact-digest.ts', 'test/helpers/autoplan-artifact-permission.ts', 'test/helpers/autoplan-artifact-recorder.ts', 'test/helpers/capture-parity-baseline.ts', 'test/helpers/claude-pty-runner.ts', 'test/helpers/dx-selected-navigation.ts', 'test/helpers/e2e-gate.ts', 'test/helpers/eng-cache-writer-decision.ts', 'test/helpers/hermetic-skill-runtime.ts', 'test/helpers/native-auto-decide.ts', 'test/helpers/owned-claude-transcript.ts', 'test/helpers/parity-harness.ts', 'test/helpers/plan-count-artifacts.ts', 'test/helpers/plan-count-file-permission.ts', 'test/helpers/plan-count-fixture.ts', 'test/helpers/plan-count-pending-exit.ts', 'test/helpers/plan-count-pending-question.ts', 'test/helpers/plan-count-transcript.ts', 'test/helpers/plan-floor-review.ts', 'test/helpers/plan-floor-target.ts', 'test/helpers/plan-scope-selection.ts', 'test/helpers/plan-seed-submission.ts', 'test/helpers/plan-skill-question-events.ts', 'test/helpers/plan-skill-question-hook-scope.ts', 'test/helpers/plan-skill-questions.ts', 'test/helpers/pty-screen.ts', 'test/helpers/pty-trust-dialog.ts', 'test/helpers/skill-census.ts'],
'office-hours-section-loading': [ 'office-hours/**', 'bin/gstack-office-hours-review', 'lib/office-hours-review.ts', 'lib/fs-atomic.ts', 'scripts/resolvers/review.ts', 'scripts/resolvers/sections.ts', 'scripts/gen-skill-docs.ts', 'test/helpers/carve-guards.ts', 'test/helpers/auq-sdk-capture.ts', 'test/helpers/office-hours-completion.ts', 'test/helpers/llm-judge.ts', 'test/helpers/session-runner.ts', 'test/skill-e2e-office-hours-section-loading.test.ts', 'test/helpers/agent-sdk-runner.ts', 'test/helpers/auq-native-capture.ts', 'test/helpers/auto-decision-state.ts', 'test/helpers/autoplan-artifact-digest.ts', 'test/helpers/autoplan-artifact-permission.ts', 'test/helpers/autoplan-artifact-recorder.ts', 'test/helpers/capture-parity-baseline.ts', 'test/helpers/claude-pty-runner.ts', 'test/helpers/pty/**', 'test/helpers/dx-selected-navigation.ts', 'test/helpers/e2e-gate.ts', 'test/helpers/eng-cache-writer-decision.ts', 'test/helpers/hermetic-skill-runtime.ts', 'test/helpers/native-auto-decide.ts', 'test/helpers/owned-claude-transcript.ts', 'test/helpers/parity-harness.ts', 'test/helpers/plan-count-artifacts.ts', 'test/helpers/plan-count-file-permission.ts', 'test/helpers/plan-count-fixture.ts', 'test/helpers/plan-count-pending-exit.ts', 'test/helpers/plan-count-pending-question.ts', 'test/helpers/plan-count-transcript.ts', 'test/helpers/plan-floor-review.ts', 'test/helpers/plan-floor-target.ts', 'test/helpers/plan-scope-selection.ts', 'test/helpers/plan-seed-submission.ts', 'test/helpers/plan-skill-question-events.ts', 'test/helpers/plan-skill-question-hook-scope.ts', 'test/helpers/plan-skill-questions.ts', 'test/helpers/pty-screen.ts', 'test/helpers/pty-trust-dialog.ts', 'test/helpers/skill-census.ts'],
'plan-devex-peer-comparison-classification': [
+1
View File
@@ -139,6 +139,7 @@ const BASELINE = [
'test/helpers/budget-override.test.ts',
'test/helpers/capture-parity-baseline.test.ts',
'test/helpers/claude-pty-runner.scope-gate-floor.unit.test.ts',
'test/helpers/claude-pty-runner.runners.unit.test.ts', // W4 fake-driver regressions: the PTY harness is itself the subject (plan-mode paid evals stand on it)
'test/helpers/e2e-gate.unit.test.ts',
'test/helpers/eval-store.test.ts',
'test/helpers/hermetic-env.test.ts',