@vostride/agent-qa-agent 0.2.3 → 0.2.4

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/dist/index.cjs CHANGED
@@ -48,7 +48,6 @@ __export(index_exports, {
48
48
  EvidenceBlobAbsentError: () => EvidenceBlobAbsentError,
49
49
  FunctionInputError: () => FunctionInputError,
50
50
  FunctionNotBoundError: () => FunctionNotBoundError,
51
- Gate1ReceiptNotPersistedError: () => Gate1ReceiptNotPersistedError,
52
51
  IncompleteJobKindDeclarationError: () => IncompleteJobKindDeclarationError,
53
52
  InconsistentJobKindDeclarationError: () => InconsistentJobKindDeclarationError,
54
53
  JobCancellationNotRequestedError: () => JobCancellationNotRequestedError,
@@ -62,8 +61,6 @@ __export(index_exports, {
62
61
  MARK_UNHANDLED_CEILING: () => MARK_UNHANDLED_CEILING,
63
62
  MissingIdempotencyKeyError: () => MissingIdempotencyKeyError,
64
63
  OPTIONAL_FUNCTION_DEP_KEYS: () => OPTIONAL_FUNCTION_DEP_KEYS,
65
- PROPOSE_DEFAULT_MAX_GATE1_PER_JOB: () => PROPOSE_DEFAULT_MAX_GATE1_PER_JOB,
66
- PROPOSE_GATE1_ALLOWANCE_CHECKPOINT: () => PROPOSE_GATE1_ALLOWANCE_CHECKPOINT,
67
64
  QUARANTINE_ADD_FUNCTION_ID: () => QUARANTINE_ADD_FUNCTION_ID,
68
65
  QUARANTINE_LIST_FUNCTION_ID: () => QUARANTINE_LIST_FUNCTION_ID,
69
66
  QUARANTINE_RELEASE_FUNCTION_ID: () => QUARANTINE_RELEASE_FUNCTION_ID,
@@ -123,7 +120,6 @@ __export(index_exports, {
123
120
  liveUrlOf: () => liveUrlOf,
124
121
  maybeCompact: () => maybeCompact,
125
122
  mintLiveUrlToken: () => mintLiveUrlToken,
126
- parseProposeGate1Allowance: () => parseProposeGate1Allowance,
127
123
  parseScenario: () => parseScenario,
128
124
  projectAuthoringFunnel: () => projectAuthoringFunnel,
129
125
  projectPlannerTools: () => projectPlannerTools,
@@ -206,17 +202,7 @@ var FunctionNotBoundError = class extends Error {
206
202
  var AGENT_ASK_FUNCTION_ID = "agent.ask";
207
203
  var agentAskSpec = {
208
204
  id: AGENT_ASK_FUNCTION_ID,
209
- // THE SUMMARY SAYS "ENTRY POINT", and that wording is a fix rather than a flourish (392-09, from
210
- // the first live gate run). D-07 projects every registry op 1:1 into the planner's tool set, so
211
- // this op is a tool the planner is offered WHILE IT IS INSIDE ONE OF ITS OWN TURNS. Described as
212
- // "run one conversational turn", it read to the model as the natural home for any conversational
213
- // request: a plain request to list runs was planned as `agent.ask` twice out of two live runs,
214
- // and the recursive turn then failed — so a person asking for a capability in prose got a failed
215
- // turn instead of the capability. The repair is DESCRIPTION, not exclusion. Hiding a tool would
216
- // break the always-send-all law and D-07's registry projection, and it would be the wrong
217
- // diagnosis anyway: the tool was not misclassified, it was misdescribed. Every consumer of this
218
- // string — the catalogue, `fn --list`, 396's MCP listing, the planner — is better served by the
219
- // sentence that says what the op is FOR.
205
+ // Worded as an entry point, because a summary saying "one turn" made the planner recurse into it.
220
206
  summary: "The chat entry point: begin ONE new conversational turn from outside a conversation. Surfaces (a REPL, the ask verb, an MCP client) call this to START a turn \u2014 it is not a way to carry out a request while a turn is already running. It routes the utterance, executes what it resolves to, and answers with per-clause receipts.",
221
207
  resultKind: "unary",
222
208
  // Bound where a composition assembles a turn engine. A host with no engine lists this
@@ -225,34 +211,9 @@ var agentAskSpec = {
225
211
  boundThrough: "chatTurn",
226
212
  input: import_agent_qa_schema.AgentAskInputSchema,
227
213
  output: import_agent_qa_schema.AgentAskResultSchema,
228
- // `readOnly: false`, and the honesty matters more here than on any other op in the catalogue: a
229
- // turn is a variable-reach capability, so describing it as a read would let a risk ladder treat
230
- // the door to every write verb as the cheapest thing in the registry. (2026-10-01, 432-26: the
231
- // descriptor is a classification; no gate reads it to ask or deny.)
214
+ // Not read-only: a turn can reach any write verb.
232
215
  risk: { name: `fn:${AGENT_ASK_FUNCTION_ID}`, recognized: true, readOnly: false },
233
- /**
234
- * A TURN's own report of how it went (2026-08-20, Phase 399.1 D-01/D-02/D-12).
235
- *
236
- * A TURN IS A COMPOSITION, SO ITS VERDICT IS A FOLD OF ITS CLAUSES' VERDICTS. This used to fold
237
- * the turn STATUS alone, on the argument that the per-clause verdicts were already receipts and
238
- * reading them here would be a second opinion. That argument is the recorded belief that produced
239
- * gap 1: a turn whose only clause was REFUSED by a credential guardrail reported `executed` one
240
- * composition layer up, and the person reading the outer line was told a blocked mutation had been
241
- * carried out. The receipts are not a second opinion about the turn — they ARE the turn, and the
242
- * status is a summary of them. Success is the one claim a fold may never default to (D-03's
243
- * asymmetry): where the clauses do not support it, the outer word must say what they do support.
244
- *
245
- * `fail_closed` IS `failed` AND NOT `refused`. D-02 minted `refused` for a GUARDRAIL declining an
246
- * op; a fail-closed turn is the ENGINE abandoning the clauses after one of them broke, which is
247
- * an operation that did not complete. Reporting it `refused` would tell a person a control
248
- * declined their request when what happened is that something went wrong.
249
- *
250
- * AND THERE IS DELIBERATELY NO `failed` SCAN OVER THE RECEIPTS HERE (D-12). Post-399.1-09 the
251
- * engine derives its aggregate from the same vocabulary, so it can no longer answer `completed`
252
- * over a `failed` receipt; a second mechanism second-guessing the first is the redundant-mechanism
253
- * failure mode this project has already paid for, and it would hide a regression in the engine
254
- * rather than surface it.
255
- */
216
+ // A turn's verdict folds its clauses' receipts, and `fail_closed` is `failed`, never `refused`.
256
217
  classify(output) {
257
218
  switch (output.status) {
258
219
  case "completed": {
@@ -626,73 +587,17 @@ function misdirectionPathSteps(verdict, parts, test) {
626
587
  if (failing !== void 0) indexes.add(failing.stepIndex);
627
588
  return test.steps.filter((step) => indexes.has(step.stepIndex));
628
589
  }
629
- function misdirectionValidationOptions(evidence, rootPosture) {
630
- return evidence === void 0 ? {} : { gatedProducerEvidence: true, rootPosture };
631
- }
632
- function exposureKey(stepIndex, recordId) {
633
- return `${String(stepIndex)}${recordId}`;
634
- }
635
- function summarizeCrossCheck(rows, sites) {
636
- if (rows.some((row) => row.crossCheck === "flipped")) return "flipped";
637
- if (rows.some((row) => row.crossCheck === "inconclusive")) return "inconclusive";
638
- const covered = new Set(rows.map((row) => exposureKey(row.stepIndex, String(row.recordId))));
639
- const complete = sites.every(
640
- (site) => covered.has(exposureKey(site.stepIndex, String(site.recordId)))
641
- );
642
- return complete && rows.every((row) => row.crossCheck === "held") ? "held" : "not-run";
643
- }
644
- function postureReason(posture) {
645
- if (posture === "no-eval-root") {
646
- return "no evaluation root existed, so no record on this path could be cross-checked";
647
- }
648
- if (posture === "broken-eval-root") {
649
- return "the evaluation root could not be consulted, so no record on this path was cross-checked";
650
- }
651
- return void 0;
652
- }
653
- function stampVerdictMisdirectionEvidence(input) {
654
- const { verdict, parts, test, evidence, rootPosture } = input;
655
- if (evidence === void 0 || test === void 0) return verdict;
590
+ function stampVerdictMemoryOnPath(input) {
591
+ const { verdict, parts, test } = input;
592
+ if (test === void 0) return verdict;
656
593
  const steps = misdirectionPathSteps(verdict, parts, test);
657
- const sites = (0, import_agent_qa_schema4.deriveMemoryOnPathSites)(steps);
658
- if (sites.length === 0) {
659
- if (verdict.memoryOnPath === void 0 && verdict.misdirectionRuledOut === void 0) {
660
- return verdict;
661
- }
594
+ if ((0, import_agent_qa_schema4.deriveMemoryOnPathSites)(steps).length === 0) {
595
+ if (verdict.memoryOnPath === void 0) return verdict;
662
596
  const bare = { ...verdict };
663
597
  delete bare.memoryOnPath;
664
- delete bare.misdirectionRuledOut;
665
598
  return bare;
666
599
  }
667
- const keys = new Set(sites.map((site) => exposureKey(site.stepIndex, String(site.recordId))));
668
- const rows = evidence.filter(
669
- (row) => row.perTest === verdict.perTest && keys.has(exposureKey(row.stepIndex, String(row.recordId)))
670
- );
671
- const reason = postureReason(rootPosture);
672
- const block = {
673
- crossCheck: summarizeCrossCheck(rows, sites),
674
- results: rows,
675
- ...reason === void 0 ? {} : { reason },
676
- // D-19: the ONE exemption is ABSENCE, and only absence. A broken root publishes the same
677
- // empty ledger and earns nothing. The `rows.length === 0` clause is not belt-and-braces: the
678
- // validator answers on the backing BEFORE it reads the rows, so a marker beside a real ledger
679
- // would skip the ledger entirely.
680
- ...rootPosture === "no-eval-root" && rows.length === 0 ? { backing: "declared-only" } : {}
681
- };
682
- return {
683
- ...verdict,
684
- memoryOnPath: (0, import_agent_qa_schema4.deriveMemoryOnPath)(steps),
685
- misdirectionRuledOut: block
686
- };
687
- }
688
- function flippedRecordsOf(verdict) {
689
- const rows = verdict.misdirectionRuledOut?.results ?? [];
690
- const records = [];
691
- for (const row of rows) {
692
- if (row.crossCheck !== "flipped") continue;
693
- if (!records.includes(String(row.recordId))) records.push(String(row.recordId));
694
- }
695
- return records;
600
+ return { ...verdict, memoryOnPath: (0, import_agent_qa_schema4.deriveMemoryOnPath)(steps) };
696
601
  }
697
602
  var GroundingQuoteWire = import_zod2.z.union([
698
603
  import_zod2.z.object({ stepIndex: import_zod2.z.number(), quote: import_zod2.z.string() }),
@@ -809,23 +714,7 @@ function historyLine(pack, history) {
809
714
  const window = record.lastOutcomes.map((entry2) => `build ${entry2.buildOrdinal}: ${entry2.passed ? "passed" : "failed"}`).join(", ");
810
715
  return `- test ${pack.testIndex} (${pack.testName}): ${record.passes} passes, ${record.failures} failures, ${record.heals} heals, flakeCount ${record.flakeCount}` + (window === "" ? "" : `; recent: ${window}`);
811
716
  }
812
- function crossCheckLine(row) {
813
- const samples = row.samples === void 0 ? "" : `; k=${String(row.samples.k)}`;
814
- const reason = row.reason === void 0 ? "" : `; ${row.reason}`;
815
- return `- test ${String(row.perTest)}, step ${String(row.stepIndex)}, record ${String(row.recordId)}: ${row.crossCheck}${reason}${samples}`;
816
- }
817
- function crossCheckTier(packs, evidence) {
818
- if (evidence === void 0) return [];
819
- const analyzed = new Set(packs.map((pack) => pack.testIndex));
820
- const rows = evidence.filter((row) => analyzed.has(row.perTest));
821
- return [
822
- {
823
- title: "Memory misdirection cross-check (reasoning input)",
824
- body: "The deterministic removal cross-check already ran for the low-trust records this run served on the failing paths below. `flipped` means removing the record changed the outcome \u2014 the served memory is implicated. `held` means it did not. `inconclusive` and `not-run` mean nothing was established:\n" + (rows.length === 0 ? "- no record on an analyzed test\u2019s failing path was cross-checked" : rows.map(crossCheckLine).join("\n"))
825
- }
826
- ];
827
- }
828
- function contextTier(handoff, packs, history, evidence) {
717
+ function contextTier(handoff, packs, history) {
829
718
  return [
830
719
  {
831
720
  title: "Run facts",
@@ -834,8 +723,7 @@ function contextTier(handoff, packs, history, evidence) {
834
723
  {
835
724
  title: "Failure history (reasoning input)",
836
725
  body: "Recorded outcome history per analyzed test \u2014 evidence for flake-vs-app_bug reasoning, not prose to restate:\n" + packs.map((pack) => historyLine(pack, history)).join("\n")
837
- },
838
- ...crossCheckTier(packs, evidence)
726
+ }
839
727
  ];
840
728
  }
841
729
  function volatileTier(packs) {
@@ -897,8 +785,7 @@ function evaluateAttempt(text, pending, input) {
897
785
  const reason = "the output was not one parseable JSON object matching the contract: " + (error instanceof Error ? error.message : String(error));
898
786
  return {
899
787
  accepted: /* @__PURE__ */ new Map(),
900
- rejects: [...pending].map((perTest) => ({ perTest, reason })),
901
- citedByTest: /* @__PURE__ */ new Map()
788
+ rejects: [...pending].map((perTest) => ({ perTest, reason }))
902
789
  };
903
790
  }
904
791
  const byTest = /* @__PURE__ */ new Map();
@@ -908,9 +795,7 @@ function evaluateAttempt(text, pending, input) {
908
795
  }
909
796
  const rejects = [];
910
797
  const candidates = /* @__PURE__ */ new Map();
911
- const citedByTest = /* @__PURE__ */ new Map();
912
798
  const testsByIndex = new Map(handoff.tests.map((test) => [test.testIndex, test]));
913
- const rootPosture = input.rootPosture ?? "eval-root";
914
799
  for (const perTest of pending) {
915
800
  const entry2 = byTest.get(perTest);
916
801
  if (entry2 === void 0) {
@@ -918,15 +803,12 @@ function evaluateAttempt(text, pending, input) {
918
803
  continue;
919
804
  }
920
805
  const pair = candidateOf(entry2);
921
- citedByTest.set(perTest, [...pair.verdict.evidence.citedSteps]);
922
806
  candidates.set(perTest, {
923
807
  ...pair,
924
- verdict: stampVerdictMisdirectionEvidence({
808
+ verdict: stampVerdictMemoryOnPath({
925
809
  verdict: pair.verdict,
926
810
  parts: pair.parts,
927
- test: testsByIndex.get(perTest),
928
- evidence: input.misdirectionEvidence,
929
- rootPosture
811
+ test: testsByIndex.get(perTest)
930
812
  })
931
813
  });
932
814
  }
@@ -939,8 +821,7 @@ function evaluateAttempt(text, pending, input) {
939
821
  verdicts: ordered.map((pair) => pair.verdict),
940
822
  parts: ordered.map((pair) => pair.parts)
941
823
  },
942
- handoff,
943
- misdirectionValidationOptions(input.misdirectionEvidence, rootPosture)
824
+ handoff
944
825
  );
945
826
  if (!validation.ok) {
946
827
  const rejectedTests = new Set(validation.rejects.map((reject) => reject.perTest));
@@ -948,7 +829,7 @@ function evaluateAttempt(text, pending, input) {
948
829
  for (const perTest of rejectedTests) candidates.delete(perTest);
949
830
  }
950
831
  }
951
- return { accepted: candidates, rejects, citedByTest };
832
+ return { accepted: candidates, rejects };
952
833
  }
953
834
  function repairFeedback(rejects) {
954
835
  return [
@@ -974,7 +855,7 @@ async function authorRunAnalysis(model, input) {
974
855
  const baseRequest = buildTieredPrompt({
975
856
  agent_context: input.agentContext ?? "analyze-run: authoring root-cause verdicts and sentence parts for one completed run",
976
857
  stable: stableTier(),
977
- context: contextTier(input.handoff, compacted.packs, input.history, input.misdirectionEvidence),
858
+ context: contextTier(input.handoff, compacted.packs, input.history),
978
859
  volatile: volatileTier(compacted.packs)
979
860
  });
980
861
  const images = collectImages(compacted.packs, input.readEvidenceBlob, model.vision === true);
@@ -982,7 +863,6 @@ async function authorRunAnalysis(model, input) {
982
863
  const accepted = /* @__PURE__ */ new Map();
983
864
  let pending = new Set(analyzed);
984
865
  let lastRejects = [];
985
- const lastCited = /* @__PURE__ */ new Map();
986
866
  let modelCalls = 0;
987
867
  for (let attempt = 0; attempt <= AUTHOR_REPAIR_CAP && pending.size > 0; attempt += 1) {
988
868
  const attemptRequest = attempt === 0 ? request : { ...request, prompt: `${request.prompt}
@@ -991,7 +871,6 @@ ${repairFeedback(lastRejects)}` };
991
871
  const output = await model.generate(attemptRequest);
992
872
  modelCalls += 1;
993
873
  const outcome = evaluateAttempt(output.text, pending, input);
994
- for (const [perTest, cited] of outcome.citedByTest) lastCited.set(perTest, cited);
995
874
  for (const [perTest, pair] of outcome.accepted) accepted.set(perTest, pair);
996
875
  pending = new Set([...pending].filter((perTest) => !accepted.has(perTest)));
997
876
  lastRejects = outcome.rejects;
@@ -1010,7 +889,6 @@ ${repairFeedback(lastRejects)}` };
1010
889
  estimatedTokens: compacted.estimatedTokens
1011
890
  },
1012
891
  degradedTests: analyzed.filter((testIndex) => !accepted.has(testIndex)),
1013
- degradedPaths: analyzed.filter((testIndex) => !accepted.has(testIndex)).map((perTest) => ({ perTest, citedSteps: lastCited.get(perTest) ?? [] })),
1014
892
  usage: {
1015
893
  modelCalls,
1016
894
  repairCalls: Math.max(0, modelCalls - 1),
@@ -1023,22 +901,13 @@ ${repairFeedback(lastRejects)}` };
1023
901
  var import_agent_qa_schema5 = require("@vostride/agent-qa-schema");
1024
902
  var POST_RUN_CHAIN_TERMINAL_KINDS = Object.freeze([
1025
903
  "analyze-run",
1026
- "curate-memory",
1027
- "propose-improvements"
904
+ "curate-memory"
1028
905
  ]);
1029
906
  function chainJobIdsForRun(runId, idSource) {
1030
907
  const analyzeRun = idSource.jobIdFor("analyze-run", runId);
1031
- const curateMemory = idSource.jobIdFor(
1032
- "curate-memory",
1033
- `${String(analyzeRun)}->curate-memory`
1034
- );
1035
908
  return {
1036
909
  analyzeRun,
1037
- curateMemory,
1038
- proposeImprovements: idSource.jobIdFor(
1039
- "propose-improvements",
1040
- `${String(curateMemory)}->propose-improvements`
1041
- )
910
+ curateMemory: idSource.jobIdFor("curate-memory", `${String(analyzeRun)}->curate-memory`)
1042
911
  };
1043
912
  }
1044
913
  var UNKNOWN_VERDICTS_MARKER = "unknown";
@@ -1049,8 +918,7 @@ function isCount(value) {
1049
918
  return typeof value === "number" && Number.isInteger(value) && value >= 0;
1050
919
  }
1051
920
  function readVerdictSummary(payload) {
1052
- const direct = asRecord(payload.verdictSummary);
1053
- const summary = isCount(direct.total) ? direct : asRecord(asRecord(payload.upstream).verdictSummary);
921
+ const summary = asRecord(payload.verdictSummary);
1054
922
  const byClassSource = asRecord(summary.byClass);
1055
923
  if (!isCount(summary.total)) return { total: 0, byClass: {} };
1056
924
  const byClass = {};
@@ -1061,11 +929,9 @@ function readVerdictSummary(payload) {
1061
929
  }
1062
930
  function buildChainTerminalNotification(input) {
1063
931
  const payload = asRecord(input.payload);
1064
- const upstream = asRecord(payload.upstream);
1065
- const analysisFailed = payload.verdicts === UNKNOWN_VERDICTS_MARKER || asRecord(payload.upstream).analysisStatus === "failed" || input.finishingKind === "analyze-run" && input.finished === "failed";
1066
- const proposalTerminal = input.finishingKind === "propose-improvements";
1067
- const committed = proposalTerminal ? asRecord(upstream.curation) : asRecord(input.publishedValues.get("bundle-committed"));
1068
- const curationSucceeded = proposalTerminal || input.finishingKind === "curate-memory" && input.finished === "done";
932
+ const analysisFailed = payload.verdicts === UNKNOWN_VERDICTS_MARKER || input.finishingKind === "analyze-run" && input.finished === "failed";
933
+ const committed = asRecord(input.publishedValues.get("bundle-committed"));
934
+ const curationSucceeded = input.finishingKind === "curate-memory" && input.finished === "done";
1069
935
  const snapshot = curationSucceeded && committed.curationSnapshot !== void 0 ? import_agent_qa_schema5.CurationSnapshotSchema.safeParse(committed.curationSnapshot) : void 0;
1070
936
  if (snapshot !== void 0 && !snapshot.success) {
1071
937
  throw new import_agent_qa_schema5.RunNotificationSchemaError("its curation snapshot is invalid");
@@ -1078,22 +944,14 @@ function buildChainTerminalNotification(input) {
1078
944
  ...isCount(committed.deprecated) ? { deprecated: committed.deprecated } : {},
1079
945
  ...snapshot?.success ? { curationSnapshot: snapshot.data } : {}
1080
946
  } : { status: "failed" };
1081
- const authored = asRecord(input.publishedValues.get("proposals-authored"));
1082
- const proposalsSucceeded = proposalTerminal && input.finished === "done";
1083
- const proposals = !proposalTerminal ? void 0 : proposalsSucceeded ? {
1084
- status: "done",
1085
- ...isCount(authored.proposed) ? { proposed: authored.proposed } : {},
1086
- ...isCount(authored.skipped) ? { skipped: authored.skipped } : {}
1087
- } : { status: "failed" };
1088
947
  return {
1089
948
  schemaVersion: import_agent_qa_schema5.CURRENT_RUN_NOTIFICATION_SCHEMA_VERSION,
1090
949
  runId: input.runId,
1091
- outcome: analysisFailed || !curationSucceeded || proposalTerminal && !proposalsSucceeded ? "failed" : "done",
950
+ outcome: analysisFailed || !curationSucceeded ? "failed" : "done",
1092
951
  verdictSummary: readVerdictSummary(payload),
1093
952
  stages: {
1094
953
  analysis: { status: analysisFailed ? "failed" : "done" },
1095
- curation,
1096
- ...proposals === void 0 ? {} : { proposals }
954
+ curation
1097
955
  }
1098
956
  };
1099
957
  }
@@ -1351,7 +1209,6 @@ function analyzeRunFallback(input) {
1351
1209
  );
1352
1210
  }
1353
1211
  var ANALYZE_RUN_SUCCESSORS = ["curate-memory"];
1354
- var CURATE_MEMORY_SUCCESSORS = ["propose-improvements"];
1355
1212
  function asRecord2(value) {
1356
1213
  return value !== null && typeof value === "object" && !Array.isArray(value) ? value : {};
1357
1214
  }
@@ -1366,51 +1223,9 @@ function readAnalyzeRunPayload(value) {
1366
1223
  handoffSchemaVersion: record.handoffSchemaVersion,
1367
1224
  executionContext: typeof record.executionContext === "string" ? record.executionContext : void 0,
1368
1225
  ...record.gateRun === true ? { gateRun: true } : {},
1369
- ...record.excludedFromOutcomes === true ? { excludedFromOutcomes: true } : {},
1370
- ...readCarriedMisdirectionEvidence(record.misdirectionEvidence)
1226
+ ...record.excludedFromOutcomes === true ? { excludedFromOutcomes: true } : {}
1371
1227
  };
1372
1228
  }
1373
- function readCarriedMisdirectionEvidence(value) {
1374
- if (value === void 0) return {};
1375
- if (!Array.isArray(value)) return { misdirectionEvidenceUnreadable: true };
1376
- const rows = [];
1377
- for (const candidate of value) {
1378
- const parsed = import_agent_qa_schema6.MisdirectionRecordResultSchema.safeParse(candidate);
1379
- if (!parsed.success) return { misdirectionEvidenceUnreadable: true };
1380
- rows.push(parsed.data);
1381
- }
1382
- return { misdirectionEvidence: rows };
1383
- }
1384
- function readProposeImprovementsPayload(value) {
1385
- const record = asRecord2(value);
1386
- if (typeof record.runId !== "string" || record.runId === "") return void 0;
1387
- const upstreamSource = asRecord2(record.upstream);
1388
- const curationSource = asRecord2(upstreamSource.curation);
1389
- const summary = asRecord2(upstreamSource.verdictSummary);
1390
- const snapshot = curationSource.curationSnapshot === void 0 ? void 0 : import_agent_qa_schema6.CurationSnapshotSchema.safeParse(curationSource.curationSnapshot);
1391
- if (snapshot !== void 0 && !snapshot.success) {
1392
- throw new import_agent_qa_schema6.RunNotificationSchemaError("its curation snapshot is invalid");
1393
- }
1394
- const curation = {
1395
- ...isCount2(curationSource.curated) ? { curated: curationSource.curated } : {},
1396
- ...isCount2(curationSource.deprecated) ? { deprecated: curationSource.deprecated } : {},
1397
- ...curationSource.complete === true ? { complete: true } : {},
1398
- ...snapshot?.success ? { curationSnapshot: snapshot.data } : {}
1399
- };
1400
- return {
1401
- runId: record.runId,
1402
- executionContext: typeof record.executionContext === "string" ? record.executionContext : void 0,
1403
- candidateIds: Array.isArray(record.candidateIds) ? record.candidateIds.filter((id) => typeof id === "string") : [],
1404
- upstream: {
1405
- ...isCount2(summary.total) ? { verdictSummary: summary } : {},
1406
- ...upstreamSource.analysisStatus === "done" || upstreamSource.analysisStatus === "failed" ? { analysisStatus: upstreamSource.analysisStatus } : {},
1407
- ...Object.keys(curation).length === 0 ? {} : { curation }
1408
- }
1409
- };
1410
- }
1411
- function isCount2(value) {
1412
- return typeof value === "number" && Number.isInteger(value) && value >= 0;
1413
- }
1414
1229
  function permanently(reason) {
1415
1230
  return { status: "permanent", reason };
1416
1231
  }
@@ -1458,97 +1273,6 @@ function templateSentenceParts(verdict, handoff) {
1458
1273
  links: []
1459
1274
  };
1460
1275
  }
1461
- function readMisdirectionPosture(capabilities, runId) {
1462
- try {
1463
- return capabilities.readMisdirectionRootPosture?.(runId) ?? "eval-root";
1464
- } catch {
1465
- return "eval-root";
1466
- }
1467
- }
1468
- function honestUnknownFloor(refused2, test) {
1469
- const floor = (0, import_agent_qa_runner.deterministicVerdict)(
1470
- "unknown",
1471
- import_agent_qa_runner.UNKNOWN_SIGNAL_RATIONALE,
1472
- capturedStepsOnly(refused2.evidence.citedSteps, test),
1473
- refused2.perTest
1474
- );
1475
- return { ...floor, memoryMisdirectionRuledOut: false };
1476
- }
1477
- function capturedStepsOnly(cited, test) {
1478
- if (test === void 0) return [];
1479
- const captured = new Set(test.steps.map((step) => step.stepIndex));
1480
- return test.steps.map((step) => step.stepIndex).filter((stepIndex) => captured.has(stepIndex) && cited.includes(stepIndex));
1481
- }
1482
- function widenRefusedFloorPaths(verdicts, degradedPaths, handoff) {
1483
- if (degradedPaths.length === 0) return [...verdicts];
1484
- const testsByIndex = new Map(handoff.tests.map((test) => [test.testIndex, test]));
1485
- return verdicts.map((verdict) => {
1486
- const refused2 = degradedPaths.find((path) => path.perTest === verdict.perTest);
1487
- if (refused2 === void 0 || verdict.class !== "unknown") return verdict;
1488
- const widened = capturedStepsOnly(
1489
- [...verdict.evidence.citedSteps, ...refused2.citedSteps],
1490
- testsByIndex.get(verdict.perTest)
1491
- );
1492
- if (widened.length === verdict.evidence.citedSteps.length) return verdict;
1493
- return {
1494
- ...verdict,
1495
- evidence: { ...verdict.evidence, citedSteps: widened }
1496
- };
1497
- });
1498
- }
1499
- function enforceMisdirectionFloor(input) {
1500
- const { handoff, runId, evidence, rootPosture, partsOf } = input;
1501
- const testsByIndex = new Map(handoff.tests.map((test) => [test.testIndex, test]));
1502
- const stampAll = (verdicts, parts2) => verdicts.map(
1503
- (verdict, index) => stampVerdictMisdirectionEvidence({
1504
- verdict,
1505
- parts: parts2[index],
1506
- test: testsByIndex.get(verdict.perTest),
1507
- evidence,
1508
- rootPosture
1509
- })
1510
- );
1511
- const parts = partsOf(input.verdicts);
1512
- if (evidence === void 0) return { verdicts: [...input.verdicts], parts };
1513
- const stamped = stampAll(input.verdicts, parts);
1514
- const artifact = {
1515
- schemaVersion: import_agent_qa_schema6.CURRENT_ANALYSIS_SCHEMA_VERSION,
1516
- runId,
1517
- verdicts: stamped,
1518
- parts
1519
- };
1520
- const gated = (0, import_agent_qa_schema6.validateAnalysisAgainstHandoff)(
1521
- artifact,
1522
- handoff,
1523
- misdirectionValidationOptions(evidence, rootPosture)
1524
- );
1525
- let downgraded = stamped;
1526
- if (!gated.ok) {
1527
- const historical = (0, import_agent_qa_schema6.validateAnalysisAgainstHandoff)(artifact, handoff);
1528
- const preExisting = new Set(historical.ok ? [] : historical.rejects.map((r) => r.perTest));
1529
- const newlyRefused = new Set(
1530
- gated.rejects.map((reject) => reject.perTest).filter((perTest) => !preExisting.has(perTest))
1531
- );
1532
- if (newlyRefused.size > 0) {
1533
- downgraded = input.verdicts.map(
1534
- (verdict) => newlyRefused.has(verdict.perTest) ? honestUnknownFloor(verdict, testsByIndex.get(verdict.perTest)) : verdict
1535
- );
1536
- }
1537
- }
1538
- const finalParts = partsOf(downgraded);
1539
- const finalVerdicts = stampAll(downgraded, finalParts).map(withCausalAttribution);
1540
- return { verdicts: finalVerdicts, parts: finalParts };
1541
- }
1542
- function withCausalAttribution(verdict) {
1543
- if (verdict.class !== "unknown") return verdict;
1544
- const flipped = flippedRecordsOf(verdict);
1545
- if (flipped.length === 0) return verdict;
1546
- return {
1547
- ...verdict,
1548
- memoryMisdirectionRuledOut: false,
1549
- attribution: { records: flipped.map((record) => (0, import_agent_qa_schema6.asRecordId)(record)), anchors: [] }
1550
- };
1551
- }
1552
1276
  function realAnalyzeRunHandler(capabilities) {
1553
1277
  return async (context) => {
1554
1278
  const payload = readAnalyzeRunPayload(context.payload);
@@ -1575,26 +1299,9 @@ function realAnalyzeRunHandler(capabilities) {
1575
1299
  `the handoff for ${payload.runId} no longer digests to the bytes this job was enqueued against, so analysing it would answer about a different run`
1576
1300
  );
1577
1301
  }
1578
- if (payload.misdirectionEvidenceUnreadable === true) {
1579
- return permanently(
1580
- `the analyze-run payload for ${payload.runId} carries a circularity ledger this build cannot read, and a claim that cannot be checked is not a claim that may be ignored`
1581
- );
1582
- }
1583
- const publishedEvidence = handoff.misdirectionEvidence;
1584
- if (payload.misdirectionEvidence !== void 0 && (publishedEvidence === void 0 || (0, import_agent_qa_schema6.canonicalJson)(payload.misdirectionEvidence) !== (0, import_agent_qa_schema6.canonicalJson)(publishedEvidence))) {
1585
- return permanently(
1586
- `the analyze-run payload for ${payload.runId} carries circularity evidence that is not the evidence in the analysed handoff bytes; the digest covers the handoff, so a copy that disagrees with it is not about these bytes`
1587
- );
1588
- }
1589
- const rootPosture = readMisdirectionPosture(capabilities, payload.runId);
1590
1302
  const authored = await context.recordLlmAuthorship(
1591
1303
  "verdicts-authored",
1592
- // The full author (389 plan 04): the model capability arrives ONLY as this
1593
- // callback's argument. Unknown floor members are authored through
1594
- // `authorRunAnalysis` — one whole-run call, one repair, per-test degrade — and
1595
- // everything else passes through byte-identical; a floor with no unknown members
1596
- // (or no failures at all) reaches no model. Signature, artifact-write position and
1597
- // returned shape are final from plan 01.
1304
+ // The model arrives only as this argument; a floor with no unknown members reaches no model.
1598
1305
  async (model) => {
1599
1306
  const floor = projectHandoffVerdicts(handoff);
1600
1307
  const limitStopped = new Set(
@@ -1617,37 +1324,33 @@ function realAnalyzeRunHandler(capabilities) {
1617
1324
  floor,
1618
1325
  packs: buildEvidencePacks(handoff, unknownTests, history),
1619
1326
  history,
1620
- // The ledger reaches the author as DATA and the gate as AUTHORITY (D-20). Absent, it
1621
- // does neither: the request is byte-identical to the pre-422 one and the author's own
1622
- // validation runs under the historical options.
1623
- ...publishedEvidence === void 0 ? {} : { misdirectionEvidence: publishedEvidence, rootPosture },
1624
1327
  ...capabilities.analysisTokenBudget === void 0 ? {} : { tokenBudget: capabilities.analysisTokenBudget },
1625
1328
  // runId-curried so the author sees the plain `(sha) => bytes` shape.
1626
1329
  ...capabilities.readEvidenceBlob === void 0 ? {} : {
1627
1330
  readEvidenceBlob: (sha) => capabilities.readEvidenceBlob?.(payload.runId, sha)
1628
1331
  }
1629
1332
  });
1630
- verdicts2 = publishedEvidence === void 0 ? result.verdicts : widenRefusedFloorPaths(result.verdicts, result.degradedPaths, handoff);
1333
+ verdicts2 = result.verdicts;
1631
1334
  for (const parts of result.authoredParts) authoredParts.set(parts.perTest, parts);
1632
1335
  }
1633
- const partsOf = (candidates) => candidates.map(
1336
+ const sentenceParts = verdicts2.map(
1634
1337
  (verdict) => verdict.producer === "analyze-run" ? authoredParts.get(verdict.perTest) ?? templateSentenceParts(verdict, handoff) : templateSentenceParts(verdict, handoff)
1635
1338
  );
1636
- const guarded = enforceMisdirectionFloor({
1637
- verdicts: verdicts2,
1638
- handoff,
1639
- runId: payload.runId,
1640
- evidence: publishedEvidence,
1641
- rootPosture,
1642
- partsOf
1643
- });
1339
+ const testsByIndex = new Map(handoff.tests.map((test) => [test.testIndex, test]));
1340
+ const stamped = verdicts2.map(
1341
+ (verdict, index) => stampVerdictMemoryOnPath({
1342
+ verdict,
1343
+ parts: sentenceParts[index],
1344
+ test: testsByIndex.get(verdict.perTest)
1345
+ })
1346
+ );
1644
1347
  capabilities.persistAnalysis({
1645
1348
  schemaVersion: import_agent_qa_schema6.CURRENT_ANALYSIS_SCHEMA_VERSION,
1646
1349
  runId: payload.runId,
1647
- verdicts: guarded.verdicts,
1648
- parts: guarded.parts
1350
+ verdicts: stamped,
1351
+ parts: sentenceParts
1649
1352
  });
1650
- return { runId: payload.runId, verdicts: guarded.verdicts };
1353
+ return { runId: payload.runId, verdicts: stamped };
1651
1354
  }
1652
1355
  );
1653
1356
  const verdicts = authored.verdicts;
@@ -1658,9 +1361,7 @@ function realAnalyzeRunHandler(capabilities) {
1658
1361
  { kind: "analyze-run", allowedSuccessors: ANALYZE_RUN_SUCCESSORS },
1659
1362
  String(context.job.id),
1660
1363
  {
1661
- // Pitfall 6: a successor payload without these two is the DAEM-02 bug class — the
1662
- // daemon resolves a claimed job's posture from `payload.executionContext` (386
1663
- // D-09/D-12), and curation cannot find a run directory it was never told about.
1364
+ // Without these the daemon misreads the posture and curation misses the run.
1664
1365
  runId: payload.runId,
1665
1366
  executionContext: payload.executionContext ?? handoff.executionContext,
1666
1367
  verdictSummary: summarizeVerdicts(verdicts)
@@ -1697,275 +1398,12 @@ function realCurateMemoryHandler(capabilities) {
1697
1398
  deprecated: counts.deprecated,
1698
1399
  ...curationSnapshot === void 0 ? {} : { curationSnapshot }
1699
1400
  });
1700
- return {
1701
- status: "complete",
1702
- next: [
1703
- ...successorsOf(
1704
- { kind: "curate-memory", allowedSuccessors: CURATE_MEMORY_SUCCESSORS },
1705
- String(context.job.id),
1706
- {
1707
- // Pitfall 6 / 386 D-09, one edge further along: without these two the
1708
- // daemon-claimed successor resolves a drain-scoped posture and cannot address
1709
- // the run it is proposing about.
1710
- runId: record.runId,
1711
- ...record.executionContext === void 0 ? {} : { executionContext: record.executionContext },
1712
- // Absent when the fold reported none — see the capability's own comment for why the
1713
- // empty list and the missing field are deliberately not the same answer.
1714
- ...counts.candidateIds === void 0 ? {} : { candidateIds: [...counts.candidateIds] },
1715
- upstream: {
1716
- ...record.verdictSummary === void 0 ? {} : { verdictSummary: record.verdictSummary },
1717
- // The dead-analysis marker, restated where the next stage will look for it. The
1718
- // root of THIS payload belongs to the analysis; the root of the next belongs to
1719
- // the fold, so the fact has to be re-carried or it is lost at this edge.
1720
- analysisStatus: record.verdicts === UNKNOWN_VERDICTS_MARKER ? "failed" : "done",
1721
- curation: {
1722
- curated: counts.curated,
1723
- deprecated: counts.deprecated,
1724
- complete: true,
1725
- ...curationSnapshot === void 0 ? {} : { curationSnapshot }
1726
- }
1727
- }
1728
- }
1729
- )
1730
- ]
1731
- };
1732
- };
1733
- }
1734
- var PROPOSE_GATE1_ALLOWANCE_CHECKPOINT = "gate1-allowance-reserved";
1735
- var PROPOSE_DEFAULT_MAX_GATE1_PER_JOB = 4;
1736
- var GATE1_EXCLUDED_RECORD_KINDS = ["procedure", "policy"];
1737
- function isPositiveInteger(value) {
1738
- return typeof value === "number" && Number.isInteger(value) && value > 0;
1739
- }
1740
- function parseProposeGate1Allowance(outcome) {
1741
- if (!outcome.found) return { kind: "absent" };
1742
- const value = asRecord2(outcome.payload?.value);
1743
- const cap = asRecord2(value.cap);
1744
- const ids = value.selectedCandidateIds;
1745
- const unreadable = (reason) => ({ kind: "unreadable", reason });
1746
- if (typeof value.jobId !== "string" || value.jobId === "" || typeof value.runId !== "string" || value.runId === "" || typeof value.product !== "string" || value.product === "" || typeof value.corpusDigest !== "string" || value.corpusDigest === "" || !isPositiveInteger(cap.value) || cap.source !== "config" && cap.source !== "default" || !Array.isArray(ids) || !ids.every((id) => typeof id === "string" && id !== "")) {
1747
- return unreadable("the persisted Gate-1 allowance is not a readable charge");
1748
- }
1749
- if (ids.length > cap.value) {
1750
- return unreadable("the persisted Gate-1 allowance charges more slots than its own cap");
1751
- }
1752
- return {
1753
- kind: "claimed",
1754
- allowance: {
1755
- jobId: value.jobId,
1756
- runId: value.runId,
1757
- product: value.product,
1758
- corpusDigest: value.corpusDigest,
1759
- cap: { value: cap.value, source: cap.source },
1760
- selectedCandidateIds: [...ids]
1761
- }
1762
- };
1763
- }
1764
- function standingGate1(standing) {
1765
- for (const receipt of standing) if (receipt.gate === 1) return receipt;
1766
- return void 0;
1767
- }
1768
- function orderProposalCandidates(bundles, payloadCandidateIds) {
1769
- const byId = /* @__PURE__ */ new Map();
1770
- for (const bundle of bundles) if (!byId.has(bundle.bundleId)) byId.set(bundle.bundleId, bundle);
1771
- const named = [];
1772
- const seen = /* @__PURE__ */ new Set();
1773
- for (const id of payloadCandidateIds) {
1774
- if (seen.has(id)) continue;
1775
- seen.add(id);
1776
- const row = byId.get(id);
1777
- if (row !== void 0) named.push(row);
1778
- }
1779
- const product = named[0]?.product;
1780
- if (product === void 0) return { product: void 0, ordered: [] };
1781
- const sweep = bundles.filter(
1782
- (bundle) => bundle.product === product && !seen.has(bundle.bundleId) && bundle.status === "candidate"
1783
- ).sort(
1784
- (left, right) => left.openedAtOrdinal - right.openedAtOrdinal || (left.bundleId < right.bundleId ? -1 : left.bundleId > right.bundleId ? 1 : 0)
1785
- );
1786
- return { product, ordered: [...named, ...sweep] };
1787
- }
1788
- var NO_GATE1_WORK = {
1789
- reservedGate1: [],
1790
- screenedGate1: [],
1791
- recoveredGate1Receipts: [],
1792
- interruptedGate1: [],
1793
- ungatedRemaining: [],
1794
- kindExcluded: [],
1795
- stale: []
1796
- };
1797
- async function reconcileGate1Allowance(allowance, gateReceiptsFor) {
1798
- const recovered = [];
1799
- const interrupted = [];
1800
- for (const candidateId of allowance.selectedCandidateIds) {
1801
- let standing;
1802
- try {
1803
- const gates = await gateReceiptsFor({ candidateId });
1804
- standing = gates.kind === "found" ? standingGate1(gates.standing) : void 0;
1805
- } catch {
1806
- standing = void 0;
1807
- }
1808
- if (standing !== void 0 && standing.corpusVersion.corpusDigest === allowance.corpusDigest) {
1809
- recovered.push({ candidateId, verdict: standing.verdict });
1810
- } else {
1811
- interrupted.push(candidateId);
1812
- }
1813
- }
1814
- return {
1815
- ...NO_GATE1_WORK,
1816
- disposition: "resumed",
1817
- cap: allowance.cap,
1818
- reservedGate1: [...allowance.selectedCandidateIds],
1819
- recoveredGate1Receipts: recovered,
1820
- interruptedGate1: interrupted
1821
- };
1822
- }
1823
- async function screenGate1(capabilities, context, payload) {
1824
- const runReplayGate = capabilities.runReplayGate;
1825
- const readAllowance = capabilities.readProposeGate1Allowance;
1826
- const listBundles = capabilities.listBundles;
1827
- const gateReceiptsFor = capabilities.gateReceiptsFor;
1828
- const readCorpusPosture = capabilities.readProposeCorpusPosture;
1829
- if (runReplayGate === void 0 || readAllowance === void 0 || listBundles === void 0 || gateReceiptsFor === void 0 || readCorpusPosture === void 0) {
1830
- return { ...NO_GATE1_WORK, disposition: "unbound" };
1831
- }
1832
- const jobId = String(context.job.id);
1833
- let read;
1834
- try {
1835
- read = await readAllowance(jobId);
1836
- } catch (error) {
1837
- return {
1838
- ...NO_GATE1_WORK,
1839
- disposition: "allowance-unavailable",
1840
- reason: `the persisted Gate-1 allowance could not be read: ${errorTextOfUnknown(error)}`
1841
- };
1842
- }
1843
- if (read.kind === "unreadable") {
1844
- return { ...NO_GATE1_WORK, disposition: "allowance-unavailable", reason: read.reason };
1845
- }
1846
- if (read.kind === "claimed") {
1847
- const allowance2 = read.allowance;
1848
- if (allowance2.jobId !== jobId || allowance2.runId !== payload.runId) {
1849
- return {
1850
- ...NO_GATE1_WORK,
1851
- disposition: "allowance-unavailable",
1852
- reason: "the persisted Gate-1 allowance was charged for another job or run"
1853
- };
1854
- }
1855
- return await reconcileGate1Allowance(allowance2, gateReceiptsFor);
1856
- }
1857
- const cap = isPositiveInteger(capabilities.proposeGate1MaxPerJob) ? { value: capabilities.proposeGate1MaxPerJob, source: "config" } : { value: PROPOSE_DEFAULT_MAX_GATE1_PER_JOB, source: "default" };
1858
- const { product, ordered } = orderProposalCandidates(await listBundles(), payload.candidateIds);
1859
- if (product === void 0) {
1860
- return { ...NO_GATE1_WORK, disposition: "no-candidates" };
1861
- }
1862
- const posture = await readCorpusPosture({ product });
1863
- if (posture.kind !== "resolved") {
1864
- return {
1865
- ...NO_GATE1_WORK,
1866
- disposition: "posture-unavailable",
1867
- cap,
1868
- reason: posture.kind === "no-root" ? "no committed corpus root, so nothing can be screened against one" : posture.reason
1869
- };
1870
- }
1871
- const kindExcluded = [];
1872
- const stale = [];
1873
- const ungated = [];
1874
- for (const row of ordered) {
1875
- if (GATE1_EXCLUDED_RECORD_KINDS.includes(row.kind)) {
1876
- kindExcluded.push(row.bundleId);
1877
- continue;
1878
- }
1879
- if (row.status !== "candidate") continue;
1880
- const gates = await gateReceiptsFor({ candidateId: row.bundleId });
1881
- if (gates.kind !== "found") continue;
1882
- if (GATE1_EXCLUDED_RECORD_KINDS.includes(gates.recordKind)) {
1883
- kindExcluded.push(row.bundleId);
1884
- continue;
1885
- }
1886
- const standing = standingGate1(gates.standing);
1887
- if (standing !== void 0 && standing.corpusVersion.corpusDigest === posture.corpusDigest) {
1888
- continue;
1889
- }
1890
- if (standing !== void 0) stale.push(row.bundleId);
1891
- ungated.push(row.bundleId);
1892
- }
1893
- const selected = ungated.slice(0, cap.value);
1894
- const remaining = ungated.slice(cap.value);
1895
- if (selected.length === 0) {
1896
- return {
1897
- ...NO_GATE1_WORK,
1898
- disposition: "claimed",
1899
- cap,
1900
- ungatedRemaining: remaining,
1901
- kindExcluded,
1902
- stale
1903
- };
1904
- }
1905
- const allowance = {
1906
- jobId,
1907
- runId: payload.runId,
1908
- product,
1909
- corpusDigest: posture.corpusDigest,
1910
- cap,
1911
- selectedCandidateIds: selected
1912
- };
1913
- await context.publishCheckpoint(PROPOSE_GATE1_ALLOWANCE_CHECKPOINT, allowance);
1914
- const screened = [];
1915
- const interrupted = [];
1916
- for (const candidateId of selected) {
1917
- try {
1918
- const receipt = await runReplayGate((0, import_agent_qa_schema6.asRecordId)(candidateId));
1919
- screened.push({ candidateId, verdict: receipt.verdict });
1920
- } catch {
1921
- interrupted.push(candidateId);
1922
- }
1923
- }
1924
- return {
1925
- disposition: "claimed",
1926
- cap,
1927
- reservedGate1: [...selected],
1928
- screenedGate1: screened,
1929
- recoveredGate1Receipts: [],
1930
- interruptedGate1: interrupted,
1931
- ungatedRemaining: remaining,
1932
- kindExcluded,
1933
- stale
1934
- };
1935
- }
1936
- function errorTextOfUnknown(error) {
1937
- return error instanceof Error ? error.message : String(error);
1938
- }
1939
- function realProposeImprovementsHandler(capabilities) {
1940
- return async (context) => {
1941
- const payload = readProposeImprovementsPayload(context.payload);
1942
- if (payload === void 0) {
1943
- return permanently(
1944
- "the propose-improvements payload names no run, so there is no curated run to propose improvements about"
1945
- );
1946
- }
1947
- const gate1 = await screenGate1(capabilities, context, payload);
1948
- const staged = capabilities.stageAdversarialProposal === void 0 ? void 0 : await capabilities.stageAdversarialProposal({
1949
- runId: payload.runId,
1950
- executionContext: payload.executionContext,
1951
- candidateIds: payload.candidateIds,
1952
- upstream: payload.upstream
1953
- });
1954
- const checkpoint = {
1955
- runId: payload.runId,
1956
- candidateIds: [...payload.candidateIds],
1957
- ...staged === void 0 ? {} : { proposed: staged.proposed, skipped: staged.skipped },
1958
- ...gate1.disposition === "unbound" ? {} : { gate1 }
1959
- };
1960
- await context.publishCheckpoint("proposals-authored", checkpoint);
1961
1401
  return { status: "complete", next: [] };
1962
1402
  };
1963
1403
  }
1964
1404
  function declarationsFor(capabilities) {
1965
1405
  return {
1966
- // JOBQ-04 / C9. Chat is NOT a checkpointed job and never becomes one: its state of record
1967
- // is the append-only session log, and the queue's checkpoint discipline covers background
1968
- // work only. One attempt, because there is no durable progress for a second one to resume.
1406
+ // Chat is never checkpointed: its record is the session log, so one attempt.
1969
1407
  chat: {
1970
1408
  kind: "chat",
1971
1409
  checkpointed: false,
@@ -1988,25 +1426,21 @@ function declarationsFor(capabilities) {
1988
1426
  onPermanentFailure: analyzeRunFallback,
1989
1427
  handler: capabilities === void 0 ? standInHandler("analyze-run", ["verdicts-authored"], ANALYZE_RUN_SUCCESSORS) : realAnalyzeRunHandler(capabilities)
1990
1428
  },
1991
- // Two checkpoints, mirroring the v51 curation lifecycle: candidates are authored, then the
1992
- // bundle is committed. The second is the one whose recovery actually matters.
1429
+ // Two checkpoints: candidates are authored, then the bundle is committed.
1993
1430
  //
1994
- // 422 D-13: it now chains onward to the proposal stage, and `halt-chain` survives that
1995
- // unchanged — deliberately. A fold that gave up permanently committed no bundle, so there is
1996
- // nothing for a proposal stage to propose about; handing it a successor would mint a job whose
1997
- // whole premise is a fold that did not happen.
1431
+ // It declares no successor: its finish is the chain's terminal.
1998
1432
  "curate-memory": {
1999
1433
  kind: "curate-memory",
2000
1434
  checkpointed: true,
2001
1435
  checkpointSchedule: ["candidates-authored", "bundle-committed"],
2002
- allowedSuccessors: CURATE_MEMORY_SUCCESSORS,
1436
+ allowedSuccessors: [],
2003
1437
  maxAttempts: 3,
2004
1438
  backoff: { kind: "exponential", initialDelayMs: 1e3, factor: 2, maxDelayMs: 3e4 },
2005
1439
  onPermanentFailure: "halt-chain",
2006
1440
  handler: capabilities === void 0 ? standInHandler(
2007
1441
  "curate-memory",
2008
1442
  ["candidates-authored", "bundle-committed"],
2009
- CURATE_MEMORY_SUCCESSORS
1443
+ []
2010
1444
  ) : realCurateMemoryHandler(capabilities)
2011
1445
  },
2012
1446
  consolidate: {
@@ -2018,28 +1452,6 @@ function declarationsFor(capabilities) {
2018
1452
  backoff: { kind: "fixed", delayMs: 5e3 },
2019
1453
  onPermanentFailure: "halt-chain",
2020
1454
  handler: standInHandler("consolidate", ["consolidation-authored"], [])
2021
- },
2022
- // The chain's tail since 422 D-13. It declares NO successor — a fourth stage would be one
2023
- // nothing derives an id for — and halts its chain on permanent failure, which here means only
2024
- // that nothing further is enqueued: the curation behind it is committed and stays committed.
2025
- //
2026
- // 422 D-14 adds `gate1-allowance-reserved` AHEAD of `proposals-authored`, and the order is the
2027
- // contract rather than a listing convention: the charge is what a resumed attempt reads to
2028
- // learn what a previous one may already have spent, so it has to be durable before any call
2029
- // is made and therefore before the checkpoint that reports the result.
2030
- "propose-improvements": {
2031
- kind: "propose-improvements",
2032
- checkpointed: true,
2033
- checkpointSchedule: [PROPOSE_GATE1_ALLOWANCE_CHECKPOINT, "proposals-authored"],
2034
- allowedSuccessors: [],
2035
- maxAttempts: 2,
2036
- backoff: { kind: "fixed", delayMs: 5e3 },
2037
- onPermanentFailure: "halt-chain",
2038
- handler: capabilities === void 0 ? standInHandler(
2039
- "propose-improvements",
2040
- [PROPOSE_GATE1_ALLOWANCE_CHECKPOINT, "proposals-authored"],
2041
- []
2042
- ) : realProposeImprovementsHandler(capabilities)
2043
1455
  }
2044
1456
  };
2045
1457
  }
@@ -2105,12 +1517,7 @@ function toRunTestDetail(test, resolved) {
2105
1517
  filePath: test.filePath,
2106
1518
  testIndex: test.testIndex,
2107
1519
  outcome: test.outcome,
2108
- // Step evidence stays in the handoff document; 389's evidence links address it by
2109
- // runId + testIndex. Projecting it here would make the cheapest read the most expensive.
2110
- // The same law covers sentences (389 D-11): this projection carries class/producer/
2111
- // confidence from the resolved verdict and NEVER a rendered sentence — an unbound
2112
- // analysis port answers as artifact-absent (the deterministic floor), so the cheapest
2113
- // read stays cheap in every composition.
1520
+ // Step evidence and sentences stay out, so the cheapest read stays cheap in every composition.
2114
1521
  stepCount: test.steps.length,
2115
1522
  ...resolved === void 0 ? {} : {
2116
1523
  rootCause: {
@@ -2149,12 +1556,7 @@ var runsGetSpec = {
2149
1556
  input: import_agent_qa_schema7.RunsGetInputSchema,
2150
1557
  output: import_agent_qa_schema7.RunDetailSchema,
2151
1558
  risk: { name: `fn:${RUNS_GET_FUNCTION_ID}`, recognized: true, readOnly: true },
2152
- /**
2153
- * A run that came back is a run that was found (399.1 D-01).
2154
- *
2155
- * Absence is `RunNotFoundError`, a throw, which already reaches the engine's `failed` mapping.
2156
- * The verdict a run ENDED with is not this clause's verdict: a failing run is a successful read.
2157
- */
1559
+ // A failing run is a successful read; absence throws `RunNotFoundError`.
2158
1560
  classify(output) {
2159
1561
  return {
2160
1562
  status: "executed",
@@ -2191,20 +1593,12 @@ var analysisGetSpec = {
2191
1593
  id: ANALYSIS_GET_FUNCTION_ID,
2192
1594
  summary: "Read one run's resolved verdicts, rendered sentences and failure clusters.",
2193
1595
  resultKind: "unary",
2194
- // Bound exactly where a composition supplies the artifact reader (D-16 idiom). The
2195
- // OPTIONAL `recurrence` dep is deliberately NOT the binding key: a host without history
2196
- // still serves sentences — the renderer answers the explicit no-history clause — so tying
2197
- // the binding to it would refuse a capability this host can honestly run.
1596
+ // `recurrence` is not the binding key, because a host without history still serves sentences.
2198
1597
  boundThrough: "analysis",
2199
1598
  input: import_agent_qa_schema8.AnalysisGetInputSchema,
2200
1599
  output: import_agent_qa_schema8.AnalysisGetOutputSchema,
2201
1600
  risk: { name: `fn:${ANALYSIS_GET_FUNCTION_ID}`, recognized: true, readOnly: true },
2202
- /**
2203
- * An analysis is an ANSWER, and its verdicts are what it answered (399.1 D-01).
2204
- *
2205
- * COUNTS AND THE RUN REF, never a sentence out of the artifact: the receipt is a map (392's
2206
- * charter) and every verdict sentence is on `results[]`, which D-04 renders in full beside it.
2207
- */
1601
+ // Counts and the run ref only; verdict sentences ride on `results[]`.
2208
1602
  classify(output) {
2209
1603
  return {
2210
1604
  status: "executed",
@@ -2230,8 +1624,7 @@ var analysisGetSpec = {
2230
1624
  const sentence = renderVerdictSentence(
2231
1625
  verdict,
2232
1626
  partsFor(verdict, artifact, document),
2233
- // Recurrence is a LIVE join through the D-08 seam, per call — an absent dep renders
2234
- // the explicit no-history clause, never a dropped section.
1627
+ // Recurrence is a live join per call; an absent dep renders the no-history clause.
2235
1628
  deps.recurrence,
2236
1629
  {
2237
1630
  product,
@@ -2247,15 +1640,10 @@ var analysisGetSpec = {
2247
1640
  const sentenceByPerTest = new Map(sentences.map((entry2) => [entry2.perTest, entry2.sentence]));
2248
1641
  return {
2249
1642
  runId,
2250
- // The verdict's OWN evidence, projected (406 D-01) — cited steps and cited artifacts as the
2251
- // resolved verdict already held them, so the failure view's links are this op's refs and not
2252
- // a second join over `analysis.json`. Presence is consulted OPPORTUNISTICALLY through the
2253
- // optional blob port: `boundThrough` stays `analysis`, because a host with no runtime root
2254
- // still serves a complete analysis — it simply cannot say whether the screenshots survive.
1643
+ // Presence is optional enrichment, so a host with no runtime root still serves the analysis.
2255
1644
  verdicts: await Promise.all(resolved.map(async (verdict) => {
2256
1645
  const test = document.tests.find((candidate) => candidate.testIndex === verdict.perTest);
2257
1646
  const cited = verdict.evidence.citedArtifacts;
2258
- const misdirection = (0, import_agent_qa_schema8.projectVerdictMisdirection)(verdict);
2259
1647
  return {
2260
1648
  perTest: verdict.perTest,
2261
1649
  testId: test?.testId ?? "",
@@ -2266,13 +1654,16 @@ var analysisGetSpec = {
2266
1654
  citedSteps: [...verdict.evidence.citedSteps],
2267
1655
  citedArtifacts: await annotatePresence(deps.evidenceBlobs, input.runId, cited)
2268
1656
  },
2269
- ...misdirection === void 0 ? {} : { misdirection }
1657
+ ...verdict.memoryOnPath === void 0 ? {} : {
1658
+ memoryOnPath: verdict.memoryOnPath.map((entry2) => ({
1659
+ recordId: String(entry2.recordId),
1660
+ trust: entry2.trust
1661
+ }))
1662
+ }
2270
1663
  };
2271
1664
  })),
2272
1665
  sentences,
2273
- // Render-time clustering through the ONE pure fold (D-14); the representative carries
2274
- // its already-composed sentence (D-15) — looked up, never re-rendered, so cluster and
2275
- // per-test presentation cannot drift.
1666
+ // The representative's sentence is looked up, never re-rendered, so it cannot drift.
2276
1667
  clusters: clusterVerdicts(resolved, document).map((cluster) => ({
2277
1668
  fingerprint: cluster.fingerprint,
2278
1669
  count: cluster.count,
@@ -2467,7 +1858,7 @@ function addsValueGate(input) {
2467
1858
  return {
2468
1859
  pass: true,
2469
1860
  finding: { novelElements: [...new Set(input.draftElements)], comparedTests: [] },
2470
- reason: "the suite is empty \u2014 no fingerprint coverage and no comparable text, so every element is uncovered (D-16)"
1861
+ reason: "the suite is empty \u2014 no fingerprint coverage and no comparable text, so every element is uncovered"
2471
1862
  };
2472
1863
  }
2473
1864
  const novelElements = novelElementsOf(input.draftElements, union);
@@ -2511,22 +1902,22 @@ function addsValueGate(input) {
2511
1902
  }
2512
1903
  function gateReason(input) {
2513
1904
  if (input.pass && input.unionSize > 0) {
2514
- const decided = `${input.novelElements.length} element(s) absent from the suite union of ${input.unionSize} \u2014 the fingerprint lane decided (D-14)`;
1905
+ const decided = `${input.novelElements.length} element(s) absent from the suite union of ${input.unionSize} \u2014 the fingerprint lane decided`;
2515
1906
  if (input.textCovered.length === 0) {
2516
- return `${decided}, and no evidence-less suite test resembles the draft (D-16)`;
1907
+ return `${decided}, and no evidence-less suite test resembles the draft`;
2517
1908
  }
2518
- return `${decided}; ${input.textCovered.length} evidence-less suite test(s) resemble the draft on the degraded text lane and are recorded per compared test without deciding (D-16)`;
1909
+ return `${decided}; ${input.textCovered.length} evidence-less suite test(s) resemble the draft on the degraded text lane and are recorded per compared test without deciding`;
2519
1910
  }
2520
1911
  if (input.pass) {
2521
- return "the suite fingerprint index is empty, so the degraded text lane decided: no evidence-less suite test resembles the draft (D-16)";
1912
+ return "the suite fingerprint index is empty, so the degraded text lane decided: no evidence-less suite test resembles the draft";
2522
1913
  }
2523
1914
  if (input.unionSize === 0 && input.textCovered.length > 0) {
2524
- return "the text fallback lane matched " + input.textCovered.map((entry2) => `${entry2.filePath}::${entry2.testName}`).join(", ") + ` at or above ${TEXT_FALLBACK_SIMILARITY_THRESHOLD} similarity \u2014 an evidence-less suite test this draft resembles, flagged toward already-covered (D-16)`;
1915
+ return "the text fallback lane matched " + input.textCovered.map((entry2) => `${entry2.filePath}::${entry2.testName}`).join(", ") + ` at or above ${TEXT_FALLBACK_SIMILARITY_THRESHOLD} similarity \u2014 an evidence-less suite test this draft resembles, flagged toward already-covered`;
2525
1916
  }
2526
1917
  if (input.draftElementCount === 0) {
2527
1918
  return "the draft produced no fingerprint elements, so nothing could be shown to be novel \u2014 not a finding that it duplicates the suite (check gate 1 first)";
2528
1919
  }
2529
- return `every element the draft exercised (${input.draftElementCount}) is already in the suite union of ${input.unionSize} (D-14)`;
1920
+ return `every element the draft exercised (${input.draftElementCount}) is already in the suite union of ${input.unionSize}`;
2530
1921
  }
2531
1922
 
2532
1923
  // src/authoring/dedup.ts
@@ -3486,26 +2877,18 @@ async function compileDraft(input, brief, shelf, read) {
3486
2877
  title: "Role",
3487
2878
  body: "You author agent-qa test documents. Emit ONE complete YAML test document and nothing else \u2014 no prose, no fences, no partial edit. Steps are natural language, one per line, and at least one of them must assert concrete expected content. " + REQUEST_WINS_INSTRUCTION
3488
2879
  },
3489
- // The document schema, on the same placement argument and for WINDOWS 111's reason: a brief
3490
- // serving no exemplars must still teach the format. See the constant's own header.
2880
+ // The document format sits in the stable tier, so a brief with no exemplars still teaches it.
3491
2881
  {
3492
2882
  title: TEST_DOCUMENT_FORMAT_BLOCK_TITLE,
3493
2883
  body: TEST_DOCUMENT_FORMAT_INSTRUCTION
3494
2884
  },
3495
- // D-17's syntactic half, in the STABLE tier beside the role it qualifies. It is a standing
3496
- // rule about how any step is written rather than a fact about this intent, so it belongs
3497
- // where the byte prefix is shared across invocations.
2885
+ // Stable tier: a standing rule about writing any step, shared across invocations.
3498
2886
  { title: "Procedures", body: PROCEDURE_BY_REFERENCE_INSTRUCTION }
3499
2887
  ],
3500
2888
  context: [
3501
2889
  { title: "Intent", body: input.intent },
3502
2890
  { title: "Scope", body: `${input.scope.tier}:${input.scope.key}` },
3503
- // WR-07, AND IT RIDES BESIDE THE BLOCK IT CORRECTS. `Scope` renders `${tier}:${key}` and
3504
- // that key is a PRODUCT — `deriveDefaultAuthoringScope` answers `target.product ??
3505
- // targetName` — so a stage asked for a `target` while served only the Scope block was being
3506
- // asked to guess on every project where the two differ. CONTEXT tier and not stable: these
3507
- // names are per-project facts, and the stable tier's shared byte prefix must stay
3508
- // project-independent for the prompt cache the tier law exists to enable.
2891
+ // `Scope` renders a product, not a target name, so the configured targets ride beside it.
3509
2892
  {
3510
2893
  title: CONFIGURED_TARGETS_BLOCK_TITLE,
3511
2894
  body: configuredTargetsBlockBody(targetNames)
@@ -3798,28 +3181,13 @@ var authoringDraftEditSpec = {
3798
3181
  boundThrough: "draftShelf",
3799
3182
  input: import_agent_qa_schema16.AuthoringDraftEditInputSchema,
3800
3183
  output: import_agent_qa_schema16.AuthoringDraftEditOutputSchema,
3801
- // `mutating-local`, and the contrast with `authoring.draft.write` is deliberate. That op declares
3802
- // `mutating-shared` because it spends up to nine child `agent-qa run` processes of a person's
3803
- // compute (D-10). This op takes ONE model call, starts zero runs, and writes one file — the test
3804
- // it edited, over the exact bytes it read (432 D-06). 2026-10-01 (432-19/432-24, D-12/D-15): the
3805
- // tiers once decided who was asked and where an unanswerable ask denied; nothing asks or denies
3806
- // on a tier now, and the tier stays the honest classification of what the op touches.
3807
- //
3808
- // The mechanics: `recognized: true` with no `readOnly` puts the classifier's floor at
3809
- // mutating-local, `declaredTier` states that tier rather than relying on the floor, and the name
3810
- // tokens (fn · authoring · draft · edit) hit neither destructive lexicon.
3184
+ // This op takes one model call, starts zero runs, and writes one file: the test it edited, over
3185
+ // the exact bytes it read.
3811
3186
  risk: {
3812
3187
  name: `fn:${AUTHORING_DRAFT_EDIT_FUNCTION_ID}`,
3813
- recognized: true,
3814
- declaredTier: "mutating-local"
3188
+ recognized: true
3815
3189
  },
3816
- /**
3817
- * An edit that returned STAGED a draft — there is no arm where it did not (399.1 D-01).
3818
- *
3819
- * Every refusal this op can make is a THROW (the never-guess binder, the region fence, the
3820
- * parser), which already reaches the engine's own `failed` mapping. What returns is one shape,
3821
- * and the honest report of it is what was edited and how much changed.
3822
- */
3190
+ // Every refusal throws, so a returned value always staged a draft.
3823
3191
  classify(output) {
3824
3192
  const file = output.written;
3825
3193
  if (file.kind === "not-written") {
@@ -3937,7 +3305,7 @@ function projectStop(outcome) {
3937
3305
  ...point.verdictSource === void 0 ? {} : { verdictSource: String(point.verdictSource) }
3938
3306
  },
3939
3307
  evidenceRefs: outcome.route.evidenceRefs,
3940
- // ONE SPREAD, so the kind and the spend are present on exactly the same payloads (411 D-08).
3308
+ // One spread, so the kind and the spend appear on exactly the same payloads.
3941
3309
  ...outcome.abandonment === void 0 ? {} : {
3942
3310
  repairAbandonment: outcome.abandonment.kind,
3943
3311
  repairIterations: outcome.abandonment.iterations
@@ -3954,97 +3322,14 @@ var authoringDraftWriteSpec = {
3954
3322
  boundThrough: "draftShelf",
3955
3323
  input: import_agent_qa_schema17.AuthoringDraftWriteInputSchema,
3956
3324
  output: import_agent_qa_schema17.AuthoringDraftWriteOutputSchema,
3957
- // `mutating-shared`, AND THE CONTRAST WITH `authoring.draft.verify` IS THE POINT (394-08, D-03).
3958
- //
3959
- // The mechanics first: `recognized: true` with no `readOnly` puts the classifier's floor at
3960
- // mutating-local, `declaredTier` raises it from there, and the name tokens (fn · authoring ·
3961
- // draft · write) hit neither destructive lexicon — so the declared tier is what the gate sees.
3962
- //
3963
- // `authoring-verify-draft.ts` chose `mutating-local` and its argument was correct FOR IT: an
3964
- // ask-tier op denies in every fail-closed context, and an evaluator that cannot verify a draft in
3965
- // CI is a keep-filter that stops working exactly where it needs to run unattended. Verifying is
3966
- // all cost and no consequence — gate-runs are `excludedFromOutcomes`, so they leave no trace a
3967
- // colleague reads.
3968
- //
3969
- // THIS OP IS GENUINELY DIFFERENT, and it differs in the two ways that decide a tier. It SPENDS a
3970
- // person's compute and model budget on their own machine — up to nine full child `agent-qa run`
3971
- // processes against their application (D-10) — and since 432 D-06 the artifact it produces is
3972
- // written straight into their suite.
3973
- //
3974
- // 2026-10-01 (432-19/432-23, 432 D-12/D-14/D-15): THE TIER NO LONGER ASKS. It was raised so a
3975
- // dispatch confirm would show the fan-out before the loop started, and so a fail-closed context
3976
- // (CI, the daemon) denied it with the gate's ways out (the session trust flag, a trust credential,
3977
- // a standing approval). The gate, its confirm and those ways out are deleted: every door runs this
3978
- // op without a prompt, and WTST-08's honest report on the verdict below is the control that
3979
- // remains. One call starts a loop that runs to its end; there is no mid-loop approval state and
3980
- // no approval token threaded through the stages.
3981
- //
3982
- // DO NOT HARMONISE THE TWO TIERS. They are different classifications because the ops differ;
3983
- // the tier still says honestly which one shares more.
3325
+ // Every door runs this op without a prompt. One call starts a loop that runs to its end, spending
3326
+ // up to nine child `agent-qa run` processes against the person's application, and writes the
3327
+ // draft straight into their suite; there is no mid-loop approval state.
3984
3328
  risk: {
3985
3329
  name: `fn:${AUTHORING_DRAFT_WRITE_FUNCTION_ID}`,
3986
- recognized: true,
3987
- declaredTier: "mutating-shared"
3330
+ recognized: true
3988
3331
  },
3989
- // 2026-10-02 (432-42, D-14/D-15): the per-invocation `disclose` method is deleted. It rendered the
3990
- // fan-out preview for the dispatch confirm, which 432-19 deleted, and nothing called it since; the
3991
- // fan-out report on the verdict below is what a caller reads.
3992
- /**
3993
- * This op's own outcome enum, folded into a clause verdict (2026-08-20, Phase 399.1 D-01/D-02),
3994
- * carrying the invocation's FAN-OUT REPORT (394-14 · WTST-08 · D-18's one exception).
3995
- *
3996
- * `refused` IS THE MEASURED WITNESS. 399's live acceptance recorded this op returning its stage-2
3997
- * dedup refusal while chat printed `executed authoring.draft.write completed`: the screen declined
3998
- * to author, nothing was written, and the person was told it had been. The screen WORKED, so the
3999
- * honest word is `refused` and not `failed` — the same reading D-02 minted the status for.
4000
- *
4001
- * THE OUTCOME CARRIES THE REFERENCE, because 394 D-04's requirement is refuse AND LINK: a person
4002
- * told only "duplicate" has nothing to open, and `matchedRef` is precisely the string
4003
- * `entities.resolve` takes. The refusal payload is optional on the contract, so an arm that says
4004
- * `refused` without one still says `refused` — the status is the claim that must not be lost, and
4005
- * a missing link degrades the sentence rather than the verdict.
4006
- *
4007
- * THE OTHER THREE ARMS RAN TO COMPLETION. `drafted`, `repaired` and `stopped` all end with a draft
4008
- * and a receipt — a correctly-failing draft is a VERDICT about the application, not a failure of
4009
- * this op — so each is `executed`, and the outcome names the test that was authored. A `stopped`
4010
- * invocation therefore renders `stopped <testName> — <fan-out sentence>` under a status chat and
4011
- * the parity walk already read: a spelling, never a shape (411 D-11).
4012
- *
4013
- * ---- the fan-out, migrated here from `turn-engine.ts` by 399.1-03 -----------------------------
4014
- *
4015
- * IT ARRIVES ON THE VERDICT AND NOT ON A RENDER FOLD, and the choice is load-bearing rather than
4016
- * incidental. 394-14's second cell requires the sentence to reach the APPEND-ONLY LOG — "the
4017
- * return value is what one caller sees; the log is the triage report several surfaces render" —
4018
- * and the log carries `ClauseReceipt.outcome`, not the turn's answer. A `renderResult` fold would
4019
- * have put this disclosure on the answer channel only, silently costing it the half that is
4020
- * readable after the fact. `summariseOutcome` composed a RECEIPT LINE, so the seat it vacates is
4021
- * this one; `explainAnswerLines` composed ANSWER TEXT, so its seat is `renderResult`. The two
4022
- * hardcodes were never the same kind of thing.
4023
- *
4024
- * IT IS ADMITTED BY THE CHARTER RATHER THAN EXCEPTED FROM IT. D-18 says the receipt is a MAP, and
4025
- * `FanOutReport` is counts, run REFERENCES and one boolean — no draft body, no receipt payload, no
4026
- * step evidence. The written file and its receipt ride the op's `written` field, not this line.
4027
- *
4028
- * IT IS ONE FIELD ON ONE OP, AND NOW BY CONSTRUCTION. That used to be enforced by an id
4029
- * comparison inside a shared function — a claim a later edit could widen by deleting one line. It
4030
- * is a member of THIS spec now: no other op's line is touched, because no other op declares this.
4031
- *
4032
- * WHY THE DISCLOSURE IS THE WHOLE CONTROL. WTST-08's owner decision was preview plus honest
4033
- * reporting with NO enforced budget, so the number a person is shown is all there is. The same
4034
- * surface rendered the dispatch confirm they approved; a receipt omitting what was actually spent
4035
- * would be the half that makes the other half checkable, missing. They agreed to nine runs and
4036
- * had no way to learn eleven were taken.
4037
- *
4038
- * PARSED, NEVER CAST, AND THE PARSE CANNOT MOVE THE STATUS. `FanOutReportSchema` is `.strict()`,
4039
- * so a malformed result cannot smuggle prose into a file several surfaces render; an unparsable
4040
- * report costs the SENTENCE and never the verdict, which is `classify`'s fail-closed contract read
4041
- * correctly — the disclosure degrades, the claim about what happened does not.
4042
- *
4043
- * THE SENTENCE IS `renderFanOutReport`'S AND NOTHING ELSE. A line composed here would be a second
4044
- * prose form of one report, free to drift from the confirm's own wording the moment a phrase
4045
- * moves — and mutation R of the phase's mutation driver (since removed) was the differential
4046
- * that caught it.
4047
- */
3332
+ // A refused dedup is `refused` with its matched ref; every other arm is `executed`.
4048
3333
  classify(output) {
4049
3334
  const report = import_agent_qa_schema17.FanOutReportSchema.safeParse(output.fanOut);
4050
3335
  const spent = report.success ? ` \u2014 ${(0, import_agent_qa_schema17.renderFanOutReport)(report.data)}` : "";
@@ -4090,10 +3375,7 @@ var authoringDraftWriteSpec = {
4090
3375
  intent: input.intent,
4091
3376
  scope,
4092
3377
  ...input.draftMode === void 0 ? {} : { draftMode: input.draftMode },
4093
- // 394-17 / D-12: handed on exactly as supplied, and this op invents nothing. The session
4094
- // is a fact about the SURFACE that dispatched the call — the chat engine stamps its own
4095
- // id at the invoke boundary — so a default here would attribute a CLI draft to a session
4096
- // that never asked for it.
3378
+ // Passed as supplied: the dispatching surface stamps its own session, so no default here.
4097
3379
  ...input.sessionRef === void 0 ? {} : { sessionRef: input.sessionRef }
4098
3380
  },
4099
3381
  { read, shelf }
@@ -4178,23 +3460,12 @@ var authoringFunnelGetSpec = {
4178
3460
  id: AUTHORING_FUNNEL_GET_FUNCTION_ID,
4179
3461
  summary: "Report the authoring funnel for a window \u2014 built, passed stably, added value, write-eligible \u2014 and flag a keep rate above the ceiling as the loop failing to filter.",
4180
3462
  resultKind: "unary",
4181
- // Bound exactly where a composition supplies the receipts store (the proposals inbox left in 432-17).
4182
- // An unbound host answering an all-zero funnel would say "this session authored nothing" about
4183
- // a store it has never been able to read — and worse, it would say the loop filtered
4184
- // everything, which is the one reading of a zero funnel that flatters the loop. So it refuses
4185
- // by name instead (D-09).
3463
+ // An unbound host refuses rather than answer a zero funnel that flatters the loop.
4186
3464
  boundThrough: "authoringFunnel",
4187
3465
  input: import_agent_qa_schema19.AuthoringFunnelGetInputSchema,
4188
3466
  output: import_agent_qa_schema19.AuthoringFunnelGetOutputSchema,
4189
3467
  risk: { name: `fn:${AUTHORING_FUNNEL_GET_FUNCTION_ID}`, recognized: true, readOnly: true },
4190
- /**
4191
- * The funnel's OWN one line, not a second one composed here (399.1 D-01 · WTST-05).
4192
- *
4193
- * `line` is the single rendered sentence every surface prints, and it is screened against the
4194
- * forbidden phrasings before the contract will carry it. Composing a receipt line out of the
4195
- * counters instead would be a second funnel rendering — unscreened, and free to call a high keep
4196
- * rate an achievement, which is the exact misreading D-13 exists to prevent.
4197
- */
3468
+ // The receipt carries the funnel's own screened line, never one composed from the counters.
4198
3469
  classify(output) {
4199
3470
  return { status: "executed", outcome: output.line };
4200
3471
  },
@@ -4427,7 +3698,7 @@ function classifyDraftSteps(steps) {
4427
3698
  function gateReason2(rows) {
4428
3699
  const assertions = rows.filter((row) => row.role === "assertion");
4429
3700
  if (assertions.length === 0) {
4430
- return "no step classifies as an assertion: the draft records what it did, never what should be true (D-09 clause (i))";
3701
+ return "no step classifies as an assertion: the draft records what it did, never what should be true";
4431
3702
  }
4432
3703
  if (assertions.some((row) => row.falsifiable)) {
4433
3704
  return `${assertions.filter((row) => row.falsifiable).length} of ${assertions.length} assertion steps reference concrete expected content`;
@@ -4446,7 +3717,7 @@ function gateReason2(rows) {
4446
3717
  "no quoted expected value, and no element noun this gate knows stands before an expected-state term with only function words between them"
4447
3718
  );
4448
3719
  }
4449
- return `${assertions.length} assertion step(s), none falsifiable: ${[...causes].sort().join("; ")} (D-09 clause (ii))`;
3720
+ return `${assertions.length} assertion step(s), none falsifiable: ${[...causes].sort().join("; ")}`;
4450
3721
  }
4451
3722
  function assertionStrengthGate(draft) {
4452
3723
  const table = classifyDraftSteps(draft.steps);
@@ -4478,7 +3749,7 @@ var import_agent_qa_schema20 = require("@vostride/agent-qa-schema");
4478
3749
  var GateRunNotFlaggedError = class extends Error {
4479
3750
  constructor(runId, acknowledged) {
4480
3751
  super(
4481
- `runs.start accepted ${runId} without both gate-run markers (gateRun=${String(acknowledged.gateRun)}, excludedFromOutcomes=${String(acknowledged.excludedFromOutcomes)}): an unflagged gate-run pollutes the outcome projection and the suite fingerprint union the draft is later compared against (WTST-06).`
3752
+ `runs.start accepted ${runId} without both gate-run markers (gateRun=${String(acknowledged.gateRun)}, excludedFromOutcomes=${String(acknowledged.excludedFromOutcomes)}): an unflagged gate-run pollutes the outcome projection and the suite fingerprint union the draft is later compared against.`
4482
3753
  );
4483
3754
  this.runId = runId;
4484
3755
  this.acknowledged = acknowledged;
@@ -4506,39 +3777,39 @@ function classifyGateRun(member) {
4506
3777
  if (!DEFINITIVE_MEMBER_OUTCOMES.has(member.outcome)) {
4507
3778
  return {
4508
3779
  definitive: false,
4509
- reason: `member outcome '${member.outcome}' is not a final pass or fail (D-17)`
3780
+ reason: `member outcome '${member.outcome}' is not a final pass or fail`
4510
3781
  };
4511
3782
  }
4512
3783
  for (const step of member.steps) {
4513
3784
  if (step.planningFailure !== void 0) {
4514
3785
  return {
4515
3786
  definitive: false,
4516
- reason: `planning failed structurally on step ${step.stepIndex}: the draft was never executed to a verdict, so the enum below describes the attempt, not the app (D-17)`
3787
+ reason: `planning failed structurally on step ${step.stepIndex}: the draft was never executed to a verdict, so the enum below describes the attempt, not the app`
4517
3788
  };
4518
3789
  }
4519
3790
  if (step.limitStop !== void 0) {
4520
3791
  const { limit, used, configured } = step.limitStop;
4521
3792
  return {
4522
3793
  definitive: false,
4523
- reason: `step ${step.stepIndex} stopped at its ${limit} limit (${used} of ${configured} used): the run ran out of limit, not into an answer (D-12)`
3794
+ reason: `step ${step.stepIndex} stopped at its ${limit} limit (${used} of ${configured} used): the run ran out of limit, not into an answer`
4524
3795
  };
4525
3796
  }
4526
3797
  if (step.cycle !== void 0) {
4527
3798
  return {
4528
3799
  definitive: false,
4529
- reason: `a cycle was flagged on step ${step.stepIndex} (${step.cycle.reason}): the run stopped revisiting state rather than reaching an answer (D-17)`
3800
+ reason: `a cycle was flagged on step ${step.stepIndex} (${step.cycle.reason}): the run stopped revisiting state rather than reaching an answer`
4530
3801
  };
4531
3802
  }
4532
3803
  if (step.termination !== void 0) {
4533
3804
  return {
4534
3805
  definitive: false,
4535
- reason: `step ${step.stepIndex} terminated '${step.termination.kind}' (${step.termination.reason}) \u2014 indefinitive despite member outcome '${member.outcome}', which reads definitive on its own (393-01 F1)`
3806
+ reason: `step ${step.stepIndex} terminated '${step.termination.kind}' (${step.termination.reason}) \u2014 indefinitive despite member outcome '${member.outcome}', which reads definitive on its own`
4536
3807
  };
4537
3808
  }
4538
3809
  }
4539
3810
  return {
4540
3811
  definitive: true,
4541
- reason: `member outcome '${member.outcome}' with no planning failure, limit stop, cycle flag or termination on any step \u2014 a final answer about the draft` + (member.outcome === "healed" ? "; a healed pass IS a pass (393-01 F3)" : "")
3812
+ reason: `member outcome '${member.outcome}' with no planning failure, limit stop, cycle flag or termination on any step \u2014 a final answer about the draft` + (member.outcome === "healed" ? "; a healed pass is a pass" : "")
4542
3813
  };
4543
3814
  }
4544
3815
  function gateRunStartInput(draft) {
@@ -4589,8 +3860,7 @@ async function runStabilityGates(input) {
4589
3860
  const distinctOutcomes = [...new Set(observedVerdicts)];
4590
3861
  return {
4591
3862
  executesDefinitive: gateRuns.length > 0 && gateRuns.every((row) => row.definitive),
4592
- // An evaluation that observed no verdict at all has not shown stability; it has shown nothing.
4593
- // D-12's tune-toward-reject applies — a gate with no evidence behind it is not a pass.
3863
+ // No observed verdict shows nothing, so the gate does not pass.
4594
3864
  stableVerdict: distinctOutcomes.length === 1,
4595
3865
  gateRuns,
4596
3866
  runsCompleted: gateRuns.length,
@@ -4701,7 +3971,7 @@ async function evaluateDraft(input, ports) {
4701
3971
  return receipt;
4702
3972
  }
4703
3973
  function stabilityGateOneReason(pass, runCount) {
4704
- return pass ? `all ${runCount} gate-run(s) reached a final verdict about the draft (D-17)` : `${runCount} gate-run(s) taken; at least one reached no final verdict \u2014 see gateRuns[].reason`;
3974
+ return pass ? `all ${runCount} gate-run(s) reached a final verdict about the draft` : `${runCount} gate-run(s) taken; at least one reached no final verdict \u2014 see gateRuns[].reason`;
4705
3975
  }
4706
3976
  async function consultSuiteStability(draft, targetSuitePath, distinctOutcomes, ports) {
4707
3977
  if (distinctOutcomes.length <= 1) return void 0;
@@ -4727,7 +3997,7 @@ function stabilityGateTwoReason(distinctOutcomes, earlyStopped, suiteStability)
4727
3997
  if (distinctOutcomes.length <= 1) {
4728
3998
  return `one verdict across the completed runs: ${distinctOutcomes[0] ?? "none observed"}`;
4729
3999
  }
4730
- return `the verdict flipped across runs (${distinctOutcomes.join(" -> ")})` + (earlyStopped ? " \u2014 remaining runs skipped, the flip is already proven (D-17)" : "") + (suiteStability === void 0 ? "" : ` \u2014 ${suiteStability.message}`);
4000
+ return `the verdict flipped across runs (${distinctOutcomes.join(" -> ")})` + (earlyStopped ? " \u2014 remaining runs skipped, the flip is already proven" : "") + (suiteStability === void 0 ? "" : ` \u2014 ${suiteStability.message}`);
4731
4001
  }
4732
4002
 
4733
4003
  // src/functions/ops/authoring-verify-draft.ts
@@ -4782,40 +4052,18 @@ function hasDraftExtension(draftPath) {
4782
4052
  var authoringVerifyDraftSpec = {
4783
4053
  id: AUTHORING_DRAFT_VERIFY_FUNCTION_ID,
4784
4054
  summary: "Evaluate a draft test against the four keep-gates and return its receipt.",
4785
- // 2026-10-01 (432-23, D-12): no scopes. The evaluation STARTS runs and READS the completed
4786
- // records back, and the composition invokes those sibling ops on a caller it mints (D-02,
4787
- // op-calls-op). The `run` + `read` pair once declared here kept a nested call from widening a
4788
- // grant; with no grants to widen, every door can call this op and its siblings alike.
4789
4055
  resultKind: "unary",
4790
4056
  boundThrough: "draftEvaluation",
4791
4057
  input: import_agent_qa_schema22.AuthoringVerifyDraftInputSchema,
4792
4058
  output: import_agent_qa_schema22.DraftReceiptSchema,
4793
- // The `runs.start` tier rationale, adapted — and it is the same argument because this op's whole
4794
- // effect is the runs it takes:
4795
- // `recognized: true` with NO `readOnly` puts the classifier's floor at mutating-local;
4796
- // `declaredTier` states that tier explicitly rather than relying on the floor alone;
4797
- // the name tokens (fn · authoring · draft · verify) hit neither destructive lexicon, so
4798
- // nothing raises the tier above what is declared.
4799
- // The tier was chosen when `mutating-shared` would have ASKED, and an ask in a fail-closed
4800
- // context denied, leaving 394's authoring loop unable to verify a draft in CI, the one context
4801
- // where the keep-filter most needs to run unattended. 2026-10-01 (432-19/432-23, D-12/D-15):
4802
- // nothing asks or denies on a tier any more; the tier stays the honest classification.
4803
- // Verifying a draft really is local: it spends this machine's resources, writes into this
4804
- // project's run directory and its gitignored receipts store, and — because every gate-run is
4805
- // flagged `excludedFromOutcomes` (WTST-06) — deliberately leaves no trace in the shared signals
4806
- // a colleague reads.
4059
+ // Verifying a draft spends this machine's resources, writes into this project's run directory and
4060
+ // its gitignored receipts store, and leaves no trace in the shared signals a colleague reads,
4061
+ // because every gate-run is flagged `excludedFromOutcomes`.
4807
4062
  risk: {
4808
4063
  name: `fn:${AUTHORING_DRAFT_VERIFY_FUNCTION_ID}`,
4809
- recognized: true,
4810
- declaredTier: "mutating-local"
4064
+ recognized: true
4811
4065
  },
4812
- /**
4813
- * A RECEIPT'S VERDICT ABOUT A DRAFT IS AN ANSWER, not a refusal (399.1 D-01, plan 03's razor).
4814
- *
4815
- * `rejected` here is the gate saying what it found about somebody's draft — the verification ran
4816
- * and produced its finding. `refused` is for a control declining an act it would otherwise have
4817
- * carried out, and nothing was declined: the act WAS carrying out the verification.
4818
- */
4066
+ // A rejection is the verification's finding, an answer, never `refused`.
4819
4067
  classify(output) {
4820
4068
  return {
4821
4069
  status: "executed",
@@ -4882,8 +4130,6 @@ var import_agent_qa_schema24 = require("@vostride/agent-qa-schema");
4882
4130
 
4883
4131
  // src/config-mutation/cross-boundary.ts
4884
4132
  var import_agent_qa_schema23 = require("@vostride/agent-qa-schema");
4885
- var ALLOW_PRODUCTION_PATH = "allowProduction";
4886
- var TARGET_ENVIRONMENT_PATH = /^registry\.targets\.[^.]+\.environment$/;
4887
4133
  function originOf(value) {
4888
4134
  if (typeof value !== "string") return void 0;
4889
4135
  let parsed;
@@ -4901,12 +4147,6 @@ function computeCrossBoundary(facts) {
4901
4147
  if ((0, import_agent_qa_schema23.isSecretAdjacentConfigField)(edit.configPath)) found.add("secret-adjacent-field");
4902
4148
  const newOrigin = originOf(edit.newValue);
4903
4149
  if (newOrigin !== void 0 && newOrigin !== originOf(edit.oldValue)) found.add("new-origin");
4904
- if (edit.configPath === ALLOW_PRODUCTION_PATH && edit.newValue === true && edit.oldValue !== true) {
4905
- found.add("production-opt-in");
4906
- }
4907
- if (TARGET_ENVIRONMENT_PATH.test(edit.configPath) && edit.oldValue === "production" && edit.newValue !== "production") {
4908
- found.add("production-declassified");
4909
- }
4910
4150
  }
4911
4151
  if (facts.addsHook) found.add("hook-added");
4912
4152
  const pinned = new Set(facts.pinnedFileSet);
@@ -5007,9 +4247,7 @@ async function changeConfigField(input, deps) {
5007
4247
  ...edit.previousValue === void 0 ? {} : { oldValue: edit.previousValue },
5008
4248
  newValue: input.value
5009
4249
  }],
5010
- // A field set writes a config value; it does not add a hook. `config.hook.add` is its own op and
5011
- // supplies this fact itself. Stated rather than inferred, because inferring "a hook was added"
5012
- // from a path would be the per-op map D-02 refused.
4250
+ // Stated, not inferred: a field set adds no hook; `config.hook.add` states its own.
5013
4251
  addsHook: false,
5014
4252
  candidate: candidateSet(set, [{ path: target.path, bytes: edit.bytes }])
5015
4253
  }, {
@@ -5189,7 +4427,7 @@ async function addConfigHook(input, deps) {
5189
4427
  subject: `add hook ${input.name}`,
5190
4428
  summaryLine: `add ${input.runtime} hook ${input.name} running ${input.file}`,
5191
4429
  fieldEdits: flattenScalarEdits(`${HOOKS_PATH}.${at}`, entry2, void 0),
5192
- // STATED, NOT INFERRED (D-02). This is the op that adds hooks; nothing has to guess.
4430
+ // Stated, not inferred: this op adds hooks.
5193
4431
  addsHook: true,
5194
4432
  candidate: candidateSet(set, [{ path: hooksMember.path, bytes: written.bytes }])
5195
4433
  }, { kind: "files" }, set, deps);
@@ -5227,8 +4465,7 @@ async function scaffoldConfigProject(input, deps) {
5227
4465
  targetName: verdict.targetName,
5228
4466
  baseUrl: verdict.baseUrl,
5229
4467
  ...gitignore?.bytes === void 0 ? {} : { existingGitignore: gitignore.bytes },
5230
- // MERGE MODE, AND ONLY WHEN THERE ARE BYTES TO MERGE INTO. Absent here is the from-zero road,
5231
- // whose rendered bytes are byte-identical to what 395-08 shipped and what the goldens pin.
4468
+ // Merge mode only when there are bytes to merge into; goldens pin the from-zero output.
5232
4469
  ...existingConfig.bytes === void 0 ? {} : {
5233
4470
  existingConfig: {
5234
4471
  path: existingConfig.path,
@@ -5250,9 +4487,7 @@ async function scaffoldConfigProject(input, deps) {
5250
4487
  { configPath: `${TARGETS_PATH}.${verdict.targetName}.platform`, newValue: "web" },
5251
4488
  { configPath: `${TARGETS_PATH}.${verdict.targetName}.url`, newValue: verdict.baseUrl }
5252
4489
  ],
5253
- // The scaffolded hooks file declares one hook, which is code this project would then run.
5254
- // Stated by the op, as D-02 requires, and true exactly when the file did not exist a moment
5255
- // ago — see `addsHook`'s derivation above.
4490
+ // True exactly when the hooks file did not exist; see `addsHook`'s derivation above.
5256
4491
  addsHook,
5257
4492
  candidate: candidateSet(set, [...rendered])
5258
4493
  }, { kind: "files" }, set, deps);
@@ -5519,14 +4754,7 @@ var configAuthSetSpec = {
5519
4754
  recognized: true,
5520
4755
  readOnly: false
5521
4756
  },
5522
- /**
5523
- * This op's own union, folded into a clause verdict (2026-08-20, Phase 399.1 D-01/D-02).
5524
- *
5525
- * THE FOLD IS SHARED BECAUSE THE UNION IS. Six ops answer with `ConfigChangeOutput` (432-11), and a
5526
- * per-op copy of the mapping would be a guardrail refusal that reports `refused` on some doors
5527
- * and `executed` on others the first time one copy is edited. See `config-propose-verdict.ts`
5528
- * for why `blocked` and `refused` are the same status and different words.
5529
- */
4757
+ // Shared, so every door reports a guardrail refusal alike; see `config-propose-verdict.ts`.
5530
4758
  classify: classifyConfigChangeOutput,
5531
4759
  async invoke(input, deps) {
5532
4760
  const { configFiles, configValidate, configWrite } = deps;
@@ -5555,15 +4783,7 @@ var configFieldSetSpec = {
5555
4783
  recognized: true,
5556
4784
  readOnly: false
5557
4785
  },
5558
- /**
5559
- * This op's own union, folded into a clause verdict (2026-08-20, Phase 399.1 D-01/D-02).
5560
- *
5561
- * THE MAPPING MOVED TO `config-propose-verdict.ts` IN 399.1-03, unchanged, when the other six ops
5562
- * answering with this same union got classifiers of their own. It was written here first because
5563
- * this op was the tracer; leaving a private copy behind would have made a guardrail refusal report
5564
- * `refused` on this door and `executed` on the next one the first time somebody edited one copy.
5565
- * The arms, and the reasoning for which of them is `refused`, are documented at the fold.
5566
- */
4786
+ // Shared, so every door reports a guardrail refusal alike; see `config-propose-verdict.ts`.
5567
4787
  classify: classifyConfigChangeOutput,
5568
4788
  async invoke(input, deps) {
5569
4789
  const { configFiles, configValidate, configWrite } = deps;
@@ -5592,14 +4812,7 @@ var configHookAddSpec = {
5592
4812
  recognized: true,
5593
4813
  readOnly: false
5594
4814
  },
5595
- /**
5596
- * This op's own union, folded into a clause verdict (2026-08-20, Phase 399.1 D-01/D-02).
5597
- *
5598
- * THE FOLD IS SHARED BECAUSE THE UNION IS. Six ops answer with `ConfigChangeOutput` (432-11), and a
5599
- * per-op copy of the mapping would be a guardrail refusal that reports `refused` on some doors
5600
- * and `executed` on others the first time one copy is edited. See `config-propose-verdict.ts`
5601
- * for why `blocked` and `refused` are the same status and different words.
5602
- */
4815
+ // Shared, so every door reports a guardrail refusal alike; see `config-propose-verdict.ts`.
5603
4816
  classify: classifyConfigChangeOutput,
5604
4817
  async invoke(input, deps) {
5605
4818
  const { configFiles, configValidate, configWrite } = deps;
@@ -5623,13 +4836,7 @@ var configGetSpec = {
5623
4836
  input: import_agent_qa_schema28.ConfigGetInputSchema,
5624
4837
  output: import_agent_qa_schema28.MaskedResolvedConfigSchema,
5625
4838
  risk: { name: `fn:${CONFIG_GET_FUNCTION_ID}`, recognized: true, readOnly: true },
5626
- /**
5627
- * A read that answered — the count of what it resolved, and nothing out of it (399.1 D-01).
5628
- *
5629
- * NOT ONE ENTRY'S VALUE, ever. This op's result carries a person's configuration, placeholder-
5630
- * masked; the receipt is a map and the masked payload travels on `results[]` where the surface's
5631
- * own unmasker decides what a human may see (D-04's boundary, not this fold's).
5632
- */
4839
+ // Counts only, never an entry's value; the masked payload travels on `results[]`.
5633
4840
  classify(output) {
5634
4841
  const count = output.entries.length;
5635
4842
  return {
@@ -5657,14 +4864,7 @@ var configTargetCreateSpec = {
5657
4864
  recognized: true,
5658
4865
  readOnly: false
5659
4866
  },
5660
- /**
5661
- * This op's own union, folded into a clause verdict (2026-08-20, Phase 399.1 D-01/D-02).
5662
- *
5663
- * THE FOLD IS SHARED BECAUSE THE UNION IS. Six ops answer with `ConfigChangeOutput` (432-11), and a
5664
- * per-op copy of the mapping would be a guardrail refusal that reports `refused` on some doors
5665
- * and `executed` on others the first time one copy is edited. See `config-propose-verdict.ts`
5666
- * for why `blocked` and `refused` are the same status and different words.
5667
- */
4867
+ // Shared, so every door reports a guardrail refusal alike; see `config-propose-verdict.ts`.
5668
4868
  classify: classifyConfigChangeOutput,
5669
4869
  async invoke(input, deps) {
5670
4870
  const { configFiles, configValidate, configWrite } = deps;
@@ -5693,14 +4893,7 @@ var configProjectScaffoldSpec = {
5693
4893
  recognized: true,
5694
4894
  readOnly: false
5695
4895
  },
5696
- /**
5697
- * This op's own union, folded into a clause verdict (2026-08-20, Phase 399.1 D-01/D-02).
5698
- *
5699
- * THE FOLD IS SHARED BECAUSE THE UNION IS. Six ops answer with `ConfigChangeOutput` (432-11), and a
5700
- * per-op copy of the mapping would be a guardrail refusal that reports `refused` on some doors
5701
- * and `executed` on others the first time one copy is edited. See `config-propose-verdict.ts`
5702
- * for why `blocked` and `refused` are the same status and different words.
5703
- */
4896
+ // Shared, so every door reports a guardrail refusal alike; see `config-propose-verdict.ts`.
5704
4897
  classify: classifyConfigChangeOutput,
5705
4898
  async invoke(input, deps) {
5706
4899
  const { configFiles, configValidate, configWrite, scaffoldContent } = deps;
@@ -5729,14 +4922,7 @@ var configTargetEditSpec = {
5729
4922
  recognized: true,
5730
4923
  readOnly: false
5731
4924
  },
5732
- /**
5733
- * This op's own union, folded into a clause verdict (2026-08-20, Phase 399.1 D-01/D-02).
5734
- *
5735
- * THE FOLD IS SHARED BECAUSE THE UNION IS. Six ops answer with `ConfigChangeOutput` (432-11), and a
5736
- * per-op copy of the mapping would be a guardrail refusal that reports `refused` on some doors
5737
- * and `executed` on others the first time one copy is edited. See `config-propose-verdict.ts`
5738
- * for why `blocked` and `refused` are the same status and different words.
5739
- */
4925
+ // Shared, so every door reports a guardrail refusal alike; see `config-propose-verdict.ts`.
5740
4926
  classify: classifyConfigChangeOutput,
5741
4927
  async invoke(input, deps) {
5742
4928
  const { configFiles, configValidate, configWrite } = deps;
@@ -5836,13 +5022,7 @@ var knowledgeBriefWhySpec = {
5836
5022
  input: import_agent_qa_schema32.BriefWhyInputSchema,
5837
5023
  output: import_agent_qa_schema32.BriefWhyResultSchema,
5838
5024
  risk: { name: `fn:${KNOWLEDGE_BRIEF_WHY_FUNCTION_ID}`, recognized: true, readOnly: true },
5839
- /**
5840
- * `no-trace` IS THE HONEST ABSENCE THIS VERB EXISTS FOR (399.1 D-01).
5841
- *
5842
- * KREV-02's whole posture is that a brief whose trace is gone must be SAID to be gone rather than
5843
- * re-derived; the op that answers it is given no serving capability at all. That is an answer the
5844
- * verb is proud of, not a control declining, so the arm is `executed` with the store's own reason.
5845
- */
5025
+ // `no-trace` is the honest absence, so it folds to `executed` with the store's reason.
5846
5026
  classify(output) {
5847
5027
  switch (output.kind) {
5848
5028
  case "answered":
@@ -5872,9 +5052,7 @@ var knowledgeRecordShowSpec = {
5872
5052
  input: import_agent_qa_schema33.KnowledgeRecordShowInputSchema,
5873
5053
  output: import_agent_qa_schema33.KnowledgeRecordShowResultSchema,
5874
5054
  risk: { name: `fn:${KNOWLEDGE_RECORD_SHOW_FUNCTION_ID}`, recognized: true, readOnly: true },
5875
- /**
5876
- * "Absence is a RESULT rather than a refusal" — the contract's own words (399.1 D-01).
5877
- */
5055
+ // Absence is a result, not a refusal.
5878
5056
  classify(output) {
5879
5057
  switch (output.kind) {
5880
5058
  case "found":
@@ -5927,27 +5105,14 @@ var runsStartSpec = {
5927
5105
  boundThrough: "runInvocation",
5928
5106
  input: import_agent_qa_schema34.RunsStartInputSchema,
5929
5107
  output: import_agent_qa_schema34.RunStartAcknowledgementSchema,
5930
- // Pitfall 10, and every field here is load-bearing:
5931
- // `recognized: true` with NO `readOnly` puts the classifier's floor at mutating-local;
5932
- // `declaredTier` states that tier explicitly rather than relying on the floor alone;
5933
- // the name tokens (fn · runs · start) hit neither destructive lexicon, so nothing
5934
- // raises the tier above what is declared.
5935
- // The tier was chosen when `mutating-shared` would have asked, and an ask in a fail-closed
5936
- // context denied, leaving the authoring loop unable to start a run in CI. 2026-10-01 (432-19/
5937
- // 432-23, D-12/D-15): nothing asks or denies on a tier any more; the tier stays the honest
5938
- // classification. Starting a run really is local: it spends this machine's resources and
5939
- // writes into this project's run directory. It touches nothing another party shares.
5940
5108
  risk: {
5941
5109
  name: `fn:${RUNS_START_FUNCTION_ID}`,
5942
- recognized: true,
5943
- declaredTier: "mutating-local"
5110
+ recognized: true
5944
5111
  },
5945
5112
  /**
5946
- * AN ACKNOWLEDGEMENT IS A START, NOT AN OUTCOME (399.1 D-01).
5947
- *
5948
- * This op returns when the run has been ACCEPTED, long before it has a verdict — so the outcome
5949
- * names the run a person can follow and how much it took on, and says nothing about how it went.
5950
- * A refusal to start is a throw and already reaches the engine's `failed` mapping.
5113
+ * The op answers when the run has its verdict. The outcome line names the run, how many tests it
5114
+ * ran and its scope, and leaves how it went to the run's own record. A refusal to start is a
5115
+ * throw.
5951
5116
  */
5952
5117
  classify(output) {
5953
5118
  return {
@@ -6011,12 +5176,7 @@ var ENTITY_ACTION_TABLES = {
6011
5176
  inputSeed: { recordId: descriptor.machineId }
6012
5177
  },
6013
5178
  {
6014
- // D-11's table completion (387-08). 2026-09-30, 432-12 (D-05/D-09): forget is the explicit
6015
- // removal and it applies in the call, so the action says what it does. The record is
6016
- // tombstoned, never destroyed, and the card at this address then reads `tombstoned`. The
6017
- // seed addresses the RECORD grain because a descriptor carries the machine id it was
6018
- // sighted under, and the bundle grain takes a short-ID whose resolution is the writer's job
6019
- // rather than the card's.
5179
+ // Forget tombstones the record in the call; the seed addresses the record grain.
6020
5180
  functionId: KNOWLEDGE_FORGET_FUNCTION_ID,
6021
5181
  label: "Forget this record",
6022
5182
  inputSeed: { target: { grain: "record", recordId: descriptor.machineId } }
@@ -6114,7 +5274,7 @@ function projectKeyFacts(input) {
6114
5274
  var ForgetReceiptKindError = class extends TypeError {
6115
5275
  constructor(kind) {
6116
5276
  super(
6117
- `a forget receipt describes a MEM knowledge bundle (D-19); it cannot render a ${kind} card`
5277
+ `a forget receipt describes a MEM knowledge bundle; it cannot render a ${kind} card`
6118
5278
  );
6119
5279
  this.kind = kind;
6120
5280
  this.name = "ForgetReceiptKindError";
@@ -6182,13 +5342,7 @@ var entitiesGetSpec = {
6182
5342
  input: import_agent_qa_schema37.EntitiesGetInputSchema,
6183
5343
  output: import_agent_qa_schema37.EntityCardSchema,
6184
5344
  risk: { name: `fn:${ENTITIES_GET_FUNCTION_ID}`, recognized: true, readOnly: true },
6185
- /**
6186
- * A card that came back is a card that was found (399.1 D-01).
6187
- *
6188
- * Absence is a THROW here (`EntityNotFoundError`), not an arm, so the one returning shape is a
6189
- * hit. THE ADDRESS AND NOTHING ELSE: `kind` and `id` are the card's own name, and every fact on
6190
- * it travels on `results[]`.
6191
- */
5345
+ // Absence throws, so the only returning shape is a hit.
6192
5346
  classify(output) {
6193
5347
  return { status: "executed", outcome: `found ${output.kind} ${output.id}` };
6194
5348
  },
@@ -6375,61 +5529,22 @@ function abstainAndRecord(port, query, rows) {
6375
5529
  }
6376
5530
  var explainSpec = {
6377
5531
  id: EXPLAIN_FUNCTION_ID,
6378
- // One line, and it is the line the catalog RENDERS for this row — descriptions live on the spec
6379
- // so one source feeds chat, MCP and the catalogue (396 D-16 / 398 D-08).
5532
+ // The line the catalog renders for this row.
6380
5533
  summary: "Answer a question about what this product can do by citing the capability catalog, or say plainly that the catalog does not ground an answer.",
6381
- // 2026-10-01 (432-26, D-12): no scope. This op once declared `read` alone so that it stayed
6382
- // listable in safe mode; safe mode and scopes are deleted, and every caller lists and calls it.
6383
5534
  resultKind: "unary",
6384
- // D-09: the catalog reaches this op through a port bound at `composeLocalAgent()` (385 D-15). A
6385
- // composition without one lists the capability `unbound` BY NAME rather than degrading to a
6386
- // model-only answer — an explain that silently lost its catalog is precisely an explain that
6387
- // answers from model memory, which is the one behaviour XPLN-02 exists to forbid.
5535
+ // Unbound without a catalog, so an explain never answers from model memory.
6388
5536
  boundThrough: "capabilityCatalog",
6389
5537
  input: import_agent_qa_schema40.ExplainInputSchema,
6390
5538
  output: import_agent_qa_schema40.ExplainOutputSchema,
6391
5539
  // Read-only and recognized: it starts nothing, writes nothing a caller can address, and the one
6392
5540
  // byte it appends is a local coverage line about a question it was asked.
6393
5541
  risk: { name: `fn:${EXPLAIN_FUNCTION_ID}`, recognized: true, readOnly: true },
6394
- /**
6395
- * The answer lines this op composed, on their way to the turn's `answer` field (398-13 · D-21).
6396
- *
6397
- * MIGRATED FROM `turn-engine.ts` BY 399.1-03, ARGUMENT INTACT. It lived there as
6398
- * `explainAnswerLines`, an explicit comparison of the running clause's `functionId` against this
6399
- * op's id — a render rule in the engine, which by construction could only ever render what
6400
- * somebody had thought to name there. D-04's promote decision moved it here: this op knows what
6401
- * its own result deserves to have said about it, and the engine no longer knows this op exists.
6402
- *
6403
- * THE RECEIPT CHARTER IS UNTOUCHED, and that is still the whole reason these lines take THIS
6404
- * channel rather than the receipt's. The receipt stays the MAP — the plain `agent.explain
6405
- * completed` line — and the territory travels on the field `renderTurn` already prints and `ask`
6406
- * already shares. A second carrier on the receipt would put the answer inside the map.
6407
- *
6408
- * PARSED, NEVER CAST, and a parse failure renders NOTHING extra: the fold fails OPEN by contract
6409
- * (`foldFunctionResult`), so an unreadable result costs a person legibility and never the record.
6410
- * Every character of `renderedLines` was quoted out of a committed catalog row by the renderer
6411
- * (D-10), so nothing a model wrote can ride this channel — which is why the parse is here and not
6412
- * a cast: a doctored result must not become a door for prose.
6413
- *
6414
- * BOTH ARMS RENDER. An abstention's lines are the honest "the catalog does not ground an answer",
6415
- * and XPLN-02's whole claim is that saying so plainly is an ANSWER a person is owed, not a silence.
6416
- */
5542
+ // Parsed, never cast, so a doctored result cannot carry prose; a parse failure adds nothing.
6417
5543
  renderResult(output) {
6418
5544
  const parsed = import_agent_qa_schema40.ExplainOutputSchema.safeParse(output);
6419
5545
  return parsed.success ? parsed.data.renderedLines : [];
6420
5546
  },
6421
- /**
6422
- * AN ABSTENTION IS AN HONEST ANSWER, NOT A CONTROL DECLINING (399.1 D-01/D-02, plan 03's razor).
6423
- *
6424
- * XPLN-02's whole claim is that "the catalog does not ground an answer" is a result this op is
6425
- * PROUD of. Folding it to `refused` would tell a person a guardrail stopped their question when
6426
- * what happened is that the question was answered truthfully.
6427
- *
6428
- * COUNTS AND NO TERRITORY, and here that is load-bearing rather than stylistic. The answer text
6429
- * is this op's `renderResult` output and reaches the turn's `answer` field; a receipt outcome
6430
- * carrying a cited row's description would put the territory back inside the map, which is the
6431
- * one thing `explain.test.ts`'s receipt-charter cell exists to red on.
6432
- */
5547
+ // An abstention is an answer, never `refused`; the receipt carries counts only.
6433
5548
  classify(output) {
6434
5549
  switch (output.kind) {
6435
5550
  case "answer":
@@ -6507,14 +5622,7 @@ var entitiesResolveSpec = {
6507
5622
  input: import_agent_qa_schema41.EntitiesResolveInputSchema,
6508
5623
  output: import_agent_qa_schema41.EntityCardResolutionSchema,
6509
5624
  risk: { name: `fn:${ENTITIES_RESOLVE_FUNCTION_ID}`, recognized: true, readOnly: true },
6510
- /**
6511
- * THREE ARMS, ALL ANSWERS (399.1 D-01, plan 03's razor).
6512
- *
6513
- * `ambiguous` and `none` are the resolver refusing to GUESS, which is the never-guess contract
6514
- * doing exactly what it promises — a resolution it will not invent is the answer to the question
6515
- * asked, not a control declining an act. Reporting either as `refused` would send a person
6516
- * looking for a guardrail that never fired.
6517
- */
5625
+ // `ambiguous` and `none` are answers, never `refused`; no guardrail fired.
6518
5626
  classify(output) {
6519
5627
  switch (output.kind) {
6520
5628
  case "resolved":
@@ -6534,9 +5642,7 @@ var entitiesResolveSpec = {
6534
5642
  const resolution = await deps.entities.resolve(input.ref);
6535
5643
  return renderResolution(
6536
5644
  resolution,
6537
- // The descriptors this render is ABOUT to produce cards for — every arm of them, so an
6538
- // ambiguous set containing one test reads the ledger once and every candidate is rendered
6539
- // against the same fold (390). A `none` arm renders nothing and reads nothing.
5645
+ // Every arm's descriptors, so an ambiguous set reads the ledger once and shares one fold.
6540
5646
  await readEntityCardContext(deps, descriptorsOf(resolution))
6541
5647
  );
6542
5648
  }
@@ -6568,7 +5674,7 @@ var knowledgeAcceptSpec = {
6568
5674
  output: import_agent_qa_schema42.KnowledgeChangeOutputSchema,
6569
5675
  boundThrough: "knowledgeReview",
6570
5676
  risk: { name: `fn:${KNOWLEDGE_ACCEPT_FUNCTION_ID}`, recognized: true, readOnly: false },
6571
- // The fold the three knowledge changes share (2026-10-03, quick 261003-cpv, 432 review IN-04).
5677
+ // The fold every knowledge change op shares.
6572
5678
  classify: classifyKnowledgeChangeOutput,
6573
5679
  invoke({ operationId, ...input }, deps) {
6574
5680
  return deps.knowledgeReview.change({
@@ -6592,9 +5698,7 @@ var knowledgeBundlesListSpec = {
6592
5698
  input: import_agent_qa_schema43.KnowledgeBundlesListInputSchema,
6593
5699
  output: import_agent_qa_schema43.KnowledgeBundlesListOutputSchema,
6594
5700
  risk: { name: `fn:${KNOWLEDGE_BUNDLES_LIST_FUNCTION_ID}`, recognized: true, readOnly: true },
6595
- /**
6596
- * A listing that answered — the count, and nothing out of a bundle (399.1 D-01).
6597
- */
5701
+ // The count only, nothing out of a bundle.
6598
5702
  classify(output) {
6599
5703
  return { status: "executed", outcome: `${output.length} knowledge bundle(s)` };
6600
5704
  },
@@ -6615,7 +5719,7 @@ var KnowledgeGatesUnboundError = class extends Error {
6615
5719
  };
6616
5720
  var knowledgeGatesListSpec = {
6617
5721
  id: KNOWLEDGE_GATES_LIST_FUNCTION_ID,
6618
- summary: "Read a knowledge record\u2019s gate history, standing receipts and current promotion verdict.",
5722
+ summary: "Read a knowledge record\u2019s mark and approval receipts, promotion lines and live promotion verdict.",
6619
5723
  resultKind: "unary",
6620
5724
  input: import_agent_qa_schema44.KnowledgeGatesListInputSchema,
6621
5725
  output: import_agent_qa_schema44.KnowledgeGatesListResultSchema,
@@ -6640,7 +5744,7 @@ var knowledgeForgetSpec = {
6640
5744
  output: import_agent_qa_schema45.KnowledgeChangeOutputSchema,
6641
5745
  boundThrough: "knowledgeReview",
6642
5746
  risk: { name: `fn:${KNOWLEDGE_FORGET_FUNCTION_ID}`, recognized: true, readOnly: false },
6643
- // The fold the three knowledge changes share (2026-10-03, quick 261003-cpv, 432 review IN-04).
5747
+ // The fold every knowledge change op shares.
6644
5748
  classify: classifyKnowledgeChangeOutput,
6645
5749
  invoke({ operationId, ...input }, deps) {
6646
5750
  return deps.knowledgeReview.change({
@@ -6667,13 +5771,7 @@ var knowledgeRecordsDiffSpec = {
6667
5771
  input: import_agent_qa_schema46.KnowledgeRecordsDiffInputSchema,
6668
5772
  output: import_agent_qa_schema46.KnowledgeRecordsDiffOutputSchema,
6669
5773
  risk: { name: `fn:${KNOWLEDGE_RECORDS_DIFF_FUNCTION_ID}`, recognized: true, readOnly: true },
6670
- /**
6671
- * A diff that answered, WITH ITS BASELINE (399.1 D-01).
6672
- *
6673
- * The ordinal rides the outcome for the contract's own reason: "a change list with no baseline is
6674
- * a list whose meaning depends on remembering the question", and a receipt line is exactly the
6675
- * artifact that gets pasted somewhere the question is gone.
6676
- */
5774
+ // The ordinal rides the outcome, because a change list without its baseline loses its meaning.
6677
5775
  classify(output) {
6678
5776
  return {
6679
5777
  status: "executed",
@@ -6709,9 +5807,7 @@ var knowledgeRecordsInspectSpec = {
6709
5807
  input: import_agent_qa_schema47.KnowledgeRecordsInspectInputSchema,
6710
5808
  output: import_agent_qa_schema47.KnowledgeRecordsInspectOutputSchema,
6711
5809
  risk: { name: `fn:${KNOWLEDGE_RECORDS_INSPECT_FUNCTION_ID}`, recognized: true, readOnly: true },
6712
- /**
6713
- * An inspection that answered — the count, and no record content (399.1 D-01).
6714
- */
5810
+ // The count only, no record content.
6715
5811
  classify(output) {
6716
5812
  return { status: "executed", outcome: `${output.records.length} record(s) inspected` };
6717
5813
  },
@@ -6734,7 +5830,7 @@ var knowledgeRejectSpec = {
6734
5830
  output: import_agent_qa_schema48.KnowledgeChangeOutputSchema,
6735
5831
  boundThrough: "knowledgeReview",
6736
5832
  risk: { name: `fn:${KNOWLEDGE_REJECT_FUNCTION_ID}`, recognized: true, readOnly: false },
6737
- // The fold the three knowledge changes share (2026-10-03, quick 261003-cpv, 432 review IN-04).
5833
+ // The fold every knowledge change op shares.
6738
5834
  classify: classifyKnowledgeChangeOutput,
6739
5835
  invoke({ operationId, ...input }, deps) {
6740
5836
  return deps.knowledgeReview.change({
@@ -6756,12 +5852,7 @@ var quarantineAddSpec = {
6756
5852
  input: import_agent_qa_schema49.QuarantineAddInputSchema,
6757
5853
  output: import_agent_qa_schema49.QuarantineAddOutputSchema,
6758
5854
  risk: { name: `fn:${QUARANTINE_ADD_FUNCTION_ID}`, recognized: true, readOnly: false },
6759
- /**
6760
- * `renewed` IS IDEMPOTENCY, AND THE CONTRACT CALLS IT INFORMATION (399.1 D-01).
6761
- *
6762
- * "Already quarantined is information an operator acts on, not an error" — so both arms are
6763
- * `executed` and the outcome says which gesture the ledger recorded.
6764
- */
5855
+ // Already quarantined is information, so both arms are `executed`.
6765
5856
  classify(output) {
6766
5857
  switch (output.kind) {
6767
5858
  case "entered":
@@ -6788,17 +5879,12 @@ var quarantineListSpec = {
6788
5879
  id: QUARANTINE_LIST_FUNCTION_ID,
6789
5880
  summary: "List every quarantined test with its owner, expiry and lifecycle state.",
6790
5881
  resultKind: "unary",
6791
- // Bound exactly where a composition supplies the quarantine port. Listing quarantine state
6792
- // is not something a host can approximate: an unbound host answering `[]` would say "nothing
6793
- // is quarantined" about a ledger it has never been able to read, which is a wrong answer
6794
- // wearing a correct one's clothes. So it refuses by name instead (D-09).
5882
+ // An unbound host refuses rather than answer `[]` about a ledger it cannot read.
6795
5883
  boundThrough: "quarantine",
6796
5884
  input: import_agent_qa_schema50.QuarantineListInputSchema,
6797
5885
  output: import_agent_qa_schema50.QuarantineListOutputSchema,
6798
5886
  risk: { name: `fn:${QUARANTINE_LIST_FUNCTION_ID}`, recognized: true, readOnly: true },
6799
- /**
6800
- * A ledger listing that answered — the count, and no entry's identity legs (399.1 D-01).
6801
- */
5887
+ // The count only, no entry's identity legs.
6802
5888
  classify(output) {
6803
5889
  const count = output.entries.length;
6804
5890
  return {
@@ -6826,9 +5912,7 @@ var quarantineReleaseSpec = {
6826
5912
  input: import_agent_qa_schema51.QuarantineReleaseInputSchema,
6827
5913
  output: import_agent_qa_schema51.QuarantineReleaseOutputSchema,
6828
5914
  risk: { name: `fn:${QUARANTINE_RELEASE_FUNCTION_ID}`, recognized: true, readOnly: false },
6829
- /**
6830
- * `no-entry` IS "an ordinary answer to an ordinary question" — the contract's words (399.1 D-01).
6831
- */
5915
+ // `no-entry` is an ordinary answer, not a refusal.
6832
5916
  classify(output) {
6833
5917
  switch (output.kind) {
6834
5918
  case "released":
@@ -6878,26 +5962,7 @@ var runsEventsSpec = {
6878
5962
  input: import_agent_qa_schema52.RunsEventsInputSchema,
6879
5963
  output: import_agent_qa_schema52.RunEventEnvelopeSchema,
6880
5964
  risk: { name: `fn:${RUNS_EVENTS_FUNCTION_ID}`, recognized: true, readOnly: true },
6881
- /**
6882
- * A STREAM'S VERDICT IS ABOUT THE ACQUISITION, AND IT MUST NOT READ AN ELEMENT (399.1 D-01/D-03).
6883
- *
6884
- * WHAT THIS OP CAN HONESTLY SAY. Every refusal it makes is a THROW before the iterable exists —
6885
- * `StreamReplayFloorError` when the requested resume point is below what the log can still serve,
6886
- * which is the whole reason the spec's header insists the stream is ACQUIRED inside `invoke`
6887
- * rather than lazily on first iteration. So a stream that came back is a replay that opened, and
6888
- * that is the fact this fold reports.
6889
- *
6890
- * IT DELIBERATELY IGNORES ITS ARGUMENT. Reading an element would mean CONSUMING the caller's
6891
- * stream — a side effect, on a member both this file and {@link FunctionSpec.classify} contract as
6892
- * pure, and one that would silently eat the first event of every replay. The argument is named
6893
- * `_stream` so the intent is legible at the signature rather than in a comment somebody may not
6894
- * reach.
6895
- *
6896
- * IT IS DECLARED HERE AND NOT INHERITED. `registry.ts` registers this spec through
6897
- * `runsEventsSpec as FunctionSpec`, and an `as`-cast satisfies `tsc` while shipping an op with no
6898
- * fold — which is precisely the hole the conformance census (`classifier-census.test.ts`) exists
6899
- * to close, and precisely why the required member alone is not the whole enforcement.
6900
- */
5965
+ // Must not read an element: consuming the stream would eat the caller's first event.
6901
5966
  classify(_stream) {
6902
5967
  return { status: "executed", outcome: "replay opened \u2014 the recorded events are streaming" };
6903
5968
  },
@@ -7056,17 +6121,7 @@ var runsLiveUrlSpec = {
7056
6121
  input: import_agent_qa_schema54.RunsLiveUrlInputSchema,
7057
6122
  output: import_agent_qa_schema54.RunsLiveUrlResultSchema,
7058
6123
  risk: { name: `fn:${RUNS_LIVE_URL_FUNCTION_ID}`, recognized: true, readOnly: true },
7059
- /**
7060
- * THE OUTCOME SENTENCE NEVER CONTAINS THE TOKEN OR THE URL (LIVE-02, D-04).
7061
- *
7062
- * A clause verdict is a thing surfaces PRINT — into chat transcripts, receipts and the audit
7063
- * sink — so interpolating the result here would put a live credential into every durable record
7064
- * this op touches, from one line of "helpful" formatting. What a person needs to know is that a
7065
- * link was minted and for which handle; the link itself is already in the result they asked for.
7066
- *
7067
- * Declared explicitly rather than inherited: `registry.ts` registers this through a
7068
- * `FunctionSpec` cast, and the classifier census is what makes a missing fold red.
7069
- */
6124
+ // The outcome never holds the token or URL, because surfaces print it into durable records.
7070
6125
  classify(result) {
7071
6126
  return { status: "executed", outcome: `liveUrl minted for handle ${result.handle}` };
7072
6127
  },
@@ -7194,8 +6249,7 @@ async function readNoVerdictSkipped(runId, deps) {
7194
6249
  function projectStageDetails(state, mask) {
7195
6250
  const rows = {
7196
6251
  analysis: state?.analyzeRun,
7197
- curation: state?.curateMemory,
7198
- proposals: state?.proposeImprovements
6252
+ curation: state?.curateMemory
7199
6253
  };
7200
6254
  const details = {};
7201
6255
  for (const stage of import_agent_qa_schema56.POST_PROCESSING_DETAIL_STAGES) {
@@ -7278,9 +6332,7 @@ var runsPostProcessingSpec = {
7278
6332
  id: RUNS_POST_PROCESSING_FUNCTION_ID,
7279
6333
  summary: "Read one run's post-processing chip statuses from durable job state.",
7280
6334
  resultKind: "unary",
7281
- // Bound exactly where a composition supplies durable queue storage (D-16 idiom). A host that
7282
- // cannot see the queue lists this by name as `unbound` rather than answering all-pending
7283
- // about a chain it has no way to observe.
6335
+ // Bound where the composition supplies durable queue storage; otherwise listed `unbound`.
7284
6336
  boundThrough: "postProcessing",
7285
6337
  input: import_agent_qa_schema56.RunsPostProcessingInputSchema,
7286
6338
  output: import_agent_qa_schema56.PostProcessingStatusSchema,
@@ -7387,13 +6439,7 @@ var runsDigestSpec = {
7387
6439
  input: import_agent_qa_schema57.RunsDigestInputSchema,
7388
6440
  output: import_agent_qa_schema57.RunDigestSchema,
7389
6441
  risk: { name: `fn:${RUNS_DIGEST_FUNCTION_ID}`, recognized: true, readOnly: true },
7390
- /**
7391
- * REFS AND COUNTS, which is this op's own law rather than a house style (399.1 D-01 · 391 D-18).
7392
- *
7393
- * The digest's `lines` are its rendered territory and they travel on `results[]`, which D-04
7394
- * prints in full. A receipt line reaching into them would put a run's story inside the map — the
7395
- * exact thing D-18 pinned this op's whole shape around.
7396
- */
6442
+ // Refs and counts only; the digest's lines travel on `results[]`.
7397
6443
  classify(output) {
7398
6444
  return {
7399
6445
  status: "executed",
@@ -7412,12 +6458,10 @@ var runsDigestSpec = {
7412
6458
  const skipped = status === void 0 ? projectPostProcessingSkipped(document) : status.skipped;
7413
6459
  const sections = {
7414
6460
  runId,
7415
- // VERBATIM — the same cluster views, carrying the same already-composed representative
7416
- // sentences the one renderer produced inside `analysis.get` (389 D-05/D-15).
6461
+ // Verbatim cluster views, with the representative sentences `analysis.get` composed.
7417
6462
  verdictClusters: analysis?.clusters ?? [],
7418
6463
  chain: {
7419
- // `undefined` answers exactly as an empty chain does: nothing was enqueued for this
7420
- // run, which is what a host with no queue database can honestly say (388's own note).
6464
+ // `undefined` answers as an empty chain: nothing was enqueued for this run.
7421
6465
  ...projectPostProcessingChips(void 0),
7422
6466
  ...status === void 0 ? {} : status.chips,
7423
6467
  ...status?.notification === void 0 ? {} : { outcome: status.notification.outcome },
@@ -7425,19 +6469,14 @@ var runsDigestSpec = {
7425
6469
  },
7426
6470
  ...markChanges === void 0 ? {} : { markChanges },
7427
6471
  candidates: {
7428
- // Absent counts read as zero HERE and only here: the row omits them when curation never
7429
- // committed a bundle (388 D-11), and a digest section is a place a person reads a
7430
- // number rather than a place a distinction between "none" and "not yet" survives — the
7431
- // chain chips one line up already carry that distinction.
6472
+ // Absent counts read as zero only here; the chain chips carry none versus not yet.
7432
6473
  curated: curation?.curated ?? 0,
7433
6474
  deprecated: curation?.deprecated ?? 0
7434
6475
  },
7435
6476
  quarantine: {
7436
6477
  quarantined: quarantine.filter((entry2) => entry2.state === "quarantined").length,
7437
6478
  expired: quarantine.filter((entry2) => entry2.state === "expired").length,
7438
- // `released` entries are deliberately absent from both the counts and the refs: a
7439
- // released test is one somebody already dealt with, and listing it every run would be
7440
- // the graveyard 390 legislated against, one surface later.
6479
+ // Released entries stay out of counts and refs; somebody already dealt with them.
7441
6480
  refs: quarantine.filter((entry2) => entry2.state === "quarantined").map(quarantineRef)
7442
6481
  }
7443
6482
  };
@@ -7660,19 +6699,12 @@ var runsDetailSpec = {
7660
6699
  id: RUNS_DETAIL_FUNCTION_ID,
7661
6700
  summary: "Read one run's durable members, steps and sub-actions as the dashboard projected them.",
7662
6701
  resultKind: "unary",
7663
- // Bound exactly where a composition owns the dashboard's projection database (the D-16 idiom). A
7664
- // host that holds no such database lists this by name as `unbound` rather than answering an
7665
- // empty run about a projection it has no way to observe.
6702
+ // Bound where the composition owns the projection database; otherwise listed `unbound`.
7666
6703
  boundThrough: "runDetail",
7667
6704
  input: import_agent_qa_schema59.RunsDetailInputSchema,
7668
6705
  output: import_agent_qa_schema59.RunDetailProjectionSchema,
7669
6706
  risk: { name: `fn:${RUNS_DETAIL_FUNCTION_ID}`, recognized: true, readOnly: true },
7670
- /**
7671
- * The three counts, which are what a receipt can honestly say about a read like this one.
7672
- *
7673
- * NOT THE TOKEN SUM: a receipt line quoting a number the caller is about to render would be a
7674
- * second place that number is stated, and D-06 exists because two producers of one total drift.
7675
- */
6707
+ // Counts only, not the token sum, so the total has one producer.
7676
6708
  classify(output) {
7677
6709
  return {
7678
6710
  status: "executed",
@@ -7800,7 +6832,7 @@ var runsEvidenceSpec = {
7800
6832
  boundThrough: "runDetail",
7801
6833
  input: import_agent_qa_schema60.RunsEvidenceInputSchema,
7802
6834
  output: import_agent_qa_schema60.RunsEvidenceResultSchema,
7803
- // 431-03 (D-03/D-07): the declared output is the canonical document; validation stays `output`.
6835
+ // The declared output is the canonical document; validation stays on `output`.
7804
6836
  outputRepresentation: import_agent_qa_schema60.RunsEvidenceOutputContract,
7805
6837
  risk: { name: `fn:${RUNS_EVIDENCE_FUNCTION_ID}`, recognized: true, readOnly: true },
7806
6838
  classify(output) {
@@ -7995,9 +7027,7 @@ function projectStep(testId, testIndex, evidence) {
7995
7027
  channel3: evidence.servedBrief.channel3.map(cautionLine)
7996
7028
  },
7997
7029
  trace: traceArmOf(evidence),
7998
- // PICKED, not spread (CR-01) — see `planSourceOf`. Spread-away absence, never a `null` and
7999
- // never a zero-fill: a step that replayed no procedure carries NO `planSource` key, which is
8000
- // a different byte from one that carries an empty source (the layer's own idiom).
7030
+ // Picked, not spread: a step that replayed nothing carries no `planSource` key.
8001
7031
  ...evidence.planSource === void 0 ? {} : { planSource: planSourceOf(evidence.planSource) },
8002
7032
  ...rung === void 0 ? {} : { retrievalRung: rung }
8003
7033
  };
@@ -8072,16 +7102,7 @@ var runsKnowledgeSpec = {
8072
7102
  input: import_agent_qa_schema61.RunsKnowledgeInputSchema,
8073
7103
  output: import_agent_qa_schema61.RunKnowledgeProjectionSchema,
8074
7104
  risk: { name: `fn:${RUNS_KNOWLEDGE_FUNCTION_ID}`, recognized: true, readOnly: true },
8075
- /**
8076
- * COUNTS, NOT CONTENT (399.1 D-01 · 391 D-18's rule applied here).
8077
- *
8078
- * A receipt line names how much a run used and learned; the brief summaries, step text and
8079
- * record ids themselves stay in `results[]` where a reader asked for them. Interpolating a
8080
- * served summary here would put producer prose — possibly masked material — into an audit map.
8081
- *
8082
- * `evidence-incomplete` is `executed` and not a refusal, on `knowledge.brief.why`'s reasoning:
8083
- * a pruned handoff is an answer this verb is proud of, not a control declining.
8084
- */
7105
+ // Counts only, so no served summary or masked material reaches an audit map.
8085
7106
  classify(output) {
8086
7107
  if (output.kind === "evidence-incomplete") {
8087
7108
  return {
@@ -8189,8 +7210,7 @@ var runsKnowledgeSpec = {
8189
7210
  ...runRung === void 0 ? {} : { retrievalRung: runRung },
8190
7211
  steps: joinedSteps,
8191
7212
  curation: {
8192
- // `undefined` answers exactly as an empty chain does — nothing was enqueued for this run
8193
- // — which is what a host with no queue database can honestly say (388's own note).
7213
+ // `undefined` answers as an empty chain: nothing was enqueued for this run.
8194
7214
  status: status?.chips.curation ?? projectPostProcessingChips(void 0).curation,
8195
7215
  ...countsPresent && curationRow !== void 0 ? {
8196
7216
  counts: {
@@ -8198,8 +7218,7 @@ var runsKnowledgeSpec = {
8198
7218
  deprecated: curationRow.deprecated
8199
7219
  }
8200
7220
  } : {},
8201
- // 2026-10-18 (444-26, D-61): the run's own handoff says why its chain was never enqueued,
8202
- // by the fold runs.postprocessing calls, so it holds on a host with no queue database too.
7221
+ // The handoff's own skip reason, so it holds on a host with no queue database.
8203
7222
  ...skipped === void 0 ? {} : { skipped: { reason: skipped.reason } }
8204
7223
  },
8205
7224
  learned: {
@@ -8254,20 +7273,12 @@ var runsListSpec = {
8254
7273
  summary: "List completed runs, newest finished first (20 by default, at most 200), each naming its tests; filter by verdict, test id or title, recorded target, or completion time.",
8255
7274
  resultKind: "unary",
8256
7275
  input: import_agent_qa_schema62.RunsListInputSchema,
8257
- // 2026-08-16 (396-04, D-16): the NAMED array schema, not `z.array(RunSummarySchema)` composed
8258
- // here. The two are the same shape; only one of them is an object a surface can also name, and
8259
- // D-16's whole claim is that the advertised schema and the validated schema are one object.
7276
+ // The named array schema, so the advertised and validated schema are one object.
8260
7277
  output: import_agent_qa_schema62.RunsListOutputSchema,
8261
- // 431-03 (D-03, A1): the canonical companion, tied to `output` above. It changes only what a
8262
- // declaration publishes; `output` is still what `invokeFunction` validates with.
7278
+ // The canonical companion changes only what a declaration publishes; `output` still validates.
8263
7279
  outputRepresentation: import_agent_qa_schema62.RunsListOutputContract,
8264
- // Read ops declare `readOnly` so the static classifier lands them on the read-only
8265
- // tier — allow in every execution context. The verdict is still computed and audited
8266
- // (D-11): there is no read bypass, only a read classification.
8267
7280
  risk: { name: `fn:${RUNS_LIST_FUNCTION_ID}`, recognized: true, readOnly: true },
8268
- /**
8269
- * A listing that answered — the count, and nothing out of a run (399.1 D-01).
8270
- */
7281
+ // The count only, nothing out of a run.
8271
7282
  classify(output) {
8272
7283
  return { status: "executed", outcome: `${output.length} completed run(s)` };
8273
7284
  },
@@ -8292,20 +7303,17 @@ var import_agent_qa_schema63 = require("@vostride/agent-qa-schema");
8292
7303
  var RUNS_MARK_FUNCTION_ID = "runs.mark";
8293
7304
  var runsMarkSpec = {
8294
7305
  id: RUNS_MARK_FUNCTION_ID,
8295
- summary: "Mark a run or step false-fail / false-pass / confirmed-bug: freeze the marked decision as gold, triage, and apply the fix (a knowledge change or a test edit) in the call.",
7306
+ summary: "Mark a run or step false-fail / false-pass / confirmed-bug: triage it and apply the fix (a knowledge change or a test edit) in the call.",
8296
7307
  resultKind: "unary",
8297
7308
  boundThrough: "feedback",
8298
7309
  input: import_agent_qa_schema63.RunsMarkInputSchema,
8299
7310
  output: import_agent_qa_schema63.RunsMarkOutcomeSchema,
8300
- // D-13: a mark writes the committed eval root and, since 432-09, applies its fix to knowledge or
8301
- // a test file. mutating-local would understate its risk.
8302
- // No requiresHumanOrigin and, since 432-21 (D-12), no bearer: every caller on every door reaches it.
8303
- // 2026-10-01 (432-24, D-12): the `knowledge-write` scope it declared is gone too.
7311
+ // A mark applies its fix to committed knowledge or a test file. No requiresHumanOrigin, bearer or
7312
+ // scope: every caller on every door reaches it.
8304
7313
  risk: {
8305
7314
  name: `fn:${RUNS_MARK_FUNCTION_ID}`,
8306
7315
  recognized: true,
8307
- readOnly: false,
8308
- declaredTier: "mutating-shared"
7316
+ readOnly: false
8309
7317
  },
8310
7318
  classify(output) {
8311
7319
  switch (output.kind) {
@@ -8321,8 +7329,6 @@ var runsMarkSpec = {
8321
7329
  return { status: "refused", outcome: `step ${output.stepIndex} not found at member ${output.testIndex}` };
8322
7330
  case "ambiguous-address":
8323
7331
  return { status: "refused", outcome: "ambiguous run address: specify a member" };
8324
- case "ambiguous-correction":
8325
- return { status: "refused", outcome: "executable correction requires exactly one recorded decision" };
8326
7332
  default:
8327
7333
  return output;
8328
7334
  }
@@ -8351,17 +7357,12 @@ function maskResult(result, mask) {
8351
7357
  effects: record.evidence.effects.map((effect) => effect.direction === "confirm" ? effect : { ...effect, overturnsEvidenceToken: mask(effect.overturnsEvidenceToken) })
8352
7358
  }
8353
7359
  }))
8354
- },
8355
- groundTruth: result.groundTruth.map((item) => ({
8356
- ...item,
8357
- recordedVerdict: { ...item.recordedVerdict, reasoning: mask(item.recordedVerdict.reasoning) },
8358
- ...item.correctedExpectation === void 0 ? {} : { correctedExpectation: mask(item.correctedExpectation) }
8359
- }))
7360
+ }
8360
7361
  };
8361
7362
  }
8362
7363
  var runsMarkPreviewSpec = {
8363
7364
  id: RUNS_MARK_PREVIEW_FUNCTION_ID,
8364
- summary: "Preview what runs.mark would do for this exact input: its refusals, resolved step, labels, the knowledge records it reaches with their content and evidence effects, and the fix it would apply, without writing.",
7365
+ summary: "Preview what runs.mark would do for this exact input: its refusals, resolved step, the knowledge records it reaches with their content and evidence effects, and the fix it would apply, without writing.",
8365
7366
  resultKind: "unary",
8366
7367
  boundThrough: "feedbackReads",
8367
7368
  input: import_agent_qa_schema64.RunsMarkInputSchema,
@@ -8370,7 +7371,7 @@ var runsMarkPreviewSpec = {
8370
7371
  classify(output) {
8371
7372
  switch (output.kind) {
8372
7373
  case "consequences":
8373
- return { status: "executed", outcome: `preview: ${output.markKind} would apply ${output.draft.kind} over ${output.markedDecisionCount} ${output.markedDecisionCount === 1 ? "decision" : "decisions"} (nothing written)` };
7374
+ return { status: "executed", outcome: `preview: ${output.markKind} would apply ${output.draft.kind} at step ${output.resolvedStep.stepIndex} (nothing written)` };
8374
7375
  case "quarantined":
8375
7376
  return { status: "executed", outcome: `preview: ${output.markKind} would be quarantined as ${output.class} (nothing written)` };
8376
7377
  case "already-marked":
@@ -8379,7 +7380,6 @@ var runsMarkPreviewSpec = {
8379
7380
  case "member-not-found":
8380
7381
  case "step-not-found":
8381
7382
  case "ambiguous-address":
8382
- case "ambiguous-correction":
8383
7383
  return runsMarkSpec.classify(output);
8384
7384
  default:
8385
7385
  return output;
@@ -8414,16 +7414,11 @@ function projectEntry(receipt, changedRecords, supersededBy, mask) {
8414
7414
  ordinal: receipt.ordinal,
8415
7415
  markedAt: receipt.markedAt,
8416
7416
  ...receipt.note === void 0 ? {} : { note: mask(receipt.note) },
8417
- corrected: {
8418
- expectation: receipt.correctedExpectation !== void 0,
8419
- action: receipt.correctedAction !== void 0
8420
- },
8421
7417
  ...receipt.rootCause === void 0 ? {} : {
8422
7418
  rootCause: { class: receipt.rootCause.class, producer: mask(receipt.rootCause.producer) }
8423
7419
  },
8424
7420
  ...receipt.isRerun === void 0 ? {} : { isRerun: receipt.isRerun },
8425
7421
  disposition: receipt.disposition,
8426
- gold: receipt.gold,
8427
7422
  evidence: receipt.evidence,
8428
7423
  ...receipt.supersedes === void 0 ? {} : { supersedes: receipt.supersedes },
8429
7424
  active: supersededBy === void 0,
@@ -8684,8 +7679,7 @@ function projectLearned(knowledge, document) {
8684
7679
  curation: {
8685
7680
  status: curation.status,
8686
7681
  ...curation.counts === void 0 ? {} : { counts: { ...curation.counts } },
8687
- // 2026-10-18 (444-26, D-61): the run's own handoff says why its chain was never enqueued, by
8688
- // the fold runs.postprocessing serves; an ordinary run carries no key.
7682
+ // The handoff's own skip reason; an ordinary run carries no key.
8689
7683
  ...skipped === void 0 ? {} : { skipped: { reason: skipped.reason } }
8690
7684
  },
8691
7685
  snapshot,
@@ -8771,237 +7765,75 @@ var BUILT_IN_FUNCTION_SPECS = [
8771
7765
  runsListSpec,
8772
7766
  runsGetSpec,
8773
7767
  runsEventsSpec,
8774
- // 403 D-03: the ONE producer of live-view capability tokens. Bound through the OPTIONAL
8775
- // `liveView` dep, so a host with no served origin lists it `unbound` BY NAME rather than
8776
- // handing back a URL that resolves to nothing.
7768
+ // Bound through optional `liveView`; a host with no served origin lists it `unbound`.
8777
7769
  runsLiveUrlSpec,
8778
- // 2026-09-25 (428 D-07): the editor subject's minter, through the same `liveView` dep; a host
8779
- // that serves no live editor refuses it by name. Unprojected from MCP by ruling.
7770
+ // Same `liveView` dep; not projected to MCP.
8780
7771
  editorLiveUrlSpec,
8781
- // Bound exactly in the compositions that supply a `runInvocation` port (D-16); listed
8782
- // either way, so a host that cannot start a run reports a visible `unbound` rather than a
8783
- // hole in the catalog, and `invokeFunction` refuses it by name. `composeLocalAgent()` in
8784
- // `@vostride/agent-qa-agent-local` is the binding site.
7772
+ // Bound where a composition supplies `runInvocation`; `composeLocalAgent()` is the binding site.
8785
7773
  runsStartSpec,
8786
- // 388 D-14: THE chip-truth read. Registered here rather than beside a surface because it is
8787
- // the single producer three surfaces share — the CLI's exit summary line, 392's chat and M5's
8788
- // dashboard are all thin clients of this one op, and the 397 parity suite inherits it by
8789
- // being in the catalogue. Bound through the OPTIONAL `postProcessing` dep, so a host with no
8790
- // durable queue lists it `unbound` BY NAME instead of answering all-pending about a chain it
8791
- // cannot see.
7774
+ // Bound through optional `postProcessing`, so a host with no durable queue lists it `unbound`.
8792
7775
  runsPostProcessingSpec,
8793
- // 2026-08-27 (405 D-03): THE durable run-detail read — members, steps, sub-actions and the D-06
8794
- // token sum in ONE result. Registered here rather than beside the dashboard because it is the
8795
- // fourth-door law applied to the page that used to read SQLite from inside a route handler: the
8796
- // browser, the CLI, MCP and chat now ask one registry the same question. Bound through the
8797
- // OPTIONAL `runDetail` dep, so a host that owns no dashboard projection database lists it
8798
- // `unbound` BY NAME instead of answering an empty run about a projection it cannot see.
7776
+ // Bound through optional `runDetail`, so a host with no projection database lists it `unbound`.
8799
7777
  runsDetailSpec,
8800
- // 423 D-04: parsed evidence uses the existing detail and blob readers together.
7778
+ // Parsed evidence uses the detail and blob readers together.
8801
7779
  runsEvidenceSpec,
8802
- // 419 GATE3-01: the sovereign mark write binds only where the host supplies feedback.
7780
+ // The mark write binds only where the host supplies feedback.
8803
7781
  runsMarkSpec,
8804
- // 423 D-19: the mark history read binds through feedbackReads, never through the writer above.
7782
+ // Binds through `feedbackReads`, never through the writer above.
8805
7783
  runsMarksHistorySpec,
8806
- // 423 D-16: the consequence preview reads runs.mark's shared plan through feedbackReads, never the writer.
7784
+ // Reads `runs.mark`'s shared plan through `feedbackReads`, never the writer.
8807
7785
  runsMarkPreviewSpec,
8808
- // 2026-08-27 (405-05 D-12/D-13): THE ref-resolving read — one run's content-addressed evidence
8809
- // blob, by sha, with the content type sniffed from the bytes themselves. Registered beside
8810
- // `runs.detail` because the two are the halves of one claim: the projection carries an
8811
- // `artifactRef`, and this is how that ref becomes an image on a page. It is here rather than in
8812
- // a route for `runs.detail`'s reason — a route constructing the evidence store would be a
8813
- // private store read no roster row covers, and 408's embed and MCP would each need their own.
8814
- // Bound through the OPTIONAL `evidenceBlobs` dep, so a host with no runtime root lists it
8815
- // `unbound` BY NAME instead of reporting every artifact in the product as absent.
7786
+ // Bound through optional `evidenceBlobs`, so a host with no runtime root lists it `unbound`.
8816
7787
  runsArtifactSpec,
8817
- // 389 D-11: THE analysis read — resolved verdicts, rendered sentences, clusters, one
8818
- // producer for the CLI print, the run page and chat. Bound through the OPTIONAL `analysis`
8819
- // dep (the artifact reader), so a host that cannot see run directories lists it `unbound`
8820
- // BY NAME; the optional `recurrence` dep only enriches the sentence's recurrence clause
8821
- // and never gates the binding.
7788
+ // Bound through optional `analysis`; `recurrence` only enriches the sentence, never the binding.
8822
7789
  analysisGetSpec,
8823
7790
  knowledgeBundlesListSpec,
8824
- // 416 D-17: gate-and-promotion history, through the required knowledge port's
8825
- // optional member; missing bindings answer with a named refusal.
7791
+ // Gate history through the knowledge port's optional member; an absent one is a named refusal.
8826
7792
  knowledgeGatesListSpec,
8827
- // 387 KREV-01: the read half of the review-verb family. All three bind through the REQUIRED
8828
- // `knowledge` port, so — unlike the mutating half 387-08 registers through the optional
8829
- // `knowledgeReview` dep — there is no composition that lists these and cannot run them.
7793
+ // Bound through the required `knowledge` port, so every composition can run these.
8830
7794
  knowledgeRecordsInspectSpec,
8831
7795
  knowledgeRecordsDiffSpec,
8832
7796
  knowledgeRecordShowSpec,
8833
- // KREV-02: the honest verb. Read-tier like its four siblings, and bound everywhere for the
8834
- // same reason — its substrate is the RUNS port, which is required.
7797
+ // Bound everywhere, because its substrate is the required runs port.
8835
7798
  knowledgeBriefWhySpec,
8836
- // 2026-08-29 (407 D-05/D-06): the Knowledge panel's ONE read — what a run USED (served brief
8837
- // channels, serve-time trace arms, procedure replay/hint, the recorded retrieval rung) and what
8838
- // it LEARNED (curation counts, the record changes attributable to it, canary outcomes). Placed
8839
- // directly after `knowledge.brief.why` because it is that verb widened from one step to a whole
8840
- // run, and BOUND EVERYWHERE for the identical reason: its substrate is the RUNS port, which is
8841
- // required. The three optional deps it consults only enrich the Learned half, so binding
8842
- // through any of them would leave a host with no queue database unable to see what its own runs
8843
- // used. A pruned handoff answers `evidence-incomplete` — a result the page renders, never a
8844
- // refusal it has to catch (D-06).
7799
+ // Bound everywhere on the runs port; its optional deps only enrich the Learned half.
8845
7800
  runsKnowledgeSpec,
8846
- // 431 D-06: one completed run's address map, composed from the handoff, the run-detail rows and
8847
- // the runs.knowledge projection. Bound through `runDetail`, so a host with no projection lists
8848
- // it `unbound` BY NAME instead of mapping a run it cannot see.
7801
+ // Bound through `runDetail`, so a host with no projection lists it `unbound`.
8849
7802
  runsOverviewSpec,
8850
- // 387 KREV-01 D-17: the MUTATING half. Registered here and bound only where a composition
8851
- // supplies `knowledgeReview`, so a read-only host lists all three as `unbound` BY NAME rather
8852
- // than omitting them: a capability that is absent from a catalogue is indistinguishable from one
8853
- // that never existed, and D-09 requires the two to look different.
8854
- // 2026-09-30, 432-12 (D-05): the three changes apply in the call; the `.propose` ids are gone
8855
- // with no alias. 2026-10-01, 432-17 (D-05/D-22): `knowledge.proposal.apply` is deleted with the
8856
- // inbox; old proposal files are never read again.
7803
+ // Bound only where a composition supplies `knowledgeReview`; otherwise listed `unbound`.
8857
7804
  knowledgeAcceptSpec,
8858
7805
  knowledgeRejectSpec,
8859
7806
  knowledgeForgetSpec,
8860
7807
  configGetSpec,
8861
- // 395 D-01/D-03 · CFGM-01: the config editor's first action. Registered as a SIBLING of
8862
- // `config.get` rather than in a family of its own, because it is the write half of a story whose
8863
- // read half already ships here — and registering it is what makes it chat-reachable (392 D-07),
8864
- // projectable over MCP (396) and walkable by the parity suite (397) with no harness change.
8865
- //
8866
- // 2026-09-30, 432-11 (D-05/D-07): the config ops write in the call through the direct writer.
8867
- // 2026-10-01, 432-17 (D-05/D-09): `config.proposal.apply` and `config.undo.propose` are deleted
8868
- // with the inbox; a written change is reverted with git.
8869
- //
8870
- // They bind through OPTIONAL deps, so a host with no config files lists them `unbound` BY NAME
8871
- // rather than answering about a project it cannot read.
7808
+ // Config ops write in the call through optional deps; a host with no config lists them `unbound`.
8872
7809
  configFieldSetSpec,
8873
- // 395-05 D-01: the rest of the closed action class, registered as SIBLINGS on exactly the footing
8874
- // above. One op per action is what makes the class legible in the registry itself — the planner
8875
- // picks an action by tool name, 396 projects each one as its own MCP tool, and 397's parity walk
8876
- // enumerates them — where a single union op carrying a mode string would have projected as one
8877
- // tool whose real vocabulary lives inside a field nothing validates.
7810
+ // One op per action, because the planner and MCP pick actions by tool name.
8878
7811
  configAuthSetSpec,
8879
7812
  configHookAddSpec,
8880
7813
  configTargetCreateSpec,
8881
7814
  configTargetEditSpec,
8882
- // 395-08 D-13/D-15 · CFGM-05: the sixth config op, and the only one that configures a project
8883
- // that has no configuration. Registered rather than folded into `config.target.create` because
8884
- // the two refuse each other's case by name — a create is never an upsert, and a scaffold is
8885
- // never an overwrite — and because the planner picks actions by tool name.
7815
+ // Not folded into `config.target.create`: a create never upserts and a scaffold never overwrites.
8886
7816
  configProjectScaffoldSpec,
8887
- // 390 D-12/D-13: a new `quarantine.` domain — a taxonomy extension exactly as `entities.`
8888
- // was, because quarantine state is neither a run, a memory nor an analysis. All three bind
8889
- // through the OPTIONAL `quarantine` dep, so a host with no knowledge root lists them
8890
- // `unbound` BY NAME rather than answering an empty list about a ledger it cannot read.
8891
- // `list` is read-tier; `release` and `add` are DIRECT gated writes (no propose+apply pair —
8892
- // that idiom is for learned-knowledge mutations, and this is operational state).
7817
+ // Bound through optional `quarantine`; `release` and `add` write directly.
8893
7818
  quarantineListSpec,
8894
7819
  quarantineReleaseSpec,
8895
7820
  quarantineAddSpec,
8896
- // 391 PROP-03 / D-15 added a `proposals.` domain (list, show, reject, accept). 2026-10-01, 432-17
8897
- // (D-05/D-22): the domain is deleted with the inbox, with no alias and no hidden follow-up; old
8898
- // proposal files are never read again.
8899
- // 391 PROP-01 / D-03 added a `grants.` domain (list, revoke) over the committed standing-grant
8900
- // ledger. 2026-10-01, 432-18 (D-14/D-15/D-22): the domain is deleted with the ledger; an old
8901
- // `grants.jsonl` is never read again.
8902
- // 391 PROP-04 / D-16: the per-run digest. Filed under `runs.` beside `runs.postprocessing`
8903
- // because what it answers is a fact about a RUN. Read-tier, and it registers NO new dep: the
8904
- // projection composes from capabilities this catalogue already had (since 432-09 its substrate
8905
- // is the required runs port, and since 432-17 there is no proposals inbox to read).
7821
+ // Filed under `runs.` because it answers a fact about a run; it adds no dep.
8906
7822
  runsDigestSpec,
8907
- // 387 D-09: a new `entities.` domain, a taxonomy extension exactly as `knowledge.` was.
8908
- // Both read-tier, both bound in every composition — the directory is a REQUIRED dep, so
8909
- // there is no host that lists these and cannot run them.
7823
+ // The directory is a required dep, so every composition can run these.
8910
7824
  entitiesResolveSpec,
8911
7825
  entitiesGetSpec,
8912
- // 392 D-24: a new `agent.` domain, and the taxonomy extension that matters most — the chat turn
8913
- // entry is itself a catalogued, gated capability rather than a power the REPL holds privately
8914
- // (§3's L10 law). It binds through the OPTIONAL `chatTurn` dep, so a host with no engine lists
8915
- // it `unbound` BY NAME rather than answering an empty turn about a request it understood.
8916
- //
8917
- // `agent.chat`, the session-stateful sibling the milestone also names, is deliberately absent
8918
- // until a consumer exists: a registered entry nothing drives would still oblige 397's parity
8919
- // suite to stub it on every surface.
7826
+ // Bound through optional `chatTurn`, so a host with no engine lists it `unbound`.
8920
7827
  agentAskSpec,
8921
- // 2026-08-17 (398 D-09 · XPLN-02): the SECOND member of the `agent.` domain, and the first op
8922
- // this project has added since the 397 conformance suite closed. Registering it is the decision
8923
- // rather than a filing choice: "what can you do" is a question every surface wants to answer, and
8924
- // a surface that answered it privately would be a capability the catalogue does not list — the
8925
- // private-power pattern §3's L10 law abolishes and the census exists to make impossible. As a
8926
- // registered op it is chat-reachable through the 1:1 planner binding and `/fn` with no harness
8927
- // change, adjudicated in `mapping.ts` like every op, and walked by the parity suite for free.
8928
- //
8929
- // Bound through the OPTIONAL `capabilityCatalog` port, whose binding site is `composeLocalAgent()`
8930
- // (385 D-15 — therefore both the CLI and the daemon). A host with no catalog lists it `unbound` BY
8931
- // NAME rather than answering from model memory, which is the exact failure XPLN-02 exists to
8932
- // forbid: an explain that quietly lost its grounding data still SOUNDS like an explain.
7828
+ // Bound through optional `capabilityCatalog`, so a host never explains from model memory.
8933
7829
  explainSpec,
8934
- // 2026-08-10 (393 D-01): a new `authoring.` domain, and the keep-filter's entry point. The four
8935
- // gates that decide whether a generated test is worth keeping are a CATALOGUED capability rather
8936
- // than a private power of whatever writes tests — so 393's corpus proof drives the real gated
8937
- // entry point (the produced-not-literal law), 396's MCP projection and 397's parity suite inherit
8938
- // it from this census with no harness change, and the standalone question ("is this existing test
8939
- // worth keeping?") is answerable from every surface.
8940
- //
8941
- // Bound through the OPTIONAL `draftEvaluation` bundle, whose binding site is `composeLocalAgent()`
8942
- // in `@vostride/agent-qa-agent-local` (385 D-15 — one composition root, therefore both the CLI and
8943
- // the daemon). The bundle is supplied only where the host can BOTH parse a test file and start a
8944
- // run, so a host missing either half lists this capability `unbound` BY NAME rather than leaving a
8945
- // hole in the catalogue — and rather than returning a receipt whose four booleans were computed
8946
- // from no runs at all, which is the one answer that could get a draft kept on the strength of
8947
- // nothing.
8948
- //
8949
- // Registering it does NOT flip 392's `write_test` fail-closed scenario: that tool name stays
8950
- // absent from the catalogue until 394 (D-01), and nothing here mints it.
7830
+ // Bound where a host can both parse a test and start a run; otherwise listed `unbound`.
8951
7831
  authoringVerifyDraftSpec,
8952
- // 2026-08-11 (394 D-01 · WTST-01): the authoring LOOP's one public entry, beside the evaluator
8953
- // it composes. All six stages — brief, dedup, compile, verify, route, compound — run INSIDE this
8954
- // op, because the stage order is an invariant and registering a stage each would make it a hope
8955
- // about the plan the chat planner happened to make rather than a property of the code. Everything
8956
- // under the surface still crosses the function layer: stage 4 dispatches `authoring.draft.verify`
8957
- // through `invokeFunction` on a caller minted with exactly that op's declared scopes.
8958
- //
8959
- // Bound through the OPTIONAL `draftShelf` bundle — the model and the shelf — whose binding site
8960
- // is `composeLocalAgent()` in `@vostride/agent-qa-agent-local` (385 D-15, therefore both the CLI
8961
- // and the daemon). The read half (`authoringRead`) is supplied with it or not at all and the
8962
- // invoke refuses on either by the same name, so a host that cannot serve an authoring brief says
8963
- // `unbound` BY NAME rather than compiling a test against an empty one — a plausible draft
8964
- // authored against nothing this project knows, which is the failure that looks most like success.
8965
- //
8966
- // Inverting the entry above: registering THIS one DOES flip 392's `write_test` fail-closed chat
8967
- // scenarios, because the tool name they were waiting on now exists in the catalogue the planner
8968
- // binds 1:1. Plan 11 performs the flip and pins planned == executed.
7832
+ // Every stage runs inside this op, so a planner cannot reorder or skip one.
8969
7833
  authoringDraftWriteSpec,
8970
- // 2026-08-11 (394-07 D-12/D-13 · WTST-05): the honesty funnel's ONE read, beside the loop it
8971
- // measures. It is registered rather than left a private computation for the same reason the two
8972
- // entries above it are: the number that says whether the keep-filter is filtering must be the
8973
- // SAME number in chat, in the CLI and in the per-run digest, and a projection reachable only
8974
- // from whichever surface owned it would become three answers the moment the second surface
8975
- // wanted one. Read-tier and `readOnly` — it starts nothing and writes nothing, which is D-14
8976
- // expressed as a risk descriptor rather than as a promise.
8977
- //
8978
- // Bound through the OPTIONAL `authoringFunnel` bundle, whose binding site is
8979
- // `composeLocalAgent()` in `@vostride/agent-qa-agent-local` (385 D-15 — therefore both the CLI
8980
- // and the daemon). A host with no runtime root lists it `unbound` BY NAME rather than answering
8981
- // an all-zero funnel: zero built with zero write-eligible does not read as "nothing happened", it
8982
- // reads as a loop that filtered everything, which is the one wrong answer that would make the
8983
- // acceptance-failure flag unable to fire on the very hosts that most need it.
7834
+ // An unbound host refuses rather than answer a zero funnel that reads as filtering everything.
8984
7835
  authoringFunnelGetSpec,
8985
- // 2026-08-11 (394-09 D-21 · WTST-07): the user-facing edit, and the patch contract's SECOND real
8986
- // consumer. Until this op existed, `applyPatchSetToTestDoc` and the RFC-6902 vocabulary had one
8987
- // caller — the repair loop — and a contract with one consumer is a contract shaped like its one
8988
- // caller. That is not a style objection: this project has twice paid for a one-sided contract
8989
- // that looked correct because only one side ever exercised it (the two-sided contract law).
8990
- //
8991
- // It is NOT a stage of `authoring.draft.write`, which is the argument `loop-ordering.test.ts`
8992
- // requires beside a new `authoring.` id. That pin forbids promoting a loop stage to its own
8993
- // registered op, because a planner holding one could reorder or skip the rest. This verb takes an
8994
- // existing COMMITTED test and a change to make to it; it has no position in the six-stage order,
8995
- // and invoking it before, during or after a loop invocation answers the same question.
8996
- //
8997
- // `mutating-local` and NOT the write op's `mutating-shared`: it takes one model call, starts zero
8998
- // runs, and writes only to the gitignored draft shelf. The consent that matters for an edit is
8999
- // the inbox accept that turns the proposal into a commit, which 391 already owns.
9000
- //
9001
- // Bound through the OPTIONAL `draftShelf` bundle; `draftEvaluation` is checked by the same name
9002
- // inside the invoke, because resolving the target's bytes and applying the patch set are two
9003
- // halves of one capability and a host that had only one of them would list this op `bound` and
9004
- // then fail far from whichever half was missing.
7836
+ // Not a loop stage: it edits a committed test; `draftEvaluation` is checked inside the invoke.
9005
7837
  authoringDraftEditSpec
9006
7838
  ];
9007
7839
  var REGISTRY_INTERNALS = /* @__PURE__ */ new WeakMap();
@@ -9023,16 +7855,7 @@ function declarationView(spec, deps) {
9023
7855
  return Object.freeze({
9024
7856
  id: spec.id,
9025
7857
  summary: spec.summary,
9026
- // 2026-10-01 (432-20, D-10/D-12): no `requiredScopes` and no `requiresHumanOrigin`. Both were
9027
- // projected here so a listing and the dispatch checks read one field; the checks are deleted,
9028
- // and 432-39 deleted both members from the metadata type. The view is built field by field, so
9029
- // an old key smuggled onto a spec object still cannot ride through by accident.
9030
- // 2026-10-02 (432-42, D-14): no `discloses` column; the per-op disclosure is deleted.
9031
- // 399.1 D-01/D-04: the two 399.1 folds, projected as conditional spreads so absent stays
9032
- // absent — the callables stay on the spec, and what crosses to a listing is the
9033
- // boolean fact that this op folds its own result. The golden ledger reads both columns off
9034
- // here, so "which ops classify their own refusals" is a census over produced facts rather than
9035
- // over somebody's reading of forty-three op files.
7858
+ // Conditional spreads keep absent absent; only the boolean fact crosses to a listing.
9036
7859
  ...spec.classify === void 0 ? {} : { classifies: true },
9037
7860
  ...spec.renderResult === void 0 ? {} : { rendersResult: true },
9038
7861
  resultKind: spec.resultKind,
@@ -9339,24 +8162,12 @@ var CHAT_RESOLVER_TABLE = Object.freeze([
9339
8162
  }),
9340
8163
  rule({
9341
8164
  alias: "status",
9342
- // ADJUDICATION (the plan asks for it recorded here): the candidates were `runs.list` and
9343
- // `runs.get`. `runs.get` addresses exactly one run BY ID and refuses without one, so it
9344
- // cannot answer a person who typed a bare word — the id is the very thing they did not
9345
- // supply. `runs.list` takes `{}`, answers the 20 most recently finished runs newest first
9346
- // (431 D-08), and is the only read in the registry whose contract answers "what has happened
9347
- // here lately" without being told what to look at. `status <run>` is not minted:
9348
- // `digest <run>` already owns "tell me about that one run", and two verbs for it would be
9349
- // two answers.
8165
+ // `runs.list` takes `{}` and answers recent runs; `runs.get` refuses without the run id.
9350
8166
  resolve: (clause) => isExactly("status")(clause) ? { kind: "op", functionId: RUNS_LIST_FUNCTION_ID, input: {} } : void 0
9351
8167
  }),
9352
8168
  rule({
9353
8169
  alias: "test-ref",
9354
- // 387 D-05's never-guess ladder does the resolving, and the ref it receives is WHAT THE
9355
- // PERSON TYPED, verbatim. `entities.resolve` accepts "any reference at all — short-ID, URI,
9356
- // or free text", so pre-chewing `test 42` into `42` here would be this file inventing a
9357
- // second resolution grammar in front of the one that exists to be the only one. Two forms
9358
- // match: the `test <n>` phrase and a bare well-formed short-ID, the latter recognised through
9359
- // the schema's own parser rather than a regex spelled here.
8170
+ // The ref passes verbatim to `entities.resolve`, which owns the only resolution grammar.
9360
8171
  resolve: (clause) => {
9361
8172
  const trimmed = clause.trim();
9362
8173
  const named = argumentAfter("test", clause);
@@ -9378,8 +8189,6 @@ var CHAT_RESOLVER_TABLE = Object.freeze([
9378
8189
  return { kind: "op", functionId: RUNS_DIGEST_FUNCTION_ID, input: { runId: reference } };
9379
8190
  }
9380
8191
  }),
9381
- // 432-13 (D-05/D-14): the `proposals` inbox alias is gone. Changes apply in the call, so there is
9382
- // no pending-decision inbox to route a bare word to. 432-17 deleted the inbox and its ops too.
9383
8192
  rule({
9384
8193
  alias: "model",
9385
8194
  resolve: (clause) => {
@@ -9389,10 +8198,7 @@ var CHAT_RESOLVER_TABLE = Object.freeze([
9389
8198
  }),
9390
8199
  rule({
9391
8200
  alias: "fn",
9392
- // THE PASSTHROUGH (D-06). The op id is NOT validated here — deliberately. `invokeFunction`'s
9393
- // step 1 raises `UnknownFunctionError` naming the id before any dependency is touched, so a
9394
- // typo and a capability that has not shipped yet both come back named, for free, from the one
9395
- // place that knows what is registered. A check here would be a second catalogue.
8201
+ // The op id is unchecked here: `invokeFunction` names an unknown id before touching anything.
9396
8202
  resolve: (clause) => {
9397
8203
  const rest = argumentAfter("/fn", clause);
9398
8204
  if (rest === void 0) return void 0;
@@ -9427,11 +8233,7 @@ var CHAT_HELP_ENTRIES = Object.freeze([
9427
8233
  Object.freeze({ alias: "run", syntax: "run <test>", summary: "start a run for a test" }),
9428
8234
  Object.freeze({ alias: "status", syntax: "status", summary: "the recent runs" }),
9429
8235
  Object.freeze({ alias: "test-ref", syntax: "test <n>", summary: "show a test by reference" }),
9430
- // 2026-08-17 (398 plan 09): this line used to read `digest` / "the latest run digest", and both
9431
- // halves were false. The rule fifteen lines up requires a reference and treats a bare `digest` as
9432
- // a near-miss precisely so the table never guesses which run somebody meant — so the help text
9433
- // was advertising a guess the resolver refuses to make. The argument-contract cell in
9434
- // `help-census.test.ts` is what now holds the two together.
8236
+ // `digest` needs a run reference: the resolver treats a bare `digest` as a near-miss.
9435
8237
  Object.freeze({ alias: "digest", syntax: "digest <run>", summary: "that run's digest" }),
9436
8238
  Object.freeze({
9437
8239
  alias: "fn",
@@ -9455,26 +8257,6 @@ var CHAT_HELP_TEXT = [
9455
8257
  "Anything else is planned by the model and reconciled against the table before anything runs."
9456
8258
  ].join("\n");
9457
8259
 
9458
- // src/chat/retired-chat-verbs.ts
9459
- var RETIRED_PIN = "/pin";
9460
- var RETIRED_INBOX = "proposals";
9461
- function isRetiredPin(lowered) {
9462
- if (lowered === RETIRED_PIN) return true;
9463
- if (!lowered.startsWith(RETIRED_PIN)) return false;
9464
- const next = lowered.charAt(RETIRED_PIN.length);
9465
- return next === " " || next === " ";
9466
- }
9467
- function retiredChatVerbReason(clause) {
9468
- const lowered = clause.trim().toLowerCase();
9469
- if (isRetiredPin(lowered)) {
9470
- return "/pin was retired in this version: nothing asks before an operation runs, so there is nothing to pin. Nothing in this request was run.";
9471
- }
9472
- if (lowered === RETIRED_INBOX) {
9473
- return "the proposals inbox was retired in this version: changes apply when they are made, so nothing waits for a decision. Nothing in this request was run.";
9474
- }
9475
- return void 0;
9476
- }
9477
-
9478
8260
  // src/chat/session-repair.ts
9479
8261
  var import_agent_qa_schema68 = require("@vostride/agent-qa-schema");
9480
8262
  var TURN_CLOSING_KINDS = ["turn_complete", "aborted"];
@@ -9581,11 +8363,6 @@ function refusalName(error) {
9581
8363
  function refusalMessage(error) {
9582
8364
  return error instanceof Error && error.message !== "" ? error.message : refusalName(error);
9583
8365
  }
9584
- function refusalSentenceOf(error) {
9585
- if (typeof error !== "object" || error === null) return void 0;
9586
- const sentence = error.neutralReason;
9587
- return typeof sentence === "string" && sentence.trim() !== "" ? sentence : void 0;
9588
- }
9589
8366
  function crossBoundaryLines(answer) {
9590
8367
  if (answer.crossBoundary !== true) return [];
9591
8368
  const reasons = answer.crossBoundaryReasons ?? [];
@@ -9725,12 +8502,6 @@ async function runTurnThrough(deps, opened, input) {
9725
8502
  // make "stage 1 did not recognise this" and "this build cannot do it" the same bytes.
9726
8503
  outcome: mapped.length + directives.length === clauses.length ? "resolved" : "unresolved"
9727
8504
  });
9728
- for (const clause of clauses) {
9729
- if (mapped.some((resolved) => resolved.clause.index === clause.index)) continue;
9730
- if (directives.some((entry2) => entry2.clause.index === clause.index)) continue;
9731
- const retired = retiredChatVerbReason(clause.text);
9732
- if (retired !== void 0) return refuse(clause.text, retired);
9733
- }
9734
8505
  for (const entry2 of directives) {
9735
8506
  const notBound = directiveBindingRefusal(directiveHandlers, entry2);
9736
8507
  if (notBound !== void 0) return refuse(entry2.clause.text, notBound);
@@ -9774,15 +8545,7 @@ async function runTurnThrough(deps, opened, input) {
9774
8545
  turnId,
9775
8546
  at: deps.now(),
9776
8547
  stage: "planner",
9777
- // The stage RESOLVED when the model produced something to reconcile — a plan, or an
9778
- // answer. It did not when the model was unreachable or said nothing. Whether what it
9779
- // produced survives reconciliation is the next stage's question, and answering it in
9780
- // this field would make "the model proposed nothing" and "the reconciler refused the
9781
- // proposal" the same bytes for every reader of the log.
9782
- //
9783
- // ONE TERM, NOT TWO: an `answer_only` call IS a tool call, so the disjunction this used to
9784
- // spell (`|| planned.answer !== undefined`) named the same set twice through a projection
9785
- // that no longer exists (392-14).
8548
+ // Resolved when the model produced a plan or an answer, whatever reconciliation decides.
9786
8549
  outcome: planned.failure === void 0 && planned.toolCalls.length > 0 ? "resolved" : "unresolved"
9787
8550
  });
9788
8551
  }
@@ -9915,8 +8678,6 @@ async function runTurnThrough(deps, opened, input) {
9915
8678
  status: "failed",
9916
8679
  outcome: refusalName(error)
9917
8680
  };
9918
- const refusal = refusalSentenceOf(error);
9919
- if (refusal !== void 0) answerLines.push(refusal);
9920
8681
  }
9921
8682
  }
9922
8683
  if (receipt.status === "failed") failed = true;
@@ -10296,82 +9057,46 @@ function ceilingExceeded(counts) {
10296
9057
  var SCENARIO_CORPUS_VERSION = 10;
10297
9058
  var entry = (value) => value;
10298
9059
  var SCENARIO_CORPUS = Object.freeze([
10299
- // --- deterministic: the ten canon aliases (392-02) -------------------------------------------
9060
+ // Deterministic: the canon aliases.
10300
9061
  entry({ id: "run", class: "deterministic", lane: "hermetic", kind: "should_execute" }),
10301
9062
  entry({ id: "status", class: "deterministic", lane: "hermetic", kind: "should_execute" }),
10302
9063
  entry({ id: "test-ref", class: "deterministic", lane: "hermetic", kind: "should_execute" }),
10303
9064
  entry({ id: "digest", class: "deterministic", lane: "hermetic", kind: "should_execute" }),
10304
- // 432-13: the inbox alias is retired; the cell is its measured absence (v10).
9065
+ // `proposals` is an ordinary clause stage 1 does not resolve, so the hermetic turn refuses it.
10305
9066
  entry({ id: "proposals", class: "deterministic", lane: "hermetic", kind: "fail_closed" }),
10306
9067
  entry({ id: "fn", class: "deterministic", lane: "hermetic", kind: "should_execute" }),
10307
9068
  // The directives. `executed: 0` on a `should_execute` arm is the SHAPE, not a compromise: a
10308
9069
  // directive names no capability, so it crosses the function layer zero times on a turn that did
10309
- // exactly what was asked (392-08's flip). 432-13 retired `/pin`; its cell is its absence (v10).
9070
+ // exactly what was asked. `/pin` is not a directive but an ordinary clause stage 1 does not
9071
+ // resolve, so the hermetic turn refuses it.
10310
9072
  entry({ id: "model", class: "deterministic", lane: "hermetic", kind: "should_execute" }),
10311
9073
  entry({ id: "pin", class: "deterministic", lane: "hermetic", kind: "fail_closed" }),
10312
9074
  entry({ id: "help", class: "deterministic", lane: "hermetic", kind: "should_execute" }),
10313
9075
  entry({ id: "quit", class: "deterministic", lane: "hermetic", kind: "should_execute" }),
10314
- // --- deterministic: the three stage-1 edge scenarios (392-02) ---------------------------------
9076
+ // Deterministic: the stage-1 edge scenarios.
10315
9077
  entry({ id: "quoted-conjunction", class: "deterministic", lane: "hermetic", kind: "should_execute" }),
10316
9078
  entry({ id: "near-miss-alias", class: "deterministic", lane: "hermetic", kind: "fail_closed" }),
10317
- // DID NOT FLIP, and the reason is a measurement rather than an oversight (394-11). This line was
10318
- // written to flip when the authoring loop registered `write_test`. 394 registered the loop as
10319
- // `authoring.draft.write` — `write_test` is the spec's noun for the capability and is not a
10320
- // function id anywhere in the registry — so the utterance still carries an id nothing registers,
10321
- // and the cell still proves the one thing it was admitted for: `/fn` validates no op id, and
10322
- // `invokeFunction` names an unknown one before any dependency is touched. A phase that registers
10323
- // ops can make an unknown-op test pass for the wrong reason; this one did not.
9079
+ // `write_test` is not a registered id, so `/fn` reaches `invokeFunction` with an unknown op.
10324
9080
  entry({ id: "fn-unknown-op", class: "deterministic", lane: "hermetic", kind: "fail_closed" }),
10325
- // --- planner: natural language, live lane (392-09) --------------------------------------------
9081
+ // Planner: natural language, live lane.
10326
9082
  entry({ id: "list-recent-runs", class: "planner", lane: "live", kind: "should_execute" }),
10327
9083
  entry({ id: "explain-flaky", class: "planner", lane: "live", kind: "should_execute" }),
10328
- // D-08's LIVE arm, FLIPPED (394-11). It was admitted as the cell proving the planner could not
10329
- // invent an authoring capability out of prose; the loop shipping makes the same prose routable,
10330
- // and the flip is what says so. Its file pins planned == executed, so a turn that planned the
10331
- // capability without reaching it reds here rather than reading as arrival.
9084
+ // Pins planned equals executed, so a turn that planned authoring without reaching it fails.
10332
9085
  entry({ id: "write-test-for-checkout", class: "planner", lane: "live", kind: "should_execute" }),
10333
- // --- planner: 395's config arrival, ADMITTED (395-09) ------------------------------------------
10334
- // The first member this corpus has ever gained for a capability rather than for a defect. 392
10335
- // D-08 designed this as a flip and there was nothing to flip: no config cell was ever admitted,
10336
- // which 395's research established by enumerating every file above. So the handoff is executed as
10337
- // an ADMISSION — the size moves as well as the denominator, and the pair of pins in
10338
- // `scenario-manifest.test.ts` is what makes the two movements distinguishable after the fact.
10339
- // The cell pins planned == executed == 1 on `config.field.set`, the propose op D-03 gave any
10340
- // schema-addressable path; it deliberately stops short of `config.proposal.apply`, which is the
10341
- // verb that changes a person's git history and the only one in the family that is gated.
9086
+ // Pins one planned and executed `config.field.set`, the propose op for any schema path.
10342
9087
  entry({ id: "config-edit-timeout", class: "planner", lane: "live", kind: "should_execute" }),
10343
- // --- planner: 398's explain arrival, ADMITTED (398-07) -----------------------------------------
10344
- // The corpus's second admission for a capability rather than for a defect, and the first pair.
10345
- // `agent.explain` answers a question about what this product can do BY CITING the committed
10346
- // capability catalog, so these two cells are what make "never from model memory" checkable at the
10347
- // routing level: a turn that answered either utterance in prose completes without executing
10348
- // anything, and `planned == executed == 1` on the op id is what tells the two apart.
9088
+ // A prose answer executes nothing, so one executed `agent.explain` proves the catalog was cited.
10349
9089
  entry({ id: "what-can-you-do", class: "planner", lane: "live", kind: "should_execute" }),
10350
9090
  entry({ id: "how-do-i-explain", class: "planner", lane: "live", kind: "should_execute" }),
10351
- // --- compound: the canon pair, live lane (392-02) ---------------------------------------------
9091
+ // Compound: the canon pair, live lane.
10352
9092
  entry({ id: "run-42-and-digest", class: "compound", lane: "live", kind: "should_execute" }),
10353
- // The spec's own example, FLIPPED (394-11). Both clauses are routable now, so D-10's pre-flight
10354
- // atomicity has a plan it can admit instead of a whole turn it must refuse.
9093
+ // Both clauses route, so pre-flight atomicity has a plan it can admit.
10355
9094
  entry({ id: "write-test-2fa-and-run", class: "compound", lane: "live", kind: "should_execute" }),
10356
- // --- compound: the two gap-round regression cells (392-11) -------------------------------------
10357
- // The verifier's own probes, admitted so neither defect can return silently. Both are
10358
- // `fail_closed`, so neither enters the ceiling denominator: what they add is the ability to SEE a
10359
- // refused turn that carried something out, which `executed == 0` alone never could.
9095
+ // Fail-closed cells that see a refused turn which carried something out.
10360
9096
  entry({ id: "run-42-and-delete-root", class: "compound", lane: "live", kind: "fail_closed" }),
10361
- // STAYS REFUSING THROUGH 394's FLIP (394-11). Its second clause is a write-test request, so a
10362
- // reader who found the other two write-test cells flipped could reasonably take this one for an
10363
- // oversight. It is not. What this cell measures is CR-04 — a refused turn that had ALREADY
10364
- // recorded a pin and an `approval_decision` row — and its refusal comes from the hermetic lane's
10365
- // tripwire model, not from the authoring capability being absent. Flipping it would remove the
10366
- // corpus's only cell naming a directive on a turn that fails, to prove something two live cells
10367
- // already prove.
9097
+ // Its refusal comes from the hermetic lane's tripwire model, not from authoring being absent.
10368
9098
  entry({ id: "pin-and-write-test", class: "compound", lane: "hermetic", kind: "fail_closed" }),
10369
- // --- compound: the second gap round's two cells (392-14) ---------------------------------------
10370
- // What the round-2 verification found the corpus still could not see: a directive BATCH whose
10371
- // later entry refuses (the earlier one's pin and its `approval_decision` row survived), and the
10372
- // empty-prose `answer_only` that erased a clause on a `completed` turn. Both `fail_closed`, both
10373
- // HERMETIC — the lanes are named exceptions in `scenario-manifest.test.ts`, and the denominators
10374
- // are unmoved at 11 hermetic / 3 live.
9099
+ // A refused later directive in a batch, and an empty-prose `answer_only`.
10375
9100
  entry({
10376
9101
  id: "run-42-and-delete-root-empty-answer",
10377
9102
  class: "compound",
@@ -10379,10 +9104,7 @@ var SCENARIO_CORPUS = Object.freeze([
10379
9104
  kind: "fail_closed"
10380
9105
  }),
10381
9106
  entry({ id: "pin-and-pin-nonsense", class: "compound", lane: "hermetic", kind: "fail_closed" }),
10382
- // --- compound: the third gap round's cell (392-15) ---------------------------------------------
10383
- // The mixed-mapping configuration NO cell in either lane had: a table-mapped clause beside a
10384
- // planner-bound one on a turn that completed, with the model making an extra call about the
10385
- // mapped clause (CR-01). `fail_closed` and hermetic, so the denominators are unmoved again.
9107
+ // A table-mapped clause beside a planner-bound one, plus a model call about the mapped one.
10386
9108
  entry({
10387
9109
  id: "run-42-and-summarise-extra-call",
10388
9110
  class: "compound",
@@ -10403,10 +9125,7 @@ var ROLE_BLOCK = {
10403
9125
  var PLANNING_BLOCK = {
10404
9126
  title: "How to answer",
10405
9127
  body: (
10406
- // "OF THE LIST BELOW", not "of the request". The `Request` block carries the WHOLE utterance
10407
- // while `Clauses to answer` carries only what stage 1 could not bind, so a count scoped to the
10408
- // request asks for calls about clauses that are already resolved — and every one of those is a
10409
- // call reconciliation cannot attribute to anything (392-VERIFICATION round 3).
9128
+ // Scoped to the list, because the request also holds clauses stage 1 already bound.
10410
9129
  "Call one action tool per clause of the list below, in utterance order. Order is meaning: later clauses routinely depend on earlier ones, so the sequence you emit is the sequence that will be considered.\n\nUse `answer_only` ONLY when no tool you were offered can produce what was asked for. You have no knowledge of this project beyond what the tools return, so a question a tool can answer must be routed to that tool: answering it yourself would put a plausible-looking invention where the project data belongs. A turn answered this way performs zero actions and returns your text. Name the clause you are answering in `clause`, copied verbatim from the list above: the call covers that clause and no other, so a request with two clauses needs one call per clause you answer.\n\nUse `mark_unhandled` when no available tool can carry out a clause, naming that clause and saying which capability would be needed. This refuses the whole turn without performing any of it, and that is the correct outcome. Never substitute a tool that looks close: a request nobody can satisfy and a request satisfied by the wrong action are not the same event, and the person can only recover from the first one.\n\nA tool's required inputs are exactly the `required` list in its schema. Never mark a clause unhandled because a field outside that list is missing: omit the field, or fill it from the person's own words when they name it.\n\nBind arguments only from what the person actually supplied. If a clause needs an identifier and none was given, that clause is unhandled \u2014 do not invent one."
10411
9130
  )
10412
9131
  };
@@ -10483,18 +9202,11 @@ function createPlannerStage(deps) {
10483
9202
  var import_ai2 = require("ai");
10484
9203
  var import_zod3 = require("zod");
10485
9204
  var ANSWER_ONLY_INPUT_SCHEMA = import_zod3.z.object({
10486
- // NON-EMPTY for the same reason `text` is, one field over (392-15, WR-01). `reconcile.ts` has
10487
- // rejected `clause: ""` since the field was required — a claim that names nothing covers nothing
10488
- // — while the contract the model was SHOWN still admitted it. The two halves of one field cannot
10489
- // be allowed to disagree in the direction that lets the model emit a call the reader will refuse.
9205
+ // Non-empty, matching the reader in `reconcile.ts`, so the model is not shown a call it refuses.
10490
9206
  clause: import_zod3.z.string().min(1).describe(
10491
9207
  "The part of the request, quoted verbatim from the clauses you were given, that this answer is about."
10492
9208
  ),
10493
- // NON-EMPTY, and that is the model-facing half of the coverage predicate (392-14). `z.string()`
10494
- // admitted `""`, so the one call that erases a clause — naming it, answering nothing — was
10495
- // inside the contract the model was shown. The reader in `reconcile.ts` moved in the SAME commit
10496
- // and is deliberately one notch stricter (it also rejects whitespace-only prose): the two halves
10497
- // of a claim's meaning cannot be allowed to disagree in the direction that completes more.
9209
+ // Non-empty; the reader in `reconcile.ts` is one notch stricter and rejects whitespace-only text.
10498
9210
  text: import_zod3.z.string().min(1).describe("The answer, in prose, for a turn that asks for information.")
10499
9211
  });
10500
9212
  var MARK_UNHANDLED_INPUT_SCHEMA = import_zod3.z.object({
@@ -10586,18 +9298,6 @@ function projectPlannerTools(source, caller) {
10586
9298
  return tools;
10587
9299
  }
10588
9300
 
10589
- // src/ports/gates.ts
10590
- var Gate1ReceiptNotPersistedError = class extends Error {
10591
- constructor(candidateId, recorded) {
10592
- super(
10593
- `Gate 1 for candidate ${candidateId} produced a receipt the writer did not acknowledge (${recorded}). The replay work was spent and nothing was persisted, so this call establishes no screening result for that candidate.`
10594
- );
10595
- this.candidateId = candidateId;
10596
- this.recorded = recorded;
10597
- }
10598
- name = "Gate1ReceiptNotPersistedError";
10599
- };
10600
-
10601
9301
  // src/ports/job-store.ts
10602
9302
  var StaleJobStoreEpochError = class extends Error {
10603
9303
  constructor(heldEpoch, observedEpoch) {
@@ -10725,10 +9425,7 @@ function createAgentJobQueue(options) {
10725
9425
  const ids = chainJobIdsForRun(runId, idSource);
10726
9426
  return {
10727
9427
  dedupeKey: runId,
10728
- // All THREE derived ids since 422 D-13. The store's rule is stated over the candidates that
10729
- // EXIST, so a chain halted at the fold — whose proposal row was never written — still
10730
- // terminates, while a chain that enqueued the proposal job cannot notify before it lands.
10731
- candidateJobIds: [ids.analyzeRun, ids.curateMemory, ids.proposeImprovements],
9428
+ candidateJobIds: [ids.analyzeRun, ids.curateMemory],
10732
9429
  payloadJson: (0, import_agent_qa_schema70.canonicalJson)(
10733
9430
  buildChainTerminalNotification({
10734
9431
  runId,
@@ -11011,7 +9708,6 @@ function createAgentJobQueue(options) {
11011
9708
  EvidenceBlobAbsentError,
11012
9709
  FunctionInputError,
11013
9710
  FunctionNotBoundError,
11014
- Gate1ReceiptNotPersistedError,
11015
9711
  IncompleteJobKindDeclarationError,
11016
9712
  InconsistentJobKindDeclarationError,
11017
9713
  JobCancellationNotRequestedError,
@@ -11025,8 +9721,6 @@ function createAgentJobQueue(options) {
11025
9721
  MARK_UNHANDLED_CEILING,
11026
9722
  MissingIdempotencyKeyError,
11027
9723
  OPTIONAL_FUNCTION_DEP_KEYS,
11028
- PROPOSE_DEFAULT_MAX_GATE1_PER_JOB,
11029
- PROPOSE_GATE1_ALLOWANCE_CHECKPOINT,
11030
9724
  QUARANTINE_ADD_FUNCTION_ID,
11031
9725
  QUARANTINE_LIST_FUNCTION_ID,
11032
9726
  QUARANTINE_RELEASE_FUNCTION_ID,
@@ -11086,7 +9780,6 @@ function createAgentJobQueue(options) {
11086
9780
  liveUrlOf,
11087
9781
  maybeCompact,
11088
9782
  mintLiveUrlToken,
11089
- parseProposeGate1Allowance,
11090
9783
  parseScenario,
11091
9784
  projectAuthoringFunnel,
11092
9785
  projectPlannerTools,