@crouton-kit/crouter 0.3.42 → 0.3.44
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/crouter +12 -1
- package/bin/crtr +12 -1
- package/bin/crtrd +12 -1
- package/dist/builtin-memory/05-kinds/advisor/00-base.md +5 -0
- package/dist/builtin-memory/05-kinds/design/00-base.md +8 -1
- package/dist/builtin-memory/05-kinds/developer/00-base.md +7 -0
- package/dist/builtin-memory/05-kinds/explore/00-base.md +7 -0
- package/dist/builtin-memory/05-kinds/general/00-base.md +5 -1
- package/dist/builtin-memory/05-kinds/plan/00-base.md +8 -1
- package/dist/builtin-memory/05-kinds/plan/reviewers/architecture-fit.md +8 -4
- package/dist/builtin-memory/05-kinds/plan/reviewers/code-smells.md +5 -1
- package/dist/builtin-memory/05-kinds/plan/reviewers/pattern-consistency.md +6 -0
- package/dist/builtin-memory/05-kinds/plan/reviewers/requirements-coverage.md +5 -1
- package/dist/builtin-memory/05-kinds/plan/reviewers/security.md +6 -1
- package/dist/builtin-memory/05-kinds/product/00-base.md +4 -0
- package/dist/builtin-memory/05-kinds/review/00-base.md +6 -0
- package/dist/builtin-memory/05-kinds/spec/00-base.md +3 -0
- package/dist/builtin-memory/wedged-child-on-runaway-bash.md +34 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/__tests__/memory-slash-commands.test.ts +184 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/memory-slash-commands.ts +166 -0
- package/dist/clients/attach/attach-cmd.js +306 -306
- package/dist/commands/memory/delete.d.ts +1 -0
- package/dist/commands/memory/delete.js +77 -0
- package/dist/commands/memory/lint.js +10 -0
- package/dist/commands/memory/shared.js +1 -0
- package/dist/commands/memory/write.js +7 -1
- package/dist/commands/memory.js +3 -2
- package/dist/commands/node.js +35 -9
- package/dist/core/__tests__/pid-zombie.test.d.ts +1 -0
- package/dist/core/__tests__/pid-zombie.test.js +42 -0
- package/dist/core/canvas/pid.d.ts +14 -3
- package/dist/core/canvas/pid.js +41 -4
- package/dist/core/memory-resolver.d.ts +6 -0
- package/dist/core/memory-resolver.js +1 -1
- package/dist/core/runtime/broker.js +13 -5
- package/dist/core/runtime/launch.d.ts +1 -0
- package/dist/core/runtime/launch.js +4 -3
- package/dist/core/runtime/spawn.js +18 -3
- package/dist/core/runtime/stop-guard.js +19 -0
- package/dist/core/runtime/structured-output.d.ts +12 -0
- package/dist/core/runtime/structured-output.js +90 -0
- package/dist/core/substrate/schema.d.ts +15 -0
- package/dist/core/substrate/schema.js +9 -0
- package/dist/pi-extensions/canvas-structured-output.d.ts +9 -0
- package/dist/pi-extensions/canvas-structured-output.js +150 -0
- package/dist/prompts/review.js +14 -0
- package/package.json +1 -1
|
@@ -17,8 +17,21 @@
|
|
|
17
17
|
// • otherwise → a TERMINAL node with nothing live to wait for and no
|
|
18
18
|
// final pushed. Re-prompt it to finish or escalate.
|
|
19
19
|
import { hasActiveLiveSubscription, hasPendingSelfTrigger, getNode } from '../canvas/index.js';
|
|
20
|
+
import { hasPendingStructuredOutput, readOutputRequest } from './structured-output.js';
|
|
20
21
|
export const STALL_REPROMPT = "You've stopped but you're not waiting on anyone and haven't finished. " +
|
|
21
22
|
'Run `crtr push final "<result>"` if the work is done, or `crtr human ask` if you are blocked or need the user.';
|
|
23
|
+
function structuredOutputReprompt(nodeId) {
|
|
24
|
+
let schema = '{}';
|
|
25
|
+
try {
|
|
26
|
+
const request = readOutputRequest(nodeId);
|
|
27
|
+
if (request !== null)
|
|
28
|
+
schema = JSON.stringify(request.schema, null, 2);
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
/* keep a deterministic reprompt even if the schema file was corrupted */
|
|
32
|
+
}
|
|
33
|
+
return `You must call the \`submit\` tool with a result matching the required schema before you can stop. You cannot finish or go dormant any other way while this request is pending.\n\nRequired schema:\n\n\`\`\`json\n${schema}\n\`\`\``;
|
|
34
|
+
}
|
|
22
35
|
/** Decide what to do when a node stops. Pure given the canvas + this turn's
|
|
23
36
|
* signals — the stophook supplies the signals and enacts the action. */
|
|
24
37
|
export function evaluateStop(nodeId, signals) {
|
|
@@ -32,6 +45,12 @@ export function evaluateStop(nodeId, signals) {
|
|
|
32
45
|
if (node !== null && (node.status === 'done' || node.status === 'dead' || node.status === 'canceled')) {
|
|
33
46
|
return { action: 'allow', reason: 'finished' };
|
|
34
47
|
}
|
|
48
|
+
// A pending structured-output request overrides every normal dormancy path:
|
|
49
|
+
// terminal mode must finish through submit, and one-off mode must answer the
|
|
50
|
+
// outstanding request before the node is freed to stop normally again.
|
|
51
|
+
if (hasPendingStructuredOutput(nodeId)) {
|
|
52
|
+
return { action: 'reprompt', reason: 'stalled', message: structuredOutputReprompt(nodeId) };
|
|
53
|
+
}
|
|
35
54
|
// A RESIDENT node is interactable / human-driven and is never forced to submit
|
|
36
55
|
// a final: stopping to go dormant is always legitimate (the inbox or the human
|
|
37
56
|
// wakes it). Keyed on lifecycle, not parent — whether it has a parent doesn't
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export type StructuredOutputMode = 'terminal' | 'oneoff';
|
|
2
|
+
export interface StructuredOutputRequest {
|
|
3
|
+
mode: StructuredOutputMode;
|
|
4
|
+
schema: Record<string, unknown>;
|
|
5
|
+
}
|
|
6
|
+
export declare function outputSchemaPath(nodeId: string): string;
|
|
7
|
+
export declare function outputResultPath(nodeId: string): string;
|
|
8
|
+
export declare function parseOutputSchemaValue(value: string | undefined): Record<string, unknown> | null;
|
|
9
|
+
export declare function writeOutputSchema(nodeId: string, mode: StructuredOutputMode, schema: Record<string, unknown>): string;
|
|
10
|
+
export declare function readOutputRequest(nodeId: string): StructuredOutputRequest | null;
|
|
11
|
+
export declare function removeOutputSchema(nodeId: string): void;
|
|
12
|
+
export declare function hasPendingStructuredOutput(nodeId: string): boolean;
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, unlinkSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { dirname, resolve } from 'node:path';
|
|
3
|
+
import { nodeDir, contextDir } from '../canvas/paths.js';
|
|
4
|
+
import { InputError } from '../io.js';
|
|
5
|
+
export function outputSchemaPath(nodeId) {
|
|
6
|
+
return `${nodeDir(nodeId)}/output-schema.json`;
|
|
7
|
+
}
|
|
8
|
+
export function outputResultPath(nodeId) {
|
|
9
|
+
return `${contextDir(nodeId)}/result.json`;
|
|
10
|
+
}
|
|
11
|
+
function isObject(value) {
|
|
12
|
+
return value !== null && typeof value === 'object' && !Array.isArray(value);
|
|
13
|
+
}
|
|
14
|
+
export function parseOutputSchemaValue(value) {
|
|
15
|
+
const raw = value?.trim();
|
|
16
|
+
if (raw === undefined || raw === '')
|
|
17
|
+
return null;
|
|
18
|
+
let text;
|
|
19
|
+
let source;
|
|
20
|
+
if (raw.startsWith('{')) {
|
|
21
|
+
text = raw;
|
|
22
|
+
source = 'inline JSON';
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
const path = resolve(raw);
|
|
26
|
+
source = path;
|
|
27
|
+
try {
|
|
28
|
+
text = readFileSync(path, 'utf8');
|
|
29
|
+
}
|
|
30
|
+
catch (err) {
|
|
31
|
+
throw new InputError({
|
|
32
|
+
error: 'bad_output_schema',
|
|
33
|
+
message: `could not read output schema from ${path}: ${err.message}`,
|
|
34
|
+
field: 'output-schema',
|
|
35
|
+
next: 'Pass a readable JSON Schema file path, or inline JSON beginning with `{`.',
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
let parsed;
|
|
40
|
+
try {
|
|
41
|
+
parsed = JSON.parse(text);
|
|
42
|
+
}
|
|
43
|
+
catch (err) {
|
|
44
|
+
throw new InputError({
|
|
45
|
+
error: 'bad_output_schema',
|
|
46
|
+
message: `output schema from ${source} is not valid JSON: ${err.message}`,
|
|
47
|
+
field: 'output-schema',
|
|
48
|
+
next: 'Pass valid JSON whose top-level value is an object.',
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
if (!isObject(parsed)) {
|
|
52
|
+
throw new InputError({
|
|
53
|
+
error: 'bad_output_schema',
|
|
54
|
+
message: `output schema from ${source} must be a JSON object`,
|
|
55
|
+
field: 'output-schema',
|
|
56
|
+
next: 'Pass a JSON Schema object, not an array, string, number, boolean, or null.',
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
return parsed;
|
|
60
|
+
}
|
|
61
|
+
export function writeOutputSchema(nodeId, mode, schema) {
|
|
62
|
+
const path = outputSchemaPath(nodeId);
|
|
63
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
64
|
+
const request = { mode, schema };
|
|
65
|
+
writeFileSync(path, `${JSON.stringify(request, null, 2)}\n`, 'utf8');
|
|
66
|
+
return path;
|
|
67
|
+
}
|
|
68
|
+
export function readOutputRequest(nodeId) {
|
|
69
|
+
const path = outputSchemaPath(nodeId);
|
|
70
|
+
if (!existsSync(path))
|
|
71
|
+
return null;
|
|
72
|
+
const parsed = JSON.parse(readFileSync(path, 'utf8'));
|
|
73
|
+
if (!isObject(parsed))
|
|
74
|
+
return null;
|
|
75
|
+
const mode = parsed['mode'];
|
|
76
|
+
const schema = parsed['schema'];
|
|
77
|
+
if ((mode !== 'terminal' && mode !== 'oneoff') || !isObject(schema))
|
|
78
|
+
return null;
|
|
79
|
+
return { mode, schema };
|
|
80
|
+
}
|
|
81
|
+
export function removeOutputSchema(nodeId) {
|
|
82
|
+
const path = outputSchemaPath(nodeId);
|
|
83
|
+
try {
|
|
84
|
+
unlinkSync(path);
|
|
85
|
+
}
|
|
86
|
+
catch { /* already gone */ }
|
|
87
|
+
}
|
|
88
|
+
export function hasPendingStructuredOutput(nodeId) {
|
|
89
|
+
return existsSync(outputSchemaPath(nodeId));
|
|
90
|
+
}
|
|
@@ -58,6 +58,21 @@ export interface SubstrateSchema {
|
|
|
58
58
|
* than the node subject. Absent ⇒ no frontmatter trigger. Frontmatter key
|
|
59
59
|
* `read-when`. */
|
|
60
60
|
readWhen?: GatePredicate;
|
|
61
|
+
/** Opt-in: this doc is invocable as a pi slash command (`/<name>`, `/` in a
|
|
62
|
+
* nested name rendered as `:`). Default `false` — most docs are consulted,
|
|
63
|
+
* not invoked. Frontmatter key `slash`. */
|
|
64
|
+
slash: boolean;
|
|
65
|
+
/** The gap this doc exists to close — the observed agent failure that
|
|
66
|
+
* prompted it (CTO ruling 2026-07-03, `taste/document-substrate` §"Rationale
|
|
67
|
+
* is a frontmatter field, never delivered"). MAINTAINER-FACING ONLY: excluded
|
|
68
|
+
* from every delivered surface by construction — it is frontmatter, never
|
|
69
|
+
* body, so it never reaches a boot render, on-read injection, or `memory
|
|
70
|
+
* read` content output; only the raw file at `path` (or `memory read
|
|
71
|
+
* --frontmatter`) shows it. It is NOT read-routing (`whenAndWhyToRead` owns
|
|
72
|
+
* that) and NOT a content summary (`shortForm` owns that) — it answers
|
|
73
|
+
* "what observed failure made this doc exist," never "why obey it." Absent
|
|
74
|
+
* when the doc carries none. Frontmatter key `rationale`. */
|
|
75
|
+
rationale?: string;
|
|
61
76
|
}
|
|
62
77
|
/** A fully-resolved substrate document: the parsed schema PLUS the resolver's
|
|
63
78
|
* path-derived identity and body. This single object flows through the whole
|
|
@@ -94,6 +94,8 @@ export function parseSubstrateFrontmatter(fm) {
|
|
|
94
94
|
gate: parseGate(fm.gate),
|
|
95
95
|
appliesTo: parseAppliesTo(fm['applies-to']),
|
|
96
96
|
readWhen: parseGate(fm['read-when']),
|
|
97
|
+
slash: fm.slash === true,
|
|
98
|
+
rationale: parseRationale(fm['rationale']),
|
|
97
99
|
};
|
|
98
100
|
}
|
|
99
101
|
/** Parse a resolved MemoryDoc into a fully-typed SubstrateDoc (schema + the
|
|
@@ -121,6 +123,13 @@ export function previewLine(doc) {
|
|
|
121
123
|
function strField(v) {
|
|
122
124
|
return typeof v === 'string' ? v : '';
|
|
123
125
|
}
|
|
126
|
+
/** Resolve an optional `rationale` field: a non-empty string is carried as-is
|
|
127
|
+
* (multi-line YAML block scalars parse to a plain string, so no special
|
|
128
|
+
* handling is needed); anything else (absent, blank, non-string) yields
|
|
129
|
+
* `undefined` — the doc simply carries no rationale. */
|
|
130
|
+
function parseRationale(v) {
|
|
131
|
+
return typeof v === 'string' && v.trim() !== '' ? v : undefined;
|
|
132
|
+
}
|
|
124
133
|
/** Resolve a visibility field to a ladder rung, falling back to the neutral
|
|
125
134
|
* floor when absent/invalid. */
|
|
126
135
|
function parseRung(v, fallback) {
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
type PiEvents = 'before_agent_start' | 'agent_start';
|
|
2
|
+
interface PiLike {
|
|
3
|
+
on: (event: PiEvents, handler: (event: any, ctx: any) => void | Promise<void>) => void;
|
|
4
|
+
registerTool: (definition: Record<string, unknown>) => void;
|
|
5
|
+
getActiveTools?: () => string[];
|
|
6
|
+
setActiveTools?: (tools: string[]) => void;
|
|
7
|
+
}
|
|
8
|
+
export declare function registerCanvasStructuredOutput(pi: PiLike): void;
|
|
9
|
+
export default registerCanvasStructuredOutput;
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
// canvas-structured-output.ts — dynamic `submit` tool for schema-shaped node results.
|
|
2
|
+
//
|
|
3
|
+
// Loaded into every canvas node. Inert unless nodes/<id>/output-schema.json exists.
|
|
4
|
+
import { mkdirSync, writeFileSync } from 'node:fs';
|
|
5
|
+
import { dirname } from 'node:path';
|
|
6
|
+
import { getNode } from '../core/canvas/index.js';
|
|
7
|
+
import { pushFinal, pushUpdate } from '../core/feed/feed.js';
|
|
8
|
+
import { outputResultPath, readOutputRequest, removeOutputSchema, } from '../core/runtime/structured-output.js';
|
|
9
|
+
function reportBody(resultPath, json) {
|
|
10
|
+
return `Structured output submitted.\n\nResult path: ${resultPath}\n\n\`\`\`json\n${json}\n\`\`\`\n`;
|
|
11
|
+
}
|
|
12
|
+
function activateTool(pi) {
|
|
13
|
+
try {
|
|
14
|
+
const current = pi.getActiveTools?.() ?? [];
|
|
15
|
+
if (!current.includes('submit'))
|
|
16
|
+
pi.setActiveTools?.([...current, 'submit']);
|
|
17
|
+
}
|
|
18
|
+
catch {
|
|
19
|
+
/* best-effort; registration refresh normally activates new extension tools */
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
function retireTool(pi) {
|
|
23
|
+
try {
|
|
24
|
+
const current = pi.getActiveTools?.() ?? [];
|
|
25
|
+
pi.setActiveTools?.(current.filter((name) => name !== 'submit'));
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
/* best-effort; the execute handler is inert when no schema file exists */
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
function toolDescription(request) {
|
|
32
|
+
if (request.mode === 'terminal') {
|
|
33
|
+
return 'Submit your final structured result. Calling this ends your run: the result is recorded and a final report is pushed automatically — do NOT call `crtr push final` yourself.';
|
|
34
|
+
}
|
|
35
|
+
return 'Submit the requested one-off structured result. Calling this records the result, pushes an update report automatically, frees you from the structured-output gate, and lets you continue working.';
|
|
36
|
+
}
|
|
37
|
+
export function registerCanvasStructuredOutput(pi) {
|
|
38
|
+
const nodeId = process.env['CRTR_NODE_ID'];
|
|
39
|
+
if (nodeId === undefined || nodeId.trim() === '')
|
|
40
|
+
return;
|
|
41
|
+
let registeredKey = null;
|
|
42
|
+
let active = false;
|
|
43
|
+
const ensureSubmitTool = (activate) => {
|
|
44
|
+
const request = readOutputRequest(nodeId);
|
|
45
|
+
if (request === null) {
|
|
46
|
+
if (active) {
|
|
47
|
+
active = false;
|
|
48
|
+
retireTool(pi);
|
|
49
|
+
}
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
const key = JSON.stringify(request);
|
|
53
|
+
if (registeredKey !== key) {
|
|
54
|
+
pi.registerTool({
|
|
55
|
+
name: 'submit',
|
|
56
|
+
label: 'Submit',
|
|
57
|
+
description: toolDescription(request),
|
|
58
|
+
promptSnippet: request.mode === 'terminal'
|
|
59
|
+
? 'Submit the final structured result and end this node'
|
|
60
|
+
: 'Submit the requested one-off structured result',
|
|
61
|
+
promptGuidelines: request.mode === 'terminal'
|
|
62
|
+
? [
|
|
63
|
+
'Use submit as your final action when the required structured result is ready.',
|
|
64
|
+
'After calling submit, do not call crtr push final yourself and do not emit another assistant response.',
|
|
65
|
+
]
|
|
66
|
+
: [
|
|
67
|
+
'Use submit to answer the pending one-off structured-output request before stopping or going dormant.',
|
|
68
|
+
'After one-off submit succeeds, continue with any remaining work normally.',
|
|
69
|
+
],
|
|
70
|
+
parameters: request.schema,
|
|
71
|
+
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
72
|
+
const current = readOutputRequest(nodeId);
|
|
73
|
+
if (current === null) {
|
|
74
|
+
return {
|
|
75
|
+
content: [{ type: 'text', text: 'No structured output is currently requested.' }],
|
|
76
|
+
details: { submitted: false, reason: 'no_request' },
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
if (JSON.stringify(current) !== key) {
|
|
80
|
+
registeredKey = null;
|
|
81
|
+
ensureSubmitTool(true);
|
|
82
|
+
return {
|
|
83
|
+
content: [{ type: 'text', text: 'The structured-output request changed while you were working. Call submit again using the current schema.' }],
|
|
84
|
+
details: { submitted: false, reason: 'schema_replaced' },
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
const resultPath = outputResultPath(nodeId);
|
|
88
|
+
const json = JSON.stringify(params, null, 2);
|
|
89
|
+
mkdirSync(dirname(resultPath), { recursive: true });
|
|
90
|
+
writeFileSync(resultPath, `${json}\n`, 'utf8');
|
|
91
|
+
const body = reportBody(resultPath, json);
|
|
92
|
+
if (current.mode === 'terminal') {
|
|
93
|
+
try {
|
|
94
|
+
await pushFinal(nodeId, body);
|
|
95
|
+
}
|
|
96
|
+
catch (err) {
|
|
97
|
+
const status = getNode(nodeId)?.status;
|
|
98
|
+
const alreadyFinalized = status === 'done' || status === 'dead' || status === 'canceled' ||
|
|
99
|
+
(err instanceof Error && err.message.startsWith("illegal lifecycle transition: 'finalize' from status='"));
|
|
100
|
+
if (!alreadyFinalized)
|
|
101
|
+
throw err;
|
|
102
|
+
}
|
|
103
|
+
removeOutputSchema(nodeId);
|
|
104
|
+
active = false;
|
|
105
|
+
retireTool(pi);
|
|
106
|
+
try {
|
|
107
|
+
ctx?.shutdown?.();
|
|
108
|
+
}
|
|
109
|
+
catch { /* ignore */ }
|
|
110
|
+
return {
|
|
111
|
+
content: [{ type: 'text', text: `Structured output submitted and finalized: ${resultPath}` }],
|
|
112
|
+
details: { submitted: true, mode: current.mode, resultPath, result: params },
|
|
113
|
+
terminate: true,
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
await pushUpdate(nodeId, body);
|
|
117
|
+
removeOutputSchema(nodeId);
|
|
118
|
+
active = false;
|
|
119
|
+
retireTool(pi);
|
|
120
|
+
return {
|
|
121
|
+
content: [{ type: 'text', text: `Structured output submitted: ${resultPath}` }],
|
|
122
|
+
details: { submitted: true, mode: current.mode, resultPath, result: params },
|
|
123
|
+
};
|
|
124
|
+
},
|
|
125
|
+
});
|
|
126
|
+
registeredKey = key;
|
|
127
|
+
}
|
|
128
|
+
if (activate && !active) {
|
|
129
|
+
active = true;
|
|
130
|
+
activateTool(pi);
|
|
131
|
+
}
|
|
132
|
+
};
|
|
133
|
+
try {
|
|
134
|
+
ensureSubmitTool(false);
|
|
135
|
+
}
|
|
136
|
+
catch { /* malformed files are enforced by the stop-guard */ }
|
|
137
|
+
pi.on('before_agent_start', () => {
|
|
138
|
+
try {
|
|
139
|
+
ensureSubmitTool(true);
|
|
140
|
+
}
|
|
141
|
+
catch { /* keep the node alive; stop-guard will reprompt */ }
|
|
142
|
+
});
|
|
143
|
+
pi.on('agent_start', () => {
|
|
144
|
+
try {
|
|
145
|
+
ensureSubmitTool(true);
|
|
146
|
+
}
|
|
147
|
+
catch { /* keep the node alive; stop-guard will reprompt */ }
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
export default registerCanvasStructuredOutput;
|
package/dist/prompts/review.js
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Builds the guidance delivered to spec/plan reviewer agents.
|
|
3
|
+
*
|
|
4
|
+
* Why this exists (CTO, 2026-07-03): reviewer agents without calibration
|
|
5
|
+
* drift to rubber-stamping or nitpicking, so the decision tables force a
|
|
6
|
+
* real verdict — but the deeper point is that this reviews AGENT-written
|
|
7
|
+
* work, not generic review. Agents have a specific failure profile: a check
|
|
8
|
+
* earns a place here only when it targets a mistake agents actually make
|
|
9
|
+
* (unrequested features, placeholder sections, noise comments), and a check
|
|
10
|
+
* for something agents reliably get right (e.g. arithmetic/logic
|
|
11
|
+
* correctness) is pure noise. Maintain the checklists empirically: add a
|
|
12
|
+
* check when we observe agents failing at something, cut one that never
|
|
13
|
+
* catches anything.
|
|
14
|
+
*/
|
|
1
15
|
const SUBMIT_INSTRUCTIONS = `## Delivering your review
|
|
2
16
|
|
|
3
17
|
When your review is complete, deliver your verdict as instructed by
|