@akagilnc/pi-workflow-roles 0.1.3932 → 0.1.3975

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.
Files changed (162) hide show
  1. package/CLAUDE.md +1 -1
  2. package/dist/acp-host/production-host.js +2389 -6018
  3. package/dist/analyst-gate-cycles-read.js +15 -19
  4. package/dist/audit-escalation.js +16 -46
  5. package/dist/auditor-dossier-tool.js +7 -62
  6. package/dist/collector-identity.js +0 -157
  7. package/dist/collector-ledger.js +2 -42
  8. package/dist/compliance-transport.js +40 -14
  9. package/dist/diarist-contracts.js +2 -40
  10. package/dist/doctor-contracts.js +39 -108
  11. package/dist/doctor-evidence.js +1 -5
  12. package/dist/engine-detour-tool.js +1 -1
  13. package/dist/gatekeeper-role.js +49 -38
  14. package/dist/headless-host/production-host.js +4814 -8450
  15. package/dist/host-contracts.js +0 -5
  16. package/dist/merger-contracts.js +4 -6
  17. package/dist/navigator-attendance.js +30 -52
  18. package/dist/navigator-invocation-identity.js +0 -1
  19. package/dist/navigator-public-session.js +2 -1
  20. package/dist/notary-contracts.js +4 -10
  21. package/dist/package-contracts/auditor-output.js +5 -23
  22. package/dist/package-contracts/fixer-output.js +25 -49
  23. package/dist/package-contracts/gatekeeper-output.js +3 -13
  24. package/dist/package-contracts/navigator-output.js +4 -7
  25. package/dist/package-contracts/reviewer-output.js +1 -95
  26. package/dist/package-contracts/terminating-tools.js +33 -144
  27. package/dist/package-contracts/worker-output.js +1 -3
  28. package/dist/public-cli/auto-resume.js +30 -68
  29. package/dist/public-cli/case-dossier-delivery.js +5 -17
  30. package/dist/public-cli/diarist-run.js +9 -4
  31. package/dist/public-cli/inspector-run.js +2 -8
  32. package/dist/public-cli/instruction-seat-run.js +3 -7
  33. package/dist/public-cli/invocation.js +5 -2
  34. package/dist/public-cli/main.js +6068 -6964
  35. package/dist/public-cli/notary-run.js +1 -8
  36. package/dist/public-cli/post-admission.js +314 -113
  37. package/dist/public-cli/run-lifecycle.js +14 -38
  38. package/dist/public-cli/settlement.js +209 -390
  39. package/dist/public-cli/terminal.js +51 -45
  40. package/dist/public-role-summons.js +1 -12
  41. package/dist/reviewer-dispatch.js +12 -258
  42. package/dist/submission-correctable-error.js +0 -12
  43. package/dist/submission-errors.js +6 -1
  44. package/dist/submission-ledger.js +125 -168
  45. package/dist/ticket-provenance-contracts.js +2 -49
  46. package/dist/ticket-provenance.js +82 -31
  47. package/extensions/role-runtime.ts +1 -6
  48. package/package.json +1 -1
  49. package/resources/836-deleted-machine-instruction-inventory.md +18 -0
  50. package/src/acp-host/role-turn-host.ts +8 -3
  51. package/src/analyst-gate-cycles-read.ts +17 -29
  52. package/src/audit-escalation.ts +20 -50
  53. package/src/auditor-dossier-tool.ts +5 -103
  54. package/src/canonical-skill-binding.ts +3 -2
  55. package/src/collector-identity.ts +0 -179
  56. package/src/collector-ledger.ts +3 -46
  57. package/src/collector-role.ts +32 -61
  58. package/src/collector-tool-schemas.ts +20 -14
  59. package/src/compliance-transport.ts +55 -17
  60. package/src/countersign-role.ts +17 -8
  61. package/src/diarist-contracts.ts +3 -36
  62. package/src/diarist-role.ts +13 -7
  63. package/src/diarist.ts +4 -16
  64. package/src/doctor-contracts.ts +73 -94
  65. package/src/doctor-evidence.ts +1 -1
  66. package/src/doctor-role.ts +3 -3
  67. package/src/engine-detour-tool.ts +4 -1
  68. package/src/external-host-turn-loop.ts +9 -3
  69. package/src/gatekeeper-pass-envelope.ts +7 -12
  70. package/src/gatekeeper-role.ts +56 -50
  71. package/src/gleaner-left-role.ts +4 -2
  72. package/src/headless-host/role-turn-host.ts +4 -5
  73. package/src/host-contracts.ts +3 -8
  74. package/src/judge-role.ts +19 -13
  75. package/src/merger-contracts.ts +10 -6
  76. package/src/merger-role.ts +1 -5
  77. package/src/navigator-attendance.ts +37 -74
  78. package/src/navigator-invocation-identity.ts +0 -6
  79. package/src/navigator-public-session.ts +2 -1
  80. package/src/notary-contracts.ts +7 -10
  81. package/src/package-contracts/auditor-output.ts +4 -21
  82. package/src/package-contracts/fixer-output.ts +34 -52
  83. package/src/package-contracts/gatekeeper-output.ts +5 -22
  84. package/src/package-contracts/navigator-output.ts +7 -7
  85. package/src/package-contracts/reviewer-output.ts +2 -150
  86. package/src/package-contracts/terminating-tools.ts +32 -147
  87. package/src/package-contracts/worker-output.ts +0 -1
  88. package/src/pi/adapter.ts +3 -8
  89. package/src/public-cli/auto-resume.ts +41 -94
  90. package/src/public-cli/case-dossier-delivery.ts +5 -15
  91. package/src/public-cli/countersign-run.ts +14 -6
  92. package/src/public-cli/diarist-run.ts +11 -9
  93. package/src/public-cli/inspector-run.ts +2 -18
  94. package/src/public-cli/instruction-seat-run.ts +3 -17
  95. package/src/public-cli/invocation.ts +5 -2
  96. package/src/public-cli/merger-run.ts +1 -1
  97. package/src/public-cli/notary-run.ts +1 -18
  98. package/src/public-cli/post-admission.ts +385 -115
  99. package/src/public-cli/run-lifecycle.ts +13 -44
  100. package/src/public-cli/settlement.ts +314 -562
  101. package/src/public-cli/terminal.ts +66 -72
  102. package/src/public-role-summons.ts +5 -30
  103. package/src/reviewer-dispatch.ts +29 -331
  104. package/src/reviewer-role.ts +16 -83
  105. package/src/role-envelope.ts +16 -24
  106. package/src/role-runtime-dependencies.ts +1 -6
  107. package/src/role-runtime.ts +65 -201
  108. package/src/submission-correctable-error.ts +0 -14
  109. package/src/submission-errors.ts +6 -1
  110. package/src/submission-ledger.ts +187 -187
  111. package/src/ticket-provenance-contracts.ts +4 -60
  112. package/src/ticket-provenance.ts +98 -32
  113. package/src/worker-role.ts +35 -36
  114. package/dist/activation-ledger-session.js +0 -105
  115. package/dist/activation-ledger.js +0 -139
  116. package/dist/activation-trace.js +0 -33
  117. package/dist/atomic-write.js +0 -23
  118. package/dist/auditor-role.js +0 -12
  119. package/dist/canonical-skill-binding.js +0 -61
  120. package/dist/collector-handbook.js +0 -142
  121. package/dist/collector-receipt.js +0 -107
  122. package/dist/collector-role.js +0 -566
  123. package/dist/collector-tool-schemas.js +0 -107
  124. package/dist/countersign-role.js +0 -28
  125. package/dist/diarist-role.js +0 -44
  126. package/dist/diarist.js +0 -66
  127. package/dist/doctor-role.js +0 -75
  128. package/dist/fixer-bash-seatbelt.js +0 -13
  129. package/dist/gatekeeper-pass-envelope.js +0 -77
  130. package/dist/gleaner-left-role.js +0 -26
  131. package/dist/inspector-role.js +0 -29
  132. package/dist/judge-role.js +0 -104
  133. package/dist/merger-role.js +0 -55
  134. package/dist/navigator-role.js +0 -12
  135. package/dist/notary-role.js +0 -134
  136. package/dist/oauth-keepalive.js +0 -158
  137. package/dist/pi/adapter.js +0 -223
  138. package/dist/reviewer-agent.js +0 -122
  139. package/dist/reviewer-child-executor.js +0 -194
  140. package/dist/reviewer-construction.js +0 -103
  141. package/dist/reviewer-execution-ledger.js +0 -166
  142. package/dist/reviewer-failure-diagnostic.js +0 -17
  143. package/dist/reviewer-role.js +0 -159
  144. package/dist/reviewer-scope-prompt.js +0 -21
  145. package/dist/reviewer-settlement.js +0 -66
  146. package/dist/reviewer-workspace.js +0 -132
  147. package/dist/role-runtime.js +0 -1604
  148. package/dist/stderr-jsonl.js +0 -26
  149. package/dist/tool-execution-observation.js +0 -141
  150. package/dist/worker-role.js +0 -345
  151. package/dist/worker-submission-gates.js +0 -305
  152. package/src/collector-receipt.ts +0 -140
  153. package/src/diagnostic-tail.ts +0 -18
  154. package/src/reviewer-agent.ts +0 -135
  155. package/src/reviewer-child-executor.ts +0 -252
  156. package/src/reviewer-construction.ts +0 -195
  157. package/src/reviewer-execution-ledger.ts +0 -212
  158. package/src/reviewer-failure-diagnostic.ts +0 -18
  159. package/src/reviewer-scope-prompt.ts +0 -24
  160. package/src/reviewer-settlement.ts +0 -74
  161. package/src/reviewer-workspace.ts +0 -105
  162. package/src/shape-unreadable-failure.ts +0 -49
@@ -1,305 +0,0 @@
1
- /** #242/#369 worker gates ①② at submission seam. Durability: ADR 0065 createRecordSession only. */
2
- import { execFileSync } from "node:child_process";
3
- import { existsSync, lstatSync, readdirSync, readFileSync, rmdirSync, rmSync } from "node:fs";
4
- import { resolve } from "node:path";
5
- import { createRecordSession, WORKER_SUBMISSION_GATE_KIND, } from "./archivist-record-entry.js";
6
- import { sitianReport } from "./sitian-facade.js";
7
- import { WorkerCommitReminderError, WorkerPrefixReminderError, WorkerUnfinishedReasonReminderError, } from "./submission-errors.js";
8
- export { WorkerCommitReminderError, WorkerPrefixReminderError, WorkerUnfinishedReasonReminderError } from "./submission-errors.js";
9
- export const WORKER_SUBMISSION_GATE_RECORD_KIND = WORKER_SUBMISSION_GATE_KIND;
10
- export const WORKER_COMMIT_BASELINE_ENTRY_TYPE = "commit-baseline";
11
- export const WORKER_COMMIT_REMINDER_BOUNCE_ENTRY_TYPE = "commit-reminder-bounce";
12
- export const WORKER_PREFIX_REMINDER_BOUNCE_ENTRY_TYPE = "prefix-reminder-bounce";
13
- /** Statuses that enter the officer submission gate (ADR 0066 gate-1-status-matrix / ADR 0072 skip-statuses). */
14
- export const WORKER_DONE_STATUSES = new Set(["completed", "partially_completed"]);
15
- /** Historical package hook ownership marker — uninstall criterion only. */
16
- const HOOK_MARKER = "ak-roles: worker-submission-gates reference-transaction";
17
- const HOOKS_DIR = "ak-roles-hooks";
18
- const HOOK_FILE = "reference-transaction";
19
- /** Open platform-prefix domain (constitution #10) — not a closed singleton. */
20
- const PLATFORM_PREFIX = /^[A-Za-z][A-Za-z0-9_-]*:/;
21
- const UNFINISHED_REASON_BOUNCE_LIMIT = 2;
22
- function git(cwd, args) {
23
- return execFileSync("git", args, {
24
- cwd, encoding: "utf8", stdio: ["ignore", "pipe", "pipe"],
25
- env: { ...process.env, GIT_DIR: undefined, GIT_WORK_TREE: undefined, GIT_COMMON_DIR: undefined },
26
- }).trim();
27
- }
28
- function gitFile(file, args) {
29
- return execFileSync("git", ["config", "--file", file, ...args], {
30
- encoding: "utf8", stdio: ["ignore", "pipe", "pipe"],
31
- env: { ...process.env, GIT_DIR: undefined, GIT_WORK_TREE: undefined, GIT_COMMON_DIR: undefined },
32
- }).trim();
33
- }
34
- function statusOf(error) {
35
- return typeof error === "object" && error !== null && "status" in error
36
- ? error.status
37
- : undefined;
38
- }
39
- function tryGetAll(file, key) {
40
- if (!existsSync(file))
41
- return [];
42
- try {
43
- const out = gitFile(file, ["--get-all", key]);
44
- return out.length === 0 ? [] : out.split("\n");
45
- }
46
- catch (error) {
47
- // --get-all exit 1 = absent; other failures stay loud.
48
- if (statusOf(error) !== 1)
49
- throw error;
50
- return [];
51
- }
52
- }
53
- /** True only when the file exists and carries the historical package marker.
54
- * Read failures propagate — never disguised as "not owned". */
55
- function ownedHook(path) {
56
- if (!existsSync(path))
57
- return false;
58
- return readFileSync(path, "utf8").includes(HOOK_MARKER);
59
- }
60
- /** Escape a hooksPath value for git config --unset value-pattern (POSIX ERE). */
61
- function escapeGitConfigValueRegex(value) {
62
- return value.replace(/[\\^$.*+?()[\]{}|]/g, "\\$&");
63
- }
64
- /**
65
- * Remove only package-owned core.hooksPath values; keep every foreign value.
66
- * --unset without a value-pattern exits 5 for both "absent" and "multi-value",
67
- * so multi-valued keys must be addressed per matching value.
68
- */
69
- function unsetOwnedHooksPath(file) {
70
- const owned = [];
71
- for (const value of tryGetAll(file, "core.hooksPath")) {
72
- if (!ownedHook(resolve(value, HOOK_FILE)))
73
- continue;
74
- try {
75
- // --unset-all + exact value-pattern drops every duplicate owned copy; foreign stays.
76
- gitFile(file, [
77
- "--unset-all",
78
- "core.hooksPath",
79
- `^${escapeGitConfigValueRegex(value)}$`,
80
- ]);
81
- }
82
- catch (error) {
83
- // 5 = this specific value already absent (not multi-value ambiguity).
84
- if (statusOf(error) !== 5)
85
- throw error;
86
- }
87
- owned.push(value);
88
- }
89
- return owned;
90
- }
91
- /** Delete only the package-owned hook file; rmdir solely when empty. */
92
- function rmOwnedDir(dir) {
93
- const hookPath = resolve(dir, HOOK_FILE);
94
- if (!ownedHook(hookPath))
95
- return;
96
- rmSync(hookPath, { force: true });
97
- if (existsSync(dir) && readdirSync(dir).length === 0)
98
- rmdirSync(dir);
99
- }
100
- function linkedGitDirs(commonDir) {
101
- const root = resolve(commonDir, "worktrees");
102
- if (!existsSync(root))
103
- return [];
104
- // Enumeration/lstat failures propagate — never skip a linked admin dir silently.
105
- // lstat does not follow: symlink entries are not directories and stay out of range.
106
- return readdirSync(root)
107
- .map((name) => resolve(root, name))
108
- .filter((dir) => lstatSync(dir).isDirectory());
109
- }
110
- /**
111
- * ADR 0070 §4 — private one-shot uninstall on arm.
112
- * Range: current repo + enumerable worktree admin dirs. Owned hooksPath/files only.
113
- * Never rolls back extensions.worktreeConfig / migrated bare|worktree / foreign hooksPath.
114
- */
115
- function uninstallPackageWorkerHooks(cwd) {
116
- let inside;
117
- try {
118
- inside = git(cwd, ["rev-parse", "--is-inside-work-tree"]);
119
- }
120
- catch {
121
- return;
122
- }
123
- if (inside !== "true")
124
- return;
125
- const commonDir = git(cwd, ["rev-parse", "--path-format=absolute", "--git-common-dir"]);
126
- // Unset owned hooksPath before deleting the marker file (ownership check needs it).
127
- const clear = (configFile) => {
128
- for (const hooks of unsetOwnedHooksPath(configFile))
129
- rmOwnedDir(hooks);
130
- };
131
- clear(resolve(commonDir, "config"));
132
- clear(resolve(commonDir, "config.worktree"));
133
- rmOwnedDir(resolve(commonDir, HOOKS_DIR));
134
- const legacy = resolve(commonDir, "hooks", HOOK_FILE);
135
- if (ownedHook(legacy))
136
- rmSync(legacy, { force: true });
137
- for (const gitDir of linkedGitDirs(commonDir)) {
138
- clear(resolve(gitDir, "config.worktree"));
139
- rmOwnedDir(resolve(gitDir, HOOKS_DIR));
140
- }
141
- }
142
- function isRecord(value) {
143
- return typeof value === "object" && value !== null && !Array.isArray(value);
144
- }
145
- function unfinishedReasonPresent(details) {
146
- if (typeof details !== "object" || details === null)
147
- return false;
148
- const reason = details.reason;
149
- return typeof reason === "string" && reason.trim().length > 0;
150
- }
151
- function readGateState(session) {
152
- let baseline;
153
- let reminded = false;
154
- let prefixReminded = false;
155
- for (const entry of session.getEntries()) {
156
- if (entry.type !== "custom")
157
- continue;
158
- if (entry.customType === WORKER_COMMIT_BASELINE_ENTRY_TYPE) {
159
- const data = entry.data;
160
- if (isRecord(data) && (data.head === null || typeof data.head === "string")) {
161
- baseline = data.head;
162
- }
163
- }
164
- else if (entry.customType === WORKER_COMMIT_REMINDER_BOUNCE_ENTRY_TYPE) {
165
- reminded = true;
166
- }
167
- else if (entry.customType === WORKER_PREFIX_REMINDER_BOUNCE_ENTRY_TYPE) {
168
- prefixReminded = true;
169
- }
170
- }
171
- return { baseline, reminded, prefixReminded };
172
- }
173
- function isAncestor(cwd, ancestor, descendant) {
174
- try {
175
- git(cwd, ["merge-base", "--is-ancestor", ancestor, descendant]);
176
- return true;
177
- }
178
- catch (error) {
179
- if (statusOf(error) === 1)
180
- return false;
181
- throw error;
182
- }
183
- }
184
- /**
185
- * Reliable window (ADR 0070). null = unreliable tip-SHA baseline; [] = empty.
186
- * Structured git-log fields only — never parse a shell command string.
187
- */
188
- function reliableWindow(cwd, baseline, head) {
189
- if (baseline !== null && !isAncestor(cwd, baseline, head))
190
- return null;
191
- const range = baseline === null ? head : `${baseline}..${head}`;
192
- const raw = git(cwd, ["log", "--format=%P%x1e%s", range]);
193
- if (raw.length === 0)
194
- return [];
195
- return raw.split("\n").flatMap((line) => {
196
- const sep = line.indexOf("\x1e");
197
- if (sep < 0)
198
- return [];
199
- return [{
200
- subject: line.slice(sep + 1),
201
- merge: line.slice(0, sep).trim().includes(" "),
202
- }];
203
- });
204
- }
205
- export function createWorkerSubmissionGate(options = {}) {
206
- let baseline;
207
- let root;
208
- let reminded = false;
209
- let prefixReminded = false;
210
- let unfinishedReasonBounces = 0;
211
- let record;
212
- /** Parent session file retained so every gate sitian write path-derives the same ledger home. */
213
- let sessionParent;
214
- const explicitHome = typeof options.home === "string" && options.home.length > 0 ? options.home : undefined;
215
- const head = (cwd) => {
216
- try {
217
- return git(cwd, ["rev-parse", "HEAD"]);
218
- }
219
- catch {
220
- git(cwd, ["rev-parse", "--git-dir"]); // surface real git failures
221
- return null;
222
- }
223
- };
224
- const gateSitian = (cwd, payload) => {
225
- sitianReport({
226
- level: "event",
227
- kind: "gate",
228
- cwd,
229
- ...(sessionParent === undefined ? {} : { sessionParent }),
230
- ...(explicitHome === undefined ? {} : { home: explicitHome }),
231
- payload,
232
- source: "worker-submission-gates",
233
- });
234
- };
235
- return {
236
- arm(cwd, parent) {
237
- uninstallPackageWorkerHooks(cwd);
238
- root = cwd;
239
- sessionParent = parent?.getSessionFile();
240
- record = createRecordSession({
241
- cwd,
242
- kind: WORKER_SUBMISSION_GATE_RECORD_KIND,
243
- ...(parent === undefined ? {} : { parent }),
244
- });
245
- const prior = readGateState(record);
246
- if (prior.baseline !== undefined) {
247
- baseline = prior.baseline;
248
- reminded = prior.reminded;
249
- prefixReminded = prior.prefixReminded;
250
- return;
251
- }
252
- baseline = head(cwd);
253
- reminded = false;
254
- prefixReminded = false;
255
- record.appendCustomEntry(WORKER_COMMIT_BASELINE_ENTRY_TYPE, {
256
- version: 1,
257
- head: baseline,
258
- });
259
- gateSitian(cwd, {
260
- type: WORKER_COMMIT_BASELINE_ENTRY_TYPE,
261
- version: 1,
262
- head: baseline,
263
- });
264
- },
265
- assertAcceptable(status, details) {
266
- if (status === "unfinished" && !unfinishedReasonPresent(details)) {
267
- if (unfinishedReasonBounces < UNFINISHED_REASON_BOUNCE_LIMIT) {
268
- unfinishedReasonBounces += 1;
269
- throw new WorkerUnfinishedReasonReminderError();
270
- }
271
- }
272
- if (baseline === undefined || root === undefined || !WORKER_DONE_STATUSES.has(status))
273
- return;
274
- const now = head(root);
275
- const headMoved = now !== null && (baseline === null || now !== baseline);
276
- // Gate ① — forgetfulness reminder (ADR 0066; behavior unchanged).
277
- if (!headMoved && !reminded) {
278
- reminded = true;
279
- record?.appendCustomEntry(WORKER_COMMIT_REMINDER_BOUNCE_ENTRY_TYPE, { version: 1 });
280
- gateSitian(root, {
281
- type: WORKER_COMMIT_REMINDER_BOUNCE_ENTRY_TYPE,
282
- version: 1,
283
- });
284
- throw new WorkerCommitReminderError();
285
- }
286
- reminded = true;
287
- // Gate ② — open platform-prefix soft reminder (ADR 0070).
288
- if (prefixReminded || now === null)
289
- return;
290
- const window = reliableWindow(root, baseline, now);
291
- if (window === null ||
292
- window.length === 0 ||
293
- !window.some((c) => !c.merge && !PLATFORM_PREFIX.test(c.subject))) {
294
- return;
295
- }
296
- prefixReminded = true;
297
- record?.appendCustomEntry(WORKER_PREFIX_REMINDER_BOUNCE_ENTRY_TYPE, { version: 1 });
298
- gateSitian(root, {
299
- type: WORKER_PREFIX_REMINDER_BOUNCE_ENTRY_TYPE,
300
- version: 1,
301
- });
302
- throw new WorkerPrefixReminderError();
303
- },
304
- };
305
- }
@@ -1,140 +0,0 @@
1
- import { COLLECTOR_HOST } from "./collector-config.ts";
2
- import type { CollectorClock, CollectorEvidenceRecord, CollectorSnapshot } from "./collector-evidence.ts";
3
- import type { CollectorLedger, CollectorRequestAttempt } from "./collector-ledger.ts";
4
- import {
5
- enrichCollectorFindings,
6
- extractCollectorEvidenceIdentityGroups,
7
- extractCollectorUnfinishedReasons,
8
- type ExtractedCollectorIdentityGroup,
9
- } from "./collector-identity.ts";
10
- import {
11
- validateAcceptedCollectorReceipt,
12
- type CollectorEvidenceRecord as ReceiptEvidenceRecord,
13
- type CollectorReceipt as PackageCollectorReceipt,
14
- type CollectorSubmissionProjection,
15
- } from "./package-contracts/collector-output.ts";
16
-
17
- export { validateAcceptedCollectorReceipt };
18
- export type { CollectorSubmissionProjection };
19
-
20
- /**
21
- * #641 chain① receipt-local evidence projection: machine identity, integrity
22
- * digest and resolvable pointer fields only. Bodies/raw stay in the volume
23
- * (observe details + GitHub pointer); they are never transcribed into the receipt.
24
- */
25
- export type CollectorReceiptEvidenceRecord = ReceiptEvidenceRecord;
26
-
27
- /**
28
- * #676 C: single authority for receipt shape is package-contracts/collector-output.
29
- * Production builder always emits the full projection object and concrete prState;
30
- * package leaf keeps those optional so old volumes stay readable.
31
- */
32
- export type CollectorReceipt = PackageCollectorReceipt & {
33
- prState: string;
34
- groups: ExtractedCollectorIdentityGroup[];
35
- submissionProjection: CollectorSubmissionProjection;
36
- requestAttempts: CollectorRequestAttempt[];
37
- snapshots: CollectorSnapshot[];
38
- evidenceRecords: CollectorReceiptEvidenceRecord[];
39
- };
40
-
41
- function fail(message: string): never { throw new Error(message); }
42
-
43
- /** Runtime output assembles findings pointers from the model submission into the typed receipt. */
44
- export function buildCollectorReceipt(
45
- ledger: CollectorLedger,
46
- candidateRaw: unknown,
47
- clock?: CollectorClock,
48
- ): CollectorReceipt {
49
- ledger.assertNotFatal();
50
- if (ledger.unresolvedTransportFailure) fail("Collector cannot output while a transport failure is unrecovered");
51
- if (ledger.latestCompleteSnapshotId === undefined) fail("Collector output requires a complete final snapshot");
52
- if (ledger.activationTime === undefined || ledger.deadlineTime === undefined) fail("Collector output requires activation timeline");
53
- if (ledger.config.prNumber === undefined) {
54
- fail("Collector output requires a bound PR target; call ak_collector_bind_target first or pass --pr");
55
- }
56
-
57
- if (clock !== undefined) ledger.assertOutputObservationLaw(clock);
58
- else if (ledger.observedGeneration !== ledger.mutationGeneration ||
59
- (ledger.finalObservationRequired && !ledger.finalObservationCompleted)) {
60
- fail("Collector output requires a complete observe after the latest request/wait mutation");
61
- }
62
-
63
- const finalSnapshot = ledger.getSnapshot(ledger.latestCompleteSnapshotId);
64
- if (finalSnapshot === undefined || !finalSnapshot.complete) fail("Collector final snapshot is incomplete");
65
- // #676 D6: closed/merged still deliver collected materials; status is a fact on the receipt.
66
-
67
- const evidenceRecords: CollectorEvidenceRecord[] = [...ledger.allEvidence()];
68
- const snapshots = [...ledger.allSnapshots()];
69
- const evidenceIndex = new Map(evidenceRecords.map((record) => [record.evidenceId, record]));
70
- const snapshotIndex = new Map(snapshots.map((snapshot) => [snapshot.snapshotId, snapshot]));
71
- if (evidenceIndex.size !== evidenceRecords.length) fail("Collector receipt evidenceId collision");
72
- if (snapshotIndex.size !== snapshots.length) fail("Collector receipt snapshotId collision");
73
- for (const id of evidenceIndex.keys()) if (snapshotIndex.has(id)) fail(`Collector receipt id "${id}" is ambiguous`);
74
- if (!snapshotIndex.has(finalSnapshot.snapshotId)) fail("Collector receipt lacks final snapshot");
75
- for (const snapshot of snapshots) {
76
- for (const id of snapshot.evidenceIds) if (!evidenceIndex.has(id)) fail(`Collector snapshot ref "${id}" does not resolve`);
77
- }
78
-
79
- const groups = extractCollectorEvidenceIdentityGroups(evidenceRecords, finalSnapshot.headOid);
80
- // #641 chain①: the collector LLM submits findings as pointer refs; the runtime
81
- // enriches each with the machine locator from the same stored record.
82
- const findingsProjection = enrichCollectorFindings({
83
- candidate: candidateRaw,
84
- records: evidenceRecords,
85
- groups,
86
- targetHead: finalSnapshot.headOid,
87
- repository: ledger.config.repository.canonical,
88
- prNumber: ledger.config.prNumber,
89
- });
90
- for (const group of groups) {
91
- for (const material of group.materials) {
92
- if (material.evidenceId === undefined || !evidenceIndex.has(material.evidenceId)) fail("Collector material lacks a receipt-local evidence ref");
93
- }
94
- for (const finding of group.findings) {
95
- if (finding.source.evidenceId === undefined || !evidenceIndex.has(finding.source.evidenceId)) fail("Collector finding lacks a receipt-local evidence ref");
96
- }
97
- }
98
- const unfinished = extractCollectorUnfinishedReasons(candidateRaw);
99
- const submissionProjection: CollectorSubmissionProjection = {
100
- findingsSource: findingsProjection.findingsSource,
101
- findingsProjectedCount: findingsProjection.findingsProjectedCount,
102
- findingsUnprojected: findingsProjection.findingsUnprojected,
103
- unfinishedReasonsSource: unfinished.source,
104
- unfinishedReasonsProjectedCount: unfinished.reasons?.length ?? 0,
105
- unfinishedReasonsUnprojected: unfinished.unprojected,
106
- };
107
-
108
- return {
109
- host: COLLECTOR_HOST,
110
- repository: ledger.config.repository.canonical,
111
- prNumber: ledger.config.prNumber,
112
- prState: finalSnapshot.prState,
113
- manifestDigest: ledger.config.manifest.digest,
114
- activationTime: ledger.activationTime.toISOString(),
115
- deadlineTime: ledger.deadlineTime.toISOString(),
116
- finalObservationTime: finalSnapshot.completedAt ?? finalSnapshot.observedAt,
117
- finalSnapshotId: finalSnapshot.snapshotId,
118
- targetHead: finalSnapshot.headOid,
119
- groups,
120
- ...(unfinished.reasons === undefined ? {} : { unfinishedReasons: unfinished.reasons }),
121
- submissionProjection,
122
- requestAttempts: [...ledger.requestAttempts()],
123
- snapshots,
124
- evidenceRecords: evidenceRecords.map(toReceiptEvidenceRecord),
125
- };
126
- }
127
-
128
- function toReceiptEvidenceRecord(record: CollectorEvidenceRecord): CollectorReceiptEvidenceRecord {
129
- return {
130
- evidenceId: record.evidenceId,
131
- kind: record.kind,
132
- versionId: record.versionId,
133
- contentDigest: record.contentDigest,
134
- firstObservedAt: record.firstObservedAt,
135
- ...(record.githubId === undefined ? {} : { githubId: record.githubId }),
136
- ...(record.authorLogin === undefined ? {} : { authorLogin: record.authorLogin }),
137
- ...(record.htmlUrl === undefined ? {} : { htmlUrl: record.htmlUrl }),
138
- ...(record.authoritativeTime === undefined ? {} : { authoritativeTime: record.authoritativeTime }),
139
- };
140
- }
@@ -1,18 +0,0 @@
1
- /**
2
- * Bound diagnostic text: rolling tail only, not a dossier/transcript face.
3
- * One authority for host stderr retention (headless + ACP).
4
- */
5
-
6
- /** Fixed cap for retained diagnostic tails. */
7
- export const DIAGNOSTIC_TAIL_CAP = 16 * 1024;
8
-
9
- const CLIP_MARK = "…[stderr clipped]\n";
10
-
11
- /**
12
- * Retain at most DIAGNOSTIC_TAIL_CAP characters, keeping the newest bytes
13
- * when over budget. Clip mark is included inside the fixed cap.
14
- */
15
- export function retainDiagnosticTail(text: string): string {
16
- if (text.length <= DIAGNOSTIC_TAIL_CAP) return text;
17
- return CLIP_MARK + text.slice(text.length - (DIAGNOSTIC_TAIL_CAP - CLIP_MARK.length));
18
- }
@@ -1,135 +0,0 @@
1
- import type { HostContext } from "./host-contracts.ts";
2
- import { isReviewerPromptText, type ReviewerPromptText } from "./reviewer-prompt-identity.ts";
3
- import type { AcceptedReviewerExecution } from "./reviewer-dispatch.ts";
4
- import type { ReviewerTargetSnapshot, ReviewerWorkspaceDisposition, ReviewerFailureClassification, ReviewerUsage } from "./reviewer-execution-ledger.ts";
5
- import { executeReviewerChild } from "./reviewer-child-executor.ts";
6
- import { createReviewerWorkspaceOwner, type ReviewerWorkspaceFaultPoint } from "./reviewer-workspace.ts";
7
- import { normalizeReviewerFailureDiagnostic } from "./reviewer-failure-diagnostic.ts";
8
-
9
- type ReviewerLegRunResultCommon = Readonly<{ target: ReviewerTargetSnapshot; prompt: ReviewerPromptText; workspaceDisposition: ReviewerWorkspaceDisposition }>;
10
- export type ReviewerSuccessfulLegRunResult = ReviewerLegRunResultCommon & Readonly<{ status: "successful"; report: unknown; usage: ReviewerUsage; failure?: never }>;
11
- export type ReviewerFailedLegRunResult = ReviewerLegRunResultCommon & Readonly<{ status: "failed"; failure: ReviewerFailureClassification; diagnostic: string; cause?: unknown; report?: never; usage?: never }>;
12
- export type ReviewerLegRunResult = ReviewerSuccessfulLegRunResult | ReviewerFailedLegRunResult;
13
- type Envelope<L> = Readonly<{ identity: string; target: ReviewerTargetSnapshot; legs: Readonly<L> }>;
14
- export type ReviewerDispatchRunResult = Envelope<{ standards: ReviewerLegRunResult; spec?: never }> | Envelope<{ standards: ReviewerLegRunResult; spec: ReviewerLegRunResult }>;
15
- export type ReviewerSuccessfulDispatchRunResult = Envelope<{ standards: ReviewerSuccessfulLegRunResult; spec?: never }> | Envelope<{ standards: ReviewerSuccessfulLegRunResult; spec: ReviewerSuccessfulLegRunResult }>;
16
- function reviewerDispatchFailureMessage(outcome: ReviewerDispatchRunResult): string {
17
- const diagnostics = [...new Set(
18
- Object.values(outcome.legs)
19
- .filter((leg): leg is ReviewerFailedLegRunResult => leg?.status === "failed")
20
- .map((leg) => leg.diagnostic.trim())
21
- .filter((diagnostic) => diagnostic.length > 0),
22
- )];
23
- if (diagnostics.length === 0) return "Reviewer dispatch execution failed";
24
- return diagnostics.length === 1 ? diagnostics[0]! : diagnostics.join("; ");
25
- }
26
- export class ReviewerDispatchExecutionError extends Error {
27
- constructor(readonly outcome: ReviewerDispatchRunResult) {
28
- super(reviewerDispatchFailureMessage(outcome));
29
- this.name = "ReviewerDispatchExecutionError";
30
- }
31
- }
32
- export type ReviewerDispatchRunOptions = Readonly<{
33
- context: HostContext;
34
- signal?: AbortSignal;
35
- /**
36
- * Request-scoped RoleHost flag reader (#818).
37
- * Forwards to axis sub-session so envelope legs arm engine from request.engine,
38
- * not ambient process.env (same resolveEngineName gate as parent registration).
39
- */
40
- getFlag?: (name: string) => boolean | string | undefined;
41
- }>;
42
- export type ReviewerAgentRunner = { run(dispatch: AcceptedReviewerExecution, options: ReviewerDispatchRunOptions): Promise<ReviewerSuccessfulDispatchRunResult>; shutdown(): Promise<void> };
43
- export type ReviewerAgentFaultPoint = ReviewerWorkspaceFaultPoint;
44
- type Dependencies = Readonly<{
45
- fault?(operation: ReviewerAgentFaultPoint): void;
46
- /** When set, child credential/config scratch is created under this parent so cleanup proofs stay process-local. */
47
- credentialScratchParent?: string;
48
- /** Package root for optional engine method-material on legs (#378). */
49
- packageRoot?: string;
50
- }>;
51
- function classify(error: unknown, signal?: AbortSignal): ReviewerFailureClassification { if (signal?.aborted) return "cancelled"; if (typeof error === "object" && error !== null && "reviewerFailure" in error) return (error as { reviewerFailure: ReviewerFailureClassification }).reviewerFailure; return "unknown"; }
52
- function failed(error: unknown, target: ReviewerTargetSnapshot, prompt: ReviewerPromptText, signal?: AbortSignal, retained?: string): ReviewerFailedLegRunResult {
53
- const attached = typeof error === "object" && error !== null ? error as { targetSnapshot?: ReviewerTargetSnapshot; workspaceDisposition?: ReviewerWorkspaceDisposition } : {};
54
- const failure = classify(error, signal);
55
- const diagnostic = normalizeReviewerFailureDiagnostic(error, failure);
56
- return Object.freeze({
57
- status: "failed",
58
- failure,
59
- diagnostic,
60
- cause: error,
61
- target: attached.targetSnapshot ?? target,
62
- prompt,
63
- workspaceDisposition: retained === undefined ? attached.workspaceDisposition ?? "not-created" : { retained },
64
- });
65
- }
66
- export function createReviewerAgentRunner(dependencies: Dependencies = {}): ReviewerAgentRunner {
67
- const workspaceOwner = createReviewerWorkspaceOwner(dependencies.fault === undefined ? {} : { fault: dependencies.fault }); let accepted = false;
68
- return {
69
- async run(dispatch, options) {
70
- if (dispatch.recipe !== "reviewer-common-bundle-v1" || dispatch.legs.length < 1 || dispatch.legs.length > 2 || dispatch.legs[0]?.axis !== "standards" || (dispatch.legs.length === 2 && dispatch.legs[1]?.axis !== "spec")) throw new Error("Invalid accepted Reviewer dispatch cardinality or axes");
71
- if (accepted) throw new Error("Reviewer runner accepts exactly one dispatch"); accepted = true;
72
- for (const leg of dispatch.legs) if (!isReviewerPromptText(leg.prompt)) throw new Error("Accepted Reviewer prompt evidence mismatch");
73
- let batch;
74
- try { batch = await workspaceOwner.prepare(dispatch.targetSnapshot, dispatch.legs.map(l => l.axis), options.signal); }
75
- catch (error) {
76
- const prepared = typeof error === "object" && error !== null && "preparedWorkspaces" in error ? (error as { preparedWorkspaces?: readonly { axis: string; path: string }[] }).preparedWorkspaces ?? [] : [];
77
- const failedIndex = prepared.length;
78
- const legs = Object.fromEntries(dispatch.legs.map((leg, index) => [leg.axis, failed(error, dispatch.targetSnapshot, leg.prompt, options.signal, index < failedIndex ? prepared[index]!.path : undefined)]));
79
- // Siblings not yet attempted have no workspace; do not borrow the failed leg's retained path.
80
- for (let index = failedIndex + 1; index < dispatch.legs.length; index += 1) { const axis = dispatch.legs[index]!.axis; legs[axis] = Object.freeze({ ...legs[axis]!, workspaceDisposition: "not-created" }); }
81
- const target = Object.values(legs)[0]!.target; throw new ReviewerDispatchExecutionError(Object.freeze({ identity: dispatch.identity, target, legs: Object.freeze(legs) }) as ReviewerDispatchRunResult);
82
- }
83
- const settled = await Promise.allSettled(batch.workspaces.map(async workspace => {
84
- const leg = dispatch.legs.find(candidate => candidate.axis === workspace.axis)!;
85
- try {
86
- const child = await executeReviewerChild(workspace.path, leg, options.context, {
87
- ...(options.signal === undefined ? {} : { signal: options.signal }),
88
- ...(dependencies.credentialScratchParent === undefined
89
- ? {}
90
- : { credentialScratchParent: dependencies.credentialScratchParent }),
91
- ...(dependencies.packageRoot === undefined
92
- ? {}
93
- : { packageRoot: dependencies.packageRoot }),
94
- ...(options.getFlag === undefined ? {} : { getFlag: options.getFlag }),
95
- });
96
- const disposition = await workspaceOwner.dispose(workspace);
97
- return [leg.axis, Object.freeze({ status: "successful" as const, report: child.report, usage: child.usage, target: batch.target, prompt: child.prompt, workspaceDisposition: disposition })] as const;
98
- } catch (error) {
99
- // Failed legs retain their workspace for the durable failure evidence and caller cleanup.
100
- return [leg.axis, failed(error, batch.target, leg.prompt, options.signal, workspace.path)] as const;
101
- }
102
- }));
103
- const pairs = settled.map(item => item.status === "fulfilled" ? item.value : (() => { throw item.reason; })());
104
- const outcome = Object.freeze({ identity: dispatch.identity, target: batch.target, legs: Object.freeze(Object.fromEntries(pairs)) }) as ReviewerDispatchRunResult;
105
- if (Object.values(outcome.legs).some(leg => leg?.status === "failed")) throw new ReviewerDispatchExecutionError(outcome);
106
- return outcome as ReviewerSuccessfulDispatchRunResult;
107
- },
108
- shutdown: () => workspaceOwner.shutdown(),
109
- };
110
- }
111
-
112
- /**
113
- * Host-level Reviewer binding: each accepted dispatch gets a fresh one-shot runner.
114
- * Auto-resume turns must not reuse the inner one-shot slot.
115
- */
116
- export function createPerDispatchReviewerAgent(dependencies: Dependencies = {}): ReviewerAgentRunner {
117
- const active = new Set<ReviewerAgentRunner>();
118
- return {
119
- async run(dispatch, options) {
120
- const runner = createReviewerAgentRunner(dependencies);
121
- active.add(runner);
122
- try {
123
- return await runner.run(dispatch, options);
124
- } finally {
125
- active.delete(runner);
126
- await runner.shutdown();
127
- }
128
- },
129
- async shutdown() {
130
- const runners = [...active];
131
- active.clear();
132
- await Promise.all(runners.map((runner) => runner.shutdown()));
133
- },
134
- };
135
- }