@akagilnc/pi-workflow-roles 0.1.5365 → 0.1.5375

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 (170) hide show
  1. package/dist/acp-host/production-host.js +5585 -5655
  2. package/dist/activation-ledger-git.js +2 -2
  3. package/dist/activation-ledger-topology.js +1 -7
  4. package/dist/analyst-entry.js +4 -8
  5. package/dist/analyst-gate-cycles-read.js +3 -11
  6. package/dist/analyst-index.js +3 -9
  7. package/dist/analyst-ledger.js +1 -11
  8. package/dist/analyst-metric-families/acceptance-success-rework.js +1 -3
  9. package/dist/analyst-metric-families/round-timeline.js +1 -3
  10. package/dist/analyst-page.js +2 -2
  11. package/dist/archivist-record-topology.js +2 -2
  12. package/dist/audit-escalation.js +2 -1
  13. package/dist/auditor-soul.js +2 -1
  14. package/dist/collector-config.js +6 -8
  15. package/dist/compliance-transport.js +2 -1
  16. package/dist/countersign-contracts.js +2 -1
  17. package/dist/diarist-contracts.js +3 -2
  18. package/dist/doctor-contracts.js +1 -3
  19. package/dist/doctor-evidence.js +7 -8
  20. package/dist/dossier-resolution.js +1 -3
  21. package/dist/engine-detour-usage.js +1 -3
  22. package/dist/gatekeeper-role.js +2 -9
  23. package/dist/gleaner-left-contracts.js +2 -1
  24. package/dist/headless-host/description.js +14 -17
  25. package/dist/headless-host/production-host.js +1665 -1737
  26. package/dist/host-session-record.js +3 -2
  27. package/dist/inspector-contracts.js +2 -1
  28. package/dist/ledger-session-read.js +1 -3
  29. package/dist/merger-contracts.js +9 -9
  30. package/dist/migrate-book-topology.js +348 -314
  31. package/dist/navigator-attendance.js +9 -11
  32. package/dist/navigator-invocation-identity.js +3 -2
  33. package/dist/navigator-public-session.js +3 -5
  34. package/dist/navigator-session-contracts.js +8 -10
  35. package/dist/navigator-work-base.js +5 -8
  36. package/dist/notary-contracts.js +3 -5
  37. package/dist/package-contracts/auditor-output.js +1 -3
  38. package/dist/package-contracts/fixer-packet.js +3 -6
  39. package/dist/package-contracts/gatekeeper-output.js +1 -3
  40. package/dist/package-contracts/navigator-output.js +8 -8
  41. package/dist/package-contracts/terminating-infrastructure.js +5 -9
  42. package/dist/package-contracts/terminating-tools.js +4 -3
  43. package/dist/public-cli/analyst-run.js +3 -2
  44. package/dist/public-cli/auto-resume.js +4 -9
  45. package/dist/public-cli/cli.js +66 -64
  46. package/dist/public-cli/config.js +12 -11
  47. package/dist/public-cli/countersign-run.js +1 -3
  48. package/dist/public-cli/host-providers.js +7 -14
  49. package/dist/public-cli/instruction-seat-run.js +69 -43
  50. package/dist/public-cli/invocation.js +141 -136
  51. package/dist/public-cli/main.js +1919 -1968
  52. package/dist/public-cli/post-admission.js +89 -89
  53. package/dist/public-cli/role-seat-runtime.js +29 -0
  54. package/dist/public-cli/run-lifecycle.js +20 -32
  55. package/dist/public-cli/settlement.js +10 -26
  56. package/dist/public-cli/turn-request.js +14 -0
  57. package/dist/public-role-summons.js +23 -35
  58. package/dist/receipt-delivery-policy.js +1 -3
  59. package/dist/role-run-placement.js +7 -5
  60. package/dist/role-run-relocation.js +12 -19
  61. package/dist/run-terminal-artifacts.js +1 -11
  62. package/dist/run-ticket-number.js +2 -4
  63. package/dist/session-assistant-usage.js +2 -1
  64. package/dist/session-dialogue.js +1 -14
  65. package/dist/sitian-reader.js +2 -4
  66. package/dist/submission-correctable-error.js +2 -1
  67. package/dist/submission-errors.js +2 -1
  68. package/dist/submission-gate.js +2 -1
  69. package/dist/submission-ledger.js +4 -5
  70. package/dist/ticket-provenance-contracts.js +1 -3
  71. package/dist/ticket-provenance.js +2 -1
  72. package/dist/typed-provider-http.js +4 -7
  73. package/dist/unknown-value.js +28 -0
  74. package/dist/user-dialogue-stdin.js +2 -1
  75. package/package.json +1 -1
  76. package/src/acp-host/role-turn-host.ts +4 -2
  77. package/src/activation-ledger-git.ts +3 -2
  78. package/src/activation-ledger-topology.ts +4 -12
  79. package/src/analyst-entry.ts +3 -11
  80. package/src/analyst-gate-cycles-read.ts +3 -15
  81. package/src/analyst-index.ts +3 -13
  82. package/src/analyst-ledger.ts +2 -16
  83. package/src/analyst-metric-families/acceptance-success-rework.ts +2 -4
  84. package/src/analyst-metric-families/round-timeline.ts +2 -4
  85. package/src/analyst-page.ts +2 -2
  86. package/src/archivist-record-topology.ts +2 -2
  87. package/src/audit-escalation.ts +2 -1
  88. package/src/auditor-soul.ts +3 -1
  89. package/src/book-topology-migration-placement.ts +8 -21
  90. package/src/book-topology-migrators-t11.ts +16 -15
  91. package/src/book-topology-mixed-volume-migrators.ts +3 -6
  92. package/src/book-topology-record-class-migrators.ts +7 -10
  93. package/src/book-topology-runs-migrator.ts +4 -3
  94. package/src/collector-config.ts +7 -9
  95. package/src/compliance-transport.ts +2 -1
  96. package/src/countersign-contracts.ts +2 -1
  97. package/src/diarist-contracts.ts +3 -2
  98. package/src/doctor-contracts.ts +3 -1
  99. package/src/doctor-evidence.ts +8 -7
  100. package/src/doctor-role.ts +4 -2
  101. package/src/dossier-resolution.ts +2 -4
  102. package/src/engine-detour-tool.ts +0 -2
  103. package/src/engine-detour-usage.ts +2 -4
  104. package/src/external-host-turn-loop.ts +3 -1
  105. package/src/factory-board.ts +1 -8
  106. package/src/gatekeeper-role.ts +2 -10
  107. package/src/gleaner-left-contracts.ts +3 -1
  108. package/src/headless-host/description.ts +15 -18
  109. package/src/headless-host/role-turn-host.ts +10 -9
  110. package/src/host-session-record.ts +4 -2
  111. package/src/inspector-contracts.ts +2 -1
  112. package/src/ledger-session-read.ts +2 -5
  113. package/src/merger-contracts.ts +10 -9
  114. package/src/navigator-attendance.ts +10 -12
  115. package/src/navigator-invocation-identity.ts +3 -2
  116. package/src/navigator-public-session.ts +4 -6
  117. package/src/navigator-session-contracts.ts +8 -11
  118. package/src/navigator-work-base.ts +5 -8
  119. package/src/navigator-work-context.ts +2 -1
  120. package/src/notary-contracts.ts +4 -6
  121. package/src/oauth-keepalive.ts +5 -18
  122. package/src/package-contracts/auditor-output.ts +2 -4
  123. package/src/package-contracts/fixer-packet.ts +4 -6
  124. package/src/package-contracts/gatekeeper-output.ts +2 -4
  125. package/src/package-contracts/judge-output.ts +0 -1
  126. package/src/package-contracts/navigator-output.ts +8 -8
  127. package/src/package-contracts/terminating-infrastructure.ts +6 -20
  128. package/src/package-contracts/terminating-tools.ts +8 -12
  129. package/src/pi/adapter.ts +0 -1
  130. package/src/pi/role-turn-host.ts +0 -1
  131. package/src/public-cli/analyst-run.ts +4 -2
  132. package/src/public-cli/auto-resume.ts +5 -12
  133. package/src/public-cli/cli.ts +77 -83
  134. package/src/public-cli/config.ts +16 -27
  135. package/src/public-cli/countersign-run.ts +2 -4
  136. package/src/public-cli/host-providers.ts +10 -27
  137. package/src/public-cli/instruction-seat-run.ts +87 -58
  138. package/src/public-cli/invocation.ts +159 -172
  139. package/src/public-cli/post-admission.ts +115 -103
  140. package/src/public-cli/role-seat-runtime.ts +72 -0
  141. package/src/public-cli/run-lifecycle.ts +27 -67
  142. package/src/public-cli/settlement.ts +11 -33
  143. package/src/public-cli/terminal.ts +2 -17
  144. package/src/public-cli/turn-request.ts +26 -0
  145. package/src/public-role-summons.ts +24 -48
  146. package/src/receipt-delivery-policy.ts +1 -4
  147. package/src/reviewer-role.ts +0 -1
  148. package/src/role-envelope.ts +5 -3
  149. package/src/role-run-placement.ts +9 -10
  150. package/src/role-run-relocation.ts +13 -23
  151. package/src/role-runtime.ts +9 -15
  152. package/src/run-terminal-artifacts.ts +2 -16
  153. package/src/run-ticket-number.ts +4 -10
  154. package/src/session-assistant-usage.ts +3 -1
  155. package/src/session-dialogue.ts +1 -4
  156. package/src/session-identity.ts +0 -1
  157. package/src/sitian-reader.ts +2 -4
  158. package/src/submission-correctable-error.ts +3 -1
  159. package/src/submission-errors.ts +2 -1
  160. package/src/submission-gate.ts +3 -1
  161. package/src/submission-ledger.ts +5 -6
  162. package/src/ticket-provenance-contracts.ts +1 -4
  163. package/src/ticket-provenance.ts +3 -1
  164. package/src/ticket-snapshot.ts +2 -4
  165. package/src/ticket-trajectory.ts +1 -8
  166. package/src/typed-provider-http.ts +5 -15
  167. package/src/unknown-value.ts +34 -0
  168. package/src/user-dialogue-stdin.ts +3 -1
  169. package/src/worker-role.ts +2 -5
  170. package/src/worker-submission-gates.ts +5 -7
@@ -18,7 +18,7 @@ import {
18
18
  type SameTicketSummonsMaterials,
19
19
  } from "./run-lifecycle.ts";
20
20
  import { CliUsageError } from "./cli-errors.ts";
21
- import type { RoleTurnRequestProjectionOptions } from "./turn-request.ts";
21
+ import { projectPublicTurnAxes, type RoleTurnRequestProjectionOptions } from "./turn-request.ts";
22
22
  import {
23
23
  bindAdmittedTicketNumber,
24
24
  buildInstructionTransportPrompt,
@@ -119,8 +119,11 @@ import {
119
119
  persistReturnedRunState,
120
120
  runWithAutoResumeLoop,
121
121
  TurnDispatchedFailure,
122
+ writeHardenedArtifactFile,
122
123
  } from "./auto-resume.ts";
123
124
 
125
+ import { isRecord, errorText } from "../unknown-value.ts";
126
+
124
127
  function projectRelocatedTurnIdentity(
125
128
  request: RoleTurnRequest,
126
129
  result: { readonly terminal?: TerminalResult },
@@ -136,7 +139,7 @@ function projectRelocatedTurnIdentity(
136
139
  mutableRequest.runDirectory = admitted.runDirectory;
137
140
  mutableRequest.principal = admitted.principal;
138
141
  const activation = mutableRequest.activation;
139
- if (activation !== null && typeof activation === "object" && !Array.isArray(activation)) {
142
+ if (isRecord(activation)) {
140
143
  for (const field of ["taskPath", "packetPath", "prerequisitesPath", "inputPath", "requestManifestPath"] as const) {
141
144
  const record = activation as Record<string, unknown>;
142
145
  if (field in record) record[field] = rewrite(record[field]);
@@ -268,11 +271,10 @@ async function recordBestEffortPostDispatchDiagnostic<A extends AdmittedRoleInvo
268
271
  } catch (appendError) {
269
272
  try {
270
273
  const artifactsDir = await ensureRealArtifactsDirectory(admitted.runDirectory);
271
- await writeFile(
272
- join(artifactsDir, `post-admission-diagnostic-${randomUUID()}.json`),
273
- `${JSON.stringify({ version: 1, ...payload }, null, 2)}\n`,
274
- { encoding: "utf8", flag: "wx" },
275
- );
274
+ await writeHardenedArtifactFile(artifactsDir, "post-admission-diagnostic", {
275
+ version: 1,
276
+ ...payload,
277
+ });
276
278
  } catch (artifactError) {
277
279
  retentionFailure =
278
280
  `post-dispatch diagnostic durable retention failed on both channels (best-effort continue): dossier=${describeErrorIdentity(appendError)}; artifact=${describeErrorIdentity(artifactError)}`;
@@ -733,7 +735,7 @@ export async function dispatchPostAdmissionTurn<
733
735
  continue;
734
736
  }
735
737
  const payload = row.accepted;
736
- if (payload === null || typeof payload !== "object" || Array.isArray(payload)) continue;
738
+ if (!isRecord(payload)) continue;
737
739
  ticketNumber = readDeclaredTicketNumber(
738
740
  (payload as { ticketNumber?: unknown }).ticketNumber,
739
741
  );
@@ -1318,13 +1320,8 @@ export function resumeTurnRequestProjectionOptions(
1318
1320
  prompt = "";
1319
1321
  }
1320
1322
  return {
1321
- packageRoot: env.packageRoot,
1322
- home: env.home,
1323
+ ...projectPublicTurnAxes(env),
1323
1324
  ...(env.host === undefined ? {} : { host: env.host }),
1324
- agentDir: env.agentDir,
1325
- ...(env.model === undefined ? {} : { model: env.model }),
1326
- ...pickEngineAxis(env),
1327
- ...(env.timeoutMs === undefined ? {} : { timeoutMs: env.timeoutMs }),
1328
1325
  ...(env.correlationId === undefined && admitted.correlationId === undefined
1329
1326
  ? {}
1330
1327
  : { correlationId: env.correlationId ?? admitted.correlationId }),
@@ -1345,13 +1342,8 @@ export function roleTurnOptions(
1345
1342
  ): RoleTurnRequestProjectionOptions {
1346
1343
  const correlationId = env.correlationId ?? admitted.correlationId;
1347
1344
  return {
1348
- packageRoot: env.packageRoot,
1349
- home: env.home,
1345
+ ...projectPublicTurnAxes(env),
1350
1346
  ...(env.host === undefined ? {} : { host: env.host }),
1351
- agentDir: env.agentDir,
1352
- ...(env.model === undefined ? {} : { model: env.model }),
1353
- ...pickEngineAxis(env),
1354
- ...(env.timeoutMs === undefined ? {} : { timeoutMs: env.timeoutMs }),
1355
1347
  ...(correlationId === undefined || correlationId.trim() === ""
1356
1348
  ? {}
1357
1349
  : { correlationId }),
@@ -1383,6 +1375,66 @@ async function dispatchAfterWriterLease<T>(input: {
1383
1375
  }
1384
1376
  }
1385
1377
 
1378
+ /**
1379
+ * One auto-resume dispatch: deferred run-state persist settles on the same
1380
+ * path for station-child and ordinary in-call retries. The caller owns how
1381
+ * the turn request is built and which correlation id the env carries.
1382
+ */
1383
+ async function runSettledAutoResumeLoop<
1384
+ A extends AdmittedRoleInvocation,
1385
+ T extends TerminalResult,
1386
+ P,
1387
+ >(input: {
1388
+ admitted: A;
1389
+ env: PostAdmissionEnv;
1390
+ io: CliIo;
1391
+ adapters: PostAdmissionAdapters<A, T>;
1392
+ effectiveEngine?: string;
1393
+ dispatchEnv?: PostAdmissionEnv;
1394
+ buildInitialPayload: () => P;
1395
+ buildResumePayload: () => P;
1396
+ toRequest: (payload: P) => Promise<RoleTurnRequest>;
1397
+ }): Promise<{ exitCode: number; admitted?: A; terminal?: T }> {
1398
+ const adapters = withOnceSuccessfulBeforeDispatch(input.adapters);
1399
+ const dispatchEnv = input.dispatchEnv ?? input.env;
1400
+ return runWithAutoResumeLoop({
1401
+ admitted: input.admitted,
1402
+ principalAuthority: input.env.principalAuthority,
1403
+ io: input.io,
1404
+ sessionAppender: input.env.sessionAppender,
1405
+ autoResumeLimit: input.env.autoResumeLimit,
1406
+ ...(input.env.signal === undefined ? {} : { signal: input.env.signal }),
1407
+ buildInitialPayload: input.buildInitialPayload,
1408
+ buildResumePayload: input.buildResumePayload,
1409
+ dispatch: async (payload, lease, _isFirst, attemptIo) =>
1410
+ dispatchAfterWriterLease({
1411
+ ...(lease === undefined ? {} : { lease }),
1412
+ build: () => input.toRequest(payload),
1413
+ dispatch: async (request) => {
1414
+ const result = await dispatchPostAdmissionTurn({
1415
+ admitted: input.admitted,
1416
+ env: dispatchEnv,
1417
+ io: attemptIo,
1418
+ request,
1419
+ ...(lease === undefined ? {} : { lease }),
1420
+ adapters,
1421
+ persistRunState: false,
1422
+ ...(input.effectiveEngine === undefined
1423
+ ? {}
1424
+ : { effectiveEngine: input.effectiveEngine }),
1425
+ });
1426
+ return settleDeferredPersist(
1427
+ input.admitted,
1428
+ input.env.principalAuthority,
1429
+ adapters,
1430
+ attemptIo,
1431
+ result,
1432
+ );
1433
+ },
1434
+ }),
1435
+ });
1436
+ }
1437
+
1386
1438
  function isAlreadyFrozenSummonsAttachment(
1387
1439
  runDirectory: string,
1388
1440
  attachmentPath: string,
@@ -1601,7 +1653,6 @@ export async function runPostAdmissionSeatResume<
1601
1653
  try {
1602
1654
  if (env.stationChild === true) {
1603
1655
  let firstTurn: RoleTurnRequest | undefined;
1604
- const stationAdapters = withOnceSuccessfulBeforeDispatch(adapters);
1605
1656
  type StationChildAttempt = { readonly resumeTurn: boolean };
1606
1657
  // One public call → one detour scope across in-place auto-resume dispatches.
1607
1658
  const invocationScopeId = mintEngineDetourInvocationScope({
@@ -1609,68 +1660,42 @@ export async function runPostAdmissionSeatResume<
1609
1660
  ? {}
1610
1661
  : { effectiveEngine: input.effectiveEngine }),
1611
1662
  });
1612
- return await runWithAutoResumeLoop({
1663
+ return await runSettledAutoResumeLoop({
1613
1664
  admitted: loaded.admitted,
1614
- principalAuthority: env.principalAuthority,
1665
+ env,
1615
1666
  io: input.io,
1616
- sessionAppender: env.sessionAppender,
1617
- autoResumeLimit: env.autoResumeLimit,
1618
- ...(env.signal === undefined ? {} : { signal: env.signal }),
1667
+ adapters,
1668
+ ...(input.effectiveEngine === undefined
1669
+ ? {}
1670
+ : { effectiveEngine: input.effectiveEngine }),
1619
1671
  buildInitialPayload: (): StationChildAttempt => ({ resumeTurn: false }),
1620
1672
  buildResumePayload: (): StationChildAttempt => ({ resumeTurn: true }),
1621
- // Same as public manual resume: prior-court sealed acceptance is not a
1622
- // redispatch brake (#833). New-court station-child turns still auto-resume.
1623
- dispatch: async (payload, lease, _isFirst, attemptIo) =>
1624
- dispatchAfterWriterLease({
1625
- ...(lease === undefined ? {} : { lease }),
1626
- build: async () => {
1627
- // #840 r8 判词 class 2: this call-local retry must keep this
1628
- // court's frozen summons / 交卷 body / attachments verbatim
1629
- // (same object as firstTurn) and project only the minimal
1630
- // host-needed resume trigger — never engine handbook material,
1631
- // which would replace a 审核循环 same-ticket continuation with a bare outsourcing
1632
- // 「重新读」 envelope (#755 contract, resumeTurnRequestProjectionOptions
1633
- // above). RESUME_TRANSPORT_ENVELOPE is the same package-owned,
1634
- // non-semantic trigger that projection already uses for a
1635
- // same-ticket summons carrying no instruction/attachments.
1636
- if (payload.resumeTurn && firstTurn !== undefined) {
1637
- return {
1638
- ...firstTurn,
1639
- continuation: {
1640
- kind: "resume",
1641
- prompt: RESUME_TRANSPORT_ENVELOPE,
1642
- },
1643
- };
1644
- }
1645
- const turnRequest = withEngineDetourInvocationScope(
1646
- await buildRequestAfterLease(),
1647
- invocationScopeId,
1648
- );
1649
- firstTurn = turnRequest;
1650
- return turnRequest;
1651
- },
1652
- dispatch: async (turnRequest) => {
1653
- const result = await dispatchPostAdmissionTurn({
1654
- admitted: loaded.admitted,
1655
- env,
1656
- io: attemptIo,
1657
- request: turnRequest,
1658
- ...(lease === undefined ? {} : { lease }),
1659
- adapters: stationAdapters,
1660
- persistRunState: false,
1661
- ...(input.effectiveEngine === undefined
1662
- ? {}
1663
- : { effectiveEngine: input.effectiveEngine }),
1664
- });
1665
- return settleDeferredPersist(
1666
- loaded.admitted,
1667
- env.principalAuthority,
1668
- stationAdapters,
1669
- attemptIo,
1670
- result,
1671
- );
1672
- },
1673
- }),
1673
+ toRequest: async (payload) => {
1674
+ // #840 r8 判词 class 2: this call-local retry must keep this
1675
+ // court's frozen summons / 交卷 body / attachments verbatim
1676
+ // (same object as firstTurn) and project only the minimal
1677
+ // host-needed resume trigger — never engine handbook material,
1678
+ // which would replace a 审核循环 same-ticket continuation with a bare outsourcing
1679
+ // 「重新读」 envelope (#755 contract, resumeTurnRequestProjectionOptions
1680
+ // above). RESUME_TRANSPORT_ENVELOPE is the same package-owned,
1681
+ // non-semantic trigger that projection already uses for a
1682
+ // same-ticket summons carrying no instruction/attachments.
1683
+ if (payload.resumeTurn && firstTurn !== undefined) {
1684
+ return {
1685
+ ...firstTurn,
1686
+ continuation: {
1687
+ kind: "resume",
1688
+ prompt: RESUME_TRANSPORT_ENVELOPE,
1689
+ },
1690
+ };
1691
+ }
1692
+ const turnRequest = withEngineDetourInvocationScope(
1693
+ await buildRequestAfterLease(),
1694
+ invocationScopeId,
1695
+ );
1696
+ firstTurn = turnRequest;
1697
+ return turnRequest;
1698
+ },
1674
1699
  });
1675
1700
  }
1676
1701
  const resumed = await runPostAdmissionManualResume({
@@ -1779,7 +1804,7 @@ async function presentResumeFailurePointer(
1779
1804
  cause.thrownCause = formatErrorCauseDetail(thrown.cause);
1780
1805
  }
1781
1806
  presentStructuralRejection({
1782
- message: thrown instanceof Error ? thrown.message : String(thrown),
1807
+ message: errorText(thrown),
1783
1808
  cause,
1784
1809
  }, io);
1785
1810
  }
@@ -1873,7 +1898,6 @@ export async function runPostAdmissionResumable<
1873
1898
  terminal?: T;
1874
1899
  }> {
1875
1900
  const { admitted, env, io, buildInitialRequest, buildResumeRequest, effectiveEngine } = input;
1876
- const adapters = withOnceSuccessfulBeforeDispatch(input.adapters);
1877
1901
 
1878
1902
  // One public call → one detour scope across in-place auto-resume dispatches.
1879
1903
  const invocationScopeId = mintEngineDetourInvocationScope({
@@ -1884,32 +1908,20 @@ export async function runPostAdmissionResumable<
1884
1908
  const buildScopedResume = (): RoleTurnRequest =>
1885
1909
  withEngineDetourInvocationScope(buildResumeRequest(), invocationScopeId);
1886
1910
 
1887
- return runWithAutoResumeLoop({
1911
+ return runSettledAutoResumeLoop({
1888
1912
  admitted,
1889
- principalAuthority: env.principalAuthority,
1913
+ env,
1890
1914
  io,
1891
- sessionAppender: env.sessionAppender,
1892
- autoResumeLimit: env.autoResumeLimit,
1893
- ...(env.signal === undefined ? {} : { signal: env.signal }),
1915
+ adapters: input.adapters,
1916
+ ...(effectiveEngine === undefined ? {} : { effectiveEngine }),
1917
+ // Ordinary in-call retry keeps the admitted correlation when one was stored.
1918
+ dispatchEnv: {
1919
+ ...env,
1920
+ ...(admitted.correlationId === undefined ? {} : { correlationId: admitted.correlationId }),
1921
+ },
1894
1922
  buildInitialPayload: buildScopedInitial,
1895
1923
  buildResumePayload: buildScopedResume,
1896
- dispatch: async (request, lease, _isFirst, attemptIo) => {
1897
- const result = await dispatchPostAdmissionTurn({
1898
- admitted,
1899
- env: {
1900
- ...env,
1901
- ...(admitted.correlationId === undefined ? {} : { correlationId: admitted.correlationId }),
1902
- },
1903
- io: attemptIo,
1904
- request,
1905
- ...(lease === undefined ? {} : { lease }),
1906
- adapters,
1907
- persistRunState: false,
1908
- // #600: every attempt (initial + auto-resume) writes seat engine when present.
1909
- ...(effectiveEngine === undefined ? {} : { effectiveEngine }),
1910
- });
1911
- return settleDeferredPersist(admitted, env.principalAuthority, adapters, attemptIo, result);
1912
- },
1924
+ toRequest: async (request) => request,
1913
1925
  });
1914
1926
  }
1915
1927
 
@@ -0,0 +1,72 @@
1
+ /**
2
+ * One seat-runtime assembly for the public CLI and nested summons.
3
+ * Order is host selection, the caller's argv parse, the missing-model fact,
4
+ * then host-facing provider projection. Callers own how a missing model is shown.
5
+ */
6
+ import { pickEngineAxis } from "../package-resources/engine-material.ts";
7
+ import type { DurablePrincipalAuthority, RoleTurnHost } from "../host-contracts.ts";
8
+ import {
9
+ resolvedSeatWithModel,
10
+ type EffectiveSeat,
11
+ type SeatModelConfig,
12
+ } from "./config.ts";
13
+ import {
14
+ loadHostProvidersTable,
15
+ projectHostFacingProvider,
16
+ } from "./host-providers.ts";
17
+ import {
18
+ composeRoleTurnHostAdapters,
19
+ selectRoleTurnHost,
20
+ type NamedRoleTurnHostAdapter,
21
+ type RoleTurnHostResolutionInput,
22
+ } from "./role-turn-host-resolution.ts";
23
+ import type { PublicCallableRole } from "./registry.ts";
24
+
25
+ export type OpenedRoleSeatRuntime =
26
+ | { readonly ok: false }
27
+ | {
28
+ readonly ok: true;
29
+ readonly roleTurnHost: RoleTurnHost;
30
+ readonly hostAdapters: readonly NamedRoleTurnHostAdapter[];
31
+ readonly model?: SeatModelConfig;
32
+ readonly engine?: string;
33
+ readonly engineModel?: string;
34
+ readonly host: string;
35
+ };
36
+
37
+ export function openRoleSeatRuntime(input: {
38
+ readonly resolution: RoleTurnHostResolutionInput;
39
+ readonly principalAuthority: DurablePrincipalAuthority;
40
+ readonly role: PublicCallableRole;
41
+ readonly seat: EffectiveSeat;
42
+ readonly home: string;
43
+ readonly afterHost?: () => void;
44
+ /** Already host-facing. A second projection would rename the provider again. */
45
+ readonly hostFacingModel?: SeatModelConfig;
46
+ }): OpenedRoleSeatRuntime {
47
+ const hostAdapters = composeRoleTurnHostAdapters(
48
+ input.resolution,
49
+ input.principalAuthority,
50
+ );
51
+ const roleTurnHost = selectRoleTurnHost(hostAdapters, {
52
+ role: input.role,
53
+ seat: input.seat,
54
+ });
55
+ input.afterHost?.();
56
+ const seatWithModel = resolvedSeatWithModel(input.seat);
57
+ if (seatWithModel === undefined) return { ok: false };
58
+ const projected = input.hostFacingModel ?? projectHostFacingProvider(
59
+ seatWithModel.selection,
60
+ seatWithModel.host,
61
+ loadHostProvidersTable(input.home),
62
+ input.home,
63
+ );
64
+ return {
65
+ ok: true,
66
+ roleTurnHost,
67
+ hostAdapters,
68
+ ...(projected === undefined ? {} : { model: projected }),
69
+ ...pickEngineAxis(seatWithModel),
70
+ host: seatWithModel.host,
71
+ };
72
+ }
@@ -49,6 +49,7 @@ import {
49
49
  type PackagedRole,
50
50
  } from "../packaged-role-registry.ts";
51
51
  import {
52
+ admittedReviewerBaseFault,
52
53
  recordEffectiveInvocationModel,
53
54
  requireAuthorityRef,
54
55
  isReviewerLens,
@@ -70,6 +71,8 @@ import {
70
71
  type ReviewerLens,
71
72
  } from "./invocation.ts";
72
73
 
74
+ import { isRecord, errorText, isEnoent } from "../unknown-value.ts";
75
+
73
76
  /** Providers eligible for v1 typed-429 resume (Codex / xAI only).
74
77
  * @deprecated v1 429-only gate removed by #416 (owner 2026-08-22: "根本不要有限制"). Kept for compatibility; do not use for new branching.
75
78
  */
@@ -240,8 +243,8 @@ type RoleRunStateDisk = {
240
243
  function parseSameTicketSummonsMaterials(
241
244
  raw: unknown,
242
245
  ): SameTicketSummonsMaterials | undefined {
243
- if (raw === null || typeof raw !== "object" || Array.isArray(raw)) return undefined;
244
- const record = raw as Record<string, unknown>;
246
+ if (!isRecord(raw)) return undefined;
247
+ const record = raw;
245
248
  const instruction =
246
249
  typeof record.instruction === "string" ? record.instruction : undefined;
247
250
  const instructionEmpty =
@@ -255,9 +258,7 @@ function parseSameTicketSummonsMaterials(
255
258
  : undefined;
256
259
  let sourceRun: NotarySourceRunLocator | undefined;
257
260
  if (
258
- record.sourceRun !== null &&
259
- typeof record.sourceRun === "object" &&
260
- !Array.isArray(record.sourceRun)
261
+ isRecord(record.sourceRun)
261
262
  ) {
262
263
  const sr = record.sourceRun as Record<string, unknown>;
263
264
  if (
@@ -296,8 +297,8 @@ function parseSameTicketSummonsMaterials(
296
297
  }
297
298
 
298
299
  function parseCurrentCourtState(raw: unknown): CurrentCourtState | undefined {
299
- if (raw === null || typeof raw !== "object" || Array.isArray(raw)) return undefined;
300
- const record = raw as Record<string, unknown>;
300
+ if (!isRecord(raw)) return undefined;
301
+ const record = raw;
301
302
  if (typeof record.courtAttemptId !== "string" || record.courtAttemptId.length === 0) {
302
303
  return undefined;
303
304
  }
@@ -332,10 +333,10 @@ function parseRoleRunIdentity(raw: unknown, runDirectory: string): {
332
333
  readonly runDirectory: string;
333
334
  readonly state: RoleRunState;
334
335
  } {
335
- if (raw === null || typeof raw !== "object" || Array.isArray(raw)) {
336
+ if (!isRecord(raw)) {
336
337
  throw new TypeError("Invalid run-state.json");
337
338
  }
338
- const record = raw as Record<string, unknown>;
339
+ const record = raw;
339
340
  if (typeof record.runId !== "string" || record.runId.trim() === "") {
340
341
  throw new TypeError("Invalid run-state.json");
341
342
  }
@@ -389,11 +390,8 @@ async function readRoleRunStateDisk(
389
390
  };
390
391
  let resumable: TypedHttp429Observation | undefined;
391
392
  if (record.resumable !== undefined && record.resumable !== null) {
392
- if (
393
- typeof record.resumable === "object" &&
394
- !Array.isArray(record.resumable)
395
- ) {
396
- const r = record.resumable as Record<string, unknown>;
393
+ if (isRecord(record.resumable)) {
394
+ const r = record.resumable;
397
395
  if (
398
396
  r.httpStatus === 429 &&
399
397
  typeof r.provider === "string" &&
@@ -701,7 +699,6 @@ export type RunWriterLease = {
701
699
  /** Kind of a writer-lease diagnostic sent on the existing sink. */
702
700
  export type WriterLeaseDiagnosticKind = "stale-reclaimed";
703
701
 
704
-
705
702
  /**
706
703
  * True error identity for diagnostics — name/code/message as-is, never a
707
704
  * guessed label (failure-honesty constitution).
@@ -740,7 +737,6 @@ function isProcessAlive(pid: number): boolean {
740
737
  }
741
738
  }
742
739
 
743
-
744
740
  export type WriterLockAutopsy =
745
741
  | { verdict: "absent" }
746
742
  | { verdict: "unknown"; reason: "unparseable"; content: string }
@@ -1071,10 +1067,10 @@ export async function readRunParentPath(
1071
1067
  if (errorCodeOf(error) === "ENOENT") return undefined;
1072
1068
  throw error;
1073
1069
  }
1074
- if (raw === null || typeof raw !== "object" || Array.isArray(raw)) {
1070
+ if (!isRecord(raw)) {
1075
1071
  return undefined;
1076
1072
  }
1077
- const record = raw as Record<string, unknown>;
1073
+ const record = raw;
1078
1074
  if (typeof record.sourceRunPath === "string" && record.sourceRunPath.trim() !== "") {
1079
1075
  return record.sourceRunPath;
1080
1076
  }
@@ -1279,7 +1275,7 @@ async function loadResumableRunRecord(
1279
1275
  const raw: unknown = JSON.parse(
1280
1276
  await readFile(run.admittedRequestPath, "utf8"),
1281
1277
  );
1282
- if (raw !== null && typeof raw === "object" && !Array.isArray(raw)) {
1278
+ if (isRecord(raw)) {
1283
1279
  const record = raw as Record<string, unknown>;
1284
1280
  const storedRunDirectory =
1285
1281
  typeof record.runDirectory === "string" && record.runDirectory.trim() !== ""
@@ -1352,9 +1348,7 @@ async function loadResumableRunRecord(
1352
1348
  caseRunsPath = record.caseRunsPath;
1353
1349
  }
1354
1350
  if (
1355
- record.caseIdentity !== null &&
1356
- typeof record.caseIdentity === "object" &&
1357
- !Array.isArray(record.caseIdentity)
1351
+ isRecord(record.caseIdentity)
1358
1352
  ) {
1359
1353
  const ci = record.caseIdentity as Record<string, unknown>;
1360
1354
  if (
@@ -1372,9 +1366,7 @@ async function loadResumableRunRecord(
1372
1366
  sourceRunPath = record.sourceRunPath;
1373
1367
  }
1374
1368
  if (
1375
- record.sourceRun !== null &&
1376
- typeof record.sourceRun === "object" &&
1377
- !Array.isArray(record.sourceRun)
1369
+ isRecord(record.sourceRun)
1378
1370
  ) {
1379
1371
  const sr = record.sourceRun as Record<string, unknown>;
1380
1372
  if (
@@ -1412,9 +1404,7 @@ async function loadResumableRunRecord(
1412
1404
  mergerInputPath = record.mergerInputPath;
1413
1405
  }
1414
1406
  if (
1415
- record.derived !== null &&
1416
- typeof record.derived === "object" &&
1417
- !Array.isArray(record.derived)
1407
+ isRecord(record.derived)
1418
1408
  ) {
1419
1409
  const d = record.derived as Record<string, unknown>;
1420
1410
  if (
@@ -1451,9 +1441,7 @@ async function loadResumableRunRecord(
1451
1441
  await readFile(join(run.runDirectory, "invocation.json"), "utf8"),
1452
1442
  );
1453
1443
  if (
1454
- invocationRaw !== null &&
1455
- typeof invocationRaw === "object" &&
1456
- !Array.isArray(invocationRaw)
1444
+ isRecord(invocationRaw)
1457
1445
  ) {
1458
1446
  const rec = invocationRaw as Record<string, unknown>;
1459
1447
  if (typeof rec.provider === "string" && typeof rec.model === "string") {
@@ -1477,13 +1465,7 @@ async function loadResumableRunRecord(
1477
1465
  ) {
1478
1466
  throw error;
1479
1467
  }
1480
- if (
1481
- !(
1482
- error instanceof Error &&
1483
- "code" in error &&
1484
- (error as { code?: unknown }).code === "ENOENT"
1485
- )
1486
- ) {
1468
+ if (!isEnoent(error)) {
1487
1469
  throw new CliUsageError(
1488
1470
  `role run invocation identity is unreadable: ${runId}`,
1489
1471
  { cause: error },
@@ -1582,36 +1564,16 @@ function seatLoadedResult<R extends AdmittedRoleInvocation>(
1582
1564
  };
1583
1565
  }
1584
1566
 
1585
-
1586
1567
  export async function peekRoleRunRole(
1587
1568
  home: string,
1588
1569
  runId: string,
1589
- ): Promise<
1590
- | "judge"
1591
- | "coder"
1592
- | "fixer"
1593
- | "collector"
1594
- | "doctor"
1595
- | "reviewer"
1596
- | "merger"
1597
- | "notary"
1598
- | "countersign"
1599
- | "gleaner-left"
1600
- | "inspector"
1601
- | "gatekeeper"
1602
- | "navigator"
1603
- | "auditor"
1604
- | "diarist"
1605
- | "secretariat"
1606
- | undefined
1607
- > {
1570
+ ): Promise<PackagedRole | undefined> {
1608
1571
  const runDirectory = await findRunDirectoryById(home, runId);
1609
1572
  if (runDirectory === undefined) return undefined;
1610
1573
  const run = await readRoleRunIdentity(runDirectory);
1611
1574
  return run?.role;
1612
1575
  }
1613
1576
 
1614
-
1615
1577
  export type LoadedResumablePublicRole = {
1616
1578
  readonly admitted: AdmittedRoleInvocation;
1617
1579
  readonly run: RoleRunRecord;
@@ -1725,14 +1687,12 @@ function admitResumedRole(loaded: {
1725
1687
  }
1726
1688
  case "review-basis": {
1727
1689
  const rawBase = fields.baseRevision;
1728
- if (rawBase === undefined || rawBase.trim() === "") {
1729
- throw new CliUsageError(
1730
- `role run admitted reviewer base revision is missing: ${runId}`,
1731
- );
1732
- }
1733
- if (/\s/.test(rawBase) || rawBase.startsWith("-")) {
1690
+ const baseFault = admittedReviewerBaseFault(rawBase);
1691
+ if (baseFault !== undefined || rawBase === undefined) {
1734
1692
  throw new CliUsageError(
1735
- `role run admitted reviewer base revision is damaged: ${runId}`,
1693
+ baseFault === "damaged"
1694
+ ? `role run admitted reviewer base revision is damaged: ${runId}`
1695
+ : `role run admitted reviewer base revision is missing: ${runId}`,
1736
1696
  );
1737
1697
  }
1738
1698
  const lens = fields.lens;
@@ -1812,7 +1772,7 @@ function admitResumedRole(loaded: {
1812
1772
  try {
1813
1773
  parsedRepository = parseCollectorRepository(repositoryDisplay);
1814
1774
  } catch (error) {
1815
- const detail = error instanceof Error ? error.message : String(error);
1775
+ const detail = errorText(error);
1816
1776
  throw new CliUsageError(detail, { cause: error });
1817
1777
  }
1818
1778
  if (parsedRepository.canonical !== repository) {