@vostride/agent-qa-agent 0.2.2 → 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/README.md +78 -0
- package/dist/index.cjs +218 -1525
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +20 -2961
- package/dist/index.d.ts +20 -2961
- package/dist/index.js +219 -1527
- package/dist/index.js.map +1 -1
- package/package.json +6 -6
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
|
-
//
|
|
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
|
-
//
|
|
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
|
|
630
|
-
|
|
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
|
-
|
|
658
|
-
|
|
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
|
-
|
|
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
|
|
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:
|
|
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
|
|
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
|
|
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
|
|
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
|
|
1065
|
-
const
|
|
1066
|
-
const
|
|
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
|
|
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
|
|
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 =
|
|
1333
|
+
verdicts2 = result.verdicts;
|
|
1631
1334
|
for (const parts of result.authoredParts) authoredParts.set(parts.perTest, parts);
|
|
1632
1335
|
}
|
|
1633
|
-
const
|
|
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
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
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:
|
|
1648
|
-
parts:
|
|
1350
|
+
verdicts: stamped,
|
|
1351
|
+
parts: sentenceParts
|
|
1649
1352
|
});
|
|
1650
|
-
return { runId: payload.runId, 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
|
-
//
|
|
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
|
-
//
|
|
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
|
|
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
|
-
//
|
|
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:
|
|
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
|
-
|
|
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
|
|
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
|
-
//
|
|
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
|
|
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
|
-
//
|
|
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
|
-
...
|
|
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
|
-
//
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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}
|
|
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
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
3802
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
3958
|
-
//
|
|
3959
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
|
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("; ")}
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
-
//
|
|
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
|
|
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
|
|
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
|
-
//
|
|
4794
|
-
//
|
|
4795
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
*
|
|
5947
|
-
*
|
|
5948
|
-
*
|
|
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
|
-
//
|
|
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
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
-
//
|
|
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
|
|
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
|
-
//
|
|
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
|
|
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
|
|
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
|
-
//
|
|
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
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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:
|
|
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
|
-
//
|
|
8301
|
-
//
|
|
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,
|
|
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}
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
7778
|
+
// Parsed evidence uses the detail and blob readers together.
|
|
8801
7779
|
runsEvidenceSpec,
|
|
8802
|
-
//
|
|
7780
|
+
// The mark write binds only where the host supplies feedback.
|
|
8803
7781
|
runsMarkSpec,
|
|
8804
|
-
//
|
|
7782
|
+
// Binds through `feedbackReads`, never through the writer above.
|
|
8805
7783
|
runsMarksHistorySpec,
|
|
8806
|
-
//
|
|
7784
|
+
// Reads `runs.mark`'s shared plan through `feedbackReads`, never the writer.
|
|
8807
7785
|
runsMarkPreviewSpec,
|
|
8808
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
9091
|
+
// Compound: the canon pair, live lane.
|
|
10352
9092
|
entry({ id: "run-42-and-digest", class: "compound", lane: "live", kind: "should_execute" }),
|
|
10353
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
|
|
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,
|