@akagilnc/pi-workflow-roles 0.1.5382 → 0.1.5462

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 (87) hide show
  1. package/README.md +4 -2
  2. package/README.zh-CN.md +4 -2
  3. package/dist/acp-host/production-host.js +8843 -9012
  4. package/dist/archivist-record-pointer.js +38 -0
  5. package/dist/compliance-transport.js +7 -5
  6. package/dist/doctor-auditor.js +1 -0
  7. package/dist/engine-detour-usage.js +9 -36
  8. package/dist/gatekeeper-role.js +4 -18
  9. package/dist/headless-host/description.js +0 -209
  10. package/dist/headless-host/production-host.js +7828 -8247
  11. package/dist/host-contracts.js +8 -0
  12. package/dist/judge-role.js +14 -1
  13. package/dist/migrate-book-topology.js +215 -96
  14. package/dist/navigator-attendance.js +10 -9
  15. package/dist/navigator-invocation-identity.js +18 -0
  16. package/dist/packaged-role-registry.js +1 -9
  17. package/dist/pi/role-turn-host.js +46 -19
  18. package/dist/public-cli/auto-resume.js +29 -66
  19. package/dist/public-cli/cli.js +1 -0
  20. package/dist/public-cli/countersign-run.js +4 -18
  21. package/dist/public-cli/instruction-seat-run.js +258 -69
  22. package/dist/public-cli/main.js +7488 -7758
  23. package/dist/public-cli/post-admission.js +451 -349
  24. package/dist/public-cli/process-cancel.js +8 -0
  25. package/dist/public-cli/run-lifecycle.js +24 -94
  26. package/dist/public-cli/settlement.js +624 -1471
  27. package/dist/public-cli/terminal.js +34 -53
  28. package/dist/public-cli/turn-request.js +3 -0
  29. package/dist/public-role-summons.js +3 -8
  30. package/dist/receipt-delivery-policy.js +162 -28
  31. package/dist/run-terminal-artifacts.js +19 -14
  32. package/dist/serialize-thrown-value.js +7 -1
  33. package/dist/submission-errors.js +11 -1
  34. package/dist/submission-gate.js +27 -4
  35. package/dist/submission-ledger.js +21 -89
  36. package/package.json +1 -1
  37. package/scripts/build-package.mjs +0 -2
  38. package/src/acp-host/role-turn-host.ts +168 -75
  39. package/src/archivist-record-pointer.ts +48 -0
  40. package/src/compliance-transport.ts +13 -8
  41. package/src/doctor-auditor.ts +3 -0
  42. package/src/engine-detour-usage.ts +10 -39
  43. package/src/external-host-turn-loop.ts +100 -43
  44. package/src/gatekeeper-role.ts +7 -22
  45. package/src/headless-host/description.ts +4 -214
  46. package/src/headless-host/production-host.ts +2 -1
  47. package/src/headless-host/role-turn-host.ts +153 -186
  48. package/src/host-contracts.ts +20 -10
  49. package/src/judge-role.ts +24 -5
  50. package/src/navigator-attendance.ts +17 -12
  51. package/src/navigator-invocation-identity.ts +31 -0
  52. package/src/navigator-public-session.ts +1 -1
  53. package/src/navigator-session-contracts.ts +1 -1
  54. package/src/packaged-role-registry.ts +2 -10
  55. package/src/pi/adapter.ts +33 -11
  56. package/src/pi/role-turn-host.ts +49 -28
  57. package/src/prepared-role-turn.ts +2 -0
  58. package/src/public-cli/auto-resume.ts +27 -66
  59. package/src/public-cli/cli.ts +1 -0
  60. package/src/public-cli/countersign-run.ts +4 -22
  61. package/src/public-cli/instruction-seat-run.ts +307 -74
  62. package/src/public-cli/post-admission.ts +615 -459
  63. package/src/public-cli/process-cancel.ts +9 -0
  64. package/src/public-cli/run-lifecycle.ts +25 -126
  65. package/src/public-cli/settlement.ts +801 -1859
  66. package/src/public-cli/terminal.ts +42 -70
  67. package/src/public-cli/turn-request.ts +10 -1
  68. package/src/public-role-summons.ts +3 -8
  69. package/src/receipt-delivery-policy.ts +219 -28
  70. package/src/role-envelope.ts +21 -10
  71. package/src/role-runtime-dependencies.ts +1 -0
  72. package/src/role-runtime.ts +79 -102
  73. package/src/run-terminal-artifacts.ts +21 -17
  74. package/src/serialize-thrown-value.ts +7 -1
  75. package/src/submission-correctable-error.ts +5 -2
  76. package/src/submission-errors.ts +12 -1
  77. package/src/submission-gate.ts +34 -4
  78. package/src/submission-ledger.ts +30 -116
  79. package/src/worker-role.ts +19 -7
  80. package/src/worker-submission-gates.ts +29 -7
  81. package/dist/audit-escalation.js +0 -7
  82. package/dist/pi/known-failure.js +0 -51
  83. package/dist/typed-provider-http.js +0 -57
  84. package/dist/upstream-error-testimony.js +0 -19
  85. package/src/pi/known-failure.ts +0 -76
  86. package/src/typed-provider-http.ts +0 -89
  87. package/src/upstream-error-testimony.ts +0 -45
@@ -73,3 +73,12 @@ export function processCancelSignalName(
73
73
  export function processCancelDiagnostic(signalName: CatchableProcessSignal): string {
74
74
  return `ak-role terminated by ${signalName}`;
75
75
  }
76
+
77
+ /**
78
+ * Diagnostic line for a child the host lost to a signal. The child reported
79
+ * code=null, which is a non-normal exit and never a successful run
80
+ * (ADR 0052: 真失败退非零).
81
+ */
82
+ export function childSignalDeathDiagnostic(signal: string): string {
83
+ return `role run was killed by ${signal}`;
84
+ }
@@ -19,15 +19,6 @@ import {
19
19
  import { listBookRunDirectories } from "../role-run-placement.ts";
20
20
  import { isSafePositiveTicketNumber } from "../run-ticket-number.ts";
21
21
  import { CliUsageError } from "./cli-errors.ts";
22
- import {
23
- readLatestTypedProviderHttpObservation,
24
- } from "../typed-provider-http.ts";
25
- export {
26
- clearTypedProviderHttpObservation,
27
- recordTypedProviderHttpStatus,
28
- readLatestTypedProviderHttpObservation,
29
- type TypedProviderHttpObservation,
30
- } from "../typed-provider-http.ts";
31
22
  import type { FixerPhase } from "../package-contracts/fixer-output.ts";
32
23
  import type { FixerPrerequisite } from "../package-contracts/fixer-packet.ts";
33
24
  import { parseCollectorRepository } from "../collector-config.ts";
@@ -73,19 +64,8 @@ import {
73
64
 
74
65
  import { isRecord, errorText, isEnoent } from "../unknown-value.ts";
75
66
 
76
- /** Providers eligible for v1 typed-429 resume (Codex / xAI only).
77
- * @deprecated v1 429-only gate removed by #416 (owner 2026-08-22: "根本不要有限制"). Kept for compatibility; do not use for new branching.
78
- */
79
- export const V1_RESUMABLE_PROVIDERS = ["openai-codex", "xai"] as const;
80
- export type V1ResumableProvider = (typeof V1_RESUMABLE_PROVIDERS)[number];
81
-
82
67
  export type RoleRunState = "admitted" | "running" | "resumable" | "terminal";
83
68
 
84
- export type TypedHttp429Observation = {
85
- readonly httpStatus: 429;
86
- readonly provider: V1ResumableProvider;
87
- };
88
-
89
69
  /** Default for the #422 configurable single-call auto-resume ceiling
90
70
  * (public-cli.json top-level `autoResumeLimit`). No longer the runtime truth
91
71
  * source: runWithAutoResumeLoop receives the effective value once per call.
@@ -105,10 +85,6 @@ export type RoleRunRecord = {
105
85
  readonly admittedRequestPath: string;
106
86
  /** Coder/Fixer — preserved for resume continuation. */
107
87
  readonly phase?: CoderPhase | FixerPhase;
108
- /** Present only while state === "resumable".
109
- * @deprecated retained only for historical 429 runs; #416 no longer gates resume on this field.
110
- */
111
- readonly resumable?: TypedHttp429Observation;
112
88
  };
113
89
 
114
90
  /**
@@ -180,29 +156,6 @@ export function buildAutoResumeContinuationPrompt(options: {
180
156
  const RUN_STATE_FILE = "run-state.json";
181
157
  const WRITER_LOCK_FILE = "writer.lock";
182
158
 
183
- /** @deprecated #416: 429-only classification removed; kept for compatibility. */
184
- export function isV1ResumableProvider(
185
- provider: string,
186
- ): provider is V1ResumableProvider {
187
- return (V1_RESUMABLE_PROVIDERS as readonly string[]).includes(provider);
188
- }
189
-
190
- /** @deprecated #416: 429-only observation no longer gates resume; kept for historical runs. */
191
- export async function readTypedHttp429Observation(
192
- runDirectory: string,
193
- ): Promise<TypedHttp429Observation | undefined> {
194
- const observation = await readLatestTypedProviderHttpObservation(runDirectory);
195
- if (observation === undefined) return undefined;
196
- if (observation.httpStatus !== 429) return undefined;
197
- if (!isV1ResumableProvider(observation.provider)) return undefined;
198
- return { httpStatus: 429, provider: observation.provider };
199
- }
200
-
201
- /** Complete public resume command. Run ID is revealed only through this command text. */
202
- export function renderResumeCommand(runId: string): string {
203
- return `ak-role resume ${runId}`;
204
- }
205
-
206
159
  export async function writeRoleRunState(
207
160
  runDirectory: string,
208
161
  record: Omit<RoleRunRecord, "runDirectory">,
@@ -235,7 +188,6 @@ type RoleRunStateDisk = {
235
188
  readonly admittedRequestPath: string;
236
189
  readonly principalWire: RoleRunPrincipalWire;
237
190
  readonly phase?: CoderPhase | FixerPhase;
238
- readonly resumable?: TypedHttp429Observation;
239
191
  /** Open court turn (#637); omit when no unsealed current court. */
240
192
  readonly currentCourt?: CurrentCourtState;
241
193
  };
@@ -318,7 +270,7 @@ async function readRoleRunStateRaw(runDirectory: string): Promise<unknown | unde
318
270
  // failure (EISDIR, EACCES, ...) or a JSON.parse SyntaxError on a present
319
271
  // file is genuine infrastructure/data damage and must keep its own
320
272
  // identity — callers route it through the controlled-failure seam
321
- // (markRunRunning/markRunResumable/markRunTerminal/recordCurrentCourt)
273
+ // (markRunRunning/markRunTerminal/recordCurrentCourt)
322
274
  // instead of it being relabeled "run state missing" (#836).
323
275
  if (errorCodeOf(error) === "ENOENT") return undefined;
324
276
  throw error;
@@ -388,19 +340,6 @@ async function readRoleRunStateDisk(
388
340
  ? { sessionFile: rewriteRunDirectoryPathValue(record.sessionFile, storedRunDirectory, runDirectory) as string }
389
341
  : {}),
390
342
  };
391
- let resumable: TypedHttp429Observation | undefined;
392
- if (record.resumable !== undefined && record.resumable !== null) {
393
- if (isRecord(record.resumable)) {
394
- const r = record.resumable;
395
- if (
396
- r.httpStatus === 429 &&
397
- typeof r.provider === "string" &&
398
- isV1ResumableProvider(r.provider)
399
- ) {
400
- resumable = { httpStatus: 429, provider: r.provider };
401
- }
402
- }
403
- }
404
343
  const phase =
405
344
  record.phase === "plan" || record.phase === "apply"
406
345
  ? record.phase
@@ -420,7 +359,6 @@ async function readRoleRunStateDisk(
420
359
  ) as string,
421
360
  principalWire,
422
361
  ...(phase === undefined ? {} : { phase }),
423
- ...(resumable === undefined ? {} : { resumable }),
424
362
  ...(currentCourt === undefined ? {} : { currentCourt }),
425
363
  };
426
364
  }
@@ -442,7 +380,6 @@ async function writeRoleRunStateDisk(
442
380
  : { sessionFile: disk.principalWire.sessionFile }),
443
381
  admittedRequestPath: disk.admittedRequestPath,
444
382
  ...(disk.phase === undefined ? {} : { phase: disk.phase }),
445
- ...(disk.resumable === undefined ? {} : { resumable: disk.resumable }),
446
383
  ...(disk.currentCourt === undefined ? {} : { currentCourt: disk.currentCourt }),
447
384
  };
448
385
  await writeFile(
@@ -472,7 +409,6 @@ function materializeRoleRunFromDisk(
472
409
  runDirectory: disk.runDirectory,
473
410
  admittedRequestPath: disk.admittedRequestPath,
474
411
  ...(disk.phase === undefined ? {} : { phase: disk.phase }),
475
- ...(disk.resumable === undefined ? {} : { resumable: disk.resumable }),
476
412
  },
477
413
  };
478
414
  } catch {
@@ -561,20 +497,10 @@ export async function markRunRunning(
561
497
  if (current === undefined) {
562
498
  throw new Error("cannot mark running: run state missing");
563
499
  }
564
- // Omit resumable while a writer is active. Principal wire is passed through uninterpreted.
500
+ // Principal wire is passed through uninterpreted.
565
501
  // Preserve open currentCourt across running transitions (#637).
566
- await writeRoleRunStateDisk(runDirectory, {
567
- runId: current.runId,
568
- role: current.role,
569
- state: "running",
570
- bookKey: current.bookKey,
571
- projectRoot: current.projectRoot,
572
- runDirectory: current.runDirectory,
573
- admittedRequestPath: current.admittedRequestPath,
574
- principalWire: current.principalWire,
575
- ...(current.phase === undefined ? {} : { phase: current.phase }),
576
- ...(current.currentCourt === undefined ? {} : { currentCourt: current.currentCourt }),
577
- });
502
+ // A historical resumable payload on disk is not copied: the parser never kept it.
503
+ await writeRoleRunStateDisk(runDirectory, { ...current, state: "running" });
578
504
  await recordEffectiveInvocationModel(
579
505
  runDirectory,
580
506
  effectiveModel,
@@ -590,40 +516,13 @@ export async function markRunRunning(
590
516
  );
591
517
  }
592
518
 
593
- /** @deprecated #416: 429-only resumable marker; kept for historical runs. */
594
- export async function markRunResumable(
595
- runDirectory: string,
596
- observation: TypedHttp429Observation,
597
- ): Promise<void> {
598
- const current = await readRoleRunStateDisk(runDirectory);
599
- if (current === undefined) {
600
- throw new Error("cannot mark resumable: run state missing");
601
- }
602
- await writeRoleRunStateDisk(runDirectory, {
603
- ...current,
604
- state: "resumable",
605
- resumable: observation,
606
- });
607
- }
608
-
609
519
  export async function markRunTerminal(runDirectory: string): Promise<void> {
610
520
  const current = await readRoleRunStateDisk(runDirectory);
611
521
  if (current === undefined) {
612
522
  throw new Error("cannot mark terminal: run state missing");
613
523
  }
614
524
  // Preserve the open court's settlement identity after a failed/incomplete turn (#637).
615
- await writeRoleRunStateDisk(runDirectory, {
616
- runId: current.runId,
617
- role: current.role,
618
- state: "terminal",
619
- bookKey: current.bookKey,
620
- projectRoot: current.projectRoot,
621
- runDirectory: current.runDirectory,
622
- admittedRequestPath: current.admittedRequestPath,
623
- principalWire: current.principalWire,
624
- ...(current.phase === undefined ? {} : { phase: current.phase }),
625
- ...(current.currentCourt === undefined ? {} : { currentCourt: current.currentCourt }),
626
- });
525
+ await writeRoleRunStateDisk(runDirectory, { ...current, state: "terminal" });
627
526
  }
628
527
 
629
528
  /** Read the open court turn on a retained run, if any (#637). */
@@ -667,28 +566,32 @@ export async function clearCurrentCourt(
667
566
  ) {
668
567
  return;
669
568
  }
670
- await writeRoleRunStateDisk(runDirectory, {
671
- runId: current.runId,
672
- role: current.role,
673
- state: current.state,
674
- bookKey: current.bookKey,
675
- projectRoot: current.projectRoot,
676
- runDirectory: current.runDirectory,
677
- admittedRequestPath: current.admittedRequestPath,
678
- principalWire: current.principalWire,
679
- ...(current.phase === undefined ? {} : { phase: current.phase }),
680
- ...(current.resumable === undefined ? {} : { resumable: current.resumable }),
681
- });
569
+ const { currentCourt: _currentCourt, ...rest } = current;
570
+ await writeRoleRunStateDisk(runDirectory, rest);
682
571
  }
683
572
 
684
573
  export class RunWriterLeaseHeldError extends Error {
685
574
  readonly code = "AK_RUN_WRITER_LEASE_HELD" as const;
686
- constructor(message = "role run writer lease is already held") {
575
+ /**
576
+ * Why the lease could not be taken, as structured data: the OS errno of the
577
+ * underlying reclaim failure when there was one. Carried so a consumer
578
+ * asserts the real cause instead of recognising it in the message text
579
+ * (质量法: 机器只咬契约,不咬呈现).
580
+ */
581
+ readonly causeCode?: string | number;
582
+ constructor(message = "role run writer lease is already held", causeCode?: string | number) {
687
583
  super(message);
688
584
  this.name = "RunWriterLeaseHeldError";
585
+ if (causeCode !== undefined) this.causeCode = causeCode;
689
586
  }
690
587
  }
691
588
 
589
+ /** The OS errno of a thrown value, when it carries one. */
590
+ function errnoOf(error: unknown): string | number | undefined {
591
+ const code = (error as { code?: unknown } | null)?.code;
592
+ return typeof code === "string" || typeof code === "number" ? code : undefined;
593
+ }
594
+
692
595
  export type RunWriterLease = {
693
596
  readonly lockPath: string;
694
597
  /** Keep lease cleanup anchored when its run is relocated while held. */
@@ -970,6 +873,7 @@ export async function acquireRunWriterLease(
970
873
  } catch (reclaimError) {
971
874
  throw new RunWriterLeaseHeldError(
972
875
  `stale writer lease reclaim failed at ${lockPath} (autopsy: ${describeAutopsy(lastAutopsy)}): ${describeErrorIdentity(reclaimError)}`,
876
+ errnoOf(reclaimError),
973
877
  );
974
878
  }
975
879
  if (reclaimed) {
@@ -983,6 +887,7 @@ export async function acquireRunWriterLease(
983
887
  lastReclaimFailure !== undefined
984
888
  ? `role run writer lease stayed contested at ${lockPath} after ${WRITER_LEASE_RECLAIM_ROUNDS} reclaims (last autopsy: ${describeAutopsy(lastAutopsy)}; last reclaim failure: ${describeErrorIdentity(lastReclaimFailure)})`
985
889
  : `role run writer lease stayed contested at ${lockPath} after ${WRITER_LEASE_RECLAIM_ROUNDS} reclaims (last autopsy: ${describeAutopsy(lastAutopsy)})`,
890
+ lastReclaimFailure === undefined ? undefined : errnoOf(lastReclaimFailure),
986
891
  );
987
892
  }
988
893
 
@@ -1225,7 +1130,6 @@ async function loadResumableRunRecord(
1225
1130
  ): Promise<{
1226
1131
  readonly run: RoleRunRecord;
1227
1132
  readonly principal: DurablePrincipal;
1228
- readonly observation?: TypedHttp429Observation;
1229
1133
  readonly admittedFields: LoadedAdmittedRequestFields;
1230
1134
  }> {
1231
1135
  const runDirectory = await findRunDirectoryById(home, runId);
@@ -1492,7 +1396,6 @@ async function loadResumableRunRecord(
1492
1396
  return {
1493
1397
  run,
1494
1398
  principal,
1495
- ...(run.resumable === undefined ? {} : { observation: run.resumable }),
1496
1399
  admittedFields: {
1497
1400
  instruction,
1498
1401
  instructionEmpty,
@@ -1553,14 +1456,12 @@ function resumedBaseAdmitted(loaded: {
1553
1456
  function seatLoadedResult<R extends AdmittedRoleInvocation>(
1554
1457
  loaded: {
1555
1458
  readonly run: RoleRunRecord;
1556
- readonly observation?: TypedHttp429Observation;
1557
1459
  },
1558
1460
  admitted: R,
1559
- ): { admitted: R; run: RoleRunRecord; observation?: TypedHttp429Observation } {
1461
+ ): { admitted: R; run: RoleRunRecord } {
1560
1462
  return {
1561
1463
  admitted,
1562
1464
  run: loaded.run,
1563
- ...(loaded.observation === undefined ? {} : { observation: loaded.observation }),
1564
1465
  };
1565
1466
  }
1566
1467
 
@@ -1577,7 +1478,6 @@ export async function peekRoleRunRole(
1577
1478
  export type LoadedResumablePublicRole = {
1578
1479
  readonly admitted: AdmittedRoleInvocation;
1579
1480
  readonly run: RoleRunRecord;
1580
- readonly observation?: TypedHttp429Observation;
1581
1481
  };
1582
1482
 
1583
1483
  /**
@@ -1601,7 +1501,6 @@ export async function loadResumablePublicRole(
1601
1501
  function admitResumedRole(loaded: {
1602
1502
  readonly run: RoleRunRecord;
1603
1503
  readonly principal: DurablePrincipal;
1604
- readonly observation?: TypedHttp429Observation;
1605
1504
  readonly admittedFields: LoadedAdmittedRequestFields;
1606
1505
  }): AdmittedRoleInvocation {
1607
1506
  const role = loaded.run.role;