@tekyzinc/gsd-t 5.2.11 → 5.4.10
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/CHANGELOG.md +43 -0
- package/README.md +2 -2
- package/bin/gsd-t-model-profile.cjs +8 -15
- package/bin/gsd-t-model-tier-policy.cjs +62 -49
- package/bin/gsd-t-parallel.cjs +1 -2
- package/bin/gsd-t-schema-id-check.cjs +246 -0
- package/bin/gsd-t-verify-gate.cjs +2 -0
- package/commands/gsd-t-debug.md +1 -1
- package/commands/gsd-t-help.md +5 -5
- package/commands/gsd-t-partition.md +1 -1
- package/commands/gsd-t-status.md +4 -4
- package/package.json +1 -1
- package/templates/CLAUDE-global.md +34 -5
- package/templates/prompts/blind-adversary-subagent.md +2 -2
- package/templates/prompts/research-subagent.md +1 -1
- package/templates/stacks/_comparison.md +134 -0
- package/templates/stacks/firebase.md +31 -0
- package/templates/stacks/neo4j.md +12 -0
- package/templates/stacks/postgresql.md +42 -4
- package/templates/stacks/prisma.md +12 -5
- package/templates/stacks/supabase.md +40 -0
- package/templates/stacks/typescript.md +25 -0
- package/templates/workflows/gsd-t-debug.workflow.js +10 -10
- package/templates/workflows/gsd-t-execute.workflow.js +7 -7
- package/templates/workflows/gsd-t-phase.workflow.js +13 -13
- package/templates/workflows/gsd-t-quick.workflow.js +6 -6
- package/templates/workflows/gsd-t-verify.workflow.js +2 -2
|
@@ -7,11 +7,11 @@
|
|
|
7
7
|
// M89: Stated-Claims→classify→research wiring (auto-research-contract v1.2.0 §6.5/§1/§2/§3/§4/§7).
|
|
8
8
|
// Each debug cycle embeds the Stated-Claims snippet (§6.5) so the debug agent tags failure-root
|
|
9
9
|
// claims KNOWN|GUESSED. After each cycle, GUESSED claims are classified: external failure-root
|
|
10
|
-
// → write §7 marker (status=uncited) → research agent (model:"
|
|
10
|
+
// → write §7 marker (status=uncited) → research agent (model:"opus") → cite → flip marker
|
|
11
11
|
// (status=cited) — instead of a patch-guess (pairs with #33 circuit-breaker). Internal →
|
|
12
12
|
// grep/Read; grep-empty → escalate to external (§5.1). The existing debug-cycle ternary
|
|
13
|
-
// (model: cycle===1?"opus":(overrides["debug-cycle-2"]??"
|
|
14
|
-
// stage is a SEPARATE agent() with its own bare "
|
|
13
|
+
// (model: cycle===1?"opus":(overrides["debug-cycle-2"]??"opus")) is PRESERVED; the research
|
|
14
|
+
// stage is a SEPARATE agent() with its own bare "opus" literal. Idempotent per §4.1.
|
|
15
15
|
//
|
|
16
16
|
// M94-D11 WRITER pattern (graph-consumer-wiring-contract.md §WRITER Pattern):
|
|
17
17
|
// READER half: before the fix agent, query blast-radius + who-calls to localize the
|
|
@@ -57,7 +57,7 @@ const _args = (typeof args === "string") ? (() => { try { return JSON.parse(args
|
|
|
57
57
|
// Default to {} so the premium fallback literals apply when no invoker injects overrides.
|
|
58
58
|
// overrides values are CONCRETE model ids (resolver envelope); the bare literals below
|
|
59
59
|
// are tier ALIASES. The sandbox runtime accepts BOTH forms in model: — proven live for
|
|
60
|
-
// the
|
|
60
|
+
// the tier alias resolves to claude-opus-5 (Fable removed 2026-07-24).
|
|
61
61
|
const overrides = (_args.overrides && typeof _args.overrides === "object") ? _args.overrides : {};
|
|
62
62
|
const _CLI_ENVELOPE_SCHEMA = {
|
|
63
63
|
type: "object", required: ["ok", "exitCode"], additionalProperties: true,
|
|
@@ -184,7 +184,7 @@ async function grepForClaim(projectDir, claimText, phaseName) {
|
|
|
184
184
|
return r || { found: false, matches: [] };
|
|
185
185
|
}
|
|
186
186
|
|
|
187
|
-
// M89 §1.1 — AMBIGUOUS → LLM JUDGE (bare model:"
|
|
187
|
+
// M89 §1.1 — AMBIGUOUS → LLM JUDGE (bare model:"opus" — NOT the ?? form; "judge" is not
|
|
188
188
|
// a designated stage, so the bare literal passes the M85 tier-set check and stays DISTINCT
|
|
189
189
|
// from the debug-cycle ternary). internal/external/uncertain; uncertain → research (never
|
|
190
190
|
// guess-internal). On error → "uncertain" (fail toward research).
|
|
@@ -201,7 +201,7 @@ async function judgeAmbiguous(claimText, phaseName) {
|
|
|
201
201
|
`- "uncertain" = you cannot CONFIDENTLY place it internal — per M89 doctrine it is RESEARCHED, never guessed.`,
|
|
202
202
|
`Return JSON: { "verdict": "internal"|"external"|"uncertain", "reason": "<one line>" }. No file/web work in THIS step.`,
|
|
203
203
|
].join("\n");
|
|
204
|
-
const r = await agent(prompt, { label: "classify-judge", model: "
|
|
204
|
+
const r = await agent(prompt, { label: "classify-judge", model: "opus", schema: CLASSIFY_JUDGE_SCHEMA, phase: phaseName })
|
|
205
205
|
.catch((e) => ({ verdict: "uncertain", reason: `judge error: ${e && e.message}` }));
|
|
206
206
|
return (r && r.verdict) || "uncertain";
|
|
207
207
|
}
|
|
@@ -263,7 +263,7 @@ async function runResearchForClaim(projectDir, claimText, artifactPath, phaseNam
|
|
|
263
263
|
|
|
264
264
|
// External-claim handler closure (reused by the ambiguous→judge path).
|
|
265
265
|
const doExternal = async () => {
|
|
266
|
-
log(`Research: external failure-root → research(
|
|
266
|
+
log(`Research: external failure-root → research(opus) instead of patch-guess for "${claimKey.slice(0, 50)}"`);
|
|
267
267
|
await appendUncitedMarker(externalArtifact, claimKey);
|
|
268
268
|
const rr = await agent(
|
|
269
269
|
[
|
|
@@ -272,7 +272,7 @@ async function runResearchForClaim(projectDir, claimText, artifactPath, phaseNam
|
|
|
272
272
|
`Gap-key: "${claimKey}"`,
|
|
273
273
|
`Emit ## Verified Facts (auto-research) block with source URL + fetch date. Append the trailer \`key: ${claimKey}\` on every fact line so the §7 gate matches by claim-key (Red Team MEDIUM #2). Return StructuredOutput JSON.`,
|
|
274
274
|
].join("\n"),
|
|
275
|
-
{ label: "research", model: "
|
|
275
|
+
{ label: "research", model: "opus", schema: RESEARCH_RESULT_SCHEMA, phase: phaseName }
|
|
276
276
|
).catch((e) => ({ ok: false, gapKey: claimKey, reason: String(e && e.message) }));
|
|
277
277
|
|
|
278
278
|
if (rr && rr.ok && rr.citedBlock) {
|
|
@@ -300,7 +300,7 @@ async function runResearchForClaim(projectDir, claimText, artifactPath, phaseNam
|
|
|
300
300
|
`Gap-key: "${claimKey}"`,
|
|
301
301
|
`Emit ## Verified Facts (auto-research) block. Append the trailer \`key: ${claimKey}\` on every fact line so the §7 gate matches by claim-key (Red Team MEDIUM #2). Return StructuredOutput JSON.`,
|
|
302
302
|
].join("\n"),
|
|
303
|
-
{ label: "research", model: "
|
|
303
|
+
{ label: "research", model: "opus", schema: RESEARCH_RESULT_SCHEMA, phase: phaseName }
|
|
304
304
|
).catch((e) => ({ ok: false, gapKey: claimKey, reason: String(e && e.message) }));
|
|
305
305
|
|
|
306
306
|
if (er && er.ok && er.citedBlock) {
|
|
@@ -449,7 +449,7 @@ for (let cycle = 1; cycle <= 2; cycle++) {
|
|
|
449
449
|
label: `debug-cycle-${cycle}`,
|
|
450
450
|
phase: `Cycle ${cycle}`,
|
|
451
451
|
schema: DEBUG_CYCLE_SCHEMA,
|
|
452
|
-
model: cycle === 1 ? "opus" : (overrides["debug-cycle-2"] ?? "
|
|
452
|
+
model: cycle === 1 ? "opus" : (overrides["debug-cycle-2"] ?? "opus"),
|
|
453
453
|
}).catch((e) => ({
|
|
454
454
|
resolved: false,
|
|
455
455
|
rootCause: `agent error: ${e && e.message}`,
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
// Domain workers embed the Stated-Claims snippet (§6.5) so agents tag load-bearing claims
|
|
18
18
|
// KNOWN|GUESSED. After domain workers, the Research phase iterates GUESSED entries through
|
|
19
19
|
// bin/gsd-t-research-gate.cjs: external → write §7 marker (status=uncited) → research agent
|
|
20
|
-
// (model:"
|
|
20
|
+
// (model:"opus") → cite → flip marker (status=cited). Internal → grep/Read; grep-empty →
|
|
21
21
|
// escalate to external research + cite + marker (§5.1 ambiguous escalation). Idempotent per §4.1
|
|
22
22
|
// (exact normalized claim-key match only). Wave is a pure composer and does NOT embed this wiring
|
|
23
23
|
// (M85 zero-model: invariant; research reaches wave via its execute sub-workflow).
|
|
@@ -142,7 +142,7 @@ async function grepForClaim(projectDir, claimText, phaseName) {
|
|
|
142
142
|
|
|
143
143
|
// M89 §1.1 — the AMBIGUOUS → LLM JUDGE. When the mechanical classifier finds no string
|
|
144
144
|
// fact (class:ambiguous), the LLM decides internal/external/uncertain in natural language.
|
|
145
|
-
// Bare model:"
|
|
145
|
+
// Bare model:"opus" (the research tier — NOT the ?? override form; "judge" is not a
|
|
146
146
|
// designated stage). Returns the verdict string; on any error → "uncertain" (fail toward
|
|
147
147
|
// research — never guess-internal). The caller treats external/uncertain as research.
|
|
148
148
|
const CLASSIFY_JUDGE_SCHEMA = {
|
|
@@ -165,7 +165,7 @@ async function judgeAmbiguous(claimText, phaseName) {
|
|
|
165
165
|
`Return JSON: { "verdict": "internal"|"external"|"uncertain", "reason": "<one line>" }.`,
|
|
166
166
|
`Do NOT modify files. Do NOT run web searches in THIS step — only decide the verdict.`,
|
|
167
167
|
].join("\n");
|
|
168
|
-
const r = await agent(prompt, { label: "classify-judge", model: "
|
|
168
|
+
const r = await agent(prompt, { label: "classify-judge", model: "opus", schema: CLASSIFY_JUDGE_SCHEMA, phase: phaseName })
|
|
169
169
|
.catch((e) => ({ verdict: "uncertain", reason: `judge error: ${e && e.message}` }));
|
|
170
170
|
return (r && r.verdict) || "uncertain";
|
|
171
171
|
}
|
|
@@ -422,14 +422,14 @@ if (allGuessedClaims.length === 0) {
|
|
|
422
422
|
continue;
|
|
423
423
|
}
|
|
424
424
|
|
|
425
|
-
// External-claim handler (§7 marker → research(
|
|
425
|
+
// External-claim handler (§7 marker → research(opus) → cite → flip). Closure so the
|
|
426
426
|
// ambiguous→judge path reuses it for an "external"/"uncertain" verdict.
|
|
427
427
|
const doExternal = async () => {
|
|
428
|
-
log(`Research: external claim → write §7 marker +
|
|
428
|
+
log(`Research: external claim → write §7 marker + opus research for "${claimKey.slice(0, 50)}"${artifactPath ? "" : " (FALLBACK artifact — worker reported no path)"}`);
|
|
429
429
|
// §7: write uncited marker at classify time (to the real OR fallback artifact — fail-CLOSED)
|
|
430
430
|
await writeUncitedMarker(externalArtifact, claimKey);
|
|
431
431
|
|
|
432
|
-
// §2: research agent — bare "
|
|
432
|
+
// §2: research agent — bare "opus" tier literal (NOT the ??-override form; contract §2)
|
|
433
433
|
const researchPrompt = [
|
|
434
434
|
`Read \`${projectDir}/templates/prompts/research-subagent.md\` for the full research protocol.`,
|
|
435
435
|
`Your task: verify this external guessed claim via live web sources.`,
|
|
@@ -440,7 +440,7 @@ if (allGuessedClaims.length === 0) {
|
|
|
440
440
|
].join("\n");
|
|
441
441
|
const researchResult = await agent(researchPrompt, {
|
|
442
442
|
label: "research",
|
|
443
|
-
model: "
|
|
443
|
+
model: "opus",
|
|
444
444
|
schema: RESEARCH_RESULT_SCHEMA,
|
|
445
445
|
phase: "Research",
|
|
446
446
|
}).catch((e) => ({ ok: false, gapKey: claimKey, reason: `research agent error: ${e && e.message}` }));
|
|
@@ -49,10 +49,10 @@
|
|
|
49
49
|
// iterates each [GUESSED:*] entry through the D1 classifier, which is a MECHANICAL
|
|
50
50
|
// STRING-FACT FILTER returning internal | external | AMBIGUOUS (v1.3.0). On
|
|
51
51
|
// class:external write a §7 status=uncited marker, run the research agent (bare
|
|
52
|
-
// model:"
|
|
52
|
+
// model:"opus"), write a ## Verified Facts (auto-research) block, flip the marker to
|
|
53
53
|
// status=cited. On class:internal: grep first; if grep empty, escalate to external
|
|
54
54
|
// (§5.1). On class:AMBIGUOUS (the regex has no string fact — semantic placement is the
|
|
55
|
-
// LLM's call, NOT regex's): run a small LLM JUDGE (model:"
|
|
55
|
+
// LLM's call, NOT regex's): run a small LLM JUDGE (model:"opus") that decides
|
|
56
56
|
// internal/external/uncertain in natural language. internal→grep; external→research;
|
|
57
57
|
// UNCERTAIN→treat as external→research (uncertain = verify, NEVER guess-internal — a
|
|
58
58
|
// silent miss is the one unacceptable outcome). Idempotent: an already-cited marker
|
|
@@ -83,7 +83,7 @@ const _args = (typeof args === "string") ? (() => { try { return JSON.parse(args
|
|
|
83
83
|
// (preserves byte-identical M85 behavior for callers that have not been updated yet).
|
|
84
84
|
// overrides values are CONCRETE model ids (resolver envelope); the bare literals below
|
|
85
85
|
// are tier ALIASES. The sandbox runtime accepts BOTH forms in model: — proven live for
|
|
86
|
-
// the
|
|
86
|
+
// the tier alias resolves to claude-opus-5 (Fable removed 2026-07-24).
|
|
87
87
|
const overrides = (_args.overrides && typeof _args.overrides === "object") ? _args.overrides : {};
|
|
88
88
|
const _CLI_ENVELOPE_SCHEMA = {
|
|
89
89
|
type: "object", required: ["ok", "exitCode"], additionalProperties: true,
|
|
@@ -486,7 +486,7 @@ async function runStatedClaimsPipeline(projectDir, phaseName, phaseResult, state
|
|
|
486
486
|
|
|
487
487
|
log(`m89: claim "${claimKey}" → class:${claimClass} route:${claimRoute} — ${envelope.reason || ""}`);
|
|
488
488
|
|
|
489
|
-
// External-claim handler (§7 marker → research(
|
|
489
|
+
// External-claim handler (§7 marker → research(opus) → cite → flip). Closure so the
|
|
490
490
|
// ambiguous→judge path can reuse it for an "external"/"uncertain" verdict.
|
|
491
491
|
const doExternal = async () => {
|
|
492
492
|
// §7: Write status=uncited marker into the (real OR fallback) artifact — ALWAYS written
|
|
@@ -504,7 +504,7 @@ async function runStatedClaimsPipeline(projectDir, phaseName, phaseResult, state
|
|
|
504
504
|
).catch((e) => ({ ok: false, error: String(e && e.message) }));
|
|
505
505
|
log(`m89: wrote status=uncited marker for claim "${claimKey}" into ${externalArtifact}${primaryArtifact ? "" : " (FALLBACK artifact — worker reported no path)"}`);
|
|
506
506
|
|
|
507
|
-
// §2: Run the research agent (bare model: "
|
|
507
|
+
// §2: Run the research agent (bare model: "opus" — not the ?? override form).
|
|
508
508
|
// The research agent reads its own protocol from research-subagent.md.
|
|
509
509
|
log(`m89: running research agent for external claim "${claimKey}"`);
|
|
510
510
|
const researchResult = await agent(
|
|
@@ -519,7 +519,7 @@ async function runStatedClaimsPipeline(projectDir, phaseName, phaseResult, state
|
|
|
519
519
|
`Use WebSearch + WebFetch to find authoritative sources. Emit a ## Verified Facts (auto-research) block per §3 format. On every fact line append the trailer \`key: ${claimKey}\` so the §7 gate matches by claim-key (Red Team MEDIUM #2).`,
|
|
520
520
|
`Return JSON per the schema with ok:true and citedBlock (the full markdown block) on success, or ok:false and reason on STAGE-FAILURE.`,
|
|
521
521
|
].join("\n"),
|
|
522
|
-
{ label: "research-stage", phase: "Phase", schema: RESEARCH_RESULT_SCHEMA, model: "
|
|
522
|
+
{ label: "research-stage", phase: "Phase", schema: RESEARCH_RESULT_SCHEMA, model: "opus" }
|
|
523
523
|
).catch((e) => ({ ok: false, gapKey: claimKey, reason: `research agent error: ${e && e.message}` }));
|
|
524
524
|
|
|
525
525
|
if (researchResult && researchResult.ok && researchResult.citedBlock) {
|
|
@@ -598,7 +598,7 @@ async function runStatedClaimsPipeline(projectDir, phaseName, phaseResult, state
|
|
|
598
598
|
await doInternal();
|
|
599
599
|
} else {
|
|
600
600
|
// class:AMBIGUOUS — the mechanical filter found NO string fact. Semantic placement
|
|
601
|
-
// is the LLM's call, NOT regex's. Run the LLM JUDGE (
|
|
601
|
+
// is the LLM's call, NOT regex's. Run the LLM JUDGE (opus). internal→grep;
|
|
602
602
|
// external→research; UNCERTAIN→research (uncertain = verify, NEVER guess-internal —
|
|
603
603
|
// a silent miss is the one unacceptable outcome). The classifier never guessed a
|
|
604
604
|
// default — it deferred, and now the LLM decides (and on doubt we research).
|
|
@@ -623,7 +623,7 @@ async function runStatedClaimsPipeline(projectDir, phaseName, phaseResult, state
|
|
|
623
623
|
`Return JSON: { "verdict": "internal" | "external" | "uncertain", "reason": "<one line>" }.`,
|
|
624
624
|
`Do NOT modify files. Do NOT run web searches in THIS step — only decide the verdict.`,
|
|
625
625
|
].join("\n"),
|
|
626
|
-
{ label: "classify-judge", phase: "Phase", schema: CLASSIFY_JUDGE_SCHEMA, model: "
|
|
626
|
+
{ label: "classify-judge", phase: "Phase", schema: CLASSIFY_JUDGE_SCHEMA, model: "opus" }
|
|
627
627
|
).catch((e) => ({ verdict: "uncertain", reason: `judge error: ${e && e.message} — failing toward research` }));
|
|
628
628
|
|
|
629
629
|
const verdict = (judge && judge.verdict) || "uncertain";
|
|
@@ -674,7 +674,7 @@ async function runSolutionSpaceProbe(projectDir, phaseName, { milestone, briefPa
|
|
|
674
674
|
// probe shifts UP — it competes over high-level APPROACHES (what/why/when, actors,
|
|
675
675
|
// one-breath thesis), NOT lower-altitude implementation detail. This changes WHAT
|
|
676
676
|
// the producers compete on, never WHO competes (producers stay opus, judge differs —
|
|
677
|
-
// M82 blindness
|
|
677
|
+
// M82 blindness now via fresh context) — probe + judge run opus (Fable removed 2026-07-24).
|
|
678
678
|
const atApproachAltitude = altitude === "high-level-approach";
|
|
679
679
|
const prompt = [
|
|
680
680
|
`You are the Solution-Space Probe for the ${phaseName} phase${milestone ? ` of ${milestone}` : ""}. Decide ONE thing: should this phase generate MULTIPLE competing candidates (then a judge picks the best), or is a single draft sufficient?`,
|
|
@@ -688,7 +688,7 @@ async function runSolutionSpaceProbe(projectDir, phaseName, { milestone, briefPa
|
|
|
688
688
|
`BIAS TOWARD COMPETING: if you are uncertain, or can name even two plausibly-different approaches, choose compete=true. A wasted competition costs ~3× this one phase; a missed-better-approach costs far more downstream (more pre-mortem blocks, more bugs, more verify cycles). Err on the side of generating options.`,
|
|
689
689
|
`Return JSON per the schema: { "compete": true|false, "reason": "<one sentence>", "approaches": ["<a>","<b>",...] }.`,
|
|
690
690
|
].filter(Boolean).join("\n");
|
|
691
|
-
const opts = { label: "solution-space-probe", schema: _PROBE_SCHEMA, model: overrides["solution-space-probe"] ?? "
|
|
691
|
+
const opts = { label: "solution-space-probe", schema: _PROBE_SCHEMA, model: overrides["solution-space-probe"] ?? "opus" };
|
|
692
692
|
if (phaseNameOpt) opts.phase = phaseNameOpt;
|
|
693
693
|
const r = await agent(prompt, opts).catch(() => null);
|
|
694
694
|
// Probe failure → bias toward competing (fail-toward-options, per the cost logic).
|
|
@@ -714,7 +714,7 @@ async function runPartitionProbe(projectDir, { milestone, briefPath, userInput,
|
|
|
714
714
|
`BIAS TOWARD COMPETING: if ≥3 files/areas are in play or you're unsure, choose compete=true — the file-disjointness oracle will objectively pick the most-parallelizable valid carving among the candidates, so competing is low-risk and high-reward.`,
|
|
715
715
|
`Return JSON per the schema.`,
|
|
716
716
|
].filter(Boolean).join("\n");
|
|
717
|
-
const opts = { label: "partition-probe", schema: _PROBE_SCHEMA, model: overrides["partition-probe"] ?? "
|
|
717
|
+
const opts = { label: "partition-probe", schema: _PROBE_SCHEMA, model: overrides["partition-probe"] ?? "opus" };
|
|
718
718
|
if (phaseNameOpt) opts.phase = phaseNameOpt;
|
|
719
719
|
const r = await agent(prompt, opts).catch(() => null);
|
|
720
720
|
if (!r || typeof r.compete !== "boolean") {
|
|
@@ -1099,7 +1099,7 @@ if (!competitionOn) {
|
|
|
1099
1099
|
`IMPORTANT: use the CANDIDATE LABEL (A, B, C…) shown above as the "id" in your scores.`,
|
|
1100
1100
|
].join("\n"),
|
|
1101
1101
|
{
|
|
1102
|
-
label: "judge:rubric", phase: "Judge", model: overrides["competition-judge"] ?? "
|
|
1102
|
+
label: "judge:rubric", phase: "Judge", model: overrides["competition-judge"] ?? "opus",
|
|
1103
1103
|
schema: {
|
|
1104
1104
|
type: "object", required: ["scores"], additionalProperties: true,
|
|
1105
1105
|
properties: { scores: { type: "array", items: { type: "object", additionalProperties: true } } },
|
|
@@ -1353,7 +1353,7 @@ if (phaseName === "plan" && result && result.status !== "failed") {
|
|
|
1353
1353
|
``,
|
|
1354
1354
|
`M89 ${STATED_CLAIMS_INSTRUCTION}`,
|
|
1355
1355
|
].join("\n"),
|
|
1356
|
-
{ label: "pre-mortem", phase: "Plan Hardening", schema: PRE_MORTEM_SCHEMA, model: overrides["pre-mortem"] ?? "
|
|
1356
|
+
{ label: "pre-mortem", phase: "Plan Hardening", schema: PRE_MORTEM_SCHEMA, model: overrides["pre-mortem"] ?? "opus" }
|
|
1357
1357
|
).catch((e) => ({ verdict: "BLOCK", findings: [{ severity: "HIGH", condition: `pre-mortem agent error: ${e && e.message}`, requiredTest: "re-run pre-mortem" }], notes: "agent-error" }));
|
|
1358
1358
|
|
|
1359
1359
|
result.preMortem = preMortem;
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
// The task agent embeds the Stated-Claims snippet (§6.5) and tags load-bearing claims KNOWN|GUESSED.
|
|
9
9
|
// After the Execute phase, the Research phase iterates GUESSED entries through
|
|
10
10
|
// bin/gsd-t-research-gate.cjs: external → write §7 marker (status=uncited) → research agent
|
|
11
|
-
// (model:"
|
|
11
|
+
// (model:"opus") → cite → flip marker (status=cited). Internal → grep/Read; grep-empty →
|
|
12
12
|
// escalate to external (§5.1). Idempotent per §4.1 (exact normalized claim-key match only).
|
|
13
13
|
//
|
|
14
14
|
// M90 §2 D4-T4: Architectural-trigger wiring (protocol-class path, R-ARCH-2 "everywhere" feed).
|
|
@@ -179,7 +179,7 @@ async function grepForClaim(projectDir, claimText, phaseName) {
|
|
|
179
179
|
return r || { found: false, matches: [] };
|
|
180
180
|
}
|
|
181
181
|
|
|
182
|
-
// M89 §1.1 — AMBIGUOUS → LLM JUDGE (bare model:"
|
|
182
|
+
// M89 §1.1 — AMBIGUOUS → LLM JUDGE (bare model:"opus"). internal/external/uncertain;
|
|
183
183
|
// uncertain → research (never guess-internal). On error → "uncertain" (fail toward research).
|
|
184
184
|
const CLASSIFY_JUDGE_SCHEMA = {
|
|
185
185
|
type: "object", required: ["verdict"], additionalProperties: true,
|
|
@@ -194,7 +194,7 @@ async function judgeAmbiguous(claimText, phaseName) {
|
|
|
194
194
|
`- "uncertain" = you cannot CONFIDENTLY place it internal — per M89 doctrine it is RESEARCHED, never guessed.`,
|
|
195
195
|
`Return JSON: { "verdict": "internal"|"external"|"uncertain", "reason": "<one line>" }. No file/web work in THIS step.`,
|
|
196
196
|
].join("\n");
|
|
197
|
-
const r = await agent(prompt, { label: "classify-judge", model: "
|
|
197
|
+
const r = await agent(prompt, { label: "classify-judge", model: "opus", schema: CLASSIFY_JUDGE_SCHEMA, phase: phaseName })
|
|
198
198
|
.catch((e) => ({ verdict: "uncertain", reason: `judge error: ${e && e.message}` }));
|
|
199
199
|
return (r && r.verdict) || "uncertain";
|
|
200
200
|
}
|
|
@@ -383,7 +383,7 @@ if (guessedClaims.length === 0) {
|
|
|
383
383
|
|
|
384
384
|
// External-claim handler closure (reused by the ambiguous→judge path).
|
|
385
385
|
const doExternal = async () => {
|
|
386
|
-
log(`Research: external → marker + research(
|
|
386
|
+
log(`Research: external → marker + research(opus) for "${claimKey.slice(0, 50)}"${artifactPath ? "" : " (FALLBACK artifact — no reported path)"}`);
|
|
387
387
|
// §7 write uncited marker to the real OR fallback artifact — ALWAYS (fail-CLOSED)
|
|
388
388
|
{
|
|
389
389
|
const m = uncitedMarker(claimKey);
|
|
@@ -394,7 +394,7 @@ if (guessedClaims.length === 0) {
|
|
|
394
394
|
).catch(() => {});
|
|
395
395
|
delete artifactCache[externalArtifact];
|
|
396
396
|
}
|
|
397
|
-
// §2 research agent — bare literal model: "
|
|
397
|
+
// §2 research agent — bare literal model: "opus"
|
|
398
398
|
const rr = await agent(
|
|
399
399
|
[
|
|
400
400
|
`Read \`${projectDir}/templates/prompts/research-subagent.md\` for the research protocol.`,
|
|
@@ -402,7 +402,7 @@ if (guessedClaims.length === 0) {
|
|
|
402
402
|
`Gap-key: "${claimKey}"`,
|
|
403
403
|
`Emit ## Verified Facts (auto-research) block with source URL + fetch date. Append the trailer \`key: ${claimKey}\` on every fact line so the §7 gate matches by claim-key (Red Team MEDIUM #2). Return StructuredOutput JSON.`,
|
|
404
404
|
].join("\n"),
|
|
405
|
-
{ label: "research", model: "
|
|
405
|
+
{ label: "research", model: "opus", schema: RESEARCH_RESULT_SCHEMA, phase: "Research" }
|
|
406
406
|
).catch((e) => ({ ok: false, gapKey: claimKey, reason: String(e && e.message) }));
|
|
407
407
|
|
|
408
408
|
if (rr && rr.ok && rr.citedBlock) {
|
|
@@ -56,7 +56,7 @@ const _args = (typeof args === "string") ? (() => { try { return JSON.parse(args
|
|
|
56
56
|
// Default to {} so the premium fallback literals apply when no invoker injects overrides.
|
|
57
57
|
// overrides values are CONCRETE model ids (resolver envelope); the bare literals below
|
|
58
58
|
// are tier ALIASES. The sandbox runtime accepts BOTH forms in model: — proven live for
|
|
59
|
-
// the
|
|
59
|
+
// the tier alias resolves to claude-opus-5 (Fable removed 2026-07-24).
|
|
60
60
|
const overrides = (_args.overrides && typeof _args.overrides === "object") ? _args.overrides : {};
|
|
61
61
|
const _CLI_ENVELOPE_SCHEMA = {
|
|
62
62
|
type: "object", required: ["ok", "exitCode"], additionalProperties: true,
|
|
@@ -771,7 +771,7 @@ const stages = [
|
|
|
771
771
|
`Verdict is FAIL if you found any CRITICAL or HIGH severity bug; GRUDGING-PASS`,
|
|
772
772
|
`if you searched exhaustively and found nothing. Return JSON per the schema.`,
|
|
773
773
|
].join("\n"),
|
|
774
|
-
{ label: "red-team", phase: "Orthogonal Triad", schema: RED_TEAM_SCHEMA, model: overrides["red-team"] ?? "
|
|
774
|
+
{ label: "red-team", phase: "Orthogonal Triad", schema: RED_TEAM_SCHEMA, model: overrides["red-team"] ?? "opus" }
|
|
775
775
|
),
|
|
776
776
|
|
|
777
777
|
// Stage C — QA (test execution + shallow-test detection + contract compliance)
|