@akagilnc/pi-workflow-roles 0.1.5365 → 0.1.5368

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.
@@ -214,6 +214,9 @@ function roleRunPlacement(ledgerHome, input) {
214
214
  function roleRunArtifactsDirectory(runDirectory) {
215
215
  return join3(runDirectory, "artifacts");
216
216
  }
217
+ function isUnboundRunDirectory(runDirectory) {
218
+ return runDirectory.replaceAll("\\", "/").includes("/unbound/runs/");
219
+ }
217
220
  var init_role_run_placement = __esm({
218
221
  "src/role-run-placement.ts"() {
219
222
  "use strict";
@@ -195140,9 +195143,6 @@ async function resolveMigratingRunTicket(runDirectory) {
195140
195143
  }
195141
195144
  };
195142
195145
  }
195143
- function isUnboundRunDirectory(runDirectory) {
195144
- return runDirectory.replaceAll("\\", "/").includes("/unbound/runs/");
195145
- }
195146
195146
  function bookHistoricalRoots(booksDirectory, backupBooksDirectory, bookKey) {
195147
195147
  return [join17(booksDirectory, bookKey), join17(backupBooksDirectory, bookKey)];
195148
195148
  }
@@ -155,7 +155,7 @@ function jsonSafeReplacer() {
155
155
  * + O_NOFOLLOW where the platform provides it (a planted symlink is never
156
156
  * followed) — mirrors settlement.ts's own hardened artifact writers.
157
157
  */
158
- async function writeHardenedArtifactFile(artifactsDir, namePrefix, payload) {
158
+ export async function writeHardenedArtifactFile(artifactsDir, namePrefix, payload) {
159
159
  const filePath = join(artifactsDir, `${namePrefix}-${randomUUID()}.json`);
160
160
  const body = `${JSON.stringify(payload, jsonSafeReplacer(), 2)}\n`;
161
161
  const noFollowFlag = typeof fsConstants.O_NOFOLLOW === "number" ? fsConstants.O_NOFOLLOW : 0;
@@ -3,19 +3,19 @@ import { piDurablePrincipalAuthority } from "../pi/durable-principal.js";
3
3
  * Public ak-role CLI dispatcher (roles / config / layered help / Judge run).
4
4
  */
5
5
  import { realpath } from "node:fs/promises";
6
- import { join } from "node:path";
7
6
  import { packageMachineHome } from "../activation-ledger-topology.js";
8
7
  import { assertLegalEngineModel, assertLegalEngineName, pickEngineAxis, } from "../package-resources/engine-material.js";
9
8
  import { resolveConfiguredProvinceOfficer, } from "../institutional-resolution.js";
10
- import { clearPersistentSeatConfig, effectiveSeatConfigurations, formatModelSpec, isGateOfficerSeat, loadCredentialProviders, loadPublicCliConfig, missingResolvedSeatModelMessage, parseModelSpec, resolveEffectiveSeat, resolvedSeatWithModel, savePublicCliConfig, setAutoResumeLimit, setPersistentSeatConfig, setPersistentSeatEngine, setPersistentSeatEngineModel, setPersistentSeatHost, validatePublicCliConfigAxes, } from "./config.js";
11
- import { loadHostProvidersTable, projectHostFacingProvider, renderHostProvidersTable, } from "./host-providers.js";
9
+ import { clearPersistentSeatConfig, effectiveSeatConfigurations, formatModelSpec, isGateOfficerSeat, loadCredentialProviders, loadPublicCliConfig, missingResolvedSeatModelMessage, parseModelSpec, resolveEffectiveSeat, savePublicCliConfig, setAutoResumeLimit, setPersistentSeatConfig, setPersistentSeatEngine, setPersistentSeatEngineModel, setPersistentSeatHost, resolvePublicAgentDir, validatePublicCliConfigAxes, } from "./config.js";
10
+ import { loadHostProvidersTable, renderHostProvidersTable, } from "./host-providers.js";
12
11
  import { packagedModelParent } from "../packaged-role-registry.js";
13
12
  import { seatModelOnly } from "./registry.js";
14
13
  import { CliUsageError } from "./cli-errors.js";
15
14
  import { runMachineSkillSetup } from "./machine-method-skills.js";
16
15
  import { presentLocatedResumeFailure, } from "./post-admission.js";
17
16
  import { appendPiSessionCustomEntry } from "../pi/role-turn-host.js";
18
- import { composeRoleTurnHostAdapters, formatHostSelectionFailure, HostSelectionError, selectRoleTurnHost, } from "./role-turn-host-resolution.js";
17
+ import { openRoleSeatRuntime } from "./role-seat-runtime.js";
18
+ import { formatHostSelectionFailure, HostSelectionError, } from "./role-turn-host-resolution.js";
19
19
  import { parseAnalystArgv, parsePublicSeatArgv, } from "./invocation.js";
20
20
  import { createTypedOptionConsumer, optionsForOwner, projectCommandHelp, projectOwnerOptions, PUBLIC_NAVIGATOR_HELP_NOTE, PUBLIC_ROLE_OPTION_OWNERS, renderHumanOwnerOptionLines, } from "./option-definitions.js";
21
21
  import { TurnDispatchedFailure } from "./auto-resume.js";
@@ -89,43 +89,41 @@ function takePublicGlobalFlag(argv, index, options) {
89
89
  function createRoleEnvironment(env, options,
90
90
  /** #178: after host selection, before missing-model — structural argv parse once. */
91
91
  afterHost) {
92
- const role = options.role;
93
92
  const extraPiArgs = env.extraPiArgs;
94
93
  const timeoutMs = env.timeoutMs;
95
- // #617/#178/#788/#840: host first, then model; nested child seat selects own host.
96
- const hostAdapters = composeRoleTurnHostAdapters({
97
- packageRoot: env.packageRoot,
98
- ...(env.roleTurnHost === undefined ? {} : { roleTurnHost: env.roleTurnHost }),
99
- ...(env.hostAdapters === undefined ? {} : { hostAdapters: env.hostAdapters }),
100
- ...(extraPiArgs === undefined ? {} : { extraPiArgs }),
101
- ...(timeoutMs === undefined ? {} : { timeoutMs }),
102
- }, env.principalAuthority);
103
- const roleTurnHost = selectRoleTurnHost(hostAdapters, {
104
- role,
94
+ const opened = openRoleSeatRuntime({
95
+ resolution: {
96
+ packageRoot: env.packageRoot,
97
+ ...(env.roleTurnHost === undefined ? {} : { roleTurnHost: env.roleTurnHost }),
98
+ ...(env.hostAdapters === undefined ? {} : { hostAdapters: env.hostAdapters }),
99
+ ...(extraPiArgs === undefined ? {} : { extraPiArgs }),
100
+ ...(timeoutMs === undefined ? {} : { timeoutMs }),
101
+ },
102
+ principalAuthority: env.principalAuthority,
103
+ role: options.role,
105
104
  seat: options.seat,
105
+ home: options.home,
106
+ ...(afterHost === undefined ? {} : { afterHost }),
106
107
  });
107
- // #178: host → argv (afterHost) → missing-model → provider projection.
108
- afterHost?.();
109
- const seatWithModel = resolvedSeatWithModel(options.seat);
110
- if (seatWithModel === undefined) {
108
+ if (!opened.ok) {
111
109
  // Direct CLI has --model; dual remediation is intentional here (#178 / #916).
112
110
  throw new CliUsageError(missingResolvedSeatModelMessage(options.seat.seat, "invocation-or-config"));
113
111
  }
114
- const hostFacingSelection = projectHostFacingProvider(seatWithModel.selection, seatWithModel.host, loadHostProvidersTable(options.home), options.home);
115
112
  return {
116
113
  home: options.home,
117
114
  principalAuthority: env.principalAuthority,
118
115
  agentDir: options.agentDir,
119
116
  sessionAppender: appendPiSessionCustomEntry,
120
117
  packageRoot: env.packageRoot,
121
- roleTurnHost,
122
- hostAdapters,
118
+ roleTurnHost: opened.roleTurnHost,
119
+ hostAdapters: opened.hostAdapters,
123
120
  cwd: options.cwd,
124
121
  ...(options.credentials === undefined ? {} : { credentials: options.credentials }),
125
122
  ...(env.correlationId === undefined ? {} : { correlationId: env.correlationId }),
126
- ...(hostFacingSelection === undefined ? {} : { model: hostFacingSelection }),
127
- ...projectSeatEngine(options.seat),
128
- ...projectSeatHost(options.seat),
123
+ ...(opened.model === undefined ? {} : { model: opened.model }),
124
+ ...(opened.engine === undefined ? {} : { engine: opened.engine }),
125
+ ...(opened.engineModel === undefined ? {} : { engineModel: opened.engineModel }),
126
+ host: opened.host,
129
127
  ...(timeoutMs === undefined ? {} : { timeoutMs }),
130
128
  ...(env.createRunId === undefined ? {} : { createRunId: env.createRunId }),
131
129
  ...(options.config?.autoResumeLimit === undefined
@@ -138,18 +136,31 @@ afterHost) {
138
136
  ...(env.signal === undefined ? {} : { signal: env.signal }),
139
137
  };
140
138
  }
139
+ /** Shared preamble for a new public role command and an explicit resume. */
140
+ async function loadPublicRoleDispatchParts(env, home) {
141
+ const agentDir = resolvePublicAgentDir(env.agentDir, home);
142
+ const cwd = env.cwd ?? process.cwd();
143
+ const config = await loadAndValidateConfig(home, env.packageRoot);
144
+ const credentials = env.credentials ?? (await loadCredentialProviders(agentDir));
145
+ return { agentDir, cwd, config, credentials };
146
+ }
141
147
  /**
142
148
  * #178 single spine: resolve seat → host select → argv parse once → missing-model → run.
143
149
  * Keeps host-unregistered ahead of bad argv and missing-model.
144
150
  */
145
151
  async function dispatchPublicRoleCommand(env, home, io, parsed, role, parse, run) {
146
- const agentDir = resolveAgentDir(env, home);
147
- const cwd = env.cwd ?? process.cwd();
148
- const config = await loadAndValidateConfig(home, env.packageRoot);
149
- const credentials = env.credentials ?? (await loadCredentialProviders(agentDir));
150
- const seat = resolveEffectiveSeat(config, role, credentials, invocationFromParsed(parsed));
152
+ const parts = await loadPublicRoleDispatchParts(env, home);
153
+ const seat = resolveEffectiveSeat(parts.config, role, parts.credentials, invocationFromParsed(parsed));
151
154
  let parsedRoleArgv;
152
- const result = await run(parsed.args, createRoleEnvironment(env, { role, home, agentDir, cwd, credentials, seat, config }, () => {
155
+ const result = await run(parsed.args, createRoleEnvironment(env, {
156
+ role,
157
+ home,
158
+ agentDir: parts.agentDir,
159
+ cwd: parts.cwd,
160
+ credentials: parts.credentials,
161
+ seat,
162
+ config: parts.config,
163
+ }, () => {
153
164
  parsedRoleArgv = parse(parsed.args);
154
165
  }), () => parsedRoleArgv);
155
166
  return {
@@ -176,11 +187,6 @@ function defaultIo() {
176
187
  function resolveHome(env) {
177
188
  return env.home ?? packageMachineHome();
178
189
  }
179
- function resolveAgentDir(env, home) {
180
- return (env.agentDir ??
181
- process.env.PI_CODING_AGENT_DIR ??
182
- join(home, ".pi", "agent"));
183
- }
184
190
  function parseThinking(value) {
185
191
  // #683: opaque pass-through — no local whitelist.
186
192
  return value;
@@ -316,14 +322,6 @@ function requireCallableSeat(seat, axis, verb) {
316
322
  throw new CliUsageError(`unknown ${axis}-axis seat: ${seat}`);
317
323
  }
318
324
  }
319
- /** Single seat engine axis → run-options projection (#391 E2 / #883). */
320
- function projectSeatEngine(seat) {
321
- return pickEngineAxis(seat);
322
- }
323
- /** Single seat.host → run-options projection (#595 / #617). */
324
- function projectSeatHost(seat) {
325
- return { host: seat.host };
326
- }
327
325
  function loadAndValidateConfig(home, packageRoot) {
328
326
  return loadPublicCliConfig(home).then((config) => {
329
327
  try {
@@ -787,7 +785,7 @@ export async function runAkRole(argv, env) {
787
785
  }
788
786
  const config = await loadAndValidateConfig(home, env.packageRoot);
789
787
  const credentials = env.credentials ??
790
- (await loadCredentialProviders(resolveAgentDir(env, home)));
788
+ (await loadCredentialProviders(resolvePublicAgentDir(env.agentDir, home)));
791
789
  const seats = effectiveSeatConfigurations(config, credentials, invocationFromParsed(parsed));
792
790
  io.stdout(renderRoles(seats));
793
791
  return { exitCode: 0 };
@@ -829,23 +827,20 @@ export async function runAkRole(argv, env) {
829
827
  runId: resumeRequest.runId,
830
828
  authority: env.principalAuthority ?? piDurablePrincipalAuthority,
831
829
  };
832
- const agentDir = resolveAgentDir(env, home);
833
- const cwd = env.cwd ?? process.cwd();
834
- const config = await loadAndValidateConfig(home, env.packageRoot);
835
- const credentials = env.credentials ?? (await loadCredentialProviders(agentDir));
830
+ const parts = await loadPublicRoleDispatchParts(env, home);
836
831
  const resumeRole = await peekRoleRunRole(home, resumeRequest.runId);
837
832
  // Missing durable role keeps the judge seat table. The resume entry
838
833
  // itself is one function; it reads the stored run.
839
834
  const seatRole = resumeRole ?? "judge";
840
- const seat = resolveEffectiveSeat(config, seatRole, credentials, invocationFromParsed(parsed));
835
+ const seat = resolveEffectiveSeat(parts.config, seatRole, parts.credentials, invocationFromParsed(parsed));
841
836
  const result = await runPublicInstructionSeatResume(resumeRequest, createRoleEnvironment(env, {
842
837
  role: seatRole,
843
838
  home,
844
- agentDir,
845
- cwd,
846
- credentials,
839
+ agentDir: parts.agentDir,
840
+ cwd: parts.cwd,
841
+ credentials: parts.credentials,
847
842
  seat,
848
- config,
843
+ config: parts.config,
849
844
  }), io);
850
845
  let current = result;
851
846
  while (current.exitCode === 0 && current.admitted?.correlationId !== undefined
@@ -860,9 +855,15 @@ export async function runAkRole(argv, env) {
860
855
  const parentRole = await peekRoleRunRole(home, parentRunId);
861
856
  if (parentRole === undefined)
862
857
  break;
863
- const parentSeat = resolveEffectiveSeat(config, parentRole, credentials, invocationFromParsed(parsed));
858
+ const parentSeat = resolveEffectiveSeat(parts.config, parentRole, parts.credentials, invocationFromParsed(parsed));
864
859
  const parentEnv = createRoleEnvironment(env, {
865
- role: parentRole, home, agentDir, cwd, credentials, seat: parentSeat, config,
860
+ role: parentRole,
861
+ home,
862
+ agentDir: parts.agentDir,
863
+ cwd: parts.cwd,
864
+ credentials: parts.credentials,
865
+ seat: parentSeat,
866
+ config: parts.config,
866
867
  });
867
868
  current = await continueParentAfterChild(parentRunId, current.admitted, parentEnv, io);
868
869
  }
@@ -490,6 +490,9 @@ function credentialProvidersFromAuthData(data) {
490
490
  xai: Object.prototype.hasOwnProperty.call(record, "xai")
491
491
  };
492
492
  }
493
+ function resolvePublicAgentDir(explicit, home) {
494
+ return explicit ?? process.env.PI_CODING_AGENT_DIR ?? join(home, ".pi", "agent");
495
+ }
493
496
  async function loadCredentialProviders(agentDir) {
494
497
  try {
495
498
  const raw = await readFile(join(agentDir, "auth.json"), "utf8");
@@ -519,6 +522,7 @@ export {
519
522
  providerConfigured,
520
523
  publicCliConfigPath,
521
524
  resolveEffectiveSeat,
525
+ resolvePublicAgentDir,
522
526
  resolvedSeatWithModel,
523
527
  savePublicCliConfig,
524
528
  setAutoResumeLimit,
@@ -3,7 +3,8 @@
3
3
  * Seat differences are composition-root fields. An omitted reviewer lens
4
4
  * starts two ordinary single-axis runs here.
5
5
  */
6
- import { dirname, resolve, sep } from "node:path";
6
+ import { dirname, resolve } from "node:path";
7
+ import { isUnboundRunDirectory } from "../role-run-placement.js";
7
8
  import { AUDITOR_DOSSIER_PROMPT } from "../compliance-transport.js";
8
9
  import { bookDirectOfficerRunPointer } from "../archivist-record-pointer.js";
9
10
  import { createPiDoctorAuditor } from "../doctor-auditor.js";
@@ -22,7 +23,7 @@ import { isSafePositiveTicketNumber, readBoardTicketNumber } from "../run-ticket
22
23
  import { NotarySourceRunError, resolveNotarySourceRunLocator } from "../notary-source-run.js";
23
24
  import { engineSessionMaterialFromOptions, pickEngineAxis } from "../package-resources/engine-material.js";
24
25
  import { packagedAdmitsCountersign, packagedBindsBoardTicket, packagedRebindSourceOnResume, packagedRoleMetadata, } from "../packaged-role-registry.js";
25
- import { isAuditorSoulRole, readAuditorResumeBinding } from "../auditor-soul.js";
26
+ import { readAuditorResumeBinding } from "../auditor-soul.js";
26
27
  import { CliUsageError } from "./cli-errors.js";
27
28
  import { admitPublicRole, bindAdmittedTicketNumber, buildInstructionTransportPrompt, materializeCountersignInvocation, persistAdmittedSourceRunPath, recordAdmittedCorrelation, recordChildDiaristRun, relocateAdmittedRunToTicket, withPreparedAttachments, } from "./invocation.js";
28
29
  import { presentControlledFailure, prepareSummonsResumeMaterials, roleTurnOptions, runPostAdmissionOneShot, runPostAdmissionResumable, runPostAdmissionSeatResume, showResumeErrorPointer, resumeTurnRequestProjectionOptions, } from "./post-admission.js";
@@ -31,7 +32,7 @@ import { tryResumeSameTicketSeatRun } from "./seat-ticket-binding.js";
31
32
  import { presentStructuralRejection, readBoundSessionEntries, seatKnownFailureResolver, attachPostAuditProjection, trySettlePublicSeat, } from "./settlement.js";
32
33
  import { warnMissingMethodSkills } from "./machine-method-skills.js";
33
34
  import { formatTerminalResult, isLawfulTypedTerminalOutcome, } from "./terminal.js";
34
- import { admittedSeatTurnDetails, projectRoleTurnRequest, requiredMethodSkills, } from "./turn-request.js";
35
+ import { admittedSeatTurnDetails, projectPublicTurnAxes, projectRoleTurnRequest, requiredMethodSkills, } from "./turn-request.js";
35
36
  import { invokeCourtDiarist, latestPayloadEscalated, } from "./countersign-run.js";
36
37
  const AUDITED_ROLES = new Set(["judge", "fixer", "coder", "secretariat", "countersign", "doctor"]);
37
38
  const SECRETARIAT_STATUS_REASK = "secretariatStatus 不是 converged、escalate 之一。请重新交卷,secretariatStatus 写明其一。";
@@ -309,6 +310,29 @@ async function runOmittedLensBatch(argv, parsed, env, io) {
309
310
  io.stdout(formatTerminalResult(terminal));
310
311
  return { exitCode: failed ? 1 : 0, terminal };
311
312
  }
313
+ /**
314
+ * One same-parent lookup. Seat branches still build their own summons.
315
+ * A found child resumes that child; no prior run returns undefined so the caller mints.
316
+ */
317
+ function resumeSameParentInstructionSeat(input) {
318
+ return tryResumeSameTicketSeatRun({
319
+ home: input.env.home,
320
+ projectRoot: input.projectRoot,
321
+ role: input.role,
322
+ parentRunPath: input.parentRunPath,
323
+ ...(input.ticketNumber === undefined ? {} : { ticketNumber: input.ticketNumber }),
324
+ freshSummons: input.env.freshSummons,
325
+ summons: input.summons,
326
+ resume: (runId, materials) => runPublicInstructionSeatResume({ runId, ...(materials === undefined ? {} : { summons: materials }) }, input.env, input.io),
327
+ });
328
+ }
329
+ /** Re-ask words when the parent supplied them; otherwise the caller's own instruction. */
330
+ function sameParentInstruction(env, fallback) {
331
+ const resumeInstruction = env.reviewReask ?? env.gateReviewInstruction;
332
+ if (resumeInstruction === undefined)
333
+ return fallback;
334
+ return { instruction: resumeInstruction, instructionEmpty: false };
335
+ }
312
336
  /**
313
337
  * Countersign on the shared entry: gate parent resume, deferred materialization,
314
338
  * then the same one-shot settlement as every other seat.
@@ -319,19 +343,20 @@ async function runCountersignBody(parsed, env, io) {
319
343
  : undefined;
320
344
  if (gateParentRunPath !== undefined) {
321
345
  const resumeInstruction = env.reviewReask ?? env.gateReviewInstruction ?? parsed.instruction ?? "";
322
- const resumed = await tryResumeSameTicketSeatRun({
323
- home: env.home,
346
+ const resumed = await resumeSameParentInstructionSeat({
347
+ env,
348
+ io,
324
349
  projectRoot: resolve(parsed.project ?? env.cwd),
325
350
  role: "countersign",
326
351
  parentRunPath: gateParentRunPath,
327
- ...(isSafePositiveTicketNumber(env.boundTicketNumber) ? { ticketNumber: env.boundTicketNumber } : {}),
328
- freshSummons: env.freshSummons,
352
+ ...(isSafePositiveTicketNumber(env.boundTicketNumber)
353
+ ? { ticketNumber: env.boundTicketNumber }
354
+ : {}),
329
355
  summons: {
330
356
  sourceRunPath: gateParentRunPath,
331
357
  instruction: resumeInstruction,
332
358
  instructionEmpty: resumeInstruction.trim() === "",
333
359
  },
334
- resume: (runId, materials) => runPublicInstructionSeatResume({ runId, ...(materials === undefined ? {} : { summons: materials }) }, env, io),
335
360
  });
336
361
  if (resumed != null)
337
362
  return resumed;
@@ -364,12 +389,7 @@ async function runCountersignBody(parsed, env, io) {
364
389
  admitted = { ...admitted, sourceRunPath: gateParentRunPath };
365
390
  }
366
391
  const turnProjection = {
367
- packageRoot: env.packageRoot,
368
- home: env.home,
369
- agentDir: env.agentDir,
370
- ...(env.model === undefined ? {} : { model: env.model }),
371
- ...pickEngineAxis(env),
372
- ...(env.timeoutMs === undefined ? {} : { timeoutMs: env.timeoutMs }),
392
+ ...projectPublicTurnAxes(env),
373
393
  ...(env.correlationId === undefined || env.correlationId.trim() === ""
374
394
  ? {}
375
395
  : { correlationId: env.correlationId }),
@@ -446,17 +466,18 @@ export async function runPublicInstructionSeat(argv, env, io, role, parseArgv) {
446
466
  let auditorSubject;
447
467
  let auditorSource;
448
468
  let auditorTicket;
469
+ let resolvedNotarySource;
449
470
  if (record.sameParent === "subject-source") {
450
- if (!isAuditorSoulRole(parsed.subject)) {
471
+ if (parsed.subject === undefined) {
451
472
  presentStructuralRejection(new CliUsageError("auditor --subject requires judge|doctor"), io);
452
473
  return { exitCode: 2 };
453
474
  }
454
475
  auditorSubject = parsed.subject;
455
- const source = typeof parsed.sourceRun === "string" ? parsed.sourceRun.trim() : "";
456
- if (source === "") {
476
+ if (parsed.sourceRun === undefined) {
457
477
  presentStructuralRejection(new CliUsageError("auditor --source-run requires a run locator"), io);
458
478
  return { exitCode: 2 };
459
479
  }
480
+ const source = parsed.sourceRun;
460
481
  try {
461
482
  const resolved = await resolveNotarySourceRunLocator({ projectRoot, sourceRun: source, home: env.home });
462
483
  auditorSource = resolved.runDirectory;
@@ -469,24 +490,23 @@ export async function runPublicInstructionSeat(argv, env, io, role, parseArgv) {
469
490
  if (auditorSource === undefined)
470
491
  return { exitCode: 2 };
471
492
  const sourceDirectory = auditorSource;
472
- const resumeInstruction = env.reviewReask ?? env.gateReviewInstruction;
473
493
  const summons = {
474
- ...(resumeInstruction === undefined
475
- ? { instruction: parsed.instruction ?? "", instructionEmpty: (parsed.instruction ?? "").trim() === "" }
476
- : { instruction: resumeInstruction, instructionEmpty: false }),
494
+ ...sameParentInstruction(env, {
495
+ instruction: parsed.instruction ?? "",
496
+ instructionEmpty: (parsed.instruction ?? "").trim() === "",
497
+ }),
477
498
  attachmentPaths: parsed.attachmentPaths ?? [],
478
499
  };
479
500
  const resumed = await withAuditorSoulEnv({
480
501
  subject: auditorSubject,
481
502
  sourceRunDirectory: auditorSource,
482
- run: () => tryResumeSameTicketSeatRun({
483
- home: env.home,
503
+ run: () => resumeSameParentInstructionSeat({
504
+ env,
505
+ io,
484
506
  projectRoot,
485
507
  role,
486
508
  parentRunPath: sourceDirectory,
487
- freshSummons: env.freshSummons,
488
509
  summons,
489
- resume: (runId, materials) => runPublicInstructionSeatResume({ runId, ...(materials === undefined ? {} : { summons: materials }) }, env, io),
490
510
  }),
491
511
  });
492
512
  if (resumed != null)
@@ -495,22 +515,21 @@ export async function runPublicInstructionSeat(argv, env, io, role, parseArgv) {
495
515
  if (record.sameParent === "gate-pointer") {
496
516
  const parentRunPath = parentRunPathFromGatePointerInstruction(parsed.instruction ?? "");
497
517
  if (parentRunPath !== undefined) {
498
- const resumeInstruction = env.reviewReask ?? env.gateReviewInstruction;
499
518
  const summons = {
500
519
  sourceRunPath: parentRunPath,
501
- ...(resumeInstruction === undefined
502
- ? { instruction: parsed.instruction ?? "", instructionEmpty: (parsed.instruction ?? "").trim() === "" }
503
- : { instruction: resumeInstruction, instructionEmpty: false }),
520
+ ...sameParentInstruction(env, {
521
+ instruction: parsed.instruction ?? "",
522
+ instructionEmpty: (parsed.instruction ?? "").trim() === "",
523
+ }),
504
524
  attachmentPaths: parsed.attachmentPaths ?? [],
505
525
  };
506
- const resumed = await tryResumeSameTicketSeatRun({
507
- home: env.home,
526
+ const resumed = await resumeSameParentInstructionSeat({
527
+ env,
528
+ io,
508
529
  projectRoot,
509
530
  role,
510
531
  parentRunPath,
511
- freshSummons: env.freshSummons,
512
532
  summons,
513
- resume: (runId, materials) => runPublicInstructionSeatResume({ runId, ...(materials === undefined ? {} : { summons: materials }) }, env, io),
514
533
  });
515
534
  if (resumed != null)
516
535
  return resumed;
@@ -536,23 +555,29 @@ export async function runPublicInstructionSeat(argv, env, io, role, parseArgv) {
536
555
  const summons = {
537
556
  sourceRunPath: source.runDirectory,
538
557
  sourceRun: source,
539
- ...(resumeInstruction === undefined ? {} : { instruction: resumeInstruction, instructionEmpty: false }),
558
+ ...(resumeInstruction === undefined
559
+ ? {}
560
+ : { instruction: resumeInstruction, instructionEmpty: false }),
540
561
  };
541
- const resumed = await tryResumeSameTicketSeatRun({
542
- home: env.home,
562
+ resolvedNotarySource = source;
563
+ const resumed = await resumeSameParentInstructionSeat({
564
+ env,
565
+ io,
543
566
  projectRoot,
544
567
  role,
545
568
  parentRunPath: source.runDirectory,
546
- freshSummons: env.freshSummons,
547
569
  summons,
548
- resume: (runId, materials) => runPublicInstructionSeatResume({ runId, ...(materials === undefined ? {} : { summons: materials }) }, env, io),
549
570
  });
550
571
  if (resumed != null)
551
572
  return resumed;
552
573
  }
553
574
  let admitted;
554
575
  try {
555
- admitted = await admitPublicRole(role, parsed, env, auditorTicket === undefined ? undefined : { assertedTicketNumber: auditorTicket });
576
+ const admissionOverride = {
577
+ ...(auditorTicket === undefined ? {} : { assertedTicketNumber: auditorTicket }),
578
+ ...(resolvedNotarySource === undefined ? {} : { resolvedSourceRun: resolvedNotarySource }),
579
+ };
580
+ admitted = await admitPublicRole(role, parsed, env, auditorTicket === undefined && resolvedNotarySource === undefined ? undefined : admissionOverride);
556
581
  }
557
582
  catch (error) {
558
583
  const rejected = usageExit(error, io);
@@ -589,7 +614,7 @@ export async function runPublicInstructionSeat(argv, env, io, role, parseArgv) {
589
614
  timedOut: false, code: null, stderr: "", thrown: error,
590
615
  }, seatAdapters(admitted, env), env.principalAuthority, io);
591
616
  }
592
- if (outcome.admitted?.runDirectory.includes(`${sep}unbound${sep}runs${sep}`)) {
617
+ if (outcome.admitted !== undefined && isUnboundRunDirectory(outcome.admitted.runDirectory)) {
593
618
  await recordChildDiaristRun(admitted, outcome.admitted.runId);
594
619
  }
595
620
  if (outcome.failedWithoutEscalate !== undefined) {