Skip to content

Commit d50d474

Browse files
garrytanclaude
andcommitted
test(plan-tune): 5 cathedral E2E scenarios + touchfile registration
Plan-tune cathedral T16 (per D12 — all 5 in gate tier). One consolidated file with five describeIfSelected scenarios, each selectable by its own touchfile entry so they only run when the relevant code changes (or EVALS_ALL=1 forces all): plan-tune-hook-capture — PostToolUse hook fires → question-log fills plan-tune-enforcement — never-ask + marker + 2-way → deny+reason + auto-decided event logged plan-tune-annotation — declared profile + memory nugget → additionalContext surfaced on defer plan-tune-codex-import — synthetic JSONL → import bin → log with source=codex-import-marker plan-tune-dream-cycle — apply proposal → re-fire question → memory injected via additionalContext Each scenario fixtures an isolated git repo + bins + scripts + hooks under tmp, then exercises the cathedral chain end-to-end against real on-disk binaries (no mocks at the bin layer). GSTACK_STATE_ROOT keeps the user's real ~/.gstack untouched. These five complement the existing unit tests by proving the full sub-process chain works (not just individual functions in isolation). They DON'T spawn claude -p because the cathedral's substrate behavior is deterministic — agent compliance is no longer the variable. The existing test/skill-e2e-plan-tune.test.ts (plan-tune-inspect) still covers the LLM-driven intent-routing behavior. Cost: each scenario runs in ~1s with $0 because no claude -p invocations. Touchfile-gated, so they only run on PRs that touch cathedral code. Also fixes a bug found by the E2E: question-log-hook didn't pass the incoming tool call's cwd to spawnSync when invoking gstack-question-log, so the bin used the hook process's cwd (the repo root) instead of the session's cwd. Result: log writes landed in the wrong project bucket. Fix mirrors the same cwd-passing pattern from question-preference-hook. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 3eab893 commit d50d474

3 files changed

Lines changed: 477 additions & 2 deletions

File tree

hosts/claude/hooks/question-log-hook.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,7 @@ function detectSkill(cwd: string | undefined): string {
204204
return 'unknown';
205205
}
206206

207-
function spawnLog(payload: Record<string, unknown>): void {
207+
function spawnLog(payload: Record<string, unknown>, cwd?: string): void {
208208
// Locate the bin relative to this script's directory.
209209
const here = path.dirname(new URL(import.meta.url).pathname);
210210
// hosts/claude/hooks/ -> ../../../bin/
@@ -214,6 +214,9 @@ function spawnLog(payload: Record<string, unknown>): void {
214214
encoding: 'utf-8',
215215
stdio: ['ignore', 'pipe', 'pipe'],
216216
timeout: 3000,
217+
// Run from the originating tool call's cwd so gstack-slug resolves to
218+
// the project the user is actually in, not the hook script's location.
219+
cwd: cwd && fs.existsSync(cwd) ? cwd : undefined,
217220
});
218221
if (res.status !== 0) {
219222
logHookError(`gstack-question-log exited ${res.status}: ${res.stderr || res.stdout}`);
@@ -274,7 +277,7 @@ async function main(): Promise<void> {
274277
if (recommended) payload.recommended = recommended.slice(0, 64);
275278
if (choice.free_text) payload.free_text = String(choice.free_text);
276279

277-
spawnLog(payload);
280+
spawnLog(payload, stdin.cwd);
278281
}
279282

280283
process.exit(0);

test/helpers/touchfiles.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,13 @@ export const E2E_TOUCHFILES: Record<string, string[]> = {
191191
// /plan-tune (v1 observational)
192192
'plan-tune-inspect': ['plan-tune/**', 'scripts/question-registry.ts', 'scripts/psychographic-signals.ts', 'scripts/one-way-doors.ts', 'bin/gstack-question-log', 'bin/gstack-question-preference', 'bin/gstack-developer-profile'],
193193

194+
// /plan-tune cathedral (T16 — 5 E2E scenarios, all gate per D12)
195+
'plan-tune-hook-capture': ['hosts/claude/hooks/**', 'bin/gstack-question-log', 'bin/gstack-developer-profile', 'plan-tune/**'],
196+
'plan-tune-enforcement': ['hosts/claude/hooks/**', 'bin/gstack-question-preference', 'scripts/question-registry.ts'],
197+
'plan-tune-annotation': ['hosts/claude/hooks/**', 'scripts/declared-annotation.ts', 'scripts/psychographic-signals.ts', 'scripts/question-registry.ts'],
198+
'plan-tune-codex-import': ['bin/gstack-codex-session-import', 'bin/gstack-question-log', 'docs/spikes/codex-session-format.md'],
199+
'plan-tune-dream-cycle': ['bin/gstack-distill-free-text', 'bin/gstack-distill-apply', 'hosts/claude/hooks/**', 'plan-tune/**'],
200+
194201
// Codex offering verification
195202
'codex-offered-office-hours': ['office-hours/**', 'scripts/gen-skill-docs.ts'],
196203
'codex-offered-ceo-review': ['plan-ceo-review/**', 'scripts/gen-skill-docs.ts'],
@@ -528,6 +535,13 @@ export const E2E_TIERS: Record<string, 'gate' | 'periodic'> = {
528535
// /plan-tune — gate (core v1 DX promise: plain-English intent routing)
529536
'plan-tune-inspect': 'gate',
530537

538+
// /plan-tune cathedral (T16 per D12 — all gate)
539+
'plan-tune-hook-capture': 'gate',
540+
'plan-tune-enforcement': 'gate',
541+
'plan-tune-annotation': 'gate',
542+
'plan-tune-codex-import': 'gate',
543+
'plan-tune-dream-cycle': 'gate',
544+
531545
// Codex offering verification
532546
'codex-offered-office-hours': 'gate',
533547
'codex-offered-ceo-review': 'gate',

0 commit comments

Comments
 (0)