@akagilnc/pi-workflow-roles 0.1.4800 → 0.1.4870

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 (143) hide show
  1. package/dist/acp-host/production-host.js +19434 -18218
  2. package/dist/analyst-book-key.js +63 -0
  3. package/dist/analyst-cohort.js +167 -0
  4. package/dist/analyst-entry.js +320 -0
  5. package/dist/analyst-index.js +247 -0
  6. package/dist/analyst-ledger.js +561 -0
  7. package/dist/analyst-median.js +16 -0
  8. package/dist/analyst-metric-families/acceptance-success-rework.js +249 -0
  9. package/dist/analyst-metric-families/b2-frame-buckets-actions.js +189 -0
  10. package/dist/analyst-metric-families/gate-cycles.js +77 -0
  11. package/dist/analyst-metric-families/leg-wall-clock.js +56 -0
  12. package/dist/analyst-metric-families/round-timeline.js +126 -0
  13. package/dist/analyst-metric-families.js +23 -0
  14. package/dist/analyst-metric-family.js +11 -0
  15. package/dist/analyst-model-groups.js +135 -0
  16. package/dist/analyst-page.js +182 -0
  17. package/dist/atomic-write.js +23 -0
  18. package/dist/auditor-soul.js +1 -1
  19. package/dist/countersign-contracts.js +0 -2
  20. package/dist/diarist-contracts.js +0 -1
  21. package/dist/doctor-contracts.js +2 -2
  22. package/dist/gatekeeper-role.js +15 -16
  23. package/dist/gleaner-left-contracts.js +0 -2
  24. package/dist/headless-host/production-host.js +16967 -15749
  25. package/dist/host-contracts.js +0 -4
  26. package/dist/inspector-contracts.js +0 -2
  27. package/dist/institutional-resolution.js +4 -2
  28. package/dist/merger-contracts.js +0 -2
  29. package/dist/migrate-book-topology.js +3908 -3089
  30. package/dist/navigator-public-session.js +4 -3
  31. package/dist/notary-contracts.js +0 -2
  32. package/dist/package-contracts/auditor-output.js +0 -1
  33. package/dist/package-contracts/collector-output.js +0 -2
  34. package/dist/package-contracts/fixer-output.js +0 -2
  35. package/dist/package-contracts/gatekeeper-output.js +0 -2
  36. package/dist/package-contracts/judge-output.js +0 -2
  37. package/dist/package-contracts/navigator-output.js +0 -2
  38. package/dist/package-contracts/reviewer-output.js +0 -2
  39. package/dist/package-contracts/terminating-tools.js +32 -92
  40. package/dist/package-contracts/worker-output.js +0 -4
  41. package/dist/packaged-role-registry.js +518 -36
  42. package/dist/pi/role-turn-host.js +2 -1
  43. package/dist/public-cli/analyst-run.js +185 -0
  44. package/dist/public-cli/cli.js +885 -0
  45. package/dist/public-cli/config.js +12 -9
  46. package/dist/public-cli/countersign-run.js +4 -311
  47. package/dist/public-cli/instruction-seat-run.js +628 -158
  48. package/dist/public-cli/invocation.js +806 -1550
  49. package/dist/public-cli/main.js +6962 -9882
  50. package/dist/public-cli/option-definitions.js +51 -99
  51. package/dist/public-cli/post-admission.js +30 -2
  52. package/dist/public-cli/run-lifecycle.js +234 -353
  53. package/dist/public-cli/seat-ticket-binding.js +6 -0
  54. package/dist/public-cli/settlement.js +261 -675
  55. package/dist/public-cli/turn-request.js +76 -0
  56. package/dist/public-role-summons.js +38 -112
  57. package/dist/role-activation-flags.js +23 -45
  58. package/dist/secretariat-contracts.js +0 -2
  59. package/dist/session-identity.js +17 -8
  60. package/dist/session-opening-materials.js +3 -2
  61. package/extensions/role-runtime.ts +6 -80
  62. package/package.json +1 -1
  63. package/souls/coder.md +1 -2
  64. package/src/acp-host/role-turn-host.ts +4 -1
  65. package/src/analyst-metric-families/acceptance-success-rework.ts +3 -2
  66. package/src/auditor-role.ts +1 -2
  67. package/src/auditor-soul.ts +1 -1
  68. package/src/collector-role.ts +2 -2
  69. package/src/countersign-contracts.ts +0 -1
  70. package/src/countersign-role.ts +1 -1
  71. package/src/diarist-contracts.ts +0 -1
  72. package/src/diarist-role.ts +0 -1
  73. package/src/doctor-auditor.ts +1 -2
  74. package/src/doctor-contracts.ts +1 -1
  75. package/src/doctor-role.ts +3 -2
  76. package/src/external-host-turn-loop.ts +1 -1
  77. package/src/factory-board.ts +10 -7
  78. package/src/gatekeeper-role.ts +16 -10
  79. package/src/gleaner-left-contracts.ts +0 -1
  80. package/src/gleaner-left-role.ts +0 -1
  81. package/src/headless-host/role-turn-host.ts +7 -1
  82. package/src/host-contracts.ts +10 -6
  83. package/src/inspector-contracts.ts +0 -1
  84. package/src/inspector-role.ts +0 -2
  85. package/src/institutional-resolution.ts +6 -4
  86. package/src/judge-role.ts +3 -3
  87. package/src/merger-contracts.ts +0 -1
  88. package/src/merger-role.ts +2 -2
  89. package/src/navigator-public-session.ts +7 -6
  90. package/src/navigator-work-context.ts +6 -8
  91. package/src/notary-contracts.ts +0 -1
  92. package/src/notary-role.ts +2 -3
  93. package/src/package-contracts/auditor-output.ts +0 -1
  94. package/src/package-contracts/collector-output.ts +0 -1
  95. package/src/package-contracts/fixer-output.ts +0 -1
  96. package/src/package-contracts/gatekeeper-output.ts +0 -1
  97. package/src/package-contracts/judge-output.ts +0 -1
  98. package/src/package-contracts/navigator-output.ts +0 -1
  99. package/src/package-contracts/reviewer-output.ts +0 -1
  100. package/src/package-contracts/terminating-tools.ts +27 -99
  101. package/src/package-contracts/worker-output.ts +0 -2
  102. package/src/packaged-role-registry.ts +604 -35
  103. package/src/pi/role-turn-host.ts +2 -1
  104. package/src/public-cli/cli.ts +64 -259
  105. package/src/public-cli/config.ts +18 -10
  106. package/src/public-cli/countersign-run.ts +14 -449
  107. package/src/public-cli/instruction-seat-run.ts +758 -277
  108. package/src/public-cli/invocation.ts +1097 -2051
  109. package/src/public-cli/option-definitions.ts +62 -127
  110. package/src/public-cli/post-admission.ts +47 -2
  111. package/src/public-cli/run-lifecycle.ts +303 -613
  112. package/src/public-cli/seat-ticket-binding.ts +6 -0
  113. package/src/public-cli/settlement.ts +399 -1185
  114. package/src/public-cli/turn-request.ts +92 -1
  115. package/src/public-role-summons.ts +44 -128
  116. package/src/reviewer-role.ts +3 -2
  117. package/src/role-activation-flags.ts +20 -41
  118. package/src/role-runtime-dependencies.ts +25 -26
  119. package/src/role-runtime.ts +121 -232
  120. package/src/secretariat-contracts.ts +0 -1
  121. package/src/secretariat-role.ts +0 -2
  122. package/src/session-identity.ts +23 -8
  123. package/src/session-opening-materials.ts +2 -1
  124. package/src/worker-role.ts +3 -4
  125. package/dist/doctor-auditor.js +0 -25
  126. package/dist/public-cli/diarist-run.js +0 -130
  127. package/dist/public-cli/doctor-run.js +0 -87
  128. package/dist/public-cli/inspector-run.js +0 -151
  129. package/dist/public-cli/judge-run.js +0 -114
  130. package/dist/public-cli/notary-run.js +0 -174
  131. package/dist/public-cli/reviewer-run.js +0 -339
  132. package/src/public-cli/coder-run.ts +0 -255
  133. package/src/public-cli/collector-run.ts +0 -189
  134. package/src/public-cli/diarist-run.ts +0 -233
  135. package/src/public-cli/doctor-run.ts +0 -167
  136. package/src/public-cli/fixer-run.ts +0 -265
  137. package/src/public-cli/gleaner-left-run.ts +0 -167
  138. package/src/public-cli/inspector-run.ts +0 -261
  139. package/src/public-cli/judge-run.ts +0 -196
  140. package/src/public-cli/merger-run.ts +0 -294
  141. package/src/public-cli/notary-run.ts +0 -279
  142. package/src/public-cli/reviewer-run.ts +0 -480
  143. package/src/public-cli/secretariat-run.ts +0 -265
@@ -1,202 +1,212 @@
1
1
  /**
2
- * Shared instruction-seat run (#639 / #675 / #637): gatekeeper, navigator, auditor
3
- * share admit → turn-request → post-admission → settle.
4
- * Auditor same-parent (--source-run) re-summons resume via tryResumeSameTicketSeatRun
5
- * (#747); other instruction seats keep ticket-number principal — no independent
6
- * run/rebind/nest path. (#744: evidence-child public seat deleted.)
2
+ * One public role run: admit → turn request → post-admission → settle.
3
+ * Seat differences are composition-root fields. An omitted reviewer lens
4
+ * starts two ordinary single-axis runs here. Countersign keeps deferred
5
+ * identity on this entry; the court diarist station stays in countersign-run.
7
6
  */
7
+ import { resolve } from "node:path";
8
+
8
9
  import type { DurablePrincipalAuthority, RoleTurnRequest } from "../host-contracts.ts";
10
+ import { isSafePositiveTicketNumber, readBoardTicketNumber } from "../run-ticket-number.ts";
11
+ import { NotarySourceRunError, resolveNotarySourceRunLocator } from "../notary-source-run.ts";
9
12
  import { engineSessionMaterialFromOptions, pickEngineAxis } from "../package-resources/engine-material.ts";
10
- import { readBoardTicketNumber } from "../run-ticket-number.ts";
13
+ import {
14
+ loadPackagedMethodSkillMaterial,
15
+ type PackagedMethodSkillMaterial,
16
+ } from "../package-resources/method-skill.ts";
17
+ import type { PackagedRole } from "../packaged-role-registry.ts";
18
+ import {
19
+ packagedAdmitsCountersign,
20
+ packagedBindsBoardTicket,
21
+ packagedMethodLoadFailureCause,
22
+ packagedRebindSourceOnResume,
23
+ packagedRoleMetadata,
24
+ } from "../packaged-role-registry.ts";
25
+ import { isAuditorSoulRole } from "../auditor-soul.ts";
11
26
  import { CliUsageError } from "./cli-errors.ts";
12
27
  import {
13
- admitAuditorInvocation,
14
- admitGatekeeperInvocation,
15
- admitNavigatorInvocation,
28
+ admitPublicRole,
29
+ bindAdmittedTicketNumber,
30
+ bindCourtTicketNumbersOnAdmitted,
16
31
  buildInstructionTransportPrompt,
32
+ materializeCountersignInvocation,
17
33
  persistAdmittedSourceRunPath,
18
- type AdmittedAuditorInvocation,
19
- type AdmittedGatekeeperInvocation,
20
- type AdmittedNavigatorInvocation,
21
- type ParseInstructionArgvResult,
34
+ recordAdmittedCorrelation,
35
+ relocateAdmittedRunToTicket,
36
+ withPreparedAttachments,
37
+ type AdmittedCountersignInvocation,
38
+ type AdmittedRoleInvocation,
39
+ type PublicSeatParse,
22
40
  } from "./invocation.ts";
23
41
  import {
42
+ presentControlledFailure,
24
43
  prepareSummonsResumeMaterials,
44
+ resolveResumeMethodMaterialAdapters,
45
+ roleTurnOptions,
25
46
  runPostAdmissionOneShot,
47
+ runPostAdmissionResumable,
26
48
  runPostAdmissionSeatResume,
27
49
  resumeTurnRequestProjectionOptions,
28
50
  type PostAdmissionAdapters,
29
51
  type PostAdmissionEnv,
30
52
  } from "./post-admission.ts";
31
53
  import {
32
- loadResumableInstructionSeatRun,
54
+ buildAutoResumeContinuationPrompt,
55
+ loadResumablePublicRole,
33
56
  markRunAdmitted,
57
+ parentRunPathFromGatePointerInstruction,
34
58
  type PublicResumeRequest,
59
+ type RunWriterLease,
35
60
  type SameTicketSummonsMaterials,
36
61
  } from "./run-lifecycle.ts";
37
62
  import { tryResumeSameTicketSeatRun } from "./seat-ticket-binding.ts";
38
63
  import {
39
64
  presentStructuralRejection,
40
- readEngineDetourInfrastructureFailure,
41
- trySettleAuditorTerminalResult,
42
- trySettleGatekeeperTerminalResult,
43
- trySettleNavigatorTerminalResult,
65
+ seatKnownFailureResolver,
66
+ trySettlePublicSeat,
44
67
  } from "./settlement.ts";
45
68
  import type { CliIo } from "./cli-io.ts";
46
- import type { TerminalResult } from "./terminal.ts";
47
69
  import {
70
+ formatTerminalResult,
71
+ isLawfulTypedTerminalOutcome,
72
+ type TerminalResult,
73
+ } from "./terminal.ts";
74
+ import {
75
+ admittedSeatTurnDetails,
76
+ packagedSettleSkill,
48
77
  projectRoleTurnRequest,
49
78
  type RoleTurnRequestProjectionOptions,
50
79
  } from "./turn-request.ts";
80
+ import {
81
+ invokeCourtDiarist,
82
+ runCountersignCourtDiaristStation,
83
+ type CountersignRunEnv,
84
+ } from "./countersign-run.ts";
51
85
 
52
- export type InstructionSeatRole =
53
- | "gatekeeper"
54
- | "navigator"
55
- | "auditor";
56
-
57
- export type AdmittedInstructionSeatInvocation =
58
- | AdmittedGatekeeperInvocation
59
- | AdmittedNavigatorInvocation
60
- | AdmittedAuditorInvocation;
61
-
62
- export type InstructionSeatRunEnv = PostAdmissionEnv & {
63
- principalAuthority: DurablePrincipalAuthority;
64
- createRunId?: () => string;
65
- /**
66
- * #756 nested gate re-ask for auditor: plain-language instruction on same-ticket resume.
67
- * Only set by summonPublicRole when the prior officer reply was not three-state.
68
- * Never a public CLI argv — must not pollute the --source-run parent lookup key (#747).
69
- */
70
- reviewReask?: string;
71
- /**
72
- * #879 gate summons: verbatim parent-submission body for officer dialogue content.
73
- * Rides summons.instruction / first-mint prompt when reviewReask is absent.
74
- */
75
- gateReviewInstruction?: string;
86
+ export type InstructionSeatRunEnv = PostAdmissionEnv & Pick<
87
+ CountersignRunEnv,
88
+ "reviewReask" | "gateReviewInstruction" | "parentRunPath" | "runCourtDiaristStation"
89
+ >;
90
+
91
+ type SeatRunResult = {
92
+ exitCode: number;
93
+ admitted?: AdmittedRoleInvocation;
94
+ terminal?: TerminalResult;
76
95
  };
77
96
 
78
- /** Project an admitted instruction-seat invocation onto the host-neutral turn request. */
97
+ function roleRecord(role: PackagedRole) {
98
+ const record = packagedRoleMetadata(role);
99
+ if (record === undefined) {
100
+ throw new CliUsageError(`unknown role: ${role}`);
101
+ }
102
+ return record;
103
+ }
104
+
105
+ /** Project any admitted public role onto the host-neutral turn request. */
79
106
  export function buildInstructionSeatTurnRequest(
80
- admitted: AdmittedInstructionSeatInvocation,
107
+ admitted: AdmittedRoleInvocation,
81
108
  options: RoleTurnRequestProjectionOptions,
82
109
  ): RoleTurnRequest {
83
110
  return projectRoleTurnRequest(
84
111
  admitted,
85
- {
86
- activation: {
87
- role: admitted.role,
88
- },
89
- },
112
+ admittedSeatTurnDetails(admitted, options.packageRoot),
90
113
  options,
91
114
  );
92
115
  }
93
116
 
94
- function instructionSeatAdapters(options?: {
95
- beforeDispatch?: (
96
- admitted: AdmittedInstructionSeatInvocation,
97
- ) => void | Promise<void>;
98
- }): PostAdmissionAdapters<AdmittedInstructionSeatInvocation> {
99
- return {
100
- trySettle: (
101
- admitted: AdmittedInstructionSeatInvocation,
102
- authority: DurablePrincipalAuthority,
103
- scope?: { readonly courtAttemptId?: string },
104
- ) => {
105
- switch (admitted.role) {
106
- case "gatekeeper":
107
- return trySettleGatekeeperTerminalResult(admitted, authority, scope);
108
- case "navigator":
109
- return trySettleNavigatorTerminalResult(admitted, authority, scope);
110
- case "auditor":
111
- return trySettleAuditorTerminalResult(admitted, authority, scope);
112
- }
113
- },
114
- // Accepted receipts and failure terminals both present via shared path.
115
- shouldPresentSettled: () => true,
116
- // #675 / #357 T2: failInfrastructure abort after engine-detour tool failure must not
117
- // wash the durable toolResult diagnostic (same seam as reviewer-run / judge-run).
118
- resolveRunnerKnownFailure: async ({
119
- result,
120
- sessionFile,
121
- }: {
122
- result: { knownFailure?: import("../host-contracts.ts").RoleTurnKnownFailure };
123
- sessionFile: string;
124
- }) => {
125
- const infrastructureFailure = await readEngineDetourInfrastructureFailure(sessionFile);
126
- return infrastructureFailure === undefined
127
- ? result.knownFailure
128
- : {
129
- ...(infrastructureFailure.cause === undefined
130
- ? {}
131
- : { cause: infrastructureFailure.cause }),
132
- diagnostic: infrastructureFailure.diagnostic,
133
- ...(infrastructureFailure.identity === undefined
134
- ? {}
135
- : { identity: infrastructureFailure.identity }),
136
- };
137
- },
138
- ...(options?.beforeDispatch === undefined
139
- ? {}
140
- : { beforeDispatch: options.beforeDispatch }),
141
- };
117
+ function initialPrompt(
118
+ admitted: AdmittedRoleInvocation,
119
+ env: InstructionSeatRunEnv,
120
+ ): string {
121
+ const record = roleRecord(admitted.role);
122
+ const reask = env.reviewReask ?? env.gateReviewInstruction;
123
+ if (reask !== undefined && "reaskPrompt" in record && record.reaskPrompt === true) {
124
+ return reask;
125
+ }
126
+ return buildInstructionTransportPrompt(
127
+ admitted,
128
+ engineSessionMaterialFromOptions({
129
+ ...pickEngineAxis(env),
130
+ packageRoot: env.packageRoot,
131
+ }),
132
+ );
133
+ }
134
+
135
+ function hostTurnCwd(env: InstructionSeatRunEnv): { readonly cwd: string } | undefined {
136
+ return env.executionCwd === undefined ? undefined : { cwd: env.executionCwd };
137
+ }
138
+
139
+ function wantsFreshExecutionCopy(role: PackagedRole): boolean {
140
+ const record = roleRecord(role);
141
+ return "freshExecutionCopy" in record && record.freshExecutionCopy === true;
142
+ }
143
+
144
+ function infraFailure(role: PackagedRole) {
145
+ const resolveRunnerKnownFailure = seatKnownFailureResolver(role);
146
+ return resolveRunnerKnownFailure === undefined ? {} : { resolveRunnerKnownFailure };
147
+ }
148
+
149
+ function isBoardTicketSeat(
150
+ seat: AdmittedRoleInvocation,
151
+ ): seat is AdmittedRoleInvocation & { role: "diarist" } {
152
+ return packagedBindsBoardTicket(seat.role);
142
153
  }
143
154
 
144
- async function admitInstructionSeat(
145
- role: InstructionSeatRole,
146
- options: Parameters<typeof admitGatekeeperInvocation>[0],
147
- ): Promise<AdmittedInstructionSeatInvocation> {
148
- switch (role) {
149
- case "gatekeeper":
150
- return admitGatekeeperInvocation(options);
151
- case "navigator":
152
- return admitNavigatorInvocation(options);
153
- case "auditor":
154
- return admitAuditorInvocation(options);
155
+ async function bindAndRelocateDiarist(
156
+ admitted: AdmittedRoleInvocation & { role: "diarist" },
157
+ authority: DurablePrincipalAuthority,
158
+ lease?: RunWriterLease,
159
+ ): Promise<void> {
160
+ const boardTicket = await readBoardTicketNumber(admitted.runDirectory);
161
+ if (boardTicket === undefined) return;
162
+ if (admitted.ticketNumber === undefined) {
163
+ await bindAdmittedTicketNumber(admitted, boardTicket);
155
164
  }
165
+ await relocateAdmittedRunToTicket(admitted, authority, lease);
156
166
  }
157
167
 
158
- export async function runPublicInstructionSeatResume(
159
- request: PublicResumeRequest,
168
+ function seatAdapters(
169
+ admitted: AdmittedRoleInvocation,
160
170
  env: InstructionSeatRunEnv,
161
- io: CliIo,
162
- ): Promise<{
163
- exitCode: number;
164
- admitted?: AdmittedInstructionSeatInvocation;
165
- terminal?: TerminalResult;
166
- }> {
167
- return await runPostAdmissionSeatResume({
168
- request,
169
- env,
170
- io,
171
- load: (effective) => loadResumableInstructionSeatRun(
172
- env.home,
173
- effective.runId,
174
- env.principalAuthority,
175
- ),
176
- buildTurnRequest: async (admitted, effective) => {
177
- const summonsPrepared = await prepareSummonsResumeMaterials(
178
- admitted.runDirectory,
179
- effective.summons,
180
- );
181
- return buildInstructionSeatTurnRequest(
182
- admitted,
183
- resumeTurnRequestProjectionOptions(
184
- admitted,
185
- effective,
186
- env,
187
- summonsPrepared,
188
- ),
189
- );
190
- },
191
- adapters: instructionSeatAdapters(),
192
- ...(env.engine === undefined ? {} : { effectiveEngine: env.engine }),
193
- });
171
+ material?: PackagedMethodSkillMaterial,
172
+ ): PostAdmissionAdapters<AdmittedRoleInvocation> {
173
+ const record = roleRecord(admitted.role);
174
+ const present = "presentSettled" in record ? record.presentSettled : "default";
175
+ return {
176
+ trySettle: (seat, authority, scope) =>
177
+ trySettlePublicSeat(seat, authority, scope, material, env.packageRoot),
178
+ ...(present === "always" ? { shouldPresentSettled: () => true } : {}),
179
+ ...(present === "typed"
180
+ ? { shouldPresentSettled: (terminal: TerminalResult) => isLawfulTypedTerminalOutcome(terminal.roleOutcome) }
181
+ : {}),
182
+ ...infraFailure(admitted.role),
183
+ ...(packagedBindsBoardTicket(admitted.role)
184
+ ? {
185
+ beforeDispatch: async (seat: AdmittedRoleInvocation, lease?: RunWriterLease) => {
186
+ if (!isBoardTicketSeat(seat)) return;
187
+ if (env.correlationId !== undefined && env.correlationId.trim() !== "") {
188
+ await recordAdmittedCorrelation(seat, env.correlationId);
189
+ }
190
+ await bindAndRelocateDiarist(seat, env.principalAuthority, lease);
191
+ },
192
+ afterDispatch: async (seat: AdmittedRoleInvocation, lease?: RunWriterLease) => {
193
+ if (!isBoardTicketSeat(seat)) return;
194
+ await bindAndRelocateDiarist(seat, env.principalAuthority, lease);
195
+ },
196
+ }
197
+ : {}),
198
+ };
199
+ }
200
+
201
+ function usageExit(error: unknown, io: CliIo): SeatRunResult | undefined {
202
+ if (error instanceof CliUsageError) {
203
+ presentStructuralRejection(error, io);
204
+ return { exitCode: 2 };
205
+ }
206
+ return undefined;
194
207
  }
195
208
 
196
- /** Scope auditor subject/source-run env for the duration of one seat turn. */
197
- async function withAuditorSoulEnv<
198
- T,
199
- >(options: {
209
+ async function withAuditorSoulEnv<T>(options: {
200
210
  readonly subject?: "judge" | "doctor";
201
211
  readonly sourceRunDirectory?: string;
202
212
  readonly run: () => Promise<T>;
@@ -204,14 +214,10 @@ async function withAuditorSoulEnv<
204
214
  if (options.subject === undefined && options.sourceRunDirectory === undefined) {
205
215
  return options.run();
206
216
  }
207
- const { AK_ROLE_AUDITOR_SUBJECT_ENV, AK_ROLE_AUDITOR_SOURCE_RUN_ENV } = await import(
208
- "../auditor-soul.ts"
209
- );
217
+ const { AK_ROLE_AUDITOR_SUBJECT_ENV, AK_ROLE_AUDITOR_SOURCE_RUN_ENV } = await import("../auditor-soul.ts");
210
218
  const priorSubject = process.env[AK_ROLE_AUDITOR_SUBJECT_ENV];
211
219
  const priorSource = process.env[AK_ROLE_AUDITOR_SOURCE_RUN_ENV];
212
- if (options.subject !== undefined) {
213
- process.env[AK_ROLE_AUDITOR_SUBJECT_ENV] = options.subject;
214
- }
220
+ if (options.subject !== undefined) process.env[AK_ROLE_AUDITOR_SUBJECT_ENV] = options.subject;
215
221
  if (options.sourceRunDirectory !== undefined) {
216
222
  process.env[AK_ROLE_AUDITOR_SOURCE_RUN_ENV] = options.sourceRunDirectory;
217
223
  }
@@ -229,147 +235,295 @@ async function withAuditorSoulEnv<
229
235
  }
230
236
  }
231
237
 
232
- export async function runPublicInstructionSeat(
233
- argv: readonly string[],
238
+ async function dispatchAdmitted(
239
+ admitted: AdmittedRoleInvocation,
234
240
  env: InstructionSeatRunEnv,
235
241
  io: CliIo,
236
- role: InstructionSeatRole,
237
- parseArgv: (args: readonly string[]) => ParseInstructionArgvResult,
238
- ): Promise<{
239
- exitCode: number;
240
- admitted?: AdmittedInstructionSeatInvocation;
241
- terminal?: TerminalResult;
242
- }> {
243
- let parsed: ParseInstructionArgvResult;
244
- try {
245
- parsed = parseArgv(argv);
246
- } catch (error) {
247
- if (error instanceof CliUsageError) {
248
- presentStructuralRejection(error, io);
249
- return { exitCode: 2 };
242
+ ): Promise<SeatRunResult> {
243
+ const record = roleRecord(admitted.role);
244
+ let material: PackagedMethodSkillMaterial | undefined;
245
+ const skill = packagedSettleSkill(admitted);
246
+ if (skill !== undefined) {
247
+ try {
248
+ material = await loadPackagedMethodSkillMaterial(env.packageRoot, skill);
249
+ } catch (error) {
250
+ const knownCause = packagedMethodLoadFailureCause(admitted.role);
251
+ return await presentControlledFailure(admitted, {
252
+ timedOut: false,
253
+ code: null,
254
+ stderr: "",
255
+ thrown: error,
256
+ ...(knownCause === undefined ? {} : { knownCause }),
257
+ }, seatAdapters(admitted, env), env.principalAuthority, io) as SeatRunResult;
250
258
  }
251
- throw error;
252
259
  }
253
-
254
- let auditorSubject: "judge" | "doctor" | undefined;
255
- let auditorSourceRun: string | undefined;
256
- let auditorSourceTicket: number | undefined;
257
-
258
- // #637 / #747 / #771: resume prior seat run with this summons' materials.
259
- // Auditor (#747): parent --source-run path is the lookup key (typed inherit).
260
- // Other instruction seats: no mechanical ticket match against instruction text.
261
- // No bare catch→fresh.
262
- const projectRoot = parsed.project ?? env.cwd;
263
- if (role === "auditor") {
264
- if (parsed.subject !== "judge" && parsed.subject !== "doctor") {
265
- presentStructuralRejection(
266
- new CliUsageError("auditor --subject requires judge|doctor"),
267
- io,
268
- );
269
- return { exitCode: 2 };
270
- }
271
- auditorSubject = parsed.subject;
272
- const source = typeof parsed.sourceRun === "string" ? parsed.sourceRun.trim() : "";
273
- if (source === "") {
274
- presentStructuralRejection(
275
- new CliUsageError("auditor --source-run requires a run locator"),
260
+ const adapters = seatAdapters(admitted, env, material);
261
+ const execute = async (activeEnv: InstructionSeatRunEnv): Promise<SeatRunResult> => {
262
+ const auto = "inCallAutoResume" in record && record.inCallAutoResume === true;
263
+ const cwd = hostTurnCwd(activeEnv);
264
+ if (auto) {
265
+ return await runPostAdmissionResumable({
266
+ admitted,
267
+ env: activeEnv,
276
268
  io,
277
- );
278
- return { exitCode: 2 };
279
- }
280
- try {
281
- const { resolveNotarySourceRunLocator } = await import("../notary-source-run.ts");
282
- const resolved = await resolveNotarySourceRunLocator({
283
- projectRoot,
284
- sourceRun: source,
285
- home: env.home,
269
+ buildInitialRequest: () => buildInstructionSeatTurnRequest(
270
+ admitted,
271
+ roleTurnOptions(activeEnv, admitted, { kind: "initial", prompt: initialPrompt(admitted, activeEnv) }, cwd),
272
+ ),
273
+ buildResumeRequest: () => buildInstructionSeatTurnRequest(
274
+ admitted,
275
+ roleTurnOptions(activeEnv, admitted, {
276
+ kind: "resume",
277
+ prompt: buildAutoResumeContinuationPrompt({
278
+ packageRoot: activeEnv.packageRoot,
279
+ ...pickEngineAxis(activeEnv),
280
+ }),
281
+ }, cwd),
282
+ ),
283
+ adapters,
284
+ ...(activeEnv.engine === undefined ? {} : { effectiveEngine: activeEnv.engine }),
286
285
  });
287
- auditorSourceRun = resolved.runDirectory;
288
- // Auditor inherits board identity only — migration-derived is display, not admission.
289
- auditorSourceTicket = await readBoardTicketNumber(resolved.runDirectory);
290
- } catch (error) {
291
- presentStructuralRejection(
292
- new CliUsageError(error instanceof Error ? error.message : String(error)),
293
- io,
294
- );
295
- return { exitCode: 2 };
296
286
  }
287
+ return await runPostAdmissionOneShot({
288
+ admitted,
289
+ env: activeEnv,
290
+ io,
291
+ request: buildInstructionSeatTurnRequest(
292
+ admitted,
293
+ roleTurnOptions(activeEnv, admitted, { kind: "initial", prompt: initialPrompt(admitted, activeEnv) }, cwd),
294
+ ),
295
+ adapters,
296
+ ...(activeEnv.engine === undefined ? {} : { effectiveEngine: activeEnv.engine }),
297
+ });
298
+ };
299
+ if (!wantsFreshExecutionCopy(admitted.role)) return execute(env);
300
+ try {
301
+ if (env.executionCwd !== undefined) return await execute(env);
302
+ const { withEphemeralReviewerWorktree } = await import("../public-role-summons.ts");
303
+ return await withEphemeralReviewerWorktree({
304
+ projectRoot: admitted.projectRoot,
305
+ onCleanupDiagnostic: (diagnostic) => {
306
+ io.stderr(`${diagnostic}\n`);
307
+ },
308
+ run: (executionCwd) => execute({ ...env, executionCwd }),
309
+ });
310
+ } catch (error) {
311
+ return await presentControlledFailure(admitted, {
312
+ timedOut: false,
313
+ code: null,
314
+ stderr: "",
315
+ thrown: error,
316
+ }, adapters, env.principalAuthority, io) as SeatRunResult;
297
317
  }
318
+ }
298
319
 
299
- // #756/#879: auditor reask / verbatim submission body ride summons.instruction.
300
- // Binding pointer stays --source-run / argv 卷宗指针; content is body or reask.
301
- const resumeInstruction = env.reviewReask ?? env.gateReviewInstruction;
302
- const summons: SameTicketSummonsMaterials = {
303
- ...(resumeInstruction === undefined
320
+ /**
321
+ * Omitted lens on a parallel-lens seat: two ordinary single-axis runs, no parent run.
322
+ * Each leg reuses this call's argv and only adds `--lens`.
323
+ */
324
+ async function runOmittedLensBatch(
325
+ argv: readonly string[],
326
+ parsed: PublicSeatParse,
327
+ env: InstructionSeatRunEnv,
328
+ io: CliIo,
329
+ ): Promise<SeatRunResult> {
330
+ const { summonParallelReviewerLenses } = await import("../public-role-summons.ts");
331
+ const children = await summonParallelReviewerLenses({
332
+ argv,
333
+ cwd: env.cwd,
334
+ projectRoot: resolve(parsed.project ?? env.cwd),
335
+ baseRevision: parsed.baseRevision ?? "",
336
+ home: env.home,
337
+ agentDir: env.agentDir,
338
+ ...(env.credentials === undefined ? {} : { credentials: env.credentials }),
339
+ ...(env.model === undefined ? {} : { model: env.model }),
340
+ ...(env.host === undefined ? {} : { host: env.host }),
341
+ ...(env.engine === undefined ? {} : { engine: env.engine }),
342
+ ...(env.engineModel === undefined ? {} : { engineModel: env.engineModel }),
343
+ packageRoot: env.packageRoot,
344
+ ...(env.signal === undefined ? {} : { signal: env.signal }),
345
+ ...(env.correlationId === undefined ? {} : { correlationId: env.correlationId }),
346
+ roleTurnHost: env.roleTurnHost,
347
+ ...(env.hostAdapters === undefined ? {} : { hostAdapters: env.hostAdapters }),
348
+ principalAuthority: env.principalAuthority,
349
+ ...(env.timeoutMs === undefined ? {} : { timeoutMs: env.timeoutMs }),
350
+ });
351
+ const childResults = [children.completeness, children.correctness] as const;
352
+ const terminals = childResults
353
+ .map((child) => child.terminal)
354
+ .filter((terminal): terminal is TerminalResult => terminal !== undefined);
355
+ const failedChildren = childResults.filter((child) =>
356
+ child.terminal === undefined
357
+ || !isLawfulTypedTerminalOutcome(child.terminal.roleOutcome)).length;
358
+ const overlayExit = childResults.some((child) => child.exitCode !== 0);
359
+ const failed = failedChildren > 0 || overlayExit;
360
+ const overlayDiagnostics = [...new Set(
361
+ childResults
362
+ .map((child) => child.stderr)
363
+ .filter((text): text is string => typeof text === "string" && text !== ""),
364
+ )];
365
+ const terminal: TerminalResult = {
366
+ batch: "reviewer",
367
+ roleOutcome: failed
304
368
  ? {
305
- instruction: parsed.instruction,
306
- instructionEmpty: parsed.instruction.trim() === "",
369
+ kind: "failure",
370
+ role: "reviewer",
371
+ diagnostic: failedChildren > 0
372
+ ? "Reviewer batch child failure"
373
+ : (overlayDiagnostics[0] ?? "Reviewer batch infrastructure failure"),
374
+ decisiveFacts: { failedChildren },
375
+ payloads: terminals,
307
376
  }
308
- : { instruction: resumeInstruction, instructionEmpty: false }),
309
- attachmentPaths: parsed.attachmentPaths,
377
+ : { kind: "accepted", role: "reviewer", payloads: terminals },
378
+ reviewerChildren: {
379
+ ...(children.completeness.terminal === undefined ? {} : { completeness: children.completeness.terminal }),
380
+ ...(children.correctness.terminal === undefined ? {} : { correctness: children.correctness.terminal }),
381
+ },
382
+ reviewerChildOutcomes: {
383
+ completeness: { exitCode: children.completeness.exitCode, ...(children.completeness.stderr === undefined ? {} : { stderr: children.completeness.stderr }) },
384
+ correctness: { exitCode: children.correctness.exitCode, ...(children.correctness.stderr === undefined ? {} : { stderr: children.correctness.stderr }) },
385
+ },
386
+ navigator: {
387
+ disposition: "unavailable",
388
+ source: "unknown",
389
+ reason: "Reviewer batch has no parent-run Navigator attendance",
390
+ },
391
+ artifacts: terminals.flatMap((item) => item.artifacts),
310
392
  };
311
- if (role === "auditor" && auditorSourceRun !== undefined) {
312
- const resumed = await withAuditorSoulEnv({
313
- ...(auditorSubject === undefined ? {} : { subject: auditorSubject }),
314
- sourceRunDirectory: auditorSourceRun,
315
- run: () =>
316
- tryResumeSameTicketSeatRun({
317
- home: env.home,
318
- projectRoot,
319
- role,
320
- parentRunPath: auditorSourceRun,
321
- freshSummons: env.freshSummons,
322
- summons,
323
- resume: (runId, materials) =>
324
- runPublicInstructionSeatResume(
325
- { runId, ...(materials === undefined ? {} : { summons: materials }) },
326
- env,
327
- io,
328
- ),
329
- }),
393
+ io.stdout(formatTerminalResult(terminal));
394
+ return { exitCode: failed ? 1 : 0, terminal };
395
+ }
396
+
397
+ /**
398
+ * Countersign on the shared entry: gate parent resume, deferred materialization,
399
+ * 起居郎 identity, then the same one-shot settlement as every other seat.
400
+ * Court refresh stays on runCountersignCourtDiaristStation.
401
+ */
402
+ async function runCountersignBody(
403
+ parsed: PublicSeatParse,
404
+ env: InstructionSeatRunEnv,
405
+ io: CliIo,
406
+ ): Promise<SeatRunResult> {
407
+ const gateParentRunPath =
408
+ typeof env.parentRunPath === "string" && env.parentRunPath.trim() !== ""
409
+ ? env.parentRunPath
410
+ : undefined;
411
+ if (gateParentRunPath !== undefined) {
412
+ const resumeInstruction = env.reviewReask ?? env.gateReviewInstruction ?? parsed.instruction ?? "";
413
+ const resumed = await tryResumeSameTicketSeatRun({
414
+ home: env.home,
415
+ projectRoot: resolve(parsed.project ?? env.cwd),
416
+ role: "countersign",
417
+ parentRunPath: gateParentRunPath,
418
+ freshSummons: env.freshSummons,
419
+ summons: {
420
+ sourceRunPath: gateParentRunPath,
421
+ instruction: resumeInstruction,
422
+ instructionEmpty: resumeInstruction.trim() === "",
423
+ },
424
+ resume: (runId, materials) => runPublicInstructionSeatResume(
425
+ { runId, ...(materials === undefined ? {} : { summons: materials }) },
426
+ env,
427
+ io,
428
+ ),
330
429
  });
331
- if (resumed !== undefined) return resumed;
332
- // #836: reask without a prior same-parent run still mints; summons.instruction
333
- // already carries the reask text. Do not structurally terminate the queue.
430
+ if (resumed != null) return resumed;
334
431
  }
335
432
 
336
- let admitted: AdmittedInstructionSeatInvocation;
433
+ let admitted: AdmittedCountersignInvocation;
337
434
  try {
338
- admitted = await admitInstructionSeat(role, {
339
- home: env.home,
340
- principalAuthority: env.principalAuthority,
341
- cwd: env.cwd,
342
- instruction: parsed.instruction,
343
- attachmentPaths: parsed.attachmentPaths,
344
- ...(parsed.project === undefined ? {} : { project: parsed.project }),
345
- ...(env.createRunId === undefined ? {} : { createRunId: env.createRunId }),
346
- ...(env.model === undefined ? {} : { model: env.model }),
347
- ...(env.correlationId === undefined ? {} : { correlationId: env.correlationId }),
348
- ...(auditorSourceTicket === undefined
349
- ? {}
350
- : { assertedTicketNumber: auditorSourceTicket }),
351
- });
435
+ admitted = await admitPublicRole("countersign", parsed, env, { deferPersistence: true });
352
436
  } catch (error) {
353
- if (error instanceof CliUsageError) {
354
- presentStructuralRejection(error, io);
355
- return { exitCode: 2 };
356
- }
437
+ const rejected = usageExit(error, io);
438
+ if (rejected !== undefined) return rejected;
357
439
  throw error;
358
440
  }
359
441
 
360
- if (role === "auditor" && auditorSourceRun !== undefined) {
361
- await persistAdmittedSourceRunPath(admitted, auditorSourceRun);
362
- }
442
+ try {
443
+ return await withPreparedAttachments(parsed.attachmentPaths ?? [], async (preparedAttachments) => {
444
+ const materializeAdmission = async (ticketNumber?: number): Promise<void> => {
445
+ await materializeCountersignInvocation(admitted, {
446
+ home: env.home,
447
+ principalAuthority: env.principalAuthority,
448
+ preparedAttachments,
449
+ ...(env.model === undefined ? {} : { model: env.model }),
450
+ ...(ticketNumber === undefined ? {} : { ticketNumber }),
451
+ });
452
+ };
363
453
 
364
- return await withAuditorSoulEnv({
365
- ...(auditorSubject === undefined ? {} : { subject: auditorSubject }),
366
- ...(auditorSourceRun === undefined
367
- ? {}
368
- : { sourceRunDirectory: auditorSourceRun }),
369
- run: async () => {
454
+ let typedTicket: number | undefined;
455
+ let typedCourtTicketNumbers: readonly number[] | undefined;
456
+ let identityDiaristRan = false;
457
+
458
+ if (env.runCourtDiaristStation === undefined) {
459
+ let outcome: Awaited<ReturnType<typeof invokeCourtDiarist>>;
460
+ try {
461
+ outcome = await invokeCourtDiarist({
462
+ instruction: parsed.instruction ?? "",
463
+ projectRoot: admitted.projectRoot,
464
+ failureLabel: "unbound summons",
465
+ ...(env.boundTicketNumber === undefined ? {} : { boundTicketNumber: env.boundTicketNumber }),
466
+ }, env, io);
467
+ } catch (error) {
468
+ await materializeAdmission(
469
+ isSafePositiveTicketNumber(env.boundTicketNumber) ? env.boundTicketNumber : undefined,
470
+ );
471
+ await markRunAdmitted(admitted, env.principalAuthority);
472
+ return await presentControlledFailure(admitted, {
473
+ timedOut: false,
474
+ code: null,
475
+ stderr: "",
476
+ thrown: error,
477
+ }, seatAdapters(admitted, env), env.principalAuthority, io) as SeatRunResult;
478
+ }
479
+ identityDiaristRan = true;
480
+ if (outcome.identity.kind === "escalate" || outcome.failedWithoutEscalate !== undefined) {
481
+ const diagnostic = outcome.identity.kind === "escalate"
482
+ ? outcome.identity.diagnostic
483
+ : outcome.failedWithoutEscalate?.diagnostic ?? "";
484
+ await materializeAdmission(
485
+ isSafePositiveTicketNumber(env.boundTicketNumber) ? env.boundTicketNumber : undefined,
486
+ );
487
+ await markRunAdmitted(admitted, env.principalAuthority);
488
+ return await presentControlledFailure(admitted, {
489
+ timedOut: false,
490
+ code: null,
491
+ stderr: "",
492
+ thrown: new Error(diagnostic),
493
+ }, seatAdapters(admitted, env), env.principalAuthority, io) as SeatRunResult;
494
+ }
495
+ if (outcome.identity.kind === "ticket") {
496
+ typedTicket = isSafePositiveTicketNumber(env.boundTicketNumber)
497
+ ? env.boundTicketNumber
498
+ : outcome.identity.ticketNumber;
499
+ typedCourtTicketNumbers = outcome.identity.courtTicketNumbers;
500
+ } else if (isSafePositiveTicketNumber(env.boundTicketNumber)) {
501
+ typedTicket = env.boundTicketNumber;
502
+ }
503
+ }
504
+
505
+ await materializeAdmission(typedTicket);
370
506
  await markRunAdmitted(admitted, env.principalAuthority);
507
+ if (gateParentRunPath !== undefined) {
508
+ await persistAdmittedSourceRunPath(admitted, gateParentRunPath);
509
+ admitted = { ...admitted, sourceRunPath: gateParentRunPath };
510
+ }
511
+ if (identityDiaristRan && typedTicket !== undefined) {
512
+ try {
513
+ await bindAdmittedTicketNumber(admitted, typedTicket);
514
+ await relocateAdmittedRunToTicket(admitted, env.principalAuthority);
515
+ await bindCourtTicketNumbersOnAdmitted(admitted, typedCourtTicketNumbers ?? [typedTicket]);
516
+ } catch (error) {
517
+ return await presentControlledFailure(admitted, {
518
+ timedOut: false,
519
+ code: null,
520
+ stderr: "",
521
+ thrown: error,
522
+ }, seatAdapters(admitted, env), env.principalAuthority, io) as SeatRunResult;
523
+ }
524
+ }
371
525
 
372
- const turnRequest = buildInstructionSeatTurnRequest(admitted, {
526
+ const turnProjection: RoleTurnRequestProjectionOptions = {
373
527
  packageRoot: env.packageRoot,
374
528
  home: env.home,
375
529
  agentDir: env.agentDir,
@@ -381,7 +535,6 @@ export async function runPublicInstructionSeat(
381
535
  : { correlationId: env.correlationId }),
382
536
  continuation: {
383
537
  kind: "initial",
384
- // #879: gate first mint uses parent payload as content when present.
385
538
  prompt: (env.reviewReask ?? env.gateReviewInstruction)
386
539
  ?? buildInstructionTransportPrompt(
387
540
  admitted,
@@ -391,16 +544,344 @@ export async function runPublicInstructionSeat(
391
544
  }),
392
545
  ),
393
546
  },
394
- });
395
-
396
- return await runPostAdmissionOneShot({
547
+ };
548
+ const turnRequest = buildInstructionSeatTurnRequest(admitted, turnProjection);
549
+ const result = await runPostAdmissionOneShot({
397
550
  admitted,
398
551
  env,
399
552
  io,
400
553
  request: turnRequest,
401
- adapters: instructionSeatAdapters(),
554
+ adapters: {
555
+ ...seatAdapters(admitted, env),
556
+ beforeDispatch: async (admittedSeat, lease) => {
557
+ if (!packagedAdmitsCountersign(admittedSeat.role)) return;
558
+ if (!identityDiaristRan || typedTicket !== undefined) {
559
+ await runCountersignCourtDiaristStation(admittedSeat, env, io);
560
+ }
561
+ await relocateAdmittedRunToTicket(admittedSeat, env.principalAuthority, lease);
562
+ Object.assign(turnRequest, buildInstructionSeatTurnRequest(admittedSeat, turnProjection));
563
+ },
564
+ },
402
565
  ...(env.engine === undefined ? {} : { effectiveEngine: env.engine }),
403
566
  });
567
+ await relocateAdmittedRunToTicket(admitted, env.principalAuthority);
568
+ return result;
569
+ });
570
+ } catch (error) {
571
+ const rejected = usageExit(error, io);
572
+ if (rejected !== undefined) return rejected;
573
+ throw error;
574
+ }
575
+ }
576
+
577
+ export async function runPublicInstructionSeat(
578
+ argv: readonly string[],
579
+ env: InstructionSeatRunEnv,
580
+ io: CliIo,
581
+ role: PackagedRole,
582
+ parseArgv: (args: readonly string[]) => PublicSeatParse,
583
+ ): Promise<SeatRunResult> {
584
+ const record = roleRecord(role);
585
+ let parsed: PublicSeatParse;
586
+ try {
587
+ parsed = parseArgv(argv);
588
+ } catch (error) {
589
+ const rejected = usageExit(error, io);
590
+ if (rejected !== undefined) return rejected;
591
+ throw error;
592
+ }
593
+ if (packagedAdmitsCountersign(role)) {
594
+ return runCountersignBody(parsed, env, io);
595
+ }
596
+
597
+ if ("parallelLenses" in record && record.parallelLenses === true) {
598
+ if (parsed.baseRevision === undefined) {
599
+ presentStructuralRejection(new CliUsageError("reviewer requires --base"), io);
600
+ return { exitCode: 2 };
601
+ }
602
+ if (parsed.lens === undefined) {
603
+ return runOmittedLensBatch(argv, parsed, env, io);
604
+ }
605
+ }
606
+
607
+ const projectRoot = parsed.project ?? env.cwd;
608
+ let auditorSubject: "judge" | "doctor" | undefined;
609
+ let auditorSource: string | undefined;
610
+ let auditorTicket: number | undefined;
611
+ if (record.sameParent === "subject-source") {
612
+ if (!isAuditorSoulRole(parsed.subject)) {
613
+ presentStructuralRejection(new CliUsageError("auditor --subject requires judge|doctor"), io);
614
+ return { exitCode: 2 };
615
+ }
616
+ auditorSubject = parsed.subject;
617
+ const source = typeof parsed.sourceRun === "string" ? parsed.sourceRun.trim() : "";
618
+ if (source === "") {
619
+ presentStructuralRejection(new CliUsageError("auditor --source-run requires a run locator"), io);
620
+ return { exitCode: 2 };
621
+ }
622
+ try {
623
+ const resolved = await resolveNotarySourceRunLocator({ projectRoot, sourceRun: source, home: env.home });
624
+ auditorSource = resolved.runDirectory;
625
+ auditorTicket = await readBoardTicketNumber(resolved.runDirectory);
626
+ } catch (error) {
627
+ presentStructuralRejection(new CliUsageError(error instanceof Error ? error.message : String(error)), io);
628
+ return { exitCode: 2 };
629
+ }
630
+ if (auditorSource === undefined) return { exitCode: 2 };
631
+ const sourceDirectory = auditorSource;
632
+ const resumeInstruction = env.reviewReask ?? env.gateReviewInstruction;
633
+ const summons: SameTicketSummonsMaterials = {
634
+ ...(resumeInstruction === undefined
635
+ ? { instruction: parsed.instruction ?? "", instructionEmpty: (parsed.instruction ?? "").trim() === "" }
636
+ : { instruction: resumeInstruction, instructionEmpty: false }),
637
+ attachmentPaths: parsed.attachmentPaths ?? [],
638
+ };
639
+ const resumed = await withAuditorSoulEnv({
640
+ subject: auditorSubject,
641
+ sourceRunDirectory: auditorSource,
642
+ run: () => tryResumeSameTicketSeatRun({
643
+ home: env.home,
644
+ projectRoot,
645
+ role,
646
+ parentRunPath: sourceDirectory,
647
+ freshSummons: env.freshSummons,
648
+ summons,
649
+ resume: (runId, materials) => runPublicInstructionSeatResume(
650
+ { runId, ...(materials === undefined ? {} : { summons: materials }) },
651
+ env,
652
+ io,
653
+ ),
654
+ }),
655
+ });
656
+ if (resumed != null) return resumed;
657
+ }
658
+
659
+ if (record.sameParent === "gate-pointer") {
660
+ const parentRunPath = parentRunPathFromGatePointerInstruction(parsed.instruction ?? "");
661
+ if (parentRunPath !== undefined) {
662
+ const resumeInstruction = env.reviewReask ?? env.gateReviewInstruction;
663
+ const summons: SameTicketSummonsMaterials = {
664
+ sourceRunPath: parentRunPath,
665
+ ...(resumeInstruction === undefined
666
+ ? { instruction: parsed.instruction ?? "", instructionEmpty: (parsed.instruction ?? "").trim() === "" }
667
+ : { instruction: resumeInstruction, instructionEmpty: false }),
668
+ attachmentPaths: parsed.attachmentPaths ?? [],
669
+ };
670
+ const resumed = await tryResumeSameTicketSeatRun({
671
+ home: env.home,
672
+ projectRoot,
673
+ role,
674
+ parentRunPath,
675
+ freshSummons: env.freshSummons,
676
+ summons,
677
+ resume: (runId, materials) => runPublicInstructionSeatResume(
678
+ { runId, ...(materials === undefined ? {} : { summons: materials }) },
679
+ env,
680
+ io,
681
+ ),
682
+ });
683
+ if (resumed != null) return resumed;
684
+ }
685
+ }
686
+
687
+ if (record.sameParent === "source-locator") {
688
+ let source;
689
+ try {
690
+ source = await resolveNotarySourceRunLocator({
691
+ projectRoot,
692
+ sourceRun: parsed.sourceRun ?? "",
693
+ home: env.home,
694
+ });
695
+ } catch (error) {
696
+ if (error instanceof NotarySourceRunError) {
697
+ presentStructuralRejection(new CliUsageError(error.message, { cause: error }), io);
698
+ return { exitCode: 2 };
699
+ }
700
+ throw error;
701
+ }
702
+ const resumeInstruction = env.reviewReask ?? env.gateReviewInstruction;
703
+ const summons: SameTicketSummonsMaterials = {
704
+ sourceRunPath: source.runDirectory,
705
+ sourceRun: source,
706
+ ...(resumeInstruction === undefined ? {} : { instruction: resumeInstruction, instructionEmpty: false }),
707
+ };
708
+ const resumed = await tryResumeSameTicketSeatRun({
709
+ home: env.home,
710
+ projectRoot,
711
+ role,
712
+ parentRunPath: source.runDirectory,
713
+ freshSummons: env.freshSummons,
714
+ summons,
715
+ resume: (runId, materials) => runPublicInstructionSeatResume(
716
+ { runId, ...(materials === undefined ? {} : { summons: materials }) },
717
+ env,
718
+ io,
719
+ ),
720
+ });
721
+ if (resumed != null) return resumed;
722
+ }
723
+
724
+ let admitted: AdmittedRoleInvocation;
725
+ try {
726
+ admitted = await admitPublicRole(
727
+ role,
728
+ parsed,
729
+ env,
730
+ auditorTicket === undefined ? undefined : { assertedTicketNumber: auditorTicket },
731
+ );
732
+ } catch (error) {
733
+ const rejected = usageExit(error, io);
734
+ if (rejected !== undefined) return rejected;
735
+ throw error;
736
+ }
737
+
738
+ if (record.sameParent === "gate-pointer") {
739
+ const parentRunPath = parentRunPathFromGatePointerInstruction(parsed.instruction ?? "");
740
+ if (parentRunPath !== undefined) {
741
+ await persistAdmittedSourceRunPath(admitted, parentRunPath);
742
+ const sourcePatch = { sourceRunPath: parentRunPath };
743
+ admitted = { ...admitted, ...sourcePatch };
744
+ }
745
+ }
746
+ if (record.sameParent === "subject-source" && auditorSource !== undefined) {
747
+ await persistAdmittedSourceRunPath(admitted, auditorSource);
748
+ }
749
+
750
+ const runAdmitted = async (): Promise<SeatRunResult> => {
751
+ await markRunAdmitted(admitted, env.principalAuthority);
752
+ if (record.sameParent === "court-diarist") {
753
+ const { invokeCourtDiarist } = await import("./countersign-run.ts");
754
+ const outcome = await invokeCourtDiarist({
755
+ instruction: parsed.instruction ?? "",
756
+ projectRoot: admitted.projectRoot,
757
+ failureLabel: "secretariat unbound summons",
758
+ attachmentPaths: admitted.attachments.map((attachment) => attachment.frozenPath),
759
+ correlationId: admitted.runId,
760
+ }, {
761
+ cwd: env.cwd,
762
+ home: env.home,
763
+ agentDir: env.agentDir,
764
+ packageRoot: env.packageRoot,
765
+ ...(env.credentials === undefined ? {} : { credentials: env.credentials }),
766
+ ...(env.signal === undefined ? {} : { signal: env.signal }),
767
+ ...(env.hostAdapters === undefined ? {} : { hostAdapters: env.hostAdapters }),
768
+ }, io);
769
+ if (outcome.identity.kind === "escalate" || outcome.failedWithoutEscalate !== undefined) {
770
+ const diagnostic = outcome.identity.kind === "escalate"
771
+ ? outcome.identity.diagnostic
772
+ : outcome.failedWithoutEscalate?.diagnostic ?? "";
773
+ return await presentControlledFailure(admitted, {
774
+ timedOut: false,
775
+ code: null,
776
+ stderr: "",
777
+ thrown: new Error(diagnostic),
778
+ }, seatAdapters(admitted, env), env.principalAuthority, io) as SeatRunResult;
779
+ }
780
+ if (outcome.identity.kind === "ticket") {
781
+ try {
782
+ await bindAdmittedTicketNumber(admitted, outcome.identity.ticketNumber);
783
+ await relocateAdmittedRunToTicket(admitted, env.principalAuthority);
784
+ } catch (error) {
785
+ return await presentControlledFailure(admitted, {
786
+ timedOut: false,
787
+ code: null,
788
+ stderr: "",
789
+ thrown: error,
790
+ }, seatAdapters(admitted, env), env.principalAuthority, io) as SeatRunResult;
791
+ }
792
+ }
793
+ }
794
+ return dispatchAdmitted(admitted, env, io);
795
+ };
796
+
797
+ if (record.sameParent === "subject-source") {
798
+ return withAuditorSoulEnv({
799
+ ...(auditorSubject === undefined ? {} : { subject: auditorSubject }),
800
+ ...(auditorSource === undefined ? {} : { sourceRunDirectory: auditorSource }),
801
+ run: runAdmitted,
802
+ });
803
+ }
804
+ return runAdmitted();
805
+ }
806
+
807
+ export async function runPublicInstructionSeatResume(
808
+ request: PublicResumeRequest,
809
+ env: InstructionSeatRunEnv,
810
+ io: CliIo,
811
+ ): Promise<SeatRunResult> {
812
+ const execution: { cwd?: string } = {
813
+ ...(env.executionCwd === undefined ? {} : { cwd: env.executionCwd }),
814
+ };
815
+ return runPostAdmissionSeatResume<AdmittedRoleInvocation>({
816
+ request,
817
+ env,
818
+ io,
819
+ load: async (effective) => {
820
+ const loaded = await loadResumablePublicRole(env.home, effective.runId, env.principalAuthority);
821
+ if (
822
+ packagedRebindSourceOnResume(loaded.admitted.role)
823
+ && effective.summons?.sourceRunPath !== undefined
824
+ && effective.summons.sourceRun !== undefined
825
+ ) {
826
+ return {
827
+ ...loaded,
828
+ admitted: {
829
+ ...loaded.admitted,
830
+ sourceRunPath: effective.summons.sourceRunPath,
831
+ sourceRun: effective.summons.sourceRun,
832
+ },
833
+ };
834
+ }
835
+ return loaded;
836
+ },
837
+ buildTurnRequest: async (admitted, effective) => {
838
+ const activeEnv = execution.cwd === undefined ? env : { ...env, executionCwd: execution.cwd };
839
+ const summonsPrepared = await prepareSummonsResumeMaterials(admitted.runDirectory, effective.summons);
840
+ return buildInstructionSeatTurnRequest(
841
+ admitted,
842
+ {
843
+ ...resumeTurnRequestProjectionOptions(admitted, effective, activeEnv, summonsPrepared),
844
+ ...(execution.cwd === undefined ? {} : { cwd: execution.cwd }),
845
+ },
846
+ );
847
+ },
848
+ adapters: {
849
+ trySettle: async () => undefined,
850
+ },
851
+ afterAdmittedLoad: (admitted) => {
852
+ const skill = packagedSettleSkill(admitted);
853
+ if (skill === undefined) {
854
+ return Promise.resolve({ kind: "continue" as const, adapters: seatAdapters(admitted, env) });
855
+ }
856
+ const knownCause = packagedMethodLoadFailureCause(admitted.role);
857
+ return resolveResumeMethodMaterialAdapters({
858
+ admitted,
859
+ authority: env.principalAuthority,
860
+ io,
861
+ loadMaterial: () => loadPackagedMethodSkillMaterial(env.packageRoot, skill),
862
+ adaptersWith: (material) => seatAdapters(admitted, env, material),
863
+ emptyAdapters: seatAdapters(admitted, env),
864
+ ...(knownCause === undefined ? {} : { knownCause }),
865
+ });
866
+ },
867
+ afterAdmittedPrepare: async (admitted) => {
868
+ if (!wantsFreshExecutionCopy(admitted.role)) return {};
869
+ if (execution.cwd !== undefined) {
870
+ return { env: { ...env, executionCwd: execution.cwd } };
871
+ }
872
+ const { openEphemeralReviewerWorktree } = await import("../public-role-summons.ts");
873
+ const opened = await openEphemeralReviewerWorktree({
874
+ projectRoot: admitted.projectRoot,
875
+ onCleanupDiagnostic: (diagnostic) => {
876
+ io.stderr(`${diagnostic}\n`);
877
+ },
878
+ });
879
+ execution.cwd = opened.executionCwd;
880
+ return {
881
+ env: { ...env, executionCwd: opened.executionCwd },
882
+ cleanup: opened.close,
883
+ };
404
884
  },
885
+ ...(env.engine === undefined ? {} : { effectiveEngine: env.engine }),
405
886
  });
406
887
  }