@akagilnc/pi-workflow-roles 0.1.5504 → 0.1.5575

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 (89) hide show
  1. package/README.md +1 -1
  2. package/README.zh-CN.md +1 -1
  3. package/dist/acp-host/production-host.js +5965 -5994
  4. package/dist/analyst-gate-cycles-read.js +23 -55
  5. package/dist/analyst-ledger.js +21 -35
  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-pointer.js +38 -30
  9. package/dist/auditor-dossier-tool.js +4 -3
  10. package/dist/auditor-soul.js +3 -11
  11. package/dist/doctor-evidence.js +3 -3
  12. package/dist/engine-detour-usage.js +6 -14
  13. package/dist/headless-host/production-host.js +5316 -5324
  14. package/dist/host-descriptions.js +0 -4
  15. package/dist/host-session-record.js +266 -267
  16. package/dist/migrate-book-topology.js +1314 -696
  17. package/dist/notary-source-run.js +1 -1
  18. package/dist/packaged-role-registry.js +5 -44
  19. package/dist/pi/role-turn-host.js +53 -3
  20. package/dist/public-cli/auto-resume.js +8 -47
  21. package/dist/public-cli/instruction-seat-run.js +5 -3
  22. package/dist/public-cli/invocation.js +51 -56
  23. package/dist/public-cli/main.js +1916 -1748
  24. package/dist/public-cli/post-admission.js +96 -55
  25. package/dist/public-cli/run-lifecycle.js +27 -53
  26. package/dist/public-cli/settlement.js +157 -302
  27. package/dist/role-run-placement.js +1 -11
  28. package/dist/role-run-relocation.js +72 -50
  29. package/dist/run-dossier-files.js +30 -0
  30. package/dist/run-dossier.js +322 -0
  31. package/dist/run-terminal-artifacts.js +68 -197
  32. package/dist/run-ticket-number.js +16 -3
  33. package/dist/session-identity.js +49 -18
  34. package/dist/sitian-appender.js +13 -16
  35. package/dist/sitian-facade.js +11 -0
  36. package/dist/sitian-reader.js +44 -29
  37. package/dist/submission-gate.js +1 -1
  38. package/dist/ticket-provenance.js +22 -7
  39. package/package.json +1 -1
  40. package/scripts/build-package.mjs +2 -0
  41. package/src/acp-host/production-host.ts +1 -1
  42. package/src/acp-host/role-turn-host.ts +9 -2
  43. package/src/analyst-gate-cycles-read.ts +26 -60
  44. package/src/analyst-ledger.ts +27 -42
  45. package/src/analyst-metric-families/acceptance-success-rework.ts +24 -1
  46. package/src/analyst-metric-families/gate-cycles.ts +1 -1
  47. package/src/analyst-metric-families/round-timeline.ts +2 -5
  48. package/src/analyst-page.ts +3 -3
  49. package/src/archivist-record-entry.ts +2 -2
  50. package/src/archivist-record-pointer.ts +50 -36
  51. package/src/auditor-dossier-tool.ts +7 -5
  52. package/src/auditor-soul.ts +3 -9
  53. package/src/book-topology-migration-placement.ts +16 -3
  54. package/src/book-topology-record-class-migrators.ts +4 -2
  55. package/src/book-topology-runs-migrator.ts +6 -3
  56. package/src/doctor-contracts.ts +1 -1
  57. package/src/doctor-evidence.ts +2 -2
  58. package/src/engine-detour-tool.ts +1 -1
  59. package/src/engine-detour-usage.ts +6 -16
  60. package/src/external-host-turn-loop.ts +25 -0
  61. package/src/headless-host/production-host.ts +1 -4
  62. package/src/headless-host/role-turn-host.ts +54 -20
  63. package/src/host-descriptions.ts +0 -6
  64. package/src/host-session-record.ts +224 -140
  65. package/src/notary-source-run.ts +1 -1
  66. package/src/packaged-role-registry.ts +1 -50
  67. package/src/pi/adapter.ts +50 -7
  68. package/src/pi/role-turn-host.ts +51 -3
  69. package/src/public-cli/auto-resume.ts +7 -43
  70. package/src/public-cli/instruction-seat-run.ts +9 -2
  71. package/src/public-cli/invocation.ts +61 -87
  72. package/src/public-cli/post-admission.ts +111 -72
  73. package/src/public-cli/run-lifecycle.ts +27 -72
  74. package/src/public-cli/settlement.ts +193 -418
  75. package/src/public-cli/terminal.ts +1 -1
  76. package/src/role-run-placement.ts +2 -13
  77. package/src/role-run-relocation.ts +71 -68
  78. package/src/role-runtime.ts +6 -10
  79. package/src/run-dossier-files.ts +33 -0
  80. package/src/run-dossier.ts +357 -0
  81. package/src/run-terminal-artifacts.ts +83 -237
  82. package/src/run-ticket-number.ts +41 -11
  83. package/src/session-identity.ts +52 -20
  84. package/src/sitian-appender.ts +17 -18
  85. package/src/sitian-facade.ts +22 -0
  86. package/src/sitian-reader.ts +62 -32
  87. package/src/submission-gate.ts +1 -1
  88. package/src/ticket-provenance.ts +20 -7
  89. package/src/ticket-trajectory.ts +10 -10
@@ -13,10 +13,11 @@ import { CliUsageError } from "./cli-errors.js";
13
13
  import { projectPublicTurnAxes } from "./turn-request.js";
14
14
  import { bindAdmittedTicketNumber, buildInstructionTransportPrompt, freezeAttachmentsIntoRun, relocateAdmittedRunToTicket, } from "./invocation.js";
15
15
  import { readRecordedSubmissionRows } from "../submission-ledger.js";
16
- import { readDeclaredTicketNumber } from "../run-ticket-number.js";
16
+ import { parseTicketNumber, readDeclaredTicketNumber } from "../run-ticket-number.js";
17
17
  import { pathContainedIn } from "../activation-ledger-topology.js";
18
18
  import { pickEngineAxis } from "../package-resources/engine-material.js";
19
19
  import { readStoredHostSessionId } from "../session-identity.js";
20
+ import { reportRunRecord } from "../sitian-facade.js";
20
21
  import { createReceiptDeliveryPolicy, deliveryLimitFromConfig, } from "../receipt-delivery-policy.js";
21
22
  import { rewriteRunDirectoryPathValue } from "../role-run-relocation.js";
22
23
  import { isOfficerReviewSeat } from "../packaged-role-registry.js";
@@ -40,10 +41,9 @@ import { mintEngineDetourInvocationScope, withEngineDetourInvocationScope, } fro
40
41
  import { clearCurrentCourt, describeErrorIdentity, markRunRunning, readCurrentCourt, recordCurrentCourt, } from "./run-lifecycle.js";
41
42
  import { processCancelDiagnostic, processCancelSignalName, } from "./process-cancel.js";
42
43
  import { DEFAULT_ROLE_TURN_HOST } from "../host-descriptions.js";
43
- import { recordRunStart } from "../host-session-record.js";
44
44
  import { classifyPostAdmissionFailure, exitCodeForTerminalOutcome, explicitInternalKnownFailureClassificationInput, formatCliDiagnostic, formatErrorCauseDetail, ledgerReadScope, isLawfulTypedTerminalOutcome, presentStructuralRejection, settleFailureTerminalResult, settleHostEndedNoReceipt, noteSettlementFault, attachRecordedSubmissions, retainPackageFault, } from "./settlement.js";
45
45
  import {} from "./terminal.js";
46
- import { ensureRealArtifactsDirectory, persistReturnedRunState, presentTerminal, runWithAutoResumeLoop, TurnDispatchedFailure, } from "./auto-resume.js";
46
+ import { persistReturnedRunState, presentTerminal, runWithAutoResumeLoop, TurnDispatchedFailure, } from "./auto-resume.js";
47
47
  import { isRecord, errorText } from "../unknown-value.js";
48
48
  function projectRelocatedTurnIdentity(request, result, admitted, relocation) {
49
49
  const rewrite = (value) => rewriteRunDirectoryPathValue(value, relocation.oldRunDirectory, relocation.newRunDirectory);
@@ -87,7 +87,7 @@ async function settleProcessCancelAfterTurn(input) {
87
87
  ? { knownDiagnostic: processCancelDiagnostic(input.cancelName) }
88
88
  : { knownFailure: input.result.knownFailure }),
89
89
  cancelName: input.cancelName,
90
- }, input.invocationScopeId), input.adapters, input.env.principalAuthority, input.io, input.persistRunState, input.notePackageFault);
90
+ }, input.invocationScopeId), input.adapters, input.env.principalAuthority, input.io, input.persistRunState, input.notePackageFault, input.courtAttemptId);
91
91
  return {
92
92
  ...failed,
93
93
  turnDispatched: true,
@@ -170,7 +170,9 @@ export async function resolveResumeMethodMaterialAdapters(input) {
170
170
  return { kind: "terminal", ...terminal };
171
171
  }
172
172
  }
173
- export async function presentControlledFailure(admitted, failureInput, adapters, authority, io, persistRunState = true, notePackageFault) {
173
+ export async function presentControlledFailure(admitted, failureInput, adapters, authority, io, persistRunState = true, notePackageFault,
174
+ /** Open-court identity already on the turn request / currentCourt (#1161). */
175
+ courtAttemptId) {
174
176
  const hasThrown = Object.hasOwn(failureInput, "thrown");
175
177
  const knownFailure = failureInput.knownFailure;
176
178
  // knownFailure channel owns details when present; otherwise caller knownDetails.
@@ -231,6 +233,9 @@ export async function presentControlledFailure(admitted, failureInput, adapters,
231
233
  const settled = await settleFailureTerminalResult(admitted, failure, authority, {
232
234
  recordAttemptHistory: true,
233
235
  ...(notePackageFault === undefined ? {} : { notePackageFault }),
236
+ ...(courtAttemptId === undefined || courtAttemptId.length === 0
237
+ ? {}
238
+ : { courtAttemptId }),
234
239
  ...(failureInput.invocationScopeId === undefined ||
235
240
  failureInput.invocationScopeId.length === 0
236
241
  ? {}
@@ -263,9 +268,9 @@ export async function presentControlledFailure(admitted, failureInput, adapters,
263
268
  * the true cause through its own existing dispatch-exception machinery once
264
269
  * the retry budget is exhausted.
265
270
  */
266
- async function settleAfterTurnStarted(admitted, failureInput, adapters, authority, io, persistRunState, notePackageFault) {
271
+ async function settleAfterTurnStarted(admitted, failureInput, adapters, authority, io, persistRunState, notePackageFault, courtAttemptId) {
267
272
  try {
268
- return (await presentControlledFailure(admitted, failureInput, adapters, authority, io, persistRunState, notePackageFault));
273
+ return (await presentControlledFailure(admitted, failureInput, adapters, authority, io, persistRunState, notePackageFault, courtAttemptId));
269
274
  }
270
275
  catch (error) {
271
276
  throw new TurnDispatchedFailure(error);
@@ -321,9 +326,9 @@ function settlementScopeForTurn(request) {
321
326
  *
322
327
  * The caller owns the live delivery policy; the request projects its next send.
323
328
  */
324
- async function buildReceiptDeliveryRequest(input) {
325
- const { admitted, env, request, receiptDelivery } = input;
326
- const hostSessionId = await readStoredHostSessionId(env.host, env.principalAuthority, admitted.principal);
329
+ /** Bare in-call催交 resume: hostSessionId absent; adapter is the sole load authority. */
330
+ function buildReceiptDeliveryRequest(input) {
331
+ const { request, receiptDelivery } = input;
327
332
  return {
328
333
  ...request,
329
334
  continuation: {
@@ -332,7 +337,6 @@ async function buildReceiptDeliveryRequest(input) {
332
337
  ...receiptDelivery.deliveryState(),
333
338
  deliveryTurns: receiptDelivery.issuedDeliveryRequests() + 1,
334
339
  }),
335
- ...(hostSessionId === undefined ? {} : { hostSessionId }),
336
340
  },
337
341
  deliveryRequestLimit: receiptDelivery.limit,
338
342
  };
@@ -378,19 +382,19 @@ async function settleCompletedHostTurn(input) {
378
382
  // machinery once the retry budget is exhausted.
379
383
  let stderrLogWriteFailure;
380
384
  try {
381
- await writeFile(join(admitted.runDirectory, "stderr.log"), result.stderr, "utf8");
385
+ reportRunRecord(admitted.runDirectory, "stderr", { text: result.stderr }, "post-admission");
382
386
  }
383
387
  catch (error) {
384
388
  stderrLogWriteFailure = error;
385
- // Best-effort: stderr.log is secondary to the host terminal. A write
389
+ // Best-effort: the stderr log line is secondary to the host terminal. A write
386
390
  // failure leaves a durable note and, on a host failure, rides in
387
391
  // packageFact. It does not become the cause.
388
- await recordBestEffortPostDispatchDiagnostic(admitted, env, `stderr.log write failed (best-effort continue): ${describeErrorIdentity(error)}`, io);
392
+ await recordBestEffortPostDispatchDiagnostic(admitted, env, `stderr log write failed (best-effort continue): ${describeErrorIdentity(error)}`, io);
389
393
  }
390
394
  // Host facts are resolved before trySettle. A host failure skips trySettle
391
395
  // so a later read cannot replace that report. A clean host whose settlement
392
396
  // read throws is noted above and is not turned into a failure terminal.
393
- // stderr.log and run-state writes are notes beside the host terminal.
397
+ // the stderr log line and run-state writes are notes beside the host terminal.
394
398
  let settled;
395
399
  let settledOutcome;
396
400
  // The host CLI's own report: timeout, declared failure, cancel, or exit.
@@ -440,6 +444,9 @@ async function settleCompletedHostTurn(input) {
440
444
  deferredPersist,
441
445
  invocationScopeId: request.invocationScopeId,
442
446
  notePackageFault: courtScope.notePackageFault,
447
+ ...(courtScope.courtAttemptId === undefined
448
+ ? {}
449
+ : { courtAttemptId: courtScope.courtAttemptId }),
443
450
  })) };
444
451
  }
445
452
  if (persistRunState) {
@@ -476,11 +483,62 @@ async function settleCompletedHostTurn(input) {
476
483
  // Secondary fact only — never the cause, and never merged into the
477
484
  // host's own details.
478
485
  ...(stderrLogWriteFact === undefined ? {} : { packageFact: stderrLogWriteFact }),
479
- }, request.invocationScopeId), adapters, env.principalAuthority, io, persistRunState, courtScope.notePackageFault);
486
+ }, request.invocationScopeId), adapters, env.principalAuthority, io, persistRunState, courtScope.notePackageFault, courtScope.courtAttemptId);
480
487
  return { kind: "settled", outcome: await finishAfterTurn(withProcessCancelSkipAutoResume({ ...failed, turnDispatched: true, ...deferredPersist }, env.signal)) };
481
488
  }
482
489
  return { kind: "still-missing" };
483
490
  }
491
+ /**
492
+ * #858 / #1071: the first identifiable ticketNumber field declaration among the
493
+ * run's sealed rows files an unbound run (integer, digit string, or leading #N
494
+ * token). Terminal rows match settlement (#881): accepted and audit-escalation —
495
+ * an escalated submission still carries the original role params. Later
496
+ * receipts remain untouched; prose note/report is never consulted; this seam
497
+ * does not adjudicate a ticket change. Runs in the public call's own process
498
+ * (no role leg writes the run's current.json).
499
+ */
500
+ export async function bindSealedTicketNumber(admitted) {
501
+ if (admitted.ticketNumber !== undefined)
502
+ return;
503
+ const rows = await readRecordedSubmissionRows(admitted.projectRoot, admitted.runId, ledgerReadScope(admitted));
504
+ let ticketNumber;
505
+ for (const row of rows) {
506
+ if (row.role !== admitted.role
507
+ || (row.kind !== "accepted" && row.kind !== "audit-escalation")) {
508
+ continue;
509
+ }
510
+ const payload = row.accepted;
511
+ if (!isRecord(payload))
512
+ continue;
513
+ ticketNumber = readDeclaredTicketNumber(payload.ticketNumber);
514
+ if (ticketNumber !== undefined)
515
+ break;
516
+ }
517
+ if (ticketNumber !== undefined)
518
+ await bindAdmittedTicketNumber(admitted, ticketNumber);
519
+ }
520
+ /**
521
+ * The ticket a diarist asserted on a completed submission, whether or not the
522
+ * rest of that submission was later accepted (a bounds reask does not unsay the
523
+ * ticket). Before this ran in the leg's accept hook; the leg now only appends its
524
+ * ledger rows and the public call's own process binds the ticket from them.
525
+ */
526
+ export async function bindDiaristAssertedTicketNumber(admitted) {
527
+ if (admitted.ticketNumber !== undefined)
528
+ return;
529
+ const rows = await readRecordedSubmissionRows(admitted.projectRoot, admitted.runId, ledgerReadScope(admitted));
530
+ for (const row of rows) {
531
+ if (row.role !== admitted.role || !isRecord(row.accepted))
532
+ continue;
533
+ if (row.accepted.status !== "completed" || !("ticketNumber" in row.accepted))
534
+ continue;
535
+ const ticketNumber = parseTicketNumber(row.accepted.ticketNumber);
536
+ if (ticketNumber !== undefined) {
537
+ await bindAdmittedTicketNumber(admitted, ticketNumber);
538
+ return;
539
+ }
540
+ }
541
+ }
484
542
  export async function dispatchPostAdmissionTurn(input) {
485
543
  const { admitted, env, io, request, lease, adapters, effectiveEngine } = input;
486
544
  const persistRunState = input.persistRunState !== false;
@@ -533,7 +591,7 @@ export async function dispatchPostAdmissionTurn(input) {
533
591
  knownDiagnostic: processCancelDiagnostic(cancelBeforeFinish),
534
592
  cancelName: cancelBeforeFinish,
535
593
  skipRunStateWrite: true,
536
- }, request.invocationScopeId), adapters, env.principalAuthority, io, persistRunState, courtScope.notePackageFault)),
594
+ }, request.invocationScopeId), adapters, env.principalAuthority, io, persistRunState, courtScope.notePackageFault, courtScope.courtAttemptId)),
537
595
  turnDispatched: true,
538
596
  skipAutoResume: true,
539
597
  ...deferredPersist,
@@ -575,24 +633,7 @@ export async function dispatchPostAdmissionTurn(input) {
575
633
  // an escalated submission still carries the original role params.
576
634
  // Later receipts remain untouched; prose note/report is never consulted;
577
635
  // this seam does not adjudicate a ticket change.
578
- if (admitted.ticketNumber === undefined) {
579
- const rows = await readRecordedSubmissionRows(admitted.projectRoot, admitted.runId, ledgerReadScope(admitted));
580
- let ticketNumber;
581
- for (const row of rows) {
582
- if (row.role !== admitted.role
583
- || (row.kind !== "accepted" && row.kind !== "audit-escalation")) {
584
- continue;
585
- }
586
- const payload = row.accepted;
587
- if (!isRecord(payload))
588
- continue;
589
- ticketNumber = readDeclaredTicketNumber(payload.ticketNumber);
590
- if (ticketNumber !== undefined)
591
- break;
592
- }
593
- if (ticketNumber !== undefined)
594
- await bindAdmittedTicketNumber(admitted, ticketNumber);
595
- }
636
+ await bindSealedTicketNumber(admitted);
596
637
  // #863: shared post-admission bind must relocate unbound→ticket in-home
597
638
  // before lease release (work-seat self-report and any prior board bind).
598
639
  const relocation = await relocateAdmittedRunToTicket(admitted, env.principalAuthority, lease);
@@ -618,7 +659,7 @@ export async function dispatchPostAdmissionTurn(input) {
618
659
  code: null,
619
660
  stderr: "",
620
661
  thrown: error,
621
- }, request.invocationScopeId), adapters, env.principalAuthority, io, persistRunState, courtScope.notePackageFault)),
662
+ }, request.invocationScopeId), adapters, env.principalAuthority, io, persistRunState, courtScope.notePackageFault, courtScope.courtAttemptId)),
622
663
  ...(result.turnDispatched === true ? { turnDispatched: true } : {}),
623
664
  ...(result.skipAutoResume === true ? { skipAutoResume: true } : {}),
624
665
  ...deferredPersist,
@@ -649,7 +690,7 @@ export async function dispatchPostAdmissionTurn(input) {
649
690
  code: null,
650
691
  stderr: "",
651
692
  thrown: error,
652
- }, request.invocationScopeId), adapters, env.principalAuthority, io, persistRunState, courtScope.notePackageFault));
693
+ }, request.invocationScopeId), adapters, env.principalAuthority, io, persistRunState, courtScope.notePackageFault, courtScope.courtAttemptId));
653
694
  return { ...settled, ...deferredPersist };
654
695
  }
655
696
  }
@@ -668,7 +709,7 @@ export async function dispatchPostAdmissionTurn(input) {
668
709
  turnRequest = { ...turnRequest, stationChild: env.stationChild };
669
710
  }
670
711
  // Selected host axis rides the shared Host envelope for in-turn tools
671
- // (detour usage ledger) — never a pre-spawn invocation.json reread.
712
+ // (detour usage ledger) — never a pre-spawn current.json reread.
672
713
  if (typeof env.host === "string" && env.host.trim() !== "") {
673
714
  turnRequest = { ...turnRequest, host: env.host.trim() };
674
715
  }
@@ -685,7 +726,6 @@ export async function dispatchPostAdmissionTurn(input) {
685
726
  // host CLI's native resume. Nothing here may gate, redirect or reshape
686
727
  // that dispatch on prior conclusions, row counts or report presence;
687
728
  // the authoritative post-turn settlement reads whatever really happened.
688
- recordRunStart(admitted.runDirectory);
689
729
  turnDispatched = true;
690
730
  result = await env.roleTurnHost.executeTurn(turnRequest);
691
731
  }
@@ -699,7 +739,7 @@ export async function dispatchPostAdmissionTurn(input) {
699
739
  // call is a second fact; it must not become a new Error in its place.
700
740
  ...(processCancelName === undefined ? {} : { cancelName: processCancelName }),
701
741
  thrown: error,
702
- }, request.invocationScopeId), adapters, env.principalAuthority, io, persistRunState, courtScope.notePackageFault);
742
+ }, request.invocationScopeId), adapters, env.principalAuthority, io, persistRunState, courtScope.notePackageFault, courtScope.courtAttemptId);
703
743
  return await finishAfterTurn(withProcessCancelSkipAutoResume({ ...settled, turnDispatched: true, ...deferredPersist }, env.signal));
704
744
  }
705
745
  // #1132: settle this turn through the ONE post-turn settlement authority,
@@ -734,11 +774,9 @@ export async function dispatchPostAdmissionTurn(input) {
734
774
  let deliveryResult;
735
775
  let deliveryTurnRequest;
736
776
  try {
737
- const deliveryRequest = await buildReceiptDeliveryRequest({
738
- admitted,
739
- env,
740
- // Host and the other axes already selected on this turn ride the
741
- // shared projection. The pre-projection request does not have them.
777
+ // Host and the other axes already selected on this turn ride the
778
+ // shared projection. The pre-projection request does not have them.
779
+ const deliveryRequest = buildReceiptDeliveryRequest({
742
780
  request: turnRequest,
743
781
  receiptDelivery,
744
782
  });
@@ -758,7 +796,7 @@ export async function dispatchPostAdmissionTurn(input) {
758
796
  // its true cause, through the one settlement authority (ADR 0080).
759
797
  // The turn started, so the caller's loop resumes instead of replaying
760
798
  // the initial payload. The issued count survives that re-entry.
761
- const settled = await settleAfterTurnStarted(admitted, withEngineDetourInvocationScope({ timedOut: false, code: null, stderr: "", thrown: error }, request.invocationScopeId), adapters, env.principalAuthority, io, persistRunState);
799
+ const settled = await settleAfterTurnStarted(admitted, withEngineDetourInvocationScope({ timedOut: false, code: null, stderr: "", thrown: error }, request.invocationScopeId), adapters, env.principalAuthority, io, persistRunState, courtScope.notePackageFault, courtScope.courtAttemptId);
762
800
  return await finishAfterTurn(withProcessCancelSkipAutoResume({
763
801
  ...settled,
764
802
  turnDispatched: true,
@@ -818,6 +856,9 @@ export async function dispatchPostAdmissionTurn(input) {
818
856
  deferredPersist,
819
857
  invocationScopeId: request.invocationScopeId,
820
858
  notePackageFault: courtScope.notePackageFault,
859
+ ...(courtScope.courtAttemptId === undefined
860
+ ? {}
861
+ : { courtAttemptId: courtScope.courtAttemptId }),
821
862
  }));
822
863
  }
823
864
  if (persistRunState) {
@@ -1111,6 +1152,9 @@ export async function runPostAdmissionSeatResume(input) {
1111
1152
  };
1112
1153
  }
1113
1154
  }
1155
+ // Public explicit resume: attach the stored native id when the caller
1156
+ // left it unset (399c3c8c). In-call auto-resume / 催交 / gate retry omit
1157
+ // the field; those load inside the host adapter (host-contracts).
1114
1158
  let turnRequest = await input.buildTurnRequest(admittedForBuild, request);
1115
1159
  if (turnRequest.continuation.kind === "resume"
1116
1160
  && turnRequest.continuation.hostSessionId === undefined) {
@@ -1211,7 +1255,7 @@ export async function runPostAdmissionSeatResume(input) {
1211
1255
  catch (error) {
1212
1256
  if (error instanceof TurnDispatchedFailure)
1213
1257
  throw error;
1214
- await presentResumeFailurePointer(input.io, error, (failure) => writeResumeDiagnosticFile(loaded.admitted.runDirectory, loaded.admitted.runId, failure, loaded.admitted.role));
1258
+ await presentResumeFailurePointer(input.io, error, (failure) => writeResumeDiagnostic(loaded.admitted.runDirectory, loaded.admitted.runId, failure, loaded.admitted.role));
1215
1259
  return { exitCode: error instanceof CliUsageError ? 2 : 1 };
1216
1260
  }
1217
1261
  }
@@ -1231,12 +1275,12 @@ async function pointExistingRunFailure(home, runId, authority, io, thrown) {
1231
1275
  record = await readRoleRunState(runDirectory, authority);
1232
1276
  }
1233
1277
  catch {
1234
- await presentResumeFailurePointer(io, thrown, (failure) => writeResumeDiagnosticFile(runDirectory, runId, failure));
1278
+ await presentResumeFailurePointer(io, thrown, (failure) => writeResumeDiagnostic(runDirectory, runId, failure));
1235
1279
  return true;
1236
1280
  }
1237
1281
  if (record === undefined)
1238
1282
  return false;
1239
- await presentResumeFailurePointer(io, thrown, (failure) => writeResumeDiagnosticFile(runDirectory, runId, failure, record.role));
1283
+ await presentResumeFailurePointer(io, thrown, (failure) => writeResumeDiagnostic(runDirectory, runId, failure, record.role));
1240
1284
  return true;
1241
1285
  }
1242
1286
  export async function presentLocatedResumeFailure(home, runId, authority, io, thrown) {
@@ -1275,18 +1319,15 @@ async function presentResumeFailurePointer(io, thrown, publish) {
1275
1319
  }, io);
1276
1320
  }
1277
1321
  }
1278
- async function writeResumeDiagnosticFile(runDirectory, runId, failure, role) {
1279
- const dir = await ensureRealArtifactsDirectory(runDirectory);
1280
- const path = join(dir, `resume-diagnostic-${randomUUID()}.json`);
1281
- await writeFile(path, `${JSON.stringify({
1322
+ async function writeResumeDiagnostic(runDirectory, runId, failure, role) {
1323
+ return reportRunRecord(runDirectory, "resume-diagnostic", {
1282
1324
  runId,
1283
1325
  ...(role === undefined ? {} : { role }),
1284
1326
  diagnostic: failure.diagnostic,
1285
1327
  ...(failure.cause === undefined ? {} : { cause: failure.cause }),
1286
1328
  ...(failure.identity === undefined ? {} : { identity: failure.identity }),
1287
1329
  ...(failure.details === undefined ? {} : { details: failure.details }),
1288
- }, null, 2)}\n`, { encoding: "utf8", flag: "wx" });
1289
- return path;
1330
+ }, "post-admission").recordFile;
1290
1331
  }
1291
1332
  /**
1292
1333
  * Shared post-admission one-shot path: folds into runPostAdmissionResumable (#840 / #416).
@@ -16,6 +16,7 @@ import { retainedRunPathsMatch, rewriteAdmittedRoleRunPage, rewriteRunDirectoryP
16
16
  import { appendEngineSessionMaterial, engineSessionMaterialFromOptions, pickEngineAxis, } from "../package-resources/engine-material.js";
17
17
  import { packagedResumeSourcePath, packagedRoleMetadata, } from "../packaged-role-registry.js";
18
18
  import { admittedReviewerBaseFault, recordEffectiveInvocationModel, requireAuthorityRef, isReviewerLens, } from "./invocation.js";
19
+ import { readPageSync, writeSectionSync } from "../run-dossier.js";
19
20
  import { isRecord, errorText, isEnoent } from "../unknown-value.js";
20
21
  /** Default for the #422 configurable single-call auto-resume ceiling
21
22
  * (public-cli.json top-level `autoResumeLimit`). No longer the runtime truth
@@ -41,11 +42,10 @@ export function buildAutoResumeContinuationPrompt(options) {
41
42
  ...pickEngineAxis(options),
42
43
  })).join("\n");
43
44
  }
44
- const RUN_STATE_FILE = "run-state.json";
45
45
  const WRITER_LOCK_FILE = "writer.lock";
46
46
  export async function writeRoleRunState(runDirectory, record) {
47
47
  const payload = { ...record, runDirectory };
48
- await writeFile(join(runDirectory, RUN_STATE_FILE), `${JSON.stringify(payload, null, 2)}\n`, "utf8");
48
+ writeSectionSync(runDirectory, "runState", { ...payload });
49
49
  }
50
50
  function parseSameTicketSummonsMaterials(raw) {
51
51
  if (!isRecord(raw))
@@ -106,43 +106,34 @@ function parseCurrentCourtState(raw) {
106
106
  };
107
107
  }
108
108
  async function readRoleRunStateRaw(runDirectory) {
109
- let raw;
110
- try {
111
- raw = JSON.parse(await readFile(join(runDirectory, RUN_STATE_FILE), "utf8"));
112
- }
113
- catch (error) {
114
- // Only true absence (ENOENT) is a lawful "no run state yet". A real read
115
- // failure (EISDIR, EACCES, ...) or a JSON.parse SyntaxError on a present
116
- // file is genuine infrastructure/data damage and must keep its own
117
- // identity — callers route it through the controlled-failure seam
118
- // (markRunRunning/markRunTerminal/recordCurrentCourt)
119
- // instead of it being relabeled "run state missing" (#836).
120
- if (errorCodeOf(error) === "ENOENT")
121
- return undefined;
122
- throw error;
123
- }
124
- return raw;
109
+ // Only true absence (no state.jsonl run-state row) is a lawful "no run state
110
+ // yet". A real read failure (EISDIR, EACCES, ...) or an illegal latest payload
111
+ // is genuine infrastructure/data damage and must keep its own identity —
112
+ // callers route it through the controlled-failure seam
113
+ // (markRunRunning/markRunTerminal/recordCurrentCourt) instead of it being
114
+ // relabeled "run state missing" (#836). readPageSync throws those.
115
+ return readPageSync(runDirectory, "runState");
125
116
  }
126
117
  function parseRoleRunIdentity(raw, runDirectory) {
127
118
  if (!isRecord(raw)) {
128
- throw new TypeError("Invalid run-state.json");
119
+ throw new TypeError("Invalid state.jsonl run-state");
129
120
  }
130
121
  const record = raw;
131
122
  if (typeof record.runId !== "string" || record.runId.trim() === "") {
132
- throw new TypeError("Invalid run-state.json");
123
+ throw new TypeError("Invalid state.jsonl run-state");
133
124
  }
134
125
  const role = typeof record.role === "string" ? packagedRoleMetadata(record.role)?.role : undefined;
135
126
  if (role === undefined) {
136
- throw new TypeError("Invalid run-state.json");
127
+ throw new TypeError("Invalid state.jsonl run-state");
137
128
  }
138
129
  if (record.state !== "admitted" &&
139
130
  record.state !== "running" &&
140
131
  record.state !== "resumable" &&
141
132
  record.state !== "terminal") {
142
- throw new TypeError("Invalid run-state.json");
133
+ throw new TypeError("Invalid state.jsonl run-state");
143
134
  }
144
135
  if (typeof record.bookKey !== "string")
145
- throw new TypeError("Invalid run-state.json");
136
+ throw new TypeError("Invalid state.jsonl run-state");
146
137
  return {
147
138
  runId: record.runId,
148
139
  role,
@@ -158,11 +149,9 @@ async function readRoleRunStateDisk(runDirectory) {
158
149
  const identity = parseRoleRunIdentity(raw, runDirectory);
159
150
  const record = raw;
160
151
  if (typeof record.projectRoot !== "string")
161
- throw new TypeError("Invalid run-state.json");
152
+ throw new TypeError("Invalid state.jsonl run-state");
162
153
  if (typeof record.sessionDirectory !== "string")
163
- throw new TypeError("Invalid run-state.json");
164
- if (typeof record.admittedRequestPath !== "string")
165
- throw new TypeError("Invalid run-state.json");
154
+ throw new TypeError("Invalid state.jsonl run-state");
166
155
  const storedRunDirectory = typeof record.runDirectory === "string" && record.runDirectory.trim() !== ""
167
156
  ? record.runDirectory
168
157
  : runDirectory;
@@ -185,7 +174,6 @@ async function readRoleRunStateDisk(runDirectory) {
185
174
  bookKey: identity.bookKey,
186
175
  projectRoot: record.projectRoot,
187
176
  runDirectory: runDir,
188
- admittedRequestPath: rewriteRunDirectoryPathValue(record.admittedRequestPath, storedRunDirectory, runDirectory),
189
177
  principalWire,
190
178
  ...(phase === undefined ? {} : { phase }),
191
179
  ...(currentCourt === undefined ? {} : { currentCourt }),
@@ -203,11 +191,10 @@ async function writeRoleRunStateDisk(runDirectory, disk) {
203
191
  ...(disk.principalWire.sessionFile === undefined
204
192
  ? {}
205
193
  : { sessionFile: disk.principalWire.sessionFile }),
206
- admittedRequestPath: disk.admittedRequestPath,
207
194
  ...(disk.phase === undefined ? {} : { phase: disk.phase }),
208
195
  ...(disk.currentCourt === undefined ? {} : { currentCourt: disk.currentCourt }),
209
196
  };
210
- await writeFile(join(runDirectory, RUN_STATE_FILE), `${JSON.stringify(payload, null, 2)}\n`, "utf8");
197
+ writeSectionSync(runDirectory, "runState", payload);
211
198
  }
212
199
  /** One authority.decode of the uninterpreted wire → record + opaque principal (frozen wire itself). */
213
200
  function materializeRoleRunFromDisk(disk, authority) {
@@ -224,7 +211,6 @@ function materializeRoleRunFromDisk(disk, authority) {
224
211
  sessionDirectory: coordinates.sessionDirectory,
225
212
  sessionFile: coordinates.sessionFile,
226
213
  runDirectory: disk.runDirectory,
227
- admittedRequestPath: disk.admittedRequestPath,
228
214
  ...(disk.phase === undefined ? {} : { phase: disk.phase }),
229
215
  },
230
216
  };
@@ -265,14 +251,13 @@ export async function markRunAdmitted(admitted, authority) {
265
251
  projectRoot: admitted.projectRoot,
266
252
  sessionDirectory,
267
253
  sessionFile,
268
- admittedRequestPath: admitted.admittedRequestPath,
269
254
  ...(workerPhase === undefined ? {} : { phase: workerPhase }),
270
255
  });
271
256
  }
272
257
  /**
273
258
  * Shared dispatch execution seam: transition to running, then record the
274
259
  * effective launch model (initial or resume override) and the authoritative
275
- * seat engine/host onto invocation.json.
260
+ * seat engine/host onto the invocation section.
276
261
  * Role runners must not coordinate lifecycle ledger writes themselves.
277
262
  * Engine axis is authoritative here (#617): present string is written; omit/undefined
278
263
  * clears any prior engine key so unset-engine + resume does not keep a stale value.
@@ -664,19 +649,9 @@ export function parentRunPathFromGatePointerInstruction(instruction) {
664
649
  * Missing page → undefined; damage / non-ENOENT IO propagates.
665
650
  */
666
651
  export async function readRunParentPath(runDirectory) {
667
- let raw;
668
- try {
669
- raw = JSON.parse(await readFile(join(runDirectory, "admitted-request.json"), "utf8"));
670
- }
671
- catch (error) {
672
- if (errorCodeOf(error) === "ENOENT")
673
- return undefined;
674
- throw error;
675
- }
676
- if (!isRecord(raw)) {
652
+ const record = readPageSync(runDirectory, "admitted");
653
+ if (record === undefined)
677
654
  return undefined;
678
- }
679
- const record = raw;
680
655
  if (typeof record.sourceRunPath === "string" && record.sourceRunPath.trim() !== "") {
681
656
  return record.sourceRunPath;
682
657
  }
@@ -789,7 +764,7 @@ async function loadResumableRunRecord(home, runId, authority) {
789
764
  throw new CliUsageError(`unknown role run id: ${runId}`);
790
765
  }
791
766
  const { run, principal } = materialized;
792
- // Reconstruct admitted identity from durable run record + admitted-request.json.
767
+ // Reconstruct admitted identity from durable run record + the admitted section.
793
768
  let instruction = "";
794
769
  let instructionEmpty = true;
795
770
  let attachments = [];
@@ -817,9 +792,10 @@ async function loadResumableRunRecord(home, runId, authority) {
817
792
  let sourceRunPath;
818
793
  let sourceRun;
819
794
  try {
820
- const raw = JSON.parse(await readFile(run.admittedRequestPath, "utf8"));
821
- if (isRecord(raw)) {
822
- const record = raw;
795
+ const record = readPageSync(run.runDirectory, "admitted");
796
+ if (record === undefined)
797
+ throw new Error("state.jsonl has no admitted-request row");
798
+ {
823
799
  const storedRunDirectory = typeof record.runDirectory === "string" && record.runDirectory.trim() !== ""
824
800
  ? record.runDirectory
825
801
  : run.runDirectory;
@@ -954,9 +930,8 @@ async function loadResumableRunRecord(home, runId, authority) {
954
930
  }
955
931
  let model;
956
932
  try {
957
- const invocationRaw = JSON.parse(await readFile(join(run.runDirectory, "invocation.json"), "utf8"));
958
- if (isRecord(invocationRaw)) {
959
- const rec = invocationRaw;
933
+ const rec = readPageSync(run.runDirectory, "invocation");
934
+ if (rec !== undefined) {
960
935
  if (typeof rec.provider === "string" && typeof rec.model === "string") {
961
936
  model = {
962
937
  provider: rec.provider,
@@ -1043,7 +1018,6 @@ function resumedBaseAdmitted(loaded) {
1043
1018
  attachments: loaded.admittedFields.attachments,
1044
1019
  runDirectory: loaded.run.runDirectory,
1045
1020
  principal: loaded.principal,
1046
- admittedRequestPath: loaded.run.admittedRequestPath,
1047
1021
  ...(loaded.admittedFields.model === undefined ? {} : { model: loaded.admittedFields.model }),
1048
1022
  ...restoredTicketFields(loaded.admittedFields),
1049
1023
  };