@akagilnc/pi-workflow-roles 0.1.4802 → 0.1.4874

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 (142) hide show
  1. package/dist/acp-host/production-host.js +19434 -18218
  2. package/dist/analyst-book-key.js +63 -0
  3. package/dist/analyst-cohort.js +167 -0
  4. package/dist/analyst-entry.js +320 -0
  5. package/dist/analyst-index.js +247 -0
  6. package/dist/analyst-ledger.js +561 -0
  7. package/dist/analyst-median.js +16 -0
  8. package/dist/analyst-metric-families/acceptance-success-rework.js +249 -0
  9. package/dist/analyst-metric-families/b2-frame-buckets-actions.js +189 -0
  10. package/dist/analyst-metric-families/gate-cycles.js +77 -0
  11. package/dist/analyst-metric-families/leg-wall-clock.js +56 -0
  12. package/dist/analyst-metric-families/round-timeline.js +126 -0
  13. package/dist/analyst-metric-families.js +23 -0
  14. package/dist/analyst-metric-family.js +11 -0
  15. package/dist/analyst-model-groups.js +135 -0
  16. package/dist/analyst-page.js +182 -0
  17. package/dist/atomic-write.js +23 -0
  18. package/dist/auditor-soul.js +1 -1
  19. package/dist/countersign-contracts.js +0 -2
  20. package/dist/diarist-contracts.js +0 -1
  21. package/dist/doctor-contracts.js +2 -2
  22. package/dist/gatekeeper-role.js +15 -16
  23. package/dist/gleaner-left-contracts.js +0 -2
  24. package/dist/headless-host/production-host.js +16967 -15749
  25. package/dist/host-contracts.js +0 -4
  26. package/dist/inspector-contracts.js +0 -2
  27. package/dist/institutional-resolution.js +4 -2
  28. package/dist/merger-contracts.js +0 -2
  29. package/dist/migrate-book-topology.js +3908 -3089
  30. package/dist/navigator-public-session.js +4 -3
  31. package/dist/notary-contracts.js +0 -2
  32. package/dist/package-contracts/auditor-output.js +0 -1
  33. package/dist/package-contracts/collector-output.js +0 -2
  34. package/dist/package-contracts/fixer-output.js +0 -2
  35. package/dist/package-contracts/gatekeeper-output.js +0 -2
  36. package/dist/package-contracts/judge-output.js +0 -2
  37. package/dist/package-contracts/navigator-output.js +0 -2
  38. package/dist/package-contracts/reviewer-output.js +0 -2
  39. package/dist/package-contracts/terminating-tools.js +32 -92
  40. package/dist/package-contracts/worker-output.js +0 -4
  41. package/dist/packaged-role-registry.js +518 -36
  42. package/dist/pi/role-turn-host.js +2 -1
  43. package/dist/public-cli/analyst-run.js +185 -0
  44. package/dist/public-cli/cli.js +885 -0
  45. package/dist/public-cli/config.js +12 -9
  46. package/dist/public-cli/countersign-run.js +4 -311
  47. package/dist/public-cli/instruction-seat-run.js +628 -158
  48. package/dist/public-cli/invocation.js +806 -1550
  49. package/dist/public-cli/main.js +6962 -9882
  50. package/dist/public-cli/option-definitions.js +51 -99
  51. package/dist/public-cli/post-admission.js +30 -2
  52. package/dist/public-cli/run-lifecycle.js +234 -353
  53. package/dist/public-cli/seat-ticket-binding.js +6 -0
  54. package/dist/public-cli/settlement.js +261 -675
  55. package/dist/public-cli/turn-request.js +76 -0
  56. package/dist/public-role-summons.js +38 -112
  57. package/dist/role-activation-flags.js +23 -45
  58. package/dist/secretariat-contracts.js +0 -2
  59. package/dist/session-identity.js +17 -8
  60. package/dist/session-opening-materials.js +3 -2
  61. package/extensions/role-runtime.ts +6 -80
  62. package/package.json +1 -1
  63. package/src/acp-host/role-turn-host.ts +4 -1
  64. package/src/analyst-metric-families/acceptance-success-rework.ts +3 -2
  65. package/src/auditor-role.ts +1 -2
  66. package/src/auditor-soul.ts +1 -1
  67. package/src/collector-role.ts +2 -2
  68. package/src/countersign-contracts.ts +0 -1
  69. package/src/countersign-role.ts +1 -1
  70. package/src/diarist-contracts.ts +0 -1
  71. package/src/diarist-role.ts +0 -1
  72. package/src/doctor-auditor.ts +1 -2
  73. package/src/doctor-contracts.ts +1 -1
  74. package/src/doctor-role.ts +3 -2
  75. package/src/external-host-turn-loop.ts +1 -1
  76. package/src/factory-board.ts +10 -7
  77. package/src/gatekeeper-role.ts +16 -10
  78. package/src/gleaner-left-contracts.ts +0 -1
  79. package/src/gleaner-left-role.ts +0 -1
  80. package/src/headless-host/role-turn-host.ts +7 -1
  81. package/src/host-contracts.ts +10 -6
  82. package/src/inspector-contracts.ts +0 -1
  83. package/src/inspector-role.ts +0 -2
  84. package/src/institutional-resolution.ts +6 -4
  85. package/src/judge-role.ts +3 -3
  86. package/src/merger-contracts.ts +0 -1
  87. package/src/merger-role.ts +2 -2
  88. package/src/navigator-public-session.ts +7 -6
  89. package/src/navigator-work-context.ts +6 -8
  90. package/src/notary-contracts.ts +0 -1
  91. package/src/notary-role.ts +2 -3
  92. package/src/package-contracts/auditor-output.ts +0 -1
  93. package/src/package-contracts/collector-output.ts +0 -1
  94. package/src/package-contracts/fixer-output.ts +0 -1
  95. package/src/package-contracts/gatekeeper-output.ts +0 -1
  96. package/src/package-contracts/judge-output.ts +0 -1
  97. package/src/package-contracts/navigator-output.ts +0 -1
  98. package/src/package-contracts/reviewer-output.ts +0 -1
  99. package/src/package-contracts/terminating-tools.ts +27 -99
  100. package/src/package-contracts/worker-output.ts +0 -2
  101. package/src/packaged-role-registry.ts +604 -35
  102. package/src/pi/role-turn-host.ts +2 -1
  103. package/src/public-cli/cli.ts +64 -259
  104. package/src/public-cli/config.ts +18 -10
  105. package/src/public-cli/countersign-run.ts +14 -449
  106. package/src/public-cli/instruction-seat-run.ts +758 -277
  107. package/src/public-cli/invocation.ts +1097 -2051
  108. package/src/public-cli/option-definitions.ts +62 -127
  109. package/src/public-cli/post-admission.ts +47 -2
  110. package/src/public-cli/run-lifecycle.ts +303 -613
  111. package/src/public-cli/seat-ticket-binding.ts +6 -0
  112. package/src/public-cli/settlement.ts +399 -1185
  113. package/src/public-cli/turn-request.ts +92 -1
  114. package/src/public-role-summons.ts +44 -128
  115. package/src/reviewer-role.ts +3 -2
  116. package/src/role-activation-flags.ts +20 -41
  117. package/src/role-runtime-dependencies.ts +25 -26
  118. package/src/role-runtime.ts +121 -232
  119. package/src/secretariat-contracts.ts +0 -1
  120. package/src/secretariat-role.ts +0 -2
  121. package/src/session-identity.ts +23 -8
  122. package/src/session-opening-materials.ts +2 -1
  123. package/src/worker-role.ts +3 -4
  124. package/dist/doctor-auditor.js +0 -25
  125. package/dist/public-cli/diarist-run.js +0 -130
  126. package/dist/public-cli/doctor-run.js +0 -87
  127. package/dist/public-cli/inspector-run.js +0 -151
  128. package/dist/public-cli/judge-run.js +0 -114
  129. package/dist/public-cli/notary-run.js +0 -174
  130. package/dist/public-cli/reviewer-run.js +0 -339
  131. package/src/public-cli/coder-run.ts +0 -255
  132. package/src/public-cli/collector-run.ts +0 -189
  133. package/src/public-cli/diarist-run.ts +0 -233
  134. package/src/public-cli/doctor-run.ts +0 -167
  135. package/src/public-cli/fixer-run.ts +0 -265
  136. package/src/public-cli/gleaner-left-run.ts +0 -167
  137. package/src/public-cli/inspector-run.ts +0 -261
  138. package/src/public-cli/judge-run.ts +0 -196
  139. package/src/public-cli/merger-run.ts +0 -294
  140. package/src/public-cli/notary-run.ts +0 -279
  141. package/src/public-cli/reviewer-run.ts +0 -480
  142. package/src/public-cli/secretariat-run.ts +0 -265
@@ -17,6 +17,7 @@ import { parseCollectorRepository } from "../collector-config.js";
17
17
  import { interpretDurableCourtTicketNumbers, sameCourtTicketNumbers, } from "../diarist-contracts.js";
18
18
  import { rewriteAdmittedRoleRunPage, rewriteRunDirectoryPathValue, } from "../role-run-relocation.js";
19
19
  import { appendEngineSessionMaterial, engineSessionMaterialFromOptions, pickEngineAxis, } from "../package-resources/engine-material.js";
20
+ import { packagedResumeSourcePath, packagedRoleMetadata, } from "../packaged-role-registry.js";
20
21
  import { recordEffectiveInvocationModel, requireAuthorityRef, isReviewerLens, } from "./invocation.js";
21
22
  /** Providers eligible for v1 typed-429 resume (Codex / xAI only).
22
23
  * @deprecated v1 429-only gate removed by #416 (owner 2026-08-22: "根本不要有限制"). Kept for compatibility; do not use for new branching.
@@ -154,22 +155,8 @@ async function readRoleRunStateDisk(runDirectory) {
154
155
  if (typeof record.runId !== "string" || record.runId.trim() === "") {
155
156
  return undefined;
156
157
  }
157
- if (record.role !== "judge" &&
158
- record.role !== "coder" &&
159
- record.role !== "fixer" &&
160
- record.role !== "collector" &&
161
- record.role !== "doctor" &&
162
- record.role !== "reviewer" &&
163
- record.role !== "merger" &&
164
- record.role !== "notary" &&
165
- record.role !== "countersign" &&
166
- record.role !== "gleaner-left" &&
167
- record.role !== "inspector" &&
168
- record.role !== "gatekeeper" &&
169
- record.role !== "navigator" &&
170
- record.role !== "auditor" &&
171
- record.role !== "diarist" &&
172
- record.role !== "secretariat") {
158
+ const role = typeof record.role === "string" ? packagedRoleMetadata(record.role)?.role : undefined;
159
+ if (role === undefined) {
173
160
  return undefined;
174
161
  }
175
162
  if (record.state !== "admitted" &&
@@ -215,7 +202,7 @@ async function readRoleRunStateDisk(runDirectory) {
215
202
  const currentCourt = parseCurrentCourtState(record.currentCourt);
216
203
  return {
217
204
  runId: record.runId,
218
- role: record.role,
205
+ role,
219
206
  state: record.state,
220
207
  bookKey: record.bookKey,
221
208
  projectRoot: record.projectRoot,
@@ -299,6 +286,10 @@ export async function readRoleRunIdentity(runDirectory) {
299
286
  }
300
287
  export async function markRunAdmitted(admitted, authority) {
301
288
  const { sessionDirectory, sessionFile } = authority.decode(admitted.principal);
289
+ const record = packagedRoleMetadata(admitted.role);
290
+ const workerPhase = record !== undefined && "worker" in record && record.worker === true && "phase" in admitted
291
+ ? admitted.phase
292
+ : undefined;
302
293
  await writeRoleRunState(admitted.runDirectory, {
303
294
  runId: admitted.runId,
304
295
  role: admitted.role,
@@ -308,9 +299,7 @@ export async function markRunAdmitted(admitted, authority) {
308
299
  sessionDirectory,
309
300
  sessionFile,
310
301
  admittedRequestPath: admitted.admittedRequestPath,
311
- ...(admitted.role === "coder" || admitted.role === "fixer"
312
- ? { phase: admitted.phase }
313
- : {}),
302
+ ...(workerPhase === undefined ? {} : { phase: workerPhase }),
314
303
  });
315
304
  }
316
305
  /**
@@ -818,10 +807,11 @@ async function runHasFormedSessionPrincipal(runDirectory) {
818
807
  /**
819
808
  * Locate the latest retained run for one seat under a book (#637 / #747).
820
809
  * Same walk surface as findRunDirectoryById (listBookRunDirectories). Match by
821
- * parent run path (officer / gate seats, #747 / #987). runId is UUIDv7 —
822
- * lexicographic max is latest among runs that formed a session principal. No
823
- * parallel index. Public ticket-number selection of a prior run was deleted
824
- * (#987 Result 7); callers use explicit `ak-role resume <runId>`.
810
+ * parent run path (officer / gate seats, #747 / #987). A typed ticket number
811
+ * does not select a run. runId is UUIDv7 — lexicographic max is latest among
812
+ * runs that formed a session principal. No parallel index. Public ticket-number
813
+ * selection of a prior run was deleted (#987 Result 7); callers use explicit
814
+ * `ak-role resume <runId>`.
825
815
  * Only a truly missing book directory means no history; damage/permission errors propagate.
826
816
  */
827
817
  export async function findLatestRunIdForSeatTicket(input) {
@@ -1230,9 +1220,8 @@ async function loadResumableRunRecord(home, runId, authority) {
1230
1220
  };
1231
1221
  }
1232
1222
  /**
1233
- * Base admitted projection shared by every seat loader: durable identity +
1234
- * instruction/attachments + principal + restored ticket identity + model (#633).
1235
- * Seat loaders add only their seat-specific fields on top.
1223
+ * Base admitted projection: durable identity, instruction, attachments, principal, ticket, and model.
1224
+ * Seat restore adds only that seat's fields.
1236
1225
  */
1237
1226
  function resumedBaseAdmitted(loaded) {
1238
1227
  return {
@@ -1249,7 +1238,7 @@ function resumedBaseAdmitted(loaded) {
1249
1238
  ...restoredTicketFields(loaded.admittedFields),
1250
1239
  };
1251
1240
  }
1252
- /** Loaded-run envelope projection; seat loaders add only their seat fields. */
1241
+ /** Loaded-run envelope. */
1253
1242
  function seatLoadedResult(loaded, admitted) {
1254
1243
  return {
1255
1244
  admitted,
@@ -1257,340 +1246,232 @@ function seatLoadedResult(loaded, admitted) {
1257
1246
  ...(loaded.observation === undefined ? {} : { observation: loaded.observation }),
1258
1247
  };
1259
1248
  }
1260
- /**
1261
- * Load a resumable Judge run for resume. Rejects unknown, terminal,
1262
- * non-resumable, and non-Judge IDs without replaying dispatch.
1263
- */
1264
- export async function loadResumableJudgeRun(home, runId, authority) {
1265
- const loaded = await loadResumableRunRecord(home, runId, authority);
1266
- if (loaded.run.role !== "judge") {
1267
- throw new CliUsageError(`role run ${runId} belongs to ${loaded.run.role}, not judge`);
1268
- }
1269
- const admitted = {
1270
- role: "judge",
1271
- ...resumedBaseAdmitted(loaded),
1272
- };
1273
- return seatLoadedResult(loaded, admitted);
1274
- }
1275
- /**
1276
- * Load a resumable Coder run for resume. Phase and task path are restored from
1277
- * the admitted request so continuation stays role-correct (#109).
1278
- */
1279
- export async function loadResumableCoderRun(home, runId, authority) {
1280
- const loaded = await loadResumableRunRecord(home, runId, authority);
1281
- if (loaded.run.role !== "coder") {
1282
- throw new CliUsageError(`role run ${runId} belongs to ${loaded.run.role}, not coder`);
1283
- }
1284
- const phase = loaded.admittedFields.phase ?? loaded.run.phase;
1285
- if (phase !== "plan" && phase !== "apply") {
1286
- throw new CliUsageError(`role run admitted coder phase is missing: ${runId}`);
1287
- }
1288
- const taskPath = loaded.admittedFields.taskPath;
1289
- if (taskPath === undefined) {
1290
- throw new CliUsageError(`role run admitted coder task path is missing: ${runId}`);
1291
- }
1292
- if (loaded.admittedFields.instruction.trim() === "") {
1293
- throw new CliUsageError(`role run admitted coder task is blank: ${runId}`);
1294
- }
1295
- const admitted = {
1296
- role: "coder",
1297
- phase,
1298
- ...resumedBaseAdmitted(loaded),
1299
- instructionEmpty: false,
1300
- taskPath,
1301
- };
1302
- return seatLoadedResult(loaded, admitted);
1249
+ export async function peekRoleRunRole(home, runId) {
1250
+ const runDirectory = await findRunDirectoryById(home, runId);
1251
+ if (runDirectory === undefined)
1252
+ return undefined;
1253
+ const run = await readRoleRunIdentity(runDirectory);
1254
+ return run?.role;
1303
1255
  }
1304
1256
  /**
1305
- * Load a resumable Fixer run for resume. Phase, packet, and prerequisites are
1306
- * restored from the admitted request so continuation stays role-correct (#110).
1257
+ * One resume load. The caller supplies the package run id; the disk role
1258
+ * selects the existing restore checks. The stored native host session id is
1259
+ * read on the public explicit resume seam, not from this load.
1307
1260
  */
1308
- export async function loadResumableFixerRun(home, runId, authority) {
1261
+ export async function loadResumablePublicRole(home, runId, authority) {
1309
1262
  const loaded = await loadResumableRunRecord(home, runId, authority);
1310
- if (loaded.run.role !== "fixer") {
1311
- throw new CliUsageError(`role run ${runId} belongs to ${loaded.run.role}, not fixer`);
1312
- }
1313
- const phase = loaded.admittedFields.phase ?? loaded.run.phase;
1314
- if (phase !== "plan" && phase !== "apply") {
1315
- throw new CliUsageError(`role run admitted fixer phase is missing: ${runId}`);
1316
- }
1317
- const packetPath = loaded.admittedFields.packetPath;
1318
- if (packetPath === undefined) {
1319
- throw new CliUsageError(`role run admitted fixer packet path is missing: ${runId}`);
1320
- }
1321
- if (loaded.admittedFields.instruction.trim() === "") {
1322
- throw new CliUsageError(`role run admitted fixer instruction is blank: ${runId}`);
1323
- }
1324
- const prerequisites = loaded.admittedFields.prerequisites ?? Object.freeze([]);
1325
- const admitted = {
1326
- role: "fixer",
1327
- phase,
1328
- ...resumedBaseAdmitted(loaded),
1329
- instructionEmpty: false,
1330
- packetPath,
1331
- ...(loaded.admittedFields.prerequisitesPath === undefined
1332
- ? {}
1333
- : { prerequisitesPath: loaded.admittedFields.prerequisitesPath }),
1334
- prerequisites,
1335
- };
1336
- return seatLoadedResult(loaded, admitted);
1263
+ return seatLoadedResult(loaded, admitResumedRole(loaded));
1337
1264
  }
1338
1265
  /**
1339
- * Peek the durable role of a run id without enforcing resumable state.
1340
- * Used by public resume dispatch to pick the role-correct seat and path.
1341
- */
1342
- /**
1343
- * Load a resumable Reviewer run for resume. Fixed base is restored from the
1344
- * admitted request; caller instruction remains optional provenance only.
1266
+ * One resume restore. Admission kind comes from the composition-root record;
1267
+ * seat-only required fields stay on that kind. Instruction seats share one face.
1345
1268
  */
1346
- export async function loadResumableReviewerRun(home, runId, authority) {
1347
- const loaded = await loadResumableRunRecord(home, runId, authority);
1348
- if (loaded.run.role !== "reviewer") {
1349
- throw new CliUsageError(`role run ${runId} belongs to ${loaded.run.role}, not reviewer`);
1350
- }
1351
- // Durable restore keeps run identity — never rebrand record damage as fresh --base/--lens.
1352
- const rawBase = loaded.admittedFields.baseRevision;
1353
- if (rawBase === undefined || rawBase.trim() === "") {
1354
- throw new CliUsageError(`role run admitted reviewer base revision is missing: ${runId}`);
1355
- }
1356
- if (/\s/.test(rawBase) || rawBase.startsWith("-")) {
1357
- throw new CliUsageError(`role run admitted reviewer base revision is damaged: ${runId}`);
1358
- }
1359
- const baseRevision = rawBase;
1360
- const lens = loaded.admittedFields.lens;
1361
- if (!isReviewerLens(lens)) {
1362
- throw new CliUsageError(`role run admitted reviewer lens is missing: ${runId}`);
1363
- }
1364
- const authorityRefs = Object.freeze([
1365
- ...(loaded.admittedFields.authorityRefs ?? []),
1366
- ]);
1367
- if (authorityRefs.length === 0) {
1368
- throw new CliUsageError(`role run admitted reviewer authority refs are missing: ${runId}`);
1369
- }
1370
- const admitted = {
1371
- role: "reviewer",
1372
- ...resumedBaseAdmitted(loaded),
1373
- baseRevision,
1374
- lens,
1375
- authorityRefs,
1376
- };
1377
- return seatLoadedResult(loaded, admitted);
1378
- }
1379
- /**
1380
- * Load a resumable Countersign run for resume (#599). Ticket binding and
1381
- * attachments restore from the admitted request.
1382
- */
1383
- export async function loadResumableCountersignRun(home, runId, authority) {
1384
- const loaded = await loadResumableRunRecord(home, runId, authority);
1385
- if (loaded.run.role !== "countersign") {
1386
- throw new CliUsageError(`role run ${runId} belongs to ${loaded.run.role}, not countersign`);
1387
- }
1269
+ function admitResumedRole(loaded) {
1270
+ const role = loaded.run.role;
1271
+ const runId = loaded.run.runId;
1272
+ const record = packagedRoleMetadata(role);
1273
+ if (record === undefined) {
1274
+ throw new CliUsageError(`unknown role: ${role}`);
1275
+ }
1276
+ const fields = loaded.admittedFields;
1388
1277
  const base = resumedBaseAdmitted(loaded);
1389
- const admitted = {
1390
- role: "countersign",
1391
- ...base,
1392
- ...(base.courtTicketNumbers === undefined
1393
- ? {}
1394
- : { courtTicketNumbers: base.courtTicketNumbers }),
1395
- ...(loaded.admittedFields.courtTicketNumbersDamage === undefined
1396
- ? {}
1397
- : {
1398
- courtTicketNumbersDamage: loaded.admittedFields.courtTicketNumbersDamage,
1399
- }),
1400
- };
1401
- return seatLoadedResult(loaded, admitted);
1402
- }
1403
- /**
1404
- * Load a resumable Gleaner-Left run for resume (#599). Fixed base restores from
1405
- * the admitted request so continuation stays comparison-correct.
1406
- */
1407
- export async function loadResumableInstructionSeatRun(home, runId, authority) {
1408
- const loaded = await loadResumableRunRecord(home, runId, authority);
1409
- if (loaded.run.role !== "gatekeeper"
1410
- && loaded.run.role !== "navigator"
1411
- && loaded.run.role !== "auditor") {
1412
- throw new CliUsageError(`role run ${runId} belongs to ${loaded.run.role}, not an instruction seat`);
1413
- }
1414
- const admitted = {
1415
- role: loaded.run.role,
1416
- ...resumedBaseAdmitted(loaded),
1417
- };
1418
- return seatLoadedResult(loaded, admitted);
1419
- }
1420
- export async function loadResumableGleanerLeftRun(home, runId, authority) {
1421
- const loaded = await loadResumableRunRecord(home, runId, authority);
1422
- if (loaded.run.role !== "gleaner-left") {
1423
- throw new CliUsageError(`role run ${runId} belongs to ${loaded.run.role}, not gleaner-left`);
1424
- }
1425
- const baseRevision = loaded.admittedFields.baseRevision;
1426
- if (baseRevision === undefined || baseRevision.trim() === "") {
1427
- throw new CliUsageError(`role run admitted gleaner-left base revision is missing: ${runId}`);
1428
- }
1429
- const admitted = {
1430
- role: "gleaner-left",
1431
- ...resumedBaseAdmitted(loaded),
1432
- baseRevision,
1433
- };
1434
- return seatLoadedResult(loaded, admitted);
1435
- }
1436
- export async function loadResumableDiaristRun(home, runId, authority) {
1437
- const loaded = await loadResumableRunRecord(home, runId, authority);
1438
- if (loaded.run.role !== "diarist") {
1439
- throw new CliUsageError(`role run ${runId} belongs to ${loaded.run.role}, not diarist`);
1440
- }
1441
- const admitted = {
1442
- role: "diarist",
1443
- ...resumedBaseAdmitted(loaded),
1444
- };
1445
- return seatLoadedResult(loaded, admitted);
1446
- }
1447
- export async function loadResumableSecretariatRun(home, runId, authority) {
1448
- const loaded = await loadResumableRunRecord(home, runId, authority);
1449
- if (loaded.run.role !== "secretariat") {
1450
- throw new CliUsageError(`role run ${runId} belongs to ${loaded.run.role}, not secretariat`);
1451
- }
1452
- const admitted = {
1453
- role: "secretariat",
1454
- ...resumedBaseAdmitted(loaded),
1455
- };
1456
- return seatLoadedResult(loaded, admitted);
1457
- }
1458
- /**
1459
- * Load a resumable Merger run for resume. Derived envelope + internal input path
1460
- * are restored from the admitted request (#114).
1461
- */
1462
- export async function loadResumableMergerRun(home, runId, authority) {
1463
- const loaded = await loadResumableRunRecord(home, runId, authority);
1464
- if (loaded.run.role !== "merger") {
1465
- throw new CliUsageError(`role run ${runId} belongs to ${loaded.run.role}, not merger`);
1466
- }
1467
- const mergerInputPath = loaded.admittedFields.mergerInputPath;
1468
- if (mergerInputPath === undefined) {
1469
- throw new CliUsageError(`role run admitted merger input path is missing: ${runId}`);
1470
- }
1471
- const derived = loaded.admittedFields.derived;
1472
- if (derived === undefined) {
1473
- throw new CliUsageError(`role run admitted merger envelope is missing: ${runId}`);
1474
- }
1475
- if (loaded.admittedFields.instruction.trim() === "") {
1476
- throw new CliUsageError(`role run admitted merger task is blank: ${runId}`);
1477
- }
1478
- const admitted = {
1479
- role: "merger",
1480
- ...resumedBaseAdmitted(loaded),
1481
- instructionEmpty: false,
1482
- mergerInputPath,
1483
- derived,
1484
- };
1485
- return seatLoadedResult(loaded, admitted);
1486
- }
1487
- /**
1488
- * Load a resumable Collector run for resume (#633). Admitted repository/PR
1489
- * identity restores from the durable admitted request so the continuation
1490
- * stays binding-correct.
1491
- */
1492
- export async function loadResumableCollectorRun(home, runId, authority) {
1493
- const loaded = await loadResumableRunRecord(home, runId, authority);
1494
- if (loaded.run.role !== "collector") {
1495
- throw new CliUsageError(`role run ${runId} belongs to ${loaded.run.role}, not collector`);
1496
- }
1497
- const { prNumber, repository, repositoryDisplay, manifestDigest } = loaded.admittedFields;
1498
- // #676 A: prNumber may be unbound at admission (role bind-target). Repository is required.
1499
- if (repository === undefined ||
1500
- repositoryDisplay === undefined ||
1501
- manifestDigest === undefined) {
1502
- throw new CliUsageError(`role run admitted collector repository identity is missing: ${runId}`);
1503
- }
1504
- let parsedRepository;
1505
- try {
1506
- parsedRepository = parseCollectorRepository(repositoryDisplay);
1507
- }
1508
- catch (error) {
1509
- const detail = error instanceof Error ? error.message : String(error);
1510
- throw new CliUsageError(detail, { cause: error });
1511
- }
1512
- if (parsedRepository.canonical !== repository) {
1513
- throw new CliUsageError(`role run admitted collector repository does not match its canonical form: ${runId}`);
1514
- }
1515
- const admitted = {
1516
- role: "collector",
1517
- ...resumedBaseAdmitted(loaded),
1518
- ...(prNumber === undefined ? {} : { prNumber }),
1519
- repository: parsedRepository,
1520
- ...(loaded.admittedFields.requestManifestPath === undefined
1521
- ? {}
1522
- : { requestManifestPath: loaded.admittedFields.requestManifestPath }),
1523
- ...(loaded.admittedFields.waitWindowMs === undefined
1524
- ? {}
1525
- : { waitWindowMs: loaded.admittedFields.waitWindowMs }),
1526
- manifestDigest,
1527
- };
1528
- return seatLoadedResult(loaded, admitted);
1529
- }
1530
- /**
1531
- * Load a resumable Doctor run for resume (#633). Issue + retained case
1532
- * identity restore from the durable admitted request.
1533
- */
1534
- export async function loadResumableDoctorRun(home, runId, authority) {
1535
- const loaded = await loadResumableRunRecord(home, runId, authority);
1536
- if (loaded.run.role !== "doctor") {
1537
- throw new CliUsageError(`role run ${runId} belongs to ${loaded.run.role}, not doctor`);
1538
- }
1539
- const { issueNumber, caseRunsPath, caseIdentity } = loaded.admittedFields;
1540
- if (issueNumber === undefined ||
1541
- caseRunsPath === undefined ||
1542
- caseIdentity === undefined) {
1543
- throw new CliUsageError(`role run admitted doctor case identity is missing: ${runId}`);
1544
- }
1545
- const admitted = {
1546
- role: "doctor",
1547
- ...resumedBaseAdmitted(loaded),
1548
- issueNumber,
1549
- caseRunsPath,
1550
- caseIdentity,
1551
- };
1552
- return seatLoadedResult(loaded, admitted);
1553
- }
1554
- /**
1555
- * Load a resumable Notary run for resume (#633). Source-run locator restores
1556
- * from the durable admitted request; the locator is not re-resolved.
1557
- */
1558
- export async function loadResumableNotaryRun(home, runId, authority) {
1559
- const loaded = await loadResumableRunRecord(home, runId, authority);
1560
- if (loaded.run.role !== "notary") {
1561
- throw new CliUsageError(`role run ${runId} belongs to ${loaded.run.role}, not notary`);
1562
- }
1563
- const { sourceRunPath, sourceRun } = loaded.admittedFields;
1564
- if (sourceRunPath === undefined || sourceRun === undefined) {
1565
- throw new CliUsageError(`role run admitted notary source-run locator is missing: ${runId}`);
1278
+ switch (record.admission) {
1279
+ case "instruction": {
1280
+ if (packagedResumeSourcePath(role)) {
1281
+ const admitted = {
1282
+ role: "inspector",
1283
+ ...base,
1284
+ ...(fields.sourceRunPath === undefined
1285
+ ? {}
1286
+ : { sourceRunPath: fields.sourceRunPath }),
1287
+ };
1288
+ return admitted;
1289
+ }
1290
+ return {
1291
+ role,
1292
+ ...base,
1293
+ };
1294
+ }
1295
+ case "court-materials": {
1296
+ const admitted = {
1297
+ role: "countersign",
1298
+ ...base,
1299
+ ...(base.courtTicketNumbers === undefined
1300
+ ? {}
1301
+ : { courtTicketNumbers: base.courtTicketNumbers }),
1302
+ ...(fields.courtTicketNumbersDamage === undefined
1303
+ ? {}
1304
+ : { courtTicketNumbersDamage: fields.courtTicketNumbersDamage }),
1305
+ };
1306
+ return admitted;
1307
+ }
1308
+ case "worker-task": {
1309
+ const phase = resumedWorkerPhase(fields.phase ?? loaded.run.phase, record.phases, role, runId);
1310
+ const taskPath = fields.taskPath;
1311
+ if (taskPath === undefined) {
1312
+ throw new CliUsageError(`role run admitted coder task path is missing: ${runId}`);
1313
+ }
1314
+ if (fields.instruction.trim() === "") {
1315
+ throw new CliUsageError(`role run admitted coder task is blank: ${runId}`);
1316
+ }
1317
+ const admitted = {
1318
+ role: "coder",
1319
+ phase,
1320
+ ...base,
1321
+ instructionEmpty: false,
1322
+ taskPath,
1323
+ };
1324
+ return admitted;
1325
+ }
1326
+ case "worker-packet": {
1327
+ const phase = resumedWorkerPhase(fields.phase ?? loaded.run.phase, record.phases, role, runId);
1328
+ const packetPath = fields.packetPath;
1329
+ if (packetPath === undefined) {
1330
+ throw new CliUsageError(`role run admitted fixer packet path is missing: ${runId}`);
1331
+ }
1332
+ if (fields.instruction.trim() === "") {
1333
+ throw new CliUsageError(`role run admitted fixer instruction is blank: ${runId}`);
1334
+ }
1335
+ const prerequisites = fields.prerequisites ?? Object.freeze([]);
1336
+ const admitted = {
1337
+ role: "fixer",
1338
+ phase,
1339
+ ...base,
1340
+ instructionEmpty: false,
1341
+ packetPath,
1342
+ ...(fields.prerequisitesPath === undefined
1343
+ ? {}
1344
+ : { prerequisitesPath: fields.prerequisitesPath }),
1345
+ prerequisites,
1346
+ };
1347
+ return admitted;
1348
+ }
1349
+ case "review-basis": {
1350
+ const rawBase = fields.baseRevision;
1351
+ if (rawBase === undefined || rawBase.trim() === "") {
1352
+ throw new CliUsageError(`role run admitted reviewer base revision is missing: ${runId}`);
1353
+ }
1354
+ if (/\s/.test(rawBase) || rawBase.startsWith("-")) {
1355
+ throw new CliUsageError(`role run admitted reviewer base revision is damaged: ${runId}`);
1356
+ }
1357
+ const lens = fields.lens;
1358
+ if (!isReviewerLens(lens)) {
1359
+ throw new CliUsageError(`role run admitted reviewer lens is missing: ${runId}`);
1360
+ }
1361
+ const authorityRefs = Object.freeze([...(fields.authorityRefs ?? [])]);
1362
+ if (authorityRefs.length === 0) {
1363
+ throw new CliUsageError(`role run admitted reviewer authority refs are missing: ${runId}`);
1364
+ }
1365
+ const admitted = {
1366
+ role: "reviewer",
1367
+ ...base,
1368
+ baseRevision: rawBase,
1369
+ lens,
1370
+ authorityRefs,
1371
+ };
1372
+ return admitted;
1373
+ }
1374
+ case "gleaner": {
1375
+ const baseRevision = fields.baseRevision;
1376
+ if (baseRevision === undefined || baseRevision.trim() === "") {
1377
+ throw new CliUsageError(`role run admitted gleaner-left base revision is missing: ${runId}`);
1378
+ }
1379
+ const admitted = {
1380
+ role: "gleaner-left",
1381
+ ...base,
1382
+ baseRevision,
1383
+ };
1384
+ return admitted;
1385
+ }
1386
+ case "merge-envelope": {
1387
+ const mergerInputPath = fields.mergerInputPath;
1388
+ if (mergerInputPath === undefined) {
1389
+ throw new CliUsageError(`role run admitted merger input path is missing: ${runId}`);
1390
+ }
1391
+ const derived = fields.derived;
1392
+ if (derived === undefined) {
1393
+ throw new CliUsageError(`role run admitted merger envelope is missing: ${runId}`);
1394
+ }
1395
+ if (fields.instruction.trim() === "") {
1396
+ throw new CliUsageError(`role run admitted merger task is blank: ${runId}`);
1397
+ }
1398
+ const admitted = {
1399
+ role: "merger",
1400
+ ...base,
1401
+ instructionEmpty: false,
1402
+ mergerInputPath,
1403
+ derived,
1404
+ };
1405
+ return admitted;
1406
+ }
1407
+ case "collect-target": {
1408
+ const { prNumber, repository, repositoryDisplay, manifestDigest } = fields;
1409
+ if (repository === undefined ||
1410
+ repositoryDisplay === undefined ||
1411
+ manifestDigest === undefined) {
1412
+ throw new CliUsageError(`role run admitted collector repository identity is missing: ${runId}`);
1413
+ }
1414
+ let parsedRepository;
1415
+ try {
1416
+ parsedRepository = parseCollectorRepository(repositoryDisplay);
1417
+ }
1418
+ catch (error) {
1419
+ const detail = error instanceof Error ? error.message : String(error);
1420
+ throw new CliUsageError(detail, { cause: error });
1421
+ }
1422
+ if (parsedRepository.canonical !== repository) {
1423
+ throw new CliUsageError(`role run admitted collector repository does not match its canonical form: ${runId}`);
1424
+ }
1425
+ const admitted = {
1426
+ role: "collector",
1427
+ ...base,
1428
+ ...(prNumber === undefined ? {} : { prNumber }),
1429
+ repository: parsedRepository,
1430
+ ...(fields.requestManifestPath === undefined
1431
+ ? {}
1432
+ : { requestManifestPath: fields.requestManifestPath }),
1433
+ ...(fields.waitWindowMs === undefined ? {} : { waitWindowMs: fields.waitWindowMs }),
1434
+ manifestDigest,
1435
+ };
1436
+ return admitted;
1437
+ }
1438
+ case "case-identity": {
1439
+ const { issueNumber, caseRunsPath, caseIdentity } = fields;
1440
+ if (issueNumber === undefined ||
1441
+ caseRunsPath === undefined ||
1442
+ caseIdentity === undefined) {
1443
+ throw new CliUsageError(`role run admitted doctor case identity is missing: ${runId}`);
1444
+ }
1445
+ const admitted = {
1446
+ role: "doctor",
1447
+ ...base,
1448
+ issueNumber,
1449
+ caseRunsPath,
1450
+ caseIdentity,
1451
+ };
1452
+ return admitted;
1453
+ }
1454
+ case "source-locator": {
1455
+ const { sourceRunPath, sourceRun } = fields;
1456
+ if (sourceRunPath === undefined || sourceRun === undefined) {
1457
+ throw new CliUsageError(`role run admitted notary source-run locator is missing: ${runId}`);
1458
+ }
1459
+ const admitted = {
1460
+ role: "notary",
1461
+ ...base,
1462
+ sourceRunPath,
1463
+ sourceRun,
1464
+ };
1465
+ return admitted;
1466
+ }
1566
1467
  }
1567
- const admitted = {
1568
- role: "notary",
1569
- ...resumedBaseAdmitted(loaded),
1570
- sourceRunPath,
1571
- sourceRun,
1572
- };
1573
- return seatLoadedResult(loaded, admitted);
1574
1468
  }
1575
- /** Load a resumable Inspector run for resume (#633); base admitted identity only. */
1576
- export async function loadResumableInspectorRun(home, runId, authority) {
1577
- const loaded = await loadResumableRunRecord(home, runId, authority);
1578
- if (loaded.run.role !== "inspector") {
1579
- throw new CliUsageError(`role run ${runId} belongs to ${loaded.run.role}, not inspector`);
1469
+ /** Worker phase on resume: value must belong to the registry phase set. */
1470
+ function resumedWorkerPhase(phase, phases, role, runId) {
1471
+ if (phase === "plan" || phase === "apply") {
1472
+ if (phases.some((item) => item === phase)) {
1473
+ return phase;
1474
+ }
1580
1475
  }
1581
- const admitted = {
1582
- role: "inspector",
1583
- ...resumedBaseAdmitted(loaded),
1584
- ...(loaded.admittedFields.sourceRunPath === undefined
1585
- ? {}
1586
- : { sourceRunPath: loaded.admittedFields.sourceRunPath }),
1587
- };
1588
- return seatLoadedResult(loaded, admitted);
1589
- }
1590
- export async function peekRoleRunRole(home, runId) {
1591
- const runDirectory = await findRunDirectoryById(home, runId);
1592
- if (runDirectory === undefined)
1593
- return undefined;
1594
- const run = await readRoleRunIdentity(runDirectory);
1595
- return run?.role;
1476
+ throw new CliUsageError(`role run admitted ${role} phase is missing: ${runId}`);
1596
1477
  }