@akagilnc/pi-workflow-roles 0.1.5483 → 0.1.5571

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 (112) hide show
  1. package/README.md +1 -1
  2. package/README.zh-CN.md +1 -1
  3. package/dist/acp-host/production-host.js +6312 -6376
  4. package/dist/analyst-gate-cycles-read.js +28 -78
  5. package/dist/analyst-ledger.js +26 -42
  6. package/dist/analyst-metric-families/acceptance-success-rework.js +25 -1
  7. package/dist/analyst-metric-families/round-timeline.js +2 -5
  8. package/dist/archivist-record-entry.js +4 -3
  9. package/dist/archivist-record-pointer.js +71 -36
  10. package/dist/atomic-write.js +2 -2
  11. package/dist/auditor-dossier-tool.js +11 -6
  12. package/dist/auditor-soul.js +5 -12
  13. package/dist/collector-config.js +6 -5
  14. package/dist/doctor-evidence.js +8 -4
  15. package/dist/engine-detour-usage.js +8 -22
  16. package/dist/headless-host/production-host.js +5969 -6011
  17. package/dist/host-descriptions.js +0 -4
  18. package/dist/host-session-record.js +266 -267
  19. package/dist/ledger-session-read.js +5 -0
  20. package/dist/migrate-book-topology.js +1369 -722
  21. package/dist/navigator-public-session.js +13 -17
  22. package/dist/notary-source-run.js +8 -16
  23. package/dist/packaged-role-registry.js +5 -56
  24. package/dist/pi/durable-principal.js +2 -3
  25. package/dist/pi/role-turn-host.js +79 -15
  26. package/dist/public-cli/auto-resume.js +8 -47
  27. package/dist/public-cli/instruction-seat-run.js +9 -7
  28. package/dist/public-cli/invocation.js +67 -100
  29. package/dist/public-cli/main.js +2689 -2532
  30. package/dist/public-cli/post-admission.js +96 -55
  31. package/dist/public-cli/run-lifecycle.js +44 -100
  32. package/dist/public-cli/settlement.js +184 -429
  33. package/dist/public-cli/terminal.js +0 -12
  34. package/dist/role-run-placement.js +53 -16
  35. package/dist/role-run-relocation.js +111 -52
  36. package/dist/run-dossier-files.js +30 -0
  37. package/dist/run-dossier.js +322 -0
  38. package/dist/run-terminal-artifacts.js +69 -202
  39. package/dist/run-ticket-number.js +49 -7
  40. package/dist/session-assistant-usage.js +9 -18
  41. package/dist/session-identity.js +49 -19
  42. package/dist/sitian-appender.js +29 -18
  43. package/dist/sitian-facade.js +11 -0
  44. package/dist/sitian-reader.js +44 -29
  45. package/dist/submission-gate.js +1 -1
  46. package/dist/submission-ledger.js +4 -4
  47. package/dist/ticket-provenance-contracts.js +2 -8
  48. package/dist/ticket-provenance.js +25 -9
  49. package/package.json +1 -1
  50. package/scripts/build-package.mjs +2 -0
  51. package/src/acp-host/production-host.ts +1 -1
  52. package/src/acp-host/role-turn-host.ts +11 -4
  53. package/src/analyst-gate-cycles-read.ts +31 -88
  54. package/src/analyst-ledger.ts +36 -51
  55. package/src/analyst-metric-families/acceptance-success-rework.ts +24 -1
  56. package/src/analyst-metric-families/gate-cycles.ts +1 -1
  57. package/src/analyst-metric-families/round-timeline.ts +2 -5
  58. package/src/analyst-page.ts +3 -3
  59. package/src/archivist-record-entry.ts +6 -5
  60. package/src/archivist-record-pointer.ts +92 -42
  61. package/src/atomic-write.ts +3 -1
  62. package/src/auditor-dossier-tool.ts +14 -8
  63. package/src/auditor-soul.ts +5 -10
  64. package/src/book-topology-migration-placement.ts +16 -3
  65. package/src/book-topology-record-class-migrators.ts +4 -2
  66. package/src/book-topology-runs-migrator.ts +6 -3
  67. package/src/collector-config.ts +5 -3
  68. package/src/doctor-contracts.ts +1 -1
  69. package/src/doctor-evidence.ts +7 -3
  70. package/src/engine-detour-tool.ts +1 -1
  71. package/src/engine-detour-usage.ts +12 -25
  72. package/src/external-host-turn-loop.ts +25 -0
  73. package/src/factory-board.ts +16 -81
  74. package/src/headless-host/production-host.ts +1 -4
  75. package/src/headless-host/role-turn-host.ts +56 -21
  76. package/src/host-descriptions.ts +0 -6
  77. package/src/host-session-record.ts +224 -140
  78. package/src/ledger-session-read.ts +6 -0
  79. package/src/navigator-public-session.ts +13 -18
  80. package/src/navigator-work-context.ts +3 -1
  81. package/src/notary-role.ts +2 -1
  82. package/src/notary-source-run.ts +8 -18
  83. package/src/packaged-role-registry.ts +1 -65
  84. package/src/pi/adapter.ts +50 -7
  85. package/src/pi/durable-principal.ts +2 -4
  86. package/src/pi/role-turn-host.ts +85 -14
  87. package/src/public-cli/auto-resume.ts +7 -43
  88. package/src/public-cli/instruction-seat-run.ts +13 -6
  89. package/src/public-cli/invocation.ts +90 -144
  90. package/src/public-cli/post-admission.ts +111 -72
  91. package/src/public-cli/run-lifecycle.ts +47 -115
  92. package/src/public-cli/settlement.ts +221 -589
  93. package/src/public-cli/terminal.ts +1 -61
  94. package/src/role-envelope.ts +4 -2
  95. package/src/role-run-placement.ts +65 -17
  96. package/src/role-run-relocation.ts +110 -70
  97. package/src/role-runtime.ts +46 -69
  98. package/src/run-dossier-files.ts +33 -0
  99. package/src/run-dossier.ts +357 -0
  100. package/src/run-terminal-artifacts.ts +84 -240
  101. package/src/run-ticket-number.ts +82 -14
  102. package/src/session-assistant-usage.ts +8 -20
  103. package/src/session-identity.ts +52 -21
  104. package/src/sitian-appender.ts +33 -26
  105. package/src/sitian-facade.ts +22 -0
  106. package/src/sitian-reader.ts +62 -32
  107. package/src/submission-gate.ts +1 -1
  108. package/src/submission-ledger.ts +4 -4
  109. package/src/ticket-provenance-contracts.ts +3 -6
  110. package/src/ticket-provenance.ts +23 -11
  111. package/src/ticket-snapshot.ts +3 -2
  112. package/src/ticket-trajectory.ts +95 -109
@@ -26,10 +26,11 @@ import {
26
26
  relocateAdmittedRunToTicket,
27
27
  } from "./invocation.ts";
28
28
  import { readRecordedSubmissionRows } from "../submission-ledger.ts";
29
- import { readDeclaredTicketNumber } from "../run-ticket-number.ts";
29
+ import { parseTicketNumber, readDeclaredTicketNumber } from "../run-ticket-number.ts";
30
30
  import { pathContainedIn } from "../activation-ledger-topology.ts";
31
31
  import { pickEngineAxis } from "../package-resources/engine-material.ts";
32
32
  import { readStoredHostSessionId } from "../session-identity.ts";
33
+ import { reportRunRecord } from "../sitian-facade.ts";
33
34
  import {
34
35
  createReceiptDeliveryPolicy,
35
36
  deliveryLimitFromConfig,
@@ -86,7 +87,6 @@ import {
86
87
  type CatchableProcessSignal,
87
88
  } from "./process-cancel.ts";
88
89
  import { DEFAULT_ROLE_TURN_HOST } from "../host-descriptions.ts";
89
- import { recordRunStart } from "../host-session-record.ts";
90
90
  import {
91
91
  classifyPostAdmissionFailure,
92
92
  exitCodeForTerminalOutcome,
@@ -112,7 +112,6 @@ import {
112
112
  type TerminalResult,
113
113
  } from "./terminal.ts";
114
114
  import {
115
- ensureRealArtifactsDirectory,
116
115
  persistReturnedRunState,
117
116
  presentTerminal,
118
117
  runWithAutoResumeLoop,
@@ -175,6 +174,7 @@ async function settleProcessCancelAfterTurn<A extends AdmittedRoleInvocation, T
175
174
  deferredPersist: { needsPersist?: true } | Record<string, never>;
176
175
  invocationScopeId: string | undefined;
177
176
  notePackageFault?: (diagnostic: string) => void | Promise<void>;
177
+ courtAttemptId?: string;
178
178
  }): Promise<{
179
179
  exitCode: number;
180
180
  admitted: A;
@@ -205,6 +205,7 @@ async function settleProcessCancelAfterTurn<A extends AdmittedRoleInvocation, T
205
205
  input.io,
206
206
  input.persistRunState,
207
207
  input.notePackageFault,
208
+ input.courtAttemptId,
208
209
  );
209
210
  return {
210
211
  ...failed,
@@ -379,7 +380,7 @@ export type ControlledFailureInput = {
379
380
  knownDetails?: Readonly<Record<string, unknown>>;
380
381
  /**
381
382
  * A real failure this package hit while handling the call (e.g. the
382
- * stderr.log durable write). Recorded beside the host's report; never a
383
+ * stderr log-line write). Recorded beside the host's report; never a
383
384
  * cause, and never written into the host's open `details`.
384
385
  */
385
386
  packageFact?: PackageSideFact;
@@ -473,6 +474,8 @@ export async function presentControlledFailure<
473
474
  io: CliIo,
474
475
  persistRunState = true,
475
476
  notePackageFault?: (diagnostic: string) => void | Promise<void>,
477
+ /** Open-court identity already on the turn request / currentCourt (#1161). */
478
+ courtAttemptId?: string,
476
479
  ): Promise<{
477
480
  exitCode: number;
478
481
  admitted: A;
@@ -545,6 +548,9 @@ export async function presentControlledFailure<
545
548
  const settled = await settleFailureTerminalResult(admitted, failure, authority, {
546
549
  recordAttemptHistory: true,
547
550
  ...(notePackageFault === undefined ? {} : { notePackageFault }),
551
+ ...(courtAttemptId === undefined || courtAttemptId.length === 0
552
+ ? {}
553
+ : { courtAttemptId }),
548
554
  ...(failureInput.invocationScopeId === undefined ||
549
555
  failureInput.invocationScopeId.length === 0
550
556
  ? {}
@@ -588,6 +594,7 @@ async function settleAfterTurnStarted<
588
594
  io: CliIo,
589
595
  persistRunState: boolean,
590
596
  notePackageFault?: (diagnostic: string) => void | Promise<void>,
597
+ courtAttemptId?: string,
591
598
  ): Promise<{ exitCode: number; admitted: A; terminal: T }> {
592
599
  try {
593
600
  return (await presentControlledFailure(
@@ -598,6 +605,7 @@ async function settleAfterTurnStarted<
598
605
  io,
599
606
  persistRunState,
600
607
  notePackageFault,
608
+ courtAttemptId,
601
609
  )) as { exitCode: number; admitted: A; terminal: T };
602
610
  } catch (error) {
603
611
  throw new TurnDispatchedFailure(error);
@@ -666,18 +674,12 @@ function settlementScopeForTurn(request: RoleTurnRequest): SettlementCourtScope
666
674
  *
667
675
  * The caller owns the live delivery policy; the request projects its next send.
668
676
  */
669
- async function buildReceiptDeliveryRequest<A extends AdmittedRoleInvocation>(input: {
670
- admitted: A;
671
- env: PostAdmissionEnv;
677
+ /** Bare in-call催交 resume: hostSessionId absent; adapter is the sole load authority. */
678
+ function buildReceiptDeliveryRequest(input: {
672
679
  request: RoleTurnRequest;
673
680
  receiptDelivery: ReturnType<typeof createReceiptDeliveryPolicy>;
674
- }): Promise<RoleTurnRequest> {
675
- const { admitted, env, request, receiptDelivery } = input;
676
- const hostSessionId = await readStoredHostSessionId(
677
- env.host,
678
- env.principalAuthority,
679
- admitted.principal,
680
- );
681
+ }): RoleTurnRequest {
682
+ const { request, receiptDelivery } = input;
681
683
  return {
682
684
  ...request,
683
685
  continuation: {
@@ -686,7 +688,6 @@ async function buildReceiptDeliveryRequest<A extends AdmittedRoleInvocation>(inp
686
688
  ...receiptDelivery.deliveryState(),
687
689
  deliveryTurns: receiptDelivery.issuedDeliveryRequests() + 1,
688
690
  }),
689
- ...(hostSessionId === undefined ? {} : { hostSessionId }),
690
691
  },
691
692
  deliveryRequestLimit: receiptDelivery.limit,
692
693
  };
@@ -760,20 +761,16 @@ async function settleCompletedHostTurn<
760
761
  // machinery once the retry budget is exhausted.
761
762
  let stderrLogWriteFailure: unknown;
762
763
  try {
763
- await writeFile(
764
- join(admitted.runDirectory, "stderr.log"),
765
- result.stderr,
766
- "utf8",
767
- );
764
+ reportRunRecord(admitted.runDirectory, "stderr", { text: result.stderr }, "post-admission");
768
765
  } catch (error) {
769
766
  stderrLogWriteFailure = error;
770
- // Best-effort: stderr.log is secondary to the host terminal. A write
767
+ // Best-effort: the stderr log line is secondary to the host terminal. A write
771
768
  // failure leaves a durable note and, on a host failure, rides in
772
769
  // packageFact. It does not become the cause.
773
770
  await recordBestEffortPostDispatchDiagnostic(
774
771
  admitted,
775
772
  env,
776
- `stderr.log write failed (best-effort continue): ${describeErrorIdentity(error)}`,
773
+ `stderr log write failed (best-effort continue): ${describeErrorIdentity(error)}`,
777
774
  io,
778
775
  );
779
776
  }
@@ -781,7 +778,7 @@ async function settleCompletedHostTurn<
781
778
  // Host facts are resolved before trySettle. A host failure skips trySettle
782
779
  // so a later read cannot replace that report. A clean host whose settlement
783
780
  // read throws is noted above and is not turned into a failure terminal.
784
- // stderr.log and run-state writes are notes beside the host terminal.
781
+ // the stderr log line and run-state writes are notes beside the host terminal.
785
782
  let settled: T | undefined;
786
783
  let settledOutcome:
787
784
  | { exitCode: number; admitted: A; terminal: T; turnDispatched: true }
@@ -841,6 +838,9 @@ async function settleCompletedHostTurn<
841
838
  deferredPersist,
842
839
  invocationScopeId: request.invocationScopeId,
843
840
  notePackageFault: courtScope.notePackageFault,
841
+ ...(courtScope.courtAttemptId === undefined
842
+ ? {}
843
+ : { courtAttemptId: courtScope.courtAttemptId }),
844
844
  }),
845
845
  ) };
846
846
  }
@@ -892,6 +892,7 @@ async function settleCompletedHostTurn<
892
892
  io,
893
893
  persistRunState,
894
894
  courtScope.notePackageFault,
895
+ courtScope.courtAttemptId,
895
896
  );
896
897
  return { kind: "settled", outcome: await finishAfterTurn(
897
898
  withProcessCancelSkipAutoResume(
@@ -904,6 +905,64 @@ async function settleCompletedHostTurn<
904
905
  return { kind: "still-missing" };
905
906
  }
906
907
 
908
+ /**
909
+ * #858 / #1071: the first identifiable ticketNumber field declaration among the
910
+ * run's sealed rows files an unbound run (integer, digit string, or leading #N
911
+ * token). Terminal rows match settlement (#881): accepted and audit-escalation —
912
+ * an escalated submission still carries the original role params. Later
913
+ * receipts remain untouched; prose note/report is never consulted; this seam
914
+ * does not adjudicate a ticket change. Runs in the public call's own process
915
+ * (no role leg writes the run's current.json).
916
+ */
917
+ export async function bindSealedTicketNumber(admitted: AdmittedRoleInvocation): Promise<void> {
918
+ if (admitted.ticketNumber !== undefined) return;
919
+ const rows = await readRecordedSubmissionRows(
920
+ admitted.projectRoot,
921
+ admitted.runId,
922
+ ledgerReadScope(admitted),
923
+ );
924
+ let ticketNumber: number | undefined;
925
+ for (const row of rows) {
926
+ if (
927
+ row.role !== admitted.role
928
+ || (row.kind !== "accepted" && row.kind !== "audit-escalation")
929
+ ) {
930
+ continue;
931
+ }
932
+ const payload = row.accepted;
933
+ if (!isRecord(payload)) continue;
934
+ ticketNumber = readDeclaredTicketNumber(
935
+ (payload as { ticketNumber?: unknown }).ticketNumber,
936
+ );
937
+ if (ticketNumber !== undefined) break;
938
+ }
939
+ if (ticketNumber !== undefined) await bindAdmittedTicketNumber(admitted, ticketNumber);
940
+ }
941
+
942
+ /**
943
+ * The ticket a diarist asserted on a completed submission, whether or not the
944
+ * rest of that submission was later accepted (a bounds reask does not unsay the
945
+ * ticket). Before this ran in the leg's accept hook; the leg now only appends its
946
+ * ledger rows and the public call's own process binds the ticket from them.
947
+ */
948
+ export async function bindDiaristAssertedTicketNumber(admitted: AdmittedRoleInvocation): Promise<void> {
949
+ if (admitted.ticketNumber !== undefined) return;
950
+ const rows = await readRecordedSubmissionRows(
951
+ admitted.projectRoot,
952
+ admitted.runId,
953
+ ledgerReadScope(admitted),
954
+ );
955
+ for (const row of rows) {
956
+ if (row.role !== admitted.role || !isRecord(row.accepted)) continue;
957
+ if (row.accepted.status !== "completed" || !("ticketNumber" in row.accepted)) continue;
958
+ const ticketNumber = parseTicketNumber(row.accepted.ticketNumber);
959
+ if (ticketNumber !== undefined) {
960
+ await bindAdmittedTicketNumber(admitted, ticketNumber);
961
+ return;
962
+ }
963
+ }
964
+ }
965
+
907
966
  export async function dispatchPostAdmissionTurn<
908
967
  A extends AdmittedRoleInvocation,
909
968
  T extends TerminalResult = TerminalResult,
@@ -991,6 +1050,7 @@ export async function dispatchPostAdmissionTurn<
991
1050
  io,
992
1051
  persistRunState,
993
1052
  courtScope.notePackageFault,
1053
+ courtScope.courtAttemptId,
994
1054
  )),
995
1055
  turnDispatched: true as const,
996
1056
  skipAutoResume: true as const,
@@ -1042,29 +1102,7 @@ export async function dispatchPostAdmissionTurn<
1042
1102
  // an escalated submission still carries the original role params.
1043
1103
  // Later receipts remain untouched; prose note/report is never consulted;
1044
1104
  // this seam does not adjudicate a ticket change.
1045
- if (admitted.ticketNumber === undefined) {
1046
- const rows = await readRecordedSubmissionRows(
1047
- admitted.projectRoot,
1048
- admitted.runId,
1049
- ledgerReadScope(admitted),
1050
- );
1051
- let ticketNumber: number | undefined;
1052
- for (const row of rows) {
1053
- if (
1054
- row.role !== admitted.role
1055
- || (row.kind !== "accepted" && row.kind !== "audit-escalation")
1056
- ) {
1057
- continue;
1058
- }
1059
- const payload = row.accepted;
1060
- if (!isRecord(payload)) continue;
1061
- ticketNumber = readDeclaredTicketNumber(
1062
- (payload as { ticketNumber?: unknown }).ticketNumber,
1063
- );
1064
- if (ticketNumber !== undefined) break;
1065
- }
1066
- if (ticketNumber !== undefined) await bindAdmittedTicketNumber(admitted, ticketNumber);
1067
- }
1105
+ await bindSealedTicketNumber(admitted);
1068
1106
  // #863: shared post-admission bind must relocate unbound→ticket in-home
1069
1107
  // before lease release (work-seat self-report and any prior board bind).
1070
1108
  const relocation = await relocateAdmittedRunToTicket(admitted, env.principalAuthority, lease);
@@ -1102,6 +1140,7 @@ export async function dispatchPostAdmissionTurn<
1102
1140
  io,
1103
1141
  persistRunState,
1104
1142
  courtScope.notePackageFault,
1143
+ courtScope.courtAttemptId,
1105
1144
  )) as { exitCode: number; admitted: A; terminal: T },
1106
1145
  ...(result.turnDispatched === true ? { turnDispatched: true as const } : {}),
1107
1146
  ...(result.skipAutoResume === true ? { skipAutoResume: true as const } : {}),
@@ -1140,6 +1179,7 @@ export async function dispatchPostAdmissionTurn<
1140
1179
  io,
1141
1180
  persistRunState,
1142
1181
  courtScope.notePackageFault,
1182
+ courtScope.courtAttemptId,
1143
1183
  )) as { exitCode: number; admitted: A; terminal: T };
1144
1184
  return { ...settled, ...deferredPersist };
1145
1185
  }
@@ -1160,7 +1200,7 @@ export async function dispatchPostAdmissionTurn<
1160
1200
  turnRequest = { ...turnRequest, stationChild: env.stationChild };
1161
1201
  }
1162
1202
  // Selected host axis rides the shared Host envelope for in-turn tools
1163
- // (detour usage ledger) — never a pre-spawn invocation.json reread.
1203
+ // (detour usage ledger) — never a pre-spawn current.json reread.
1164
1204
  if (typeof env.host === "string" && env.host.trim() !== "") {
1165
1205
  turnRequest = { ...turnRequest, host: env.host.trim() };
1166
1206
  }
@@ -1186,7 +1226,6 @@ export async function dispatchPostAdmissionTurn<
1186
1226
  // host CLI's native resume. Nothing here may gate, redirect or reshape
1187
1227
  // that dispatch on prior conclusions, row counts or report presence;
1188
1228
  // the authoritative post-turn settlement reads whatever really happened.
1189
- recordRunStart(admitted.runDirectory);
1190
1229
  turnDispatched = true;
1191
1230
  result = await env.roleTurnHost.executeTurn(turnRequest);
1192
1231
  } catch (error) {
@@ -1207,6 +1246,7 @@ export async function dispatchPostAdmissionTurn<
1207
1246
  io,
1208
1247
  persistRunState,
1209
1248
  courtScope.notePackageFault,
1249
+ courtScope.courtAttemptId,
1210
1250
  );
1211
1251
  return await finishAfterTurn(
1212
1252
  withProcessCancelSkipAutoResume(
@@ -1248,11 +1288,9 @@ export async function dispatchPostAdmissionTurn<
1248
1288
  let deliveryResult: RoleTurnResult;
1249
1289
  let deliveryTurnRequest: RoleTurnRequest;
1250
1290
  try {
1251
- const deliveryRequest = await buildReceiptDeliveryRequest({
1252
- admitted,
1253
- env,
1254
- // Host and the other axes already selected on this turn ride the
1255
- // shared projection. The pre-projection request does not have them.
1291
+ // Host and the other axes already selected on this turn ride the
1292
+ // shared projection. The pre-projection request does not have them.
1293
+ const deliveryRequest = buildReceiptDeliveryRequest({
1256
1294
  request: turnRequest,
1257
1295
  receiptDelivery,
1258
1296
  });
@@ -1281,6 +1319,8 @@ export async function dispatchPostAdmissionTurn<
1281
1319
  env.principalAuthority,
1282
1320
  io,
1283
1321
  persistRunState,
1322
+ courtScope.notePackageFault,
1323
+ courtScope.courtAttemptId,
1284
1324
  );
1285
1325
  return await finishAfterTurn(
1286
1326
  withProcessCancelSkipAutoResume(
@@ -1361,6 +1401,9 @@ export async function dispatchPostAdmissionTurn<
1361
1401
  deferredPersist,
1362
1402
  invocationScopeId: request.invocationScopeId,
1363
1403
  notePackageFault: courtScope.notePackageFault,
1404
+ ...(courtScope.courtAttemptId === undefined
1405
+ ? {}
1406
+ : { courtAttemptId: courtScope.courtAttemptId }),
1364
1407
  }),
1365
1408
  );
1366
1409
  }
@@ -1758,6 +1801,9 @@ export async function runPostAdmissionSeatResume<
1758
1801
  }
1759
1802
  }
1760
1803
 
1804
+ // Public explicit resume: attach the stored native id when the caller
1805
+ // left it unset (399c3c8c). In-call auto-resume / 催交 / gate retry omit
1806
+ // the field; those load inside the host adapter (host-contracts).
1761
1807
  let turnRequest = await input.buildTurnRequest(admittedForBuild, request);
1762
1808
  if (
1763
1809
  turnRequest.continuation.kind === "resume"
@@ -1872,7 +1918,7 @@ export async function runPostAdmissionSeatResume<
1872
1918
  await presentResumeFailurePointer(
1873
1919
  input.io,
1874
1920
  error,
1875
- (failure) => writeResumeDiagnosticFile(
1921
+ (failure) => writeResumeDiagnostic(
1876
1922
  loaded.admitted.runDirectory,
1877
1923
  loaded.admitted.runId,
1878
1924
  failure,
@@ -1904,13 +1950,13 @@ async function pointExistingRunFailure(
1904
1950
  record = await readRoleRunState(runDirectory, authority);
1905
1951
  } catch {
1906
1952
  await presentResumeFailurePointer(io, thrown, (failure) =>
1907
- writeResumeDiagnosticFile(runDirectory, runId, failure),
1953
+ writeResumeDiagnostic(runDirectory, runId, failure),
1908
1954
  );
1909
1955
  return true;
1910
1956
  }
1911
1957
  if (record === undefined) return false;
1912
1958
  await presentResumeFailurePointer(io, thrown, (failure) =>
1913
- writeResumeDiagnosticFile(runDirectory, runId, failure, record.role),
1959
+ writeResumeDiagnostic(runDirectory, runId, failure, record.role),
1914
1960
  );
1915
1961
  return true;
1916
1962
  }
@@ -1966,27 +2012,20 @@ async function presentResumeFailurePointer(
1966
2012
  }
1967
2013
  }
1968
2014
 
1969
- async function writeResumeDiagnosticFile(
2015
+ async function writeResumeDiagnostic(
1970
2016
  runDirectory: string,
1971
2017
  runId: string,
1972
2018
  failure: ControlledFailure,
1973
2019
  role?: AdmittedRoleInvocation["role"],
1974
2020
  ): Promise<string> {
1975
- const dir = await ensureRealArtifactsDirectory(runDirectory);
1976
- const path = join(dir, `resume-diagnostic-${randomUUID()}.json`);
1977
- await writeFile(
1978
- path,
1979
- `${JSON.stringify({
1980
- runId,
1981
- ...(role === undefined ? {} : { role }),
1982
- diagnostic: failure.diagnostic,
1983
- ...(failure.cause === undefined ? {} : { cause: failure.cause }),
1984
- ...(failure.identity === undefined ? {} : { identity: failure.identity }),
1985
- ...(failure.details === undefined ? {} : { details: failure.details }),
1986
- }, null, 2)}\n`,
1987
- { encoding: "utf8", flag: "wx" },
1988
- );
1989
- return path;
2021
+ return reportRunRecord(runDirectory, "resume-diagnostic", {
2022
+ runId,
2023
+ ...(role === undefined ? {} : { role }),
2024
+ diagnostic: failure.diagnostic,
2025
+ ...(failure.cause === undefined ? {} : { cause: failure.cause }),
2026
+ ...(failure.identity === undefined ? {} : { identity: failure.identity }),
2027
+ ...(failure.details === undefined ? {} : { details: failure.details }),
2028
+ }, "post-admission").recordFile;
1990
2029
  }
1991
2030
 
1992
2031
  /**