@akagilnc/pi-workflow-roles 0.1.1751
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/LICENSE +202 -0
- package/README.md +104 -0
- package/README.zh-CN.md +133 -0
- package/THIRD_PARTY_NOTICES.md +60 -0
- package/dist/activation-ledger-git.js +68 -0
- package/dist/activation-ledger-session.js +120 -0
- package/dist/activation-ledger-topology.js +239 -0
- package/dist/activation-reconciliation.js +61 -0
- package/dist/audit-escalation.js +108 -0
- package/dist/auditor-dossier-tool.js +35 -0
- package/dist/canonical-json.js +78 -0
- package/dist/compliance-transport.js +77 -0
- package/dist/doctor-contracts.js +172 -0
- package/dist/dossier-resolution.js +103 -0
- package/dist/evidence-child-executor.js +661 -0
- package/dist/exact-utf8.js +12 -0
- package/dist/git-object-id.js +7 -0
- package/dist/in-process-session.js +50 -0
- package/dist/merger-contracts.js +76 -0
- package/dist/navigator-attendance.js +995 -0
- package/dist/navigator-invocation-identity.js +220 -0
- package/dist/open-tool-schema.js +39 -0
- package/dist/package-contracts/collector-output.js +50 -0
- package/dist/package-contracts/fixer-output.js +72 -0
- package/dist/package-contracts/fixer-packet.js +77 -0
- package/dist/package-contracts/judge-output.js +17 -0
- package/dist/package-contracts/reviewer-output.js +82 -0
- package/dist/package-contracts/terminating-tools.js +173 -0
- package/dist/package-contracts/worker-output.js +13 -0
- package/dist/package-owned-tool-idle.js +104 -0
- package/dist/packaged-role-registry.js +34 -0
- package/dist/public-cli/main.js +23867 -0
- package/dist/public-command-renderer.js +20 -0
- package/dist/reviewer-agent.js +93 -0
- package/dist/reviewer-child-executor.js +23 -0
- package/dist/reviewer-construction.js +95 -0
- package/dist/reviewer-dispatch.js +77 -0
- package/dist/reviewer-execution-ledger.js +160 -0
- package/dist/reviewer-failure-diagnostic.js +17 -0
- package/dist/reviewer-git-snapshot.js +38 -0
- package/dist/reviewer-pinned-git.js +146 -0
- package/dist/reviewer-preflight-error.js +15 -0
- package/dist/reviewer-prompt-identity.js +10 -0
- package/dist/reviewer-scope-prompt.js +21 -0
- package/dist/reviewer-workspace.js +151 -0
- package/dist/sha256.js +5 -0
- package/dist/sitian-record-entry.js +33 -0
- package/dist/stderr-jsonl.js +26 -0
- package/dist/stream-idle-guard.js +75 -0
- package/dist/tool-execution-observation.js +141 -0
- package/dist/uuidv7.js +21 -0
- package/dist/work-subject-identity.js +53 -0
- package/extensions/role-runtime.ts +303 -0
- package/package.json +69 -0
- package/packets/fixer-prerequisites.json +6 -0
- package/packets/fixer-repair.md +5 -0
- package/packets/judge-apply.md +77 -0
- package/packets/judge-authority.md +64 -0
- package/packets/judge-plan.md +55 -0
- package/packets/judge-review.md +49 -0
- package/packets/judge-submission.md +34 -0
- package/resources/methods/code-review/SKILL.md +92 -0
- package/resources/methods/code-review/agents/openai.yaml +3 -0
- package/resources/methods/code-review/provenance.json +26 -0
- package/resources/methods/diagnosing-bugs/SKILL.md +134 -0
- package/resources/methods/diagnosing-bugs/agents/openai.yaml +3 -0
- package/resources/methods/diagnosing-bugs/provenance.json +31 -0
- package/resources/methods/diagnosing-bugs/scripts/hitl-loop.template.sh +41 -0
- package/resources/methods/resolving-merge-conflicts/SKILL.md +14 -0
- package/resources/methods/resolving-merge-conflicts/agents/openai.yaml +3 -0
- package/resources/methods/resolving-merge-conflicts/provenance.json +26 -0
- package/resources/methods/tdd/SKILL.md +38 -0
- package/resources/methods/tdd/agents/openai.yaml +3 -0
- package/resources/methods/tdd/mocking.md +59 -0
- package/resources/methods/tdd/provenance.json +36 -0
- package/resources/methods/tdd/tests.md +77 -0
- package/resources/navigator-route-playbook.md +32 -0
- package/schemas/tool-execution-observation.schema.json +107 -0
- package/scripts/build-package.mjs +65 -0
- package/scripts/generate-tool-execution-observation-schema.ts +7 -0
- package/souls/coder.md +10 -0
- package/souls/collector.md +11 -0
- package/souls/doctor-auditor.md +23 -0
- package/souls/doctor.md +8 -0
- package/souls/fixer-auditor.md +33 -0
- package/souls/fixer.md +13 -0
- package/souls/judge-auditor.md +33 -0
- package/souls/judge.md +74 -0
- package/souls/merger.md +5 -0
- package/souls/navigator.md +5 -0
- package/souls/reviewer-auditor.md +25 -0
- package/souls/reviewer.md +11 -0
- package/src/activation-ledger-git.ts +96 -0
- package/src/activation-ledger-session.ts +188 -0
- package/src/activation-ledger-topology.ts +301 -0
- package/src/activation-ledger.ts +240 -0
- package/src/activation-reconciliation.ts +163 -0
- package/src/activation-trace.ts +38 -0
- package/src/audit-escalation.ts +177 -0
- package/src/auditor-dossier-tool.ts +48 -0
- package/src/auditor-soul.ts +28 -0
- package/src/canonical-json.ts +74 -0
- package/src/canonical-skill-binding.ts +107 -0
- package/src/collector-config.ts +89 -0
- package/src/collector-evidence.ts +461 -0
- package/src/collector-github.ts +656 -0
- package/src/collector-identity.ts +161 -0
- package/src/collector-ledger.ts +827 -0
- package/src/collector-receipt.ts +87 -0
- package/src/collector-role.ts +592 -0
- package/src/collector-tool-schemas.ts +19 -0
- package/src/compliance-transport.ts +130 -0
- package/src/doctor-auditor.ts +53 -0
- package/src/doctor-contracts.ts +166 -0
- package/src/doctor-evidence.ts +47 -0
- package/src/doctor-role.ts +18 -0
- package/src/dossier-resolution.ts +137 -0
- package/src/evidence-child-executor.ts +775 -0
- package/src/exact-utf8.ts +9 -0
- package/src/factory-board.ts +1822 -0
- package/src/git-object-id.ts +11 -0
- package/src/human-format.ts +65 -0
- package/src/in-process-session.ts +78 -0
- package/src/judge-auditor.ts +55 -0
- package/src/judge-recording-anti-forge.ts +53 -0
- package/src/judge-role.ts +160 -0
- package/src/merger-contracts.ts +71 -0
- package/src/merger-git-state.ts +76 -0
- package/src/merger-role.ts +60 -0
- package/src/navigator-attendance.ts +1254 -0
- package/src/navigator-invocation-identity.ts +446 -0
- package/src/open-tool-schema.ts +46 -0
- package/src/package-contracts/collector-output.ts +109 -0
- package/src/package-contracts/fixer-output.ts +81 -0
- package/src/package-contracts/fixer-packet.ts +93 -0
- package/src/package-contracts/judge-output.ts +39 -0
- package/src/package-contracts/reviewer-output.ts +115 -0
- package/src/package-contracts/terminating-tools.ts +259 -0
- package/src/package-contracts/worker-output.ts +36 -0
- package/src/package-owned-tool-idle.ts +134 -0
- package/src/package-resources/method-skill-binding.ts +87 -0
- package/src/package-resources/method-skill.ts +358 -0
- package/src/packaged-role-registry.ts +36 -0
- package/src/public-cli/cli-errors.ts +11 -0
- package/src/public-cli/cli-io.ts +4 -0
- package/src/public-cli/cli.ts +912 -0
- package/src/public-cli/coder-run.ts +575 -0
- package/src/public-cli/collector-run.ts +375 -0
- package/src/public-cli/command-renderer.ts +8 -0
- package/src/public-cli/config.ts +346 -0
- package/src/public-cli/doctor-run.ts +355 -0
- package/src/public-cli/explicit-internal.ts +274 -0
- package/src/public-cli/fixer-run.ts +587 -0
- package/src/public-cli/host-pi-runtime.ts +112 -0
- package/src/public-cli/invocation.ts +1958 -0
- package/src/public-cli/judge-run.ts +507 -0
- package/src/public-cli/main.ts +15 -0
- package/src/public-cli/merger-run.ts +681 -0
- package/src/public-cli/public-run-credentials.ts +71 -0
- package/src/public-cli/registry.ts +153 -0
- package/src/public-cli/reviewer-run.ts +561 -0
- package/src/public-cli/run-lifecycle.ts +884 -0
- package/src/public-cli/settlement.ts +3765 -0
- package/src/public-cli/terminal.ts +325 -0
- package/src/public-command-renderer.ts +43 -0
- package/src/reviewer-agent.ts +94 -0
- package/src/reviewer-auditor.ts +53 -0
- package/src/reviewer-child-executor.ts +31 -0
- package/src/reviewer-construction.ts +137 -0
- package/src/reviewer-dispatch.ts +94 -0
- package/src/reviewer-execution-ledger.ts +206 -0
- package/src/reviewer-failure-diagnostic.ts +18 -0
- package/src/reviewer-git-snapshot.ts +53 -0
- package/src/reviewer-pinned-git.ts +144 -0
- package/src/reviewer-preflight-error.ts +14 -0
- package/src/reviewer-prompt-identity.ts +17 -0
- package/src/reviewer-role.ts +193 -0
- package/src/reviewer-scope-prompt.ts +24 -0
- package/src/reviewer-settlement.ts +63 -0
- package/src/reviewer-workspace.ts +111 -0
- package/src/role-runtime.ts +884 -0
- package/src/sha256.ts +6 -0
- package/src/sitian-record-entry.ts +57 -0
- package/src/stderr-jsonl.ts +28 -0
- package/src/stream-idle-guard.ts +98 -0
- package/src/ticket-snapshot.ts +662 -0
- package/src/ticket-trajectory.ts +1000 -0
- package/src/tool-execution-observation.ts +168 -0
- package/src/uuidv7.ts +1 -0
- package/src/work-subject-identity.ts +94 -0
- package/src/worker-role.ts +434 -0
- package/src/worker-submission-gates.ts +225 -0
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
import { PACKAGED_ROLE_REGISTRY } from "./packaged-role-registry.js";
|
|
2
|
+
import { isUuidV7, uuidv7 } from "./uuidv7.js";
|
|
3
|
+
import { workSubjectKeysEqual } from "./work-subject-identity.js";
|
|
4
|
+
const NAVIGATOR_INVOCATION_ENTRY = "ak-navigator-invocation";
|
|
5
|
+
const NAVIGATOR_INFRASTRUCTURE_FAILURE_KIND = "role_infrastructure_failure";
|
|
6
|
+
const NAVIGATOR_INFRASTRUCTURE_FAILURE_KEYS = [
|
|
7
|
+
"kind",
|
|
8
|
+
"source",
|
|
9
|
+
"reasonCode"
|
|
10
|
+
];
|
|
11
|
+
function buildNavigatorInfrastructureFailureFact() {
|
|
12
|
+
return {
|
|
13
|
+
kind: NAVIGATOR_INFRASTRUCTURE_FAILURE_KIND,
|
|
14
|
+
source: "shared-role-lifecycle",
|
|
15
|
+
reasonCode: "host_failure"
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
function isNavigatorInfrastructureFailureFact(value) {
|
|
19
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
|
|
20
|
+
const record = value;
|
|
21
|
+
const keys = Object.keys(record);
|
|
22
|
+
if (keys.length !== NAVIGATOR_INFRASTRUCTURE_FAILURE_KEYS.length) return false;
|
|
23
|
+
for (const key of NAVIGATOR_INFRASTRUCTURE_FAILURE_KEYS) {
|
|
24
|
+
if (!Object.hasOwn(record, key)) return false;
|
|
25
|
+
}
|
|
26
|
+
return record.kind === NAVIGATOR_INFRASTRUCTURE_FAILURE_KIND && record.source === "shared-role-lifecycle" && record.reasonCode === "host_failure";
|
|
27
|
+
}
|
|
28
|
+
const PACKAGED_ROLE_OUTPUT_TOOLS = new Map(
|
|
29
|
+
PACKAGED_ROLE_REGISTRY.map((entry) => [entry.outputTool, entry.role])
|
|
30
|
+
);
|
|
31
|
+
function mintNavigatorInvocationId() {
|
|
32
|
+
return uuidv7();
|
|
33
|
+
}
|
|
34
|
+
function invocationPhaseFromUnknown(value) {
|
|
35
|
+
if (value === null || value === "plan" || value === "apply") return value;
|
|
36
|
+
return void 0;
|
|
37
|
+
}
|
|
38
|
+
function parseInvocationMarkerIdentity(data) {
|
|
39
|
+
if (data === null || typeof data !== "object" || Array.isArray(data)) return void 0;
|
|
40
|
+
const record = data;
|
|
41
|
+
const invocationId = record.invocationId;
|
|
42
|
+
if (typeof invocationId !== "string") return void 0;
|
|
43
|
+
const trimmedId = invocationId.trim();
|
|
44
|
+
if (!isUuidV7(trimmedId)) return void 0;
|
|
45
|
+
if (typeof record.role !== "string" || record.role.trim() === "") return void 0;
|
|
46
|
+
const phase = invocationPhaseFromUnknown(record.phase);
|
|
47
|
+
if (phase === void 0) return void 0;
|
|
48
|
+
if (typeof record.subjectKey !== "string" || record.subjectKey.trim() === "") return void 0;
|
|
49
|
+
return {
|
|
50
|
+
invocationId: trimmedId,
|
|
51
|
+
role: record.role,
|
|
52
|
+
phase,
|
|
53
|
+
subjectKey: record.subjectKey
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
function markerMatchesExpectedIdentity(marker, expected) {
|
|
57
|
+
if (marker.role !== expected.role) return false;
|
|
58
|
+
if (expected.phase !== void 0) {
|
|
59
|
+
if (marker.phase !== expected.phase) return false;
|
|
60
|
+
} else if (expected.allowedPhases !== void 0) {
|
|
61
|
+
if (!expected.allowedPhases.includes(marker.phase)) return false;
|
|
62
|
+
}
|
|
63
|
+
if (expected.subjectKey !== void 0) {
|
|
64
|
+
if (!workSubjectKeysEqual(marker.subjectKey, expected.subjectKey)) return false;
|
|
65
|
+
}
|
|
66
|
+
return true;
|
|
67
|
+
}
|
|
68
|
+
function classifyPackagedRoleTerminalResult(message) {
|
|
69
|
+
if (typeof message.toolName !== "string") return { kind: "nonterminal" };
|
|
70
|
+
if (!PACKAGED_ROLE_OUTPUT_TOOLS.has(message.toolName)) return { kind: "nonterminal" };
|
|
71
|
+
const infraFact = isNavigatorInfrastructureFailureFact(message.details) ? message.details : void 0;
|
|
72
|
+
if (message.isError === true) {
|
|
73
|
+
if (infraFact === void 0) return { kind: "nonterminal" };
|
|
74
|
+
return { kind: "infrastructure", fact: infraFact };
|
|
75
|
+
}
|
|
76
|
+
if (message.isError === false) {
|
|
77
|
+
if (infraFact !== void 0) return { kind: "nonterminal" };
|
|
78
|
+
return { kind: "accepted" };
|
|
79
|
+
}
|
|
80
|
+
return { kind: "nonterminal" };
|
|
81
|
+
}
|
|
82
|
+
function isDurablePackagedRoleTerminalResult(message) {
|
|
83
|
+
const classification = classifyPackagedRoleTerminalResult(message);
|
|
84
|
+
return classification.kind === "accepted" || classification.kind === "infrastructure";
|
|
85
|
+
}
|
|
86
|
+
function isAcceptedPackagedRoleTerminalResult(message) {
|
|
87
|
+
return classifyPackagedRoleTerminalResult(message).kind === "accepted";
|
|
88
|
+
}
|
|
89
|
+
function durableTerminalAt(entries, index) {
|
|
90
|
+
const entry = entries[index];
|
|
91
|
+
if (entry?.type !== "message") return void 0;
|
|
92
|
+
const message = entry.message;
|
|
93
|
+
if (message?.role !== "toolResult") return void 0;
|
|
94
|
+
if (typeof message.toolName !== "string") return void 0;
|
|
95
|
+
const role = PACKAGED_ROLE_OUTPUT_TOOLS.get(message.toolName);
|
|
96
|
+
if (role === void 0) return void 0;
|
|
97
|
+
const classification = classifyPackagedRoleTerminalResult(message);
|
|
98
|
+
if (classification.kind !== "accepted" && classification.kind !== "infrastructure") {
|
|
99
|
+
return void 0;
|
|
100
|
+
}
|
|
101
|
+
return {
|
|
102
|
+
index,
|
|
103
|
+
role,
|
|
104
|
+
toolName: message.toolName,
|
|
105
|
+
classification: classification.kind,
|
|
106
|
+
message
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
function isPackagedRoleTerminalEntry(entry) {
|
|
110
|
+
if (entry?.type !== "message") return false;
|
|
111
|
+
const message = entry.message;
|
|
112
|
+
if (message?.role !== "toolResult") return false;
|
|
113
|
+
return isDurablePackagedRoleTerminalResult(message);
|
|
114
|
+
}
|
|
115
|
+
function isInvocationMarkerEntry(entry) {
|
|
116
|
+
return entry?.type === "custom" && entry.customType === NAVIGATOR_INVOCATION_ENTRY;
|
|
117
|
+
}
|
|
118
|
+
function latestInvocationMarkerIndex(entries) {
|
|
119
|
+
for (let i = entries.length - 1; i >= 0; i -= 1) {
|
|
120
|
+
if (isInvocationMarkerEntry(entries[i])) return i;
|
|
121
|
+
}
|
|
122
|
+
return -1;
|
|
123
|
+
}
|
|
124
|
+
function findLatestDurablePackagedRoleTerminal(entries) {
|
|
125
|
+
for (let i = entries.length - 1; i >= 0; i -= 1) {
|
|
126
|
+
const terminal = durableTerminalAt(entries, i);
|
|
127
|
+
if (terminal !== void 0) return terminal;
|
|
128
|
+
}
|
|
129
|
+
return void 0;
|
|
130
|
+
}
|
|
131
|
+
function bindCurrentDurableTerminalToMarker(entries) {
|
|
132
|
+
const terminal = findLatestDurablePackagedRoleTerminal(entries);
|
|
133
|
+
if (terminal === void 0) return { kind: "absent" };
|
|
134
|
+
let markerIndex = -1;
|
|
135
|
+
for (let i = terminal.index - 1; i >= 0; i -= 1) {
|
|
136
|
+
if (isInvocationMarkerEntry(entries[i])) {
|
|
137
|
+
markerIndex = i;
|
|
138
|
+
break;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
if (markerIndex < 0) {
|
|
142
|
+
return { kind: "unbound", terminal };
|
|
143
|
+
}
|
|
144
|
+
const marker = parseInvocationMarkerIdentity(entries[markerIndex]?.data);
|
|
145
|
+
if (marker === void 0) {
|
|
146
|
+
return { kind: "unbound", terminal };
|
|
147
|
+
}
|
|
148
|
+
let windowEnd = entries.length;
|
|
149
|
+
for (let i = markerIndex + 1; i < entries.length; i += 1) {
|
|
150
|
+
if (isInvocationMarkerEntry(entries[i])) {
|
|
151
|
+
windowEnd = i;
|
|
152
|
+
break;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
let durableCount = 0;
|
|
156
|
+
for (let i = markerIndex + 1; i < windowEnd; i += 1) {
|
|
157
|
+
if (durableTerminalAt(entries, i) !== void 0) durableCount += 1;
|
|
158
|
+
}
|
|
159
|
+
if (durableCount !== 1) return { kind: "ambiguous" };
|
|
160
|
+
if (terminal.index <= markerIndex || terminal.index >= windowEnd) {
|
|
161
|
+
return { kind: "ambiguous" };
|
|
162
|
+
}
|
|
163
|
+
return {
|
|
164
|
+
kind: "bound",
|
|
165
|
+
terminal,
|
|
166
|
+
marker: { ...marker, index: markerIndex }
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
function isReceiptSettlementBindingClear(entries) {
|
|
170
|
+
return bindCurrentDurableTerminalToMarker(entries).kind !== "ambiguous";
|
|
171
|
+
}
|
|
172
|
+
function resolveLifecycleInvocationPrincipal(entries, expected) {
|
|
173
|
+
const markerIndex = latestInvocationMarkerIndex(entries);
|
|
174
|
+
if (markerIndex < 0) {
|
|
175
|
+
return { invocationId: mintNavigatorInvocationId(), resume: false };
|
|
176
|
+
}
|
|
177
|
+
const marker = parseInvocationMarkerIdentity(entries[markerIndex]?.data);
|
|
178
|
+
if (marker === void 0) {
|
|
179
|
+
return { invocationId: mintNavigatorInvocationId(), resume: false };
|
|
180
|
+
}
|
|
181
|
+
if (expected !== void 0 && !markerMatchesExpectedIdentity(marker, expected)) {
|
|
182
|
+
return { invocationId: mintNavigatorInvocationId(), resume: false };
|
|
183
|
+
}
|
|
184
|
+
for (let i = markerIndex + 1; i < entries.length; i += 1) {
|
|
185
|
+
if (isPackagedRoleTerminalEntry(entries[i])) {
|
|
186
|
+
return { invocationId: mintNavigatorInvocationId(), resume: false };
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
return { invocationId: marker.invocationId, resume: true };
|
|
190
|
+
}
|
|
191
|
+
function currentInvocationPrincipalFromSession(entries, beforeIndex = entries.length) {
|
|
192
|
+
return currentInvocationMarkerFromSession(entries, beforeIndex)?.invocationId;
|
|
193
|
+
}
|
|
194
|
+
function currentInvocationMarkerFromSession(entries, beforeIndex = entries.length) {
|
|
195
|
+
const limit = Math.min(Math.max(beforeIndex, 0), entries.length);
|
|
196
|
+
for (let i = limit - 1; i >= 0; i -= 1) {
|
|
197
|
+
const entry = entries[i];
|
|
198
|
+
if (!isInvocationMarkerEntry(entry)) continue;
|
|
199
|
+
return parseInvocationMarkerIdentity(entry?.data);
|
|
200
|
+
}
|
|
201
|
+
return void 0;
|
|
202
|
+
}
|
|
203
|
+
export {
|
|
204
|
+
NAVIGATOR_INFRASTRUCTURE_FAILURE_KIND,
|
|
205
|
+
NAVIGATOR_INVOCATION_ENTRY,
|
|
206
|
+
bindCurrentDurableTerminalToMarker,
|
|
207
|
+
buildNavigatorInfrastructureFailureFact,
|
|
208
|
+
classifyPackagedRoleTerminalResult,
|
|
209
|
+
currentInvocationMarkerFromSession,
|
|
210
|
+
currentInvocationPrincipalFromSession,
|
|
211
|
+
findLatestDurablePackagedRoleTerminal,
|
|
212
|
+
isAcceptedPackagedRoleTerminalResult,
|
|
213
|
+
isDurablePackagedRoleTerminalResult,
|
|
214
|
+
isNavigatorInfrastructureFailureFact,
|
|
215
|
+
isReceiptSettlementBindingClear,
|
|
216
|
+
markerMatchesExpectedIdentity,
|
|
217
|
+
mintNavigatorInvocationId,
|
|
218
|
+
parseInvocationMarkerIdentity,
|
|
219
|
+
resolveLifecycleInvocationPrincipal
|
|
220
|
+
};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { Type } from "typebox";
|
|
2
|
+
function described(name, schema) {
|
|
3
|
+
if (typeof schema.description === "string")
|
|
4
|
+
return schema;
|
|
5
|
+
throw new Error(`Tool field ${name} has no semantic description at its schema owner`);
|
|
6
|
+
}
|
|
7
|
+
function declarationIdentity(schema) {
|
|
8
|
+
const { description: _description, ...semantic } = schema;
|
|
9
|
+
return JSON.stringify(semantic);
|
|
10
|
+
}
|
|
11
|
+
/** Collapse transport variants into one provider-compatible, zero-required open object. */
|
|
12
|
+
export function openToolObjectFromUnion(schema) {
|
|
13
|
+
const declarations = new Map();
|
|
14
|
+
for (const variant of schema.anyOf) {
|
|
15
|
+
for (const [name, declaration] of Object.entries(variant.properties ?? {})) {
|
|
16
|
+
const entries = declarations.get(name) ?? [];
|
|
17
|
+
const identity = declarationIdentity(declaration);
|
|
18
|
+
if (!entries.some((entry) => declarationIdentity(entry) === identity))
|
|
19
|
+
entries.push(declaration);
|
|
20
|
+
declarations.set(name, entries);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
const properties = Object.fromEntries([...declarations].map(([name, entries]) => {
|
|
24
|
+
const descriptions = [...new Set(entries.map((entry) => entry.description).filter((value) => typeof value === "string"))].join(" ");
|
|
25
|
+
const declaration = entries.length === 1
|
|
26
|
+
? entries[0]
|
|
27
|
+
: Type.Union(entries, descriptions === "" ? {} : { description: descriptions });
|
|
28
|
+
return [name, Type.Optional(described(name, declaration))];
|
|
29
|
+
}));
|
|
30
|
+
const object = Type.Object(properties, { additionalProperties: true });
|
|
31
|
+
object.required = [];
|
|
32
|
+
return object;
|
|
33
|
+
}
|
|
34
|
+
/** Open a pre-existing object transport schema without changing declarations. */
|
|
35
|
+
export function openToolObject(schema) {
|
|
36
|
+
const object = Type.Object(Object.fromEntries(Object.entries(schema.properties).map(([name, declaration]) => [name, Type.Optional(described(name, declaration))])), { additionalProperties: true });
|
|
37
|
+
object.required = [];
|
|
38
|
+
return object;
|
|
39
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/** Package-owned Collector receipt leaf — no role registration surface. */
|
|
2
|
+
export const COLLECTOR_OUTPUT_TOOL = "ak_collector_output";
|
|
3
|
+
export const COLLECTOR_ACCEPTED_TEXT = "Collector receipt accepted";
|
|
4
|
+
export const COLLECTOR_HOST = "github.com";
|
|
5
|
+
function safeGet(value, key) {
|
|
6
|
+
if ((typeof value !== "object" && typeof value !== "function") || value === null)
|
|
7
|
+
return undefined;
|
|
8
|
+
try {
|
|
9
|
+
return value[key];
|
|
10
|
+
}
|
|
11
|
+
catch {
|
|
12
|
+
return undefined;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
function records(value) {
|
|
16
|
+
return Array.isArray(value) ? value.filter((item) => item !== null && typeof item === "object") : [];
|
|
17
|
+
}
|
|
18
|
+
function strings(value) {
|
|
19
|
+
return Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
|
|
20
|
+
}
|
|
21
|
+
/** Settlement projection. Presence of the canonical groups array is the one Collector terminal discriminator. */
|
|
22
|
+
export function validateAcceptedCollectorReceipt(value) {
|
|
23
|
+
const rawGroups = safeGet(value, "groups");
|
|
24
|
+
if (!Array.isArray(rawGroups))
|
|
25
|
+
throw new Error("Collector receipt has no typed groups terminal discriminator");
|
|
26
|
+
const groups = records(rawGroups).map((group) => ({
|
|
27
|
+
identity: (safeGet(group, "identity") ?? null),
|
|
28
|
+
...(typeof safeGet(group, "displayLogin") === "string" ? { displayLogin: safeGet(group, "displayLogin") } : {}),
|
|
29
|
+
attendance: true,
|
|
30
|
+
materials: records(safeGet(group, "materials")),
|
|
31
|
+
findings: records(safeGet(group, "findings")),
|
|
32
|
+
}));
|
|
33
|
+
return {
|
|
34
|
+
host: safeGet(value, "host"),
|
|
35
|
+
repository: safeGet(value, "repository"),
|
|
36
|
+
prNumber: safeGet(value, "prNumber"),
|
|
37
|
+
manifestDigest: safeGet(value, "manifestDigest"),
|
|
38
|
+
activationTime: safeGet(value, "activationTime"),
|
|
39
|
+
deadlineTime: safeGet(value, "deadlineTime"),
|
|
40
|
+
finalObservationTime: safeGet(value, "finalObservationTime"),
|
|
41
|
+
finalSnapshotId: safeGet(value, "finalSnapshotId"),
|
|
42
|
+
targetHead: safeGet(value, "targetHead"),
|
|
43
|
+
groups,
|
|
44
|
+
requestAttempts: records(safeGet(value, "requestAttempts")),
|
|
45
|
+
snapshots: records(safeGet(value, "snapshots")).map((snapshot) => ({
|
|
46
|
+
snapshotId: safeGet(snapshot, "snapshotId"), observedAt: safeGet(snapshot, "observedAt"), completedAt: safeGet(snapshot, "completedAt"), completedMono: safeGet(snapshot, "completedMono"), host: safeGet(snapshot, "host"), repository: safeGet(snapshot, "repository"), prNumber: safeGet(snapshot, "prNumber"), prState: safeGet(snapshot, "prState"), headOid: safeGet(snapshot, "headOid"), complete: safeGet(snapshot, "complete"), evidenceIds: strings(safeGet(snapshot, "evidenceIds")), pageDiagnostics: records(safeGet(snapshot, "pageDiagnostics")), normalizedByteLength: safeGet(snapshot, "normalizedByteLength"),
|
|
47
|
+
})),
|
|
48
|
+
evidenceRecords: records(safeGet(value, "evidenceRecords")).map((record) => ({ evidenceId: safeGet(record, "evidenceId"), kind: safeGet(record, "kind"), versionId: safeGet(record, "versionId"), contentDigest: safeGet(record, "contentDigest"), firstObservedAt: safeGet(record, "firstObservedAt"), raw: safeGet(record, "raw") })),
|
|
49
|
+
};
|
|
50
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { Type } from "typebox";
|
|
2
|
+
import { FIXER_PREREQUISITE_ID_PATTERN } from "./fixer-packet.js";
|
|
3
|
+
import { openToolObjectFromUnion } from "../open-tool-schema.js";
|
|
4
|
+
export const FIXER_OUTPUT_TOOL_NAME = "ak_fixer_output";
|
|
5
|
+
export const FIXER_ACCEPTED_TEXT = "Fixer report accepted";
|
|
6
|
+
const nonblankTransportString = Type.String({ minLength: 1 });
|
|
7
|
+
const authorityBlockerSchema = Type.Object({ cause: Type.Literal("authority_violation"), evidence: nonblankTransportString });
|
|
8
|
+
const prerequisiteBlockerSchema = Type.Object({ cause: Type.Literal("prerequisite_unmet"), prerequisiteId: Type.String({ pattern: FIXER_PREREQUISITE_ID_PATTERN }), evidence: nonblankTransportString });
|
|
9
|
+
const blockerSchema = Type.Union([authorityBlockerSchema, prerequisiteBlockerSchema]);
|
|
10
|
+
const exceptionSchema = Type.Object({ where: nonblankTransportString, reason: nonblankTransportString });
|
|
11
|
+
/** ⑥ test evidence slip — require submit when diff has test changes; machine does not check existence/completeness/coverage. */
|
|
12
|
+
const testEvidenceSchema = Type.Object({
|
|
13
|
+
contract: Type.String({ minLength: 1, description: "Contract the test change proves." }),
|
|
14
|
+
minimumNecessaryCost: Type.String({ minLength: 1, description: "One-line minimum necessary cost of the test change." }),
|
|
15
|
+
measuredDuration: Type.String({ minLength: 1, description: "Measured duration of the focused verification run." }),
|
|
16
|
+
}, { description: "Test evidence slip (submit when diff includes test changes; machine does not verify)." });
|
|
17
|
+
const completedClassResultSchema = Type.Object({
|
|
18
|
+
name: nonblankTransportString,
|
|
19
|
+
disposition: Type.Literal("completed"),
|
|
20
|
+
searchScope: nonblankTransportString,
|
|
21
|
+
exceptions: Type.Array(exceptionSchema),
|
|
22
|
+
commitSha: nonblankTransportString,
|
|
23
|
+
});
|
|
24
|
+
const refusedClassResultSchema = Type.Object({
|
|
25
|
+
name: nonblankTransportString,
|
|
26
|
+
disposition: Type.Literal("refused"),
|
|
27
|
+
remainingScope: nonblankTransportString,
|
|
28
|
+
blocker: blockerSchema,
|
|
29
|
+
});
|
|
30
|
+
const classResultSchema = Type.Union([completedClassResultSchema, refusedClassResultSchema]);
|
|
31
|
+
const completedClassResultsSchema = Type.Array(completedClassResultSchema, { minItems: 1 });
|
|
32
|
+
const fixerOutputVariants = Type.Union([
|
|
33
|
+
Type.Object({ status: Type.Literal("planned", { description: "Plan-phase proposal outcome." }), report: Type.String({ minLength: 1, description: "Truthful Fixer outcome report." }) }),
|
|
34
|
+
Type.Object({ status: Type.Literal("refused", { description: "Lawfully refused outcome." }), report: Type.String({ minLength: 1, description: "Truthful Fixer outcome report." }), remainingScope: Type.String({ minLength: 1, description: "Work that cannot lawfully be performed." }), blocker: Type.Unsafe({ ...blockerSchema, description: "Lawful blocker preventing completion." }) }),
|
|
35
|
+
Type.Object({ status: Type.Literal("unfinished", { description: "Honest unfinished apply outcome." }), report: Type.String({ minLength: 1, description: "Truthful Fixer outcome report." }), remainingScope: Type.String({ minLength: 1, description: "Work remaining after this invocation." }), classResults: Type.Optional(Type.Unsafe({ ...completedClassResultsSchema, description: "Completed class settlements from this invocation." })), testEvidence: Type.Optional(testEvidenceSchema) }),
|
|
36
|
+
Type.Object({ status: Type.Literal("completed", { description: "All assigned classes completed." }), report: Type.String({ minLength: 1, description: "Truthful Fixer outcome report." }), classResults: Type.Array(classResultSchema, { minItems: 1, description: "Completed class settlements." }), testEvidence: Type.Optional(testEvidenceSchema) }),
|
|
37
|
+
Type.Object({ status: Type.Literal("refused", { description: "All assigned classes lawfully refused." }), report: Type.String({ minLength: 1, description: "Truthful Fixer outcome report." }), classResults: Type.Array(classResultSchema, { minItems: 1, description: "Per-class refusal settlements." }) }),
|
|
38
|
+
Type.Object({ status: Type.Literal("partially_completed", { description: "Assigned classes include completions and lawful refusals." }), report: Type.String({ minLength: 1, description: "Truthful Fixer outcome report." }), classResults: Type.Array(classResultSchema, { minItems: 1, description: "Per-class completion or refusal settlements." }), testEvidence: Type.Optional(testEvidenceSchema) }),
|
|
39
|
+
]);
|
|
40
|
+
export const fixerOutputSchema = openToolObjectFromUnion(fixerOutputVariants);
|
|
41
|
+
export function validateFixerOutput(value, _phase) {
|
|
42
|
+
return value;
|
|
43
|
+
}
|
|
44
|
+
function safeProperty(value, property) {
|
|
45
|
+
if (value === null || typeof value !== "object")
|
|
46
|
+
return undefined;
|
|
47
|
+
try {
|
|
48
|
+
return value[property];
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
return undefined;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
/** Bind recognizable prerequisite blockers to the packet declaration. */
|
|
55
|
+
export function validateFixerOutputForPacket(value, phase, packet) {
|
|
56
|
+
const output = validateFixerOutput(value, phase);
|
|
57
|
+
const declaredIds = new Set(packet.prerequisites.map((entry) => entry.id));
|
|
58
|
+
const topLevelBlocker = safeProperty(output, "blocker");
|
|
59
|
+
const classResults = safeProperty(output, "classResults");
|
|
60
|
+
const blockers = topLevelBlocker === undefined
|
|
61
|
+
? (Array.isArray(classResults) ? classResults.map((entry) => safeProperty(entry, "blocker")) : [])
|
|
62
|
+
: [topLevelBlocker];
|
|
63
|
+
for (const blocker of blockers) {
|
|
64
|
+
if (safeProperty(blocker, "cause") !== "prerequisite_unmet")
|
|
65
|
+
continue;
|
|
66
|
+
const prerequisiteId = safeProperty(blocker, "prerequisiteId");
|
|
67
|
+
if (typeof prerequisiteId === "string" && !declaredIds.has(prerequisiteId)) {
|
|
68
|
+
throw new Error("Fixer output violates blocker.prerequisiteId declared-prerequisite constraint");
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return output;
|
|
72
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { Type } from "typebox";
|
|
2
|
+
import { Value } from "typebox/value";
|
|
3
|
+
export const FIXER_PREREQUISITE_ID_PATTERN = "^[A-Za-z0-9][A-Za-z0-9._-]*$";
|
|
4
|
+
export const fixerPrerequisiteSchema = Type.Object({
|
|
5
|
+
id: Type.String({ pattern: FIXER_PREREQUISITE_ID_PATTERN }),
|
|
6
|
+
requirement: Type.String({ pattern: "\\S" }),
|
|
7
|
+
}, { additionalProperties: false });
|
|
8
|
+
export const fixerPrerequisitesSchema = Type.Array(fixerPrerequisiteSchema);
|
|
9
|
+
function causeMessage(cause) {
|
|
10
|
+
if (cause instanceof Error)
|
|
11
|
+
return cause.message;
|
|
12
|
+
if (typeof cause === "string")
|
|
13
|
+
return cause;
|
|
14
|
+
try {
|
|
15
|
+
return JSON.stringify(cause) ?? String(cause);
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
return String(cause);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
export class FixerPacketValidationError extends Error {
|
|
22
|
+
code = "AK_INVALID_FIX_PACKET";
|
|
23
|
+
constructor(cause) {
|
|
24
|
+
const prefix = "Fixer prerequisites or instructions violate the invocation contract";
|
|
25
|
+
super(cause === undefined ? prefix : `${prefix}: ${causeMessage(cause)}`, cause === undefined ? undefined : { cause });
|
|
26
|
+
this.name = "FixerPacketValidationError";
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
function fail(cause) {
|
|
30
|
+
throw new FixerPacketValidationError(cause);
|
|
31
|
+
}
|
|
32
|
+
function parseFailure(value) {
|
|
33
|
+
if (!Array.isArray(value))
|
|
34
|
+
fail(new Error("Fixer prerequisites must be a JSON array"));
|
|
35
|
+
for (const entry of value) {
|
|
36
|
+
if (typeof entry !== "object" || entry === null || Array.isArray(entry)) {
|
|
37
|
+
fail(new Error("Fixer prerequisite entry must be an object with id and requirement fields"));
|
|
38
|
+
}
|
|
39
|
+
const keys = Object.keys(entry);
|
|
40
|
+
if (keys.length !== 2 || !keys.includes("id") || !keys.includes("requirement")) {
|
|
41
|
+
fail(new Error("Fixer prerequisite entry fields must be exactly id and requirement"));
|
|
42
|
+
}
|
|
43
|
+
if (typeof entry.id !== "string" ||
|
|
44
|
+
!(new RegExp(FIXER_PREREQUISITE_ID_PATTERN)).test(entry.id)) {
|
|
45
|
+
fail(new Error(`Fixer prerequisite id violates pattern ${FIXER_PREREQUISITE_ID_PATTERN}`));
|
|
46
|
+
}
|
|
47
|
+
if (typeof entry.requirement !== "string" ||
|
|
48
|
+
!/\S/.test(entry.requirement)) {
|
|
49
|
+
fail(new Error("Fixer prerequisite requirement must be nonblank"));
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
fail(new Error("Fixer prerequisites violate the attachment schema"));
|
|
53
|
+
}
|
|
54
|
+
export function validateFixerPrerequisites(value) {
|
|
55
|
+
if (!Value.Check(fixerPrerequisitesSchema, value))
|
|
56
|
+
parseFailure(value);
|
|
57
|
+
const entries = value;
|
|
58
|
+
const ids = new Set();
|
|
59
|
+
const prerequisites = entries.map((entry) => {
|
|
60
|
+
if (ids.has(entry.id)) {
|
|
61
|
+
fail(new Error(`Fixer prerequisites contain duplicate id: ${entry.id}`));
|
|
62
|
+
}
|
|
63
|
+
ids.add(entry.id);
|
|
64
|
+
return Object.freeze({ id: entry.id, requirement: entry.requirement });
|
|
65
|
+
});
|
|
66
|
+
return Object.freeze(prerequisites);
|
|
67
|
+
}
|
|
68
|
+
export function parseFixerPrerequisites(source) {
|
|
69
|
+
let decoded;
|
|
70
|
+
try {
|
|
71
|
+
decoded = JSON.parse(source);
|
|
72
|
+
}
|
|
73
|
+
catch (error) {
|
|
74
|
+
fail(error);
|
|
75
|
+
}
|
|
76
|
+
return validateFixerPrerequisites(decoded);
|
|
77
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/** Package-owned Judge output leaf — no role registration surface. */
|
|
2
|
+
export const JUDGE_OUTPUT_TOOL_NAME = "ak_judge_output";
|
|
3
|
+
export const JUDGE_ACCEPTED_TEXT = "Judge verdict accepted";
|
|
4
|
+
export function validateAcceptedJudgeDetails(verdict) {
|
|
5
|
+
if (verdict === null || typeof verdict !== "object" || Array.isArray(verdict))
|
|
6
|
+
throw new Error("Judge verdict has no execution discriminator");
|
|
7
|
+
let judgeStatus;
|
|
8
|
+
try {
|
|
9
|
+
judgeStatus = verdict.judgeStatus;
|
|
10
|
+
}
|
|
11
|
+
catch {
|
|
12
|
+
throw new Error("Judge verdict has no execution discriminator");
|
|
13
|
+
}
|
|
14
|
+
if (["converged", "continue", "escalate"].includes(String(judgeStatus)))
|
|
15
|
+
return verdict;
|
|
16
|
+
throw new Error("Judge verdict has no execution discriminator");
|
|
17
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/** Package-owned Reviewer intent and runtime-receipt leaves — no role registration surface. */
|
|
2
|
+
export const REVIEWER_OUTPUT_TOOL_NAME = "ak_reviewer_output";
|
|
3
|
+
export const REVIEWER_ACCEPTED_TEXT = "Reviewer report accepted";
|
|
4
|
+
function isRecord(value) {
|
|
5
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
6
|
+
}
|
|
7
|
+
function read(value, key) {
|
|
8
|
+
if (!isRecord(value))
|
|
9
|
+
return undefined;
|
|
10
|
+
try {
|
|
11
|
+
return value[key];
|
|
12
|
+
}
|
|
13
|
+
catch {
|
|
14
|
+
return undefined;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
export function validateReviewerIntent(output) {
|
|
18
|
+
const status = read(output, "status");
|
|
19
|
+
if (status === "completed")
|
|
20
|
+
return { status };
|
|
21
|
+
if (status === "refused")
|
|
22
|
+
return { status, diagnostic: read(output, "diagnostic") };
|
|
23
|
+
throw new Error("Reviewer output has no recognized execution intent");
|
|
24
|
+
}
|
|
25
|
+
/** Validate runtime-owned facts at their real identity seams (target pins + plain text). */
|
|
26
|
+
export function validateRuntimeReviewerReceipt(output) {
|
|
27
|
+
const acceptedBatch = read(output, "acceptedBatch");
|
|
28
|
+
const identities = read(output, "identities");
|
|
29
|
+
const construction = read(identities, "construction");
|
|
30
|
+
const target = read(identities, "target");
|
|
31
|
+
const reports = read(output, "reports");
|
|
32
|
+
const outcomes = read(output, "outcomes");
|
|
33
|
+
const legs = read(acceptedBatch, "legs");
|
|
34
|
+
// A recognizable accepted batch must remain bound to its exact target pin.
|
|
35
|
+
if (acceptedBatch !== undefined || construction !== undefined || target !== undefined) {
|
|
36
|
+
if (!isRecord(acceptedBatch) || !isRecord(construction) || !isRecord(target) || !Array.isArray(legs))
|
|
37
|
+
throw new Error("Incomplete Reviewer accepted-batch identity");
|
|
38
|
+
const objectFormat = read(target, "objectFormat");
|
|
39
|
+
const objectId = (value) => typeof value === "string" && new RegExp(objectFormat === "sha1" ? "^[0-9a-f]{40}$" : "^[0-9a-f]{64}$").test(value);
|
|
40
|
+
const refs = read(target, "refs");
|
|
41
|
+
const skillText = read(read(identities, "canonicalSkill"), "text");
|
|
42
|
+
if (typeof skillText !== "string" ||
|
|
43
|
+
read(construction, "recipe") !== "reviewer-common-bundle-v1" ||
|
|
44
|
+
(objectFormat !== "sha1" && objectFormat !== "sha256") || !objectId(read(target, "targetHead")) || !isRecord(refs) ||
|
|
45
|
+
Object.values(refs).some((ref) => !isRecord(ref) || !objectId(read(ref, "objectId")) || (read(ref, "peeledCommitId") !== null && !objectId(read(ref, "peeledCommitId")))))
|
|
46
|
+
throw new Error("Invalid Reviewer construction or target identity");
|
|
47
|
+
const expectedAxes = legs.map((leg) => read(leg, "axis"));
|
|
48
|
+
if (expectedAxes[0] !== "standards" || (expectedAxes.length === 2 && expectedAxes[1] !== "spec") || expectedAxes.length < 1 || expectedAxes.length > 2)
|
|
49
|
+
throw new Error("Invalid Reviewer accepted-leg projection");
|
|
50
|
+
if (!isRecord(outcomes) || !isRecord(reports))
|
|
51
|
+
throw new Error("Accepted Reviewer batch lacks outcomes or reports");
|
|
52
|
+
const outcomeAxes = Object.keys(outcomes).filter(axis => axis === "standards" || axis === "spec");
|
|
53
|
+
if (outcomeAxes.length !== expectedAxes.length || outcomeAxes.some((axis, index) => axis !== expectedAxes[index]))
|
|
54
|
+
throw new Error("Reviewer outcomes must exactly cover accepted legs in canonical order");
|
|
55
|
+
for (const [index, axisValue] of expectedAxes.entries()) {
|
|
56
|
+
const axis = axisValue;
|
|
57
|
+
const outcome = read(outcomes, axis);
|
|
58
|
+
if (!isRecord(outcome))
|
|
59
|
+
throw new Error("Reviewer accepted leg lacks outcome");
|
|
60
|
+
const expectedPrompt = read(read(legs[index], "prompt"), "text");
|
|
61
|
+
const actualPrompt = read(read(outcome, "prompt"), "text");
|
|
62
|
+
if (expectedPrompt !== actualPrompt)
|
|
63
|
+
throw new Error("Reviewer outcome prompt disagrees with accepted leg");
|
|
64
|
+
const status = read(outcome, "status");
|
|
65
|
+
const report = read(reports, axis);
|
|
66
|
+
if (status === "successful" && report === undefined)
|
|
67
|
+
throw new Error("Successful Reviewer outcome lacks report");
|
|
68
|
+
if (status === "failed" && report !== undefined)
|
|
69
|
+
throw new Error("Failed Reviewer outcome cannot bind a report");
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return output;
|
|
73
|
+
}
|
|
74
|
+
/** Project thin submitted intent onto runtime enrichment without comparing runtime-owned fields. */
|
|
75
|
+
export function projectReviewerIntentToReceipt(intentValue, receiptValue) {
|
|
76
|
+
const intent = validateReviewerIntent(intentValue);
|
|
77
|
+
const receipt = validateRuntimeReviewerReceipt(receiptValue);
|
|
78
|
+
if (receipt.status !== intent.status || (intent.status === "completed" ? receipt.diagnostic !== undefined : receipt.diagnostic !== intent.diagnostic)) {
|
|
79
|
+
throw new Error("Reviewer intent and runtime receipt disagree");
|
|
80
|
+
}
|
|
81
|
+
return receipt;
|
|
82
|
+
}
|