Skip to content

Commit 7a8a785

Browse files
committed
fix: address PR #24 review feedback (spike options, flatten safety, MCP witness gate)
- cli-args.ts: parseSpikeArgs now rejects unrecognized --options - doctor.ts: flatten repair only deletes the source .md file, removes dir only if empty (prevents data loss for dirs with extra files) - mcp.ts: method_close now requires witnessVerified=true, matching the CLI's human-in-the-loop gate
1 parent 9b3e821 commit 7a8a785

5 files changed

Lines changed: 28 additions & 6 deletions

File tree

‎docs/MCP.md‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -202,13 +202,15 @@ Check active cycle playback questions against tests
202202

203203
### `method_close`
204204

205-
Close an active cycle into its retro packet.
205+
Close an active cycle into its retro packet. Requires witnessVerified=true to confirm human witness verification.
206206

207207
**Parameters:**
208208

209209
- `cycle` (optional) `string`
210210
- `driftCheck` (required) `boolean`
211211
- `outcome` (required) `string` (hill-met, partial, not-met)
212+
- `witnessVerified` (required) `boolean` — Human attestation that the witness and human playback questions have been verified.
213+
- `summary` (optional) `string` — Retro summary.
212214

213215
### `method_sync_ship`
214216

‎src/cli-args.ts‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1289,6 +1289,9 @@ function parseSpikeArgs(args: readonly string[]): ParsedCommand {
12891289
json = true;
12901290
continue;
12911291
}
1292+
if (value?.startsWith('-')) {
1293+
throw new MethodError(`Unknown option: ${value}\n\n${usage('spike')}`);
1294+
}
12921295
if (value !== undefined) {
12931296
positionals.push(value);
12941297
}

‎src/doctor.ts‎

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -806,8 +806,12 @@ function applyRepair(root: string, issue: DoctorIssue): { status: 'applied' | 's
806806
const updated = raw.replace(/^(cycle:\s*)"[^"]*"\s*$/mu, `$1"${cycleName}"`);
807807
writeFileSync(flatPath, updated, 'utf8');
808808

809-
// Remove the old directory (all files should be the single md)
810-
rmSync(target, { recursive: true });
809+
// Remove the source file, then delete the directory only if empty
810+
rmSync(sourceFile);
811+
const remaining = readdirSync(target);
812+
if (remaining.length === 0) {
813+
rmSync(target, { recursive: true });
814+
}
811815

812816
// Also rename the corresponding retro directory if it exists
813817
const configInspection = inspectConfig(root);

‎src/mcp.ts‎

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -302,16 +302,21 @@ export const MCP_TOOLS: McpToolDef[] = [
302302
},
303303
{
304304
name: 'method_close',
305-
description: 'Close an active cycle into its retro packet.',
305+
description: 'Close an active cycle into its retro packet. Requires witnessVerified=true to confirm human witness verification.',
306306
inputSchema: {
307307
type: 'object',
308308
properties: {
309309
...workspaceProperty,
310310
cycle: { type: 'string' },
311311
driftCheck: { type: 'boolean' },
312312
outcome: { type: 'string', enum: ['hill-met', 'partial', 'not-met'] },
313+
witnessVerified: {
314+
type: 'boolean',
315+
description: 'Human attestation that the witness and human playback questions have been verified.',
316+
},
317+
summary: { type: 'string', description: 'Retro summary.' },
313318
},
314-
required: ['workspace', 'driftCheck', 'outcome'],
319+
required: ['workspace', 'driftCheck', 'outcome', 'witnessVerified'],
315320
},
316321
},
317322
{
@@ -596,7 +601,14 @@ export function createMcpServer(options: CreateMcpServerOptions = {}) {
596601
const cycleName = validateOptionalString(args.cycle, 'cycle');
597602
const driftCheck = validateBoolean(args.driftCheck, 'driftCheck');
598603
const outcome = validateOutcome(args.outcome);
599-
const cycle = await workspace.closeCycle(cycleName, driftCheck, outcome);
604+
const witnessVerified = validateBoolean(args.witnessVerified, 'witnessVerified');
605+
if (!witnessVerified) {
606+
throw new Error('witnessVerified must be true — human witness verification is required before closing a cycle.');
607+
}
608+
const summary = validateOptionalString(args.summary, 'summary');
609+
const cycle = await workspace.closeCycle(cycleName, driftCheck, outcome, {
610+
summary: summary ?? undefined,
611+
});
600612
return successResult('method_close', `Closed ${cycle.name}`, {
601613
cycle: relativizeCycle(workspace, cycle),
602614
});

‎tests/mcp.test.ts‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -839,6 +839,7 @@ describe('MCP Server', () => {
839839
cycle: 'PROCESS_test-idea-from-mcp',
840840
driftCheck: true,
841841
outcome: 'hill-met',
842+
witnessVerified: true,
842843
},
843844
},
844845
});

0 commit comments

Comments
 (0)