@akagilnc/pi-workflow-roles 0.1.5598 → 0.1.5614

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 (43) hide show
  1. package/dist/acp-host/production-host.js +406 -366
  2. package/dist/compliance-transport.js +2 -5
  3. package/dist/doctor-auditor.js +1 -1
  4. package/dist/gatekeeper-role.js +1 -1
  5. package/dist/headless-host/production-host.js +370 -330
  6. package/dist/migrate-book-topology.js +301 -291
  7. package/dist/navigator-public-session.js +4 -4
  8. package/dist/navigator-work-base.js +5 -30
  9. package/dist/packaged-role-registry.js +4 -2
  10. package/dist/pi/role-turn-host.js +10 -1
  11. package/dist/public-cli/instruction-seat-run.js +133 -38
  12. package/dist/public-cli/invocation.js +23 -26
  13. package/dist/public-cli/main.js +250 -179
  14. package/dist/public-cli/option-definitions.js +19 -0
  15. package/dist/public-cli/post-admission.js +23 -22
  16. package/dist/public-cli/run-lifecycle.js +2 -14
  17. package/dist/public-cli/turn-request.js +4 -9
  18. package/dist/public-role-summons.js +5 -3
  19. package/dist/role-run-placement.js +7 -1
  20. package/package.json +1 -1
  21. package/scripts/build-package.mjs +2 -3
  22. package/src/audited-run-identity.ts +30 -0
  23. package/src/compliance-transport.ts +1 -4
  24. package/src/doctor-auditor.ts +1 -1
  25. package/src/gatekeeper-role.ts +1 -1
  26. package/src/host-contracts.ts +6 -1
  27. package/src/navigator-public-session.ts +9 -5
  28. package/src/navigator-work-base.ts +19 -34
  29. package/src/notary-role.ts +12 -21
  30. package/src/packaged-role-registry.ts +4 -4
  31. package/src/pi/role-turn-host.ts +11 -1
  32. package/src/public-cli/instruction-seat-run.ts +162 -42
  33. package/src/public-cli/invocation.ts +35 -26
  34. package/src/public-cli/option-definitions.ts +20 -0
  35. package/src/public-cli/post-admission.ts +28 -22
  36. package/src/public-cli/run-lifecycle.ts +2 -17
  37. package/src/public-cli/turn-request.ts +9 -8
  38. package/src/public-role-summons.ts +17 -6
  39. package/src/role-envelope.ts +4 -0
  40. package/src/role-run-placement.ts +10 -1
  41. package/src/role-runtime.ts +54 -31
  42. package/dist/auditor-dossier-tool.js +0 -47
  43. package/src/auditor-dossier-tool.ts +0 -63
@@ -13,7 +13,6 @@ import { parseRunLeaf } from "./role-run-placement.js";
13
13
  import { CliUsageError } from "./public-cli/cli-errors.js";
14
14
  import { isNavigatorSeat } from "./packaged-role-registry.js";
15
15
  import {
16
- attachWorkContextPointer,
17
16
  navigatorWorkContextFile
18
17
  } from "./navigator-work-base.js";
19
18
  import { isRecord } from "./unknown-value.js";
@@ -95,13 +94,14 @@ function createNativeNavigatorSessionFactory(deps) {
95
94
  if (disposed) return;
96
95
  const resumeRunId = hostRunId;
97
96
  const workContextPath = navigatorWorkContextFile(sessionManager.getSessionDir());
98
- const argvText = existsSync(workContextPath) ? attachWorkContextPointer(text, workContextPath) : text;
97
+ const workContextLocator = existsSync(workContextPath) ? workContextPath : void 0;
99
98
  const baseSummon = {
100
99
  role: "navigator",
101
- argv: [argvText],
100
+ argv: [text],
102
101
  cwd: context.cwd,
103
102
  ...summonHome === void 0 ? {} : { home: summonHome },
104
- ...context.signal === void 0 ? {} : { signal: context.signal }
103
+ ...context.signal === void 0 ? {} : { signal: context.signal },
104
+ ...workContextLocator === void 0 ? {} : { navigatorWorkContextPath: workContextLocator }
105
105
  };
106
106
  const resumable = deps?.hostRunResumable ?? navigatorHostRunResumable;
107
107
  let summoned;
@@ -4,6 +4,7 @@ import { basename, dirname, join, resolve } from "node:path";
4
4
  import { writeFileAtomically } from "./atomic-write.js";
5
5
  import { isEnoent, isRecord } from "./unknown-value.js";
6
6
  const NAVIGATOR_WORK_CONTEXT_BASENAME = "work-context.json";
7
+ const AK_ROLE_NAVIGATOR_WORK_CONTEXT_ENV = "AK_ROLE_NAVIGATOR_WORK_CONTEXT";
7
8
  function navigatorWorkContextFile(sessionDir) {
8
9
  return join(sessionDir, NAVIGATOR_WORK_CONTEXT_BASENAME);
9
10
  }
@@ -60,33 +61,8 @@ async function readNavigatorWorkBase(path) {
60
61
  if (record.authority.trim() === "") return void 0;
61
62
  return { subject: record.subject, authority: record.authority };
62
63
  }
63
- function jsonObjectFromPrompt(prompt) {
64
- const head = prompt.trimStart().split("\n\n", 1)[0] ?? "";
65
- if (!head.startsWith("{")) return void 0;
66
- try {
67
- const parsed = JSON.parse(head);
68
- if (!isRecord(parsed)) return void 0;
69
- return parsed;
70
- } catch {
71
- return void 0;
72
- }
73
- }
74
- function workContextPathFromPrompt(prompt) {
75
- const record = jsonObjectFromPrompt(prompt);
76
- const path = record?.workContextPath;
77
- if (typeof path !== "string" || path.trim() === "") return void 0;
78
- return isNavigatorWorkContextFile(path) ? path : void 0;
79
- }
80
- function attachWorkContextPointer(text, workContextPath) {
81
- const record = jsonObjectFromPrompt(text);
82
- if (record === void 0) return text;
83
- if (typeof record.workContextPath === "string" && record.workContextPath.trim() !== "") return text;
84
- const head = text.trimStart().split("\n\n", 1)[0] ?? "";
85
- const rest = text.trimStart().slice(head.length);
86
- return `${JSON.stringify({ ...record, workContextPath })}${rest}`;
87
- }
88
- async function loadNavigatorWorkBaseSuffix(prompt) {
89
- const path = workContextPathFromPrompt(prompt);
64
+ async function loadNavigatorWorkBaseSuffix(sessionDir, locatorPath) {
65
+ const path = typeof locatorPath === "string" && locatorPath.trim() !== "" ? locatorPath.trim() : typeof process.env[AK_ROLE_NAVIGATOR_WORK_CONTEXT_ENV] === "string" && process.env[AK_ROLE_NAVIGATOR_WORK_CONTEXT_ENV].trim() !== "" ? process.env[AK_ROLE_NAVIGATOR_WORK_CONTEXT_ENV].trim() : sessionDir !== void 0 && sessionDir.trim() !== "" ? navigatorWorkContextFile(sessionDir) : void 0;
90
66
  if (path === void 0) return void 0;
91
67
  const body = await readNavigatorWorkBase(path);
92
68
  if (body === void 0) return void 0;
@@ -99,12 +75,11 @@ ${body.authority}
99
75
  </controlling_authority>`;
100
76
  }
101
77
  export {
78
+ AK_ROLE_NAVIGATOR_WORK_CONTEXT_ENV,
102
79
  NAVIGATOR_WORK_CONTEXT_BASENAME,
103
- attachWorkContextPointer,
104
80
  isNavigatorWorkContextFile,
105
81
  loadNavigatorWorkBaseSuffix,
106
82
  navigatorWorkContextFile,
107
83
  persistNavigatorWorkBase,
108
- readNavigatorWorkBase,
109
- workContextPathFromPrompt
84
+ readNavigatorWorkBase
110
85
  };
@@ -363,7 +363,8 @@ const PUBLIC_ROLE_RECORDS = [
363
363
  presentSettled: "always",
364
364
  summonResume: false,
365
365
  admission: "instruction",
366
- sameParent: "gate-pointer",
366
+ /** Structured --source-run only; instruction stays opaque caller/peer bytes (#1166). */
367
+ sameParent: "source-run",
367
368
  /** Resume restores an optional source-run path onto the admitted face. */
368
369
  resumeSourcePath: true,
369
370
  /** 台院 is a review officer and inherits the gatekeeper model. */
@@ -376,11 +377,12 @@ const PUBLIC_ROLE_RECORDS = [
376
377
  /** Court reask replaces the initial prompt. */
377
378
  reaskPrompt: true,
378
379
  gateStageLabel: "\u53F0\u9662",
380
+ /** Gate summon binds --source-run; identity is startup material (#1166). */
381
+ gateSummon: "source-run",
379
382
  activationFlags: [
380
383
  {
381
384
  field: "sourceRun",
382
385
  from: "sourceRunPath",
383
- fallback: "gate-pointer",
384
386
  flag: "ak-inspector-source-run",
385
387
  binds: "input"
386
388
  }
@@ -339,7 +339,7 @@ export function createPiRoleTurnHost(config) {
339
339
  else
340
340
  env[RECEIPT_DELIVERY_LIMIT_ENV] = String(request.deliveryRequestLimit);
341
341
  applyEngineChildEnv(env, request.engine);
342
- // Nested auditor dossier tool binds the parent run pointer when published.
342
+ // Nested auditor binds the audited source-run for identity / soul selection.
343
343
  if (typeof process.env.AK_ROLE_AUDITOR_SOURCE_RUN === "string"
344
344
  && process.env.AK_ROLE_AUDITOR_SOURCE_RUN.trim() !== "") {
345
345
  env.AK_ROLE_AUDITOR_SOURCE_RUN = process.env.AK_ROLE_AUDITOR_SOURCE_RUN;
@@ -349,6 +349,15 @@ export function createPiRoleTurnHost(config) {
349
349
  && process.env.AK_ROLE_AUDITOR_SUBJECT.trim() !== "") {
350
350
  env.AK_ROLE_AUDITOR_SUBJECT = process.env.AK_ROLE_AUDITOR_SUBJECT;
351
351
  }
352
+ // Navigator nest work-context locator for startup materials (#1166) —
353
+ // child-process scoped only from this turn request; never parent process.env.
354
+ if (typeof request.navigatorWorkContextPath === "string"
355
+ && request.navigatorWorkContextPath.trim() !== "") {
356
+ env.AK_ROLE_NAVIGATOR_WORK_CONTEXT = request.navigatorWorkContextPath.trim();
357
+ }
358
+ else {
359
+ delete env.AK_ROLE_NAVIGATOR_WORK_CONTEXT;
360
+ }
352
361
  if (config.recordLaunchedRolePackageIdentity !== undefined &&
353
362
  config.observeLaunchedRolePackageIdentity !== undefined) {
354
363
  await config.recordLaunchedRolePackageIdentity(request.runDirectory, await config.observeLaunchedRolePackageIdentity(config.packageRoot, roleEntry));
@@ -4,8 +4,7 @@
4
4
  * starts two ordinary single-axis runs here.
5
5
  */
6
6
  import { dirname, resolve } from "node:path";
7
- import { isUnboundRunDirectory } from "../role-run-placement.js";
8
- import { AUDITOR_DOSSIER_PROMPT } from "../compliance-transport.js";
7
+ import { isUnboundRunDirectory, sessionFileOf } from "../role-run-placement.js";
9
8
  import { bookDirectOfficerRunPointer, readDirectOfficerRunPointer } from "../archivist-record-pointer.js";
10
9
  import { createPiDoctorAuditor } from "../doctor-auditor.js";
11
10
  import { officerConclusionReask, gateOfficerForSubject } from "../gatekeeper-role.js";
@@ -27,10 +26,10 @@ import { NotarySourceRunError, resolveNotarySourceRunLocator } from "../notary-s
27
26
  import { packagedAdmitsCountersign, packagedBindsBoardTicket, packagedRebindSourceOnResume, packagedRoleMetadata, } from "../packaged-role-registry.js";
28
27
  import { readAuditorResumeBinding } from "../auditor-soul.js";
29
28
  import { CliUsageError } from "./cli-errors.js";
30
- import { admitPublicRole, bindAdmittedTicketNumber, buildInstructionTransportPrompt, materializeCountersignInvocation, persistAdmittedSourceRunPath, recordAdmittedCorrelation, recordChildDiaristRun, relocateAdmittedRunToTicket, } from "./invocation.js";
29
+ import { admitPublicRole, bindAdmittedTicketNumber, appendCallerFileFlagPaths, buildInstructionTransportPrompt, materializeCountersignInvocation, persistAdmittedSourceRunPath, recordAdmittedCorrelation, recordChildDiaristRun, relocateAdmittedRunToTicket, } from "./invocation.js";
31
30
  import { bindDiaristAssertedTicketNumber, presentControlledFailure, packageFaultNoteFor, prepareSummonsResumeMaterials, roleTurnOptions, runPostAdmissionOneShot, runPostAdmissionResumable, runPostAdmissionSeatResume, showResumeErrorPointer, resumeTurnRequestProjectionOptions, } from "./post-admission.js";
32
31
  import { presentTerminal } from "./auto-resume.js";
33
- import { buildAutoResumeContinuationPrompt, loadResumablePublicRole, markRunAdmitted, parentRunPathFromGatePointerInstruction, readCurrentCourt, } from "./run-lifecycle.js";
32
+ import { buildAutoResumeContinuationPrompt, loadResumablePublicRole, markRunAdmitted, readCurrentCourt, } from "./run-lifecycle.js";
34
33
  import { tryResumeSameTicketSeatRun } from "./seat-ticket-binding.js";
35
34
  import { presentStructuralRejection, readBoundSessionEntries, attachPostAuditCountersignFact, trySettlePublicSeat, } from "./settlement.js";
36
35
  import { warnMissingMethodSkills } from "./machine-method-skills.js";
@@ -168,11 +167,69 @@ function roleRecord(role) {
168
167
  export function buildInstructionSeatTurnRequest(admitted, options) {
169
168
  return projectRoleTurnRequest(admitted, admittedSeatTurnDetails(admitted, options.home, options.host), options);
170
169
  }
171
- function initialPrompt(admitted, env) {
172
- const record = roleRecord(admitted.role);
173
- const reask = env.reviewReask ?? env.gateReviewInstruction;
174
- if (reask !== undefined && "reaskPrompt" in record && record.reaskPrompt === true) {
170
+ /**
171
+ * Direct review-seat call: reconnect ledger peer-body delivery (ADR 0085 / #1166).
172
+ * Gate summons already ride gateReviewInstruction; direct --source-run must not
173
+ * leave a blank fixed-kickoff.
174
+ */
175
+ async function loadLedgerPeerBody(sourceRunDirectory, projectRoot, home) {
176
+ const runId = runIdFromRunDirectory(sourceRunDirectory);
177
+ if (runId === undefined)
178
+ return undefined;
179
+ // Bind to the already-resolved source directory — never re-discover by runId
180
+ // alone (another book may lawfully share the same id; #637 / #1166).
181
+ const rows = await readRecordedSubmissionRows(projectRoot, runId, {
182
+ home,
183
+ sessionParent: sessionFileOf(sourceRunDirectory),
184
+ });
185
+ // ADR 0085 / #1166 J10: ledger already keeps original words for every class —
186
+ // present the latest row as-is. Never filter current manuscript by accepted /
187
+ // terminal outcome kind (that resurrects a prior sealed draft).
188
+ const latest = rows.at(-1);
189
+ if (latest === undefined)
190
+ return undefined;
191
+ return readableGateItem(latest.accepted);
192
+ }
193
+ /**
194
+ * One delivery rule for review-seat dialogue on new turns and same-parent resume
195
+ * (#1166 / ADR 0085 / ADR 0087): explicit reask → non-empty caller dispatch →
196
+ * source-only ledger peer body. Identity stays in startup materials.
197
+ */
198
+ async function resolveReviewSeatDialogueBody(input) {
199
+ const reask = input.reask;
200
+ if (reask !== undefined && reask.length > 0)
175
201
  return reask;
202
+ const caller = input.callerInstruction ?? "";
203
+ if (caller.length > 0)
204
+ return caller;
205
+ const sourceRunPath = input.sourceRunPath?.trim() ?? "";
206
+ if (sourceRunPath === "")
207
+ return undefined;
208
+ return await loadLedgerPeerBody(sourceRunPath, input.projectRoot, input.home);
209
+ }
210
+ function admittedSourceRunPath(admitted) {
211
+ return "sourceRunPath" in admitted
212
+ && typeof admitted.sourceRunPath === "string"
213
+ ? admitted.sourceRunPath.trim()
214
+ : "";
215
+ }
216
+ async function resolveInitialPrompt(admitted, env) {
217
+ const record = roleRecord(admitted.role);
218
+ if ("reaskPrompt" in record && record.reaskPrompt === true) {
219
+ const sourceRunPath = admittedSourceRunPath(admitted);
220
+ const reask = env.reviewReask ?? env.gateReviewInstruction;
221
+ const body = await resolveReviewSeatDialogueBody({
222
+ ...(reask === undefined ? {} : { reask }),
223
+ callerInstruction: admitted.instruction,
224
+ ...(sourceRunPath === "" ? {} : { sourceRunPath }),
225
+ projectRoot: admitted.projectRoot,
226
+ home: env.home,
227
+ });
228
+ // #1166 J11: merge existing file-flag delivery — never early-return body alone
229
+ // when caller attach paths were admitted. Gate with no file flags stays body-only.
230
+ if (body !== undefined) {
231
+ return appendCallerFileFlagPaths(body, admitted.attachments);
232
+ }
176
233
  }
177
234
  return buildInstructionTransportPrompt(admitted);
178
235
  }
@@ -271,13 +328,17 @@ async function dispatchAdmitted(admitted, env, io) {
271
328
  if (activeEnv.correlationId !== undefined && activeEnv.correlationId.trim() !== "") {
272
329
  await recordAdmittedCorrelation(admitted, activeEnv.correlationId);
273
330
  }
331
+ const initialPromptText = await resolveInitialPrompt(admitted, activeEnv);
274
332
  const auto = "inCallAutoResume" in record && record.inCallAutoResume === true;
275
333
  if (auto) {
276
334
  return await runPostAdmissionResumable({
277
335
  admitted,
278
336
  env: activeEnv,
279
337
  io: turnIo,
280
- buildInitialRequest: () => buildInstructionSeatTurnRequest(admitted, roleTurnOptions(activeEnv, admitted, { kind: "initial", prompt: initialPrompt(admitted, activeEnv) })),
338
+ buildInitialRequest: () => buildInstructionSeatTurnRequest(admitted, roleTurnOptions(activeEnv, admitted, {
339
+ kind: "initial",
340
+ prompt: initialPromptText,
341
+ })),
281
342
  buildResumeRequest: () => buildInstructionSeatTurnRequest(admitted, roleTurnOptions(activeEnv, admitted, {
282
343
  kind: "resume",
283
344
  prompt: buildAutoResumeContinuationPrompt(),
@@ -290,7 +351,10 @@ async function dispatchAdmitted(admitted, env, io) {
290
351
  admitted,
291
352
  env: activeEnv,
292
353
  io: turnIo,
293
- request: buildInstructionSeatTurnRequest(admitted, roleTurnOptions(activeEnv, admitted, { kind: "initial", prompt: initialPrompt(admitted, activeEnv) })),
354
+ request: buildInstructionSeatTurnRequest(admitted, roleTurnOptions(activeEnv, admitted, {
355
+ kind: "initial",
356
+ prompt: initialPromptText,
357
+ })),
294
358
  adapters,
295
359
  ...(activeEnv.engine === undefined ? {} : { effectiveEngine: activeEnv.engine }),
296
360
  });
@@ -400,12 +464,23 @@ function resumeSameParentInstructionSeat(input) {
400
464
  resume: (runId, materials) => runPublicInstructionSeatResume({ runId, ...(materials === undefined ? {} : { summons: materials }) }, input.env, input.io),
401
465
  });
402
466
  }
403
- /** Re-ask words when the parent supplied them; otherwise the caller's own instruction. */
404
- function sameParentInstruction(env, fallback) {
405
- const resumeInstruction = env.reviewReask ?? env.gateReviewInstruction;
406
- if (resumeInstruction === undefined)
407
- return fallback;
408
- return { instruction: resumeInstruction, instructionEmpty: false };
467
+ /**
468
+ * Same delivery rule as resolveInitialPrompt for same-parent resume summons.
469
+ * Reask / explicit caller text / source-only ledger peer — one authority.
470
+ */
471
+ async function sameParentDialogue(env, fallback, sourceRunPath, projectRoot) {
472
+ const reask = env.reviewReask ?? env.gateReviewInstruction;
473
+ const body = await resolveReviewSeatDialogueBody({
474
+ ...(reask === undefined ? {} : { reask }),
475
+ callerInstruction: fallback.instruction,
476
+ sourceRunPath,
477
+ projectRoot,
478
+ home: env.home,
479
+ });
480
+ if (body !== undefined) {
481
+ return { instruction: body, instructionEmpty: false };
482
+ }
483
+ return fallback;
409
484
  }
410
485
  /**
411
486
  * Countersign on the shared entry: gate parent resume, deferred materialization,
@@ -430,6 +505,9 @@ async function runCountersignBody(parsed, env, io) {
430
505
  sourceRunPath: gateParentRunPath,
431
506
  instruction: resumeInstruction,
432
507
  instructionEmpty: resumeInstruction.length === 0,
508
+ // #1166 J11: same-parent resume delivers this call's file-flag paths
509
+ // through the shared summons → appendCallerFileFlagPaths rule.
510
+ attachmentPaths: parsed.attachmentPaths ?? [],
433
511
  },
434
512
  });
435
513
  if (resumed != null)
@@ -462,10 +540,14 @@ async function runCountersignBody(parsed, env, io) {
462
540
  await persistAdmittedSourceRunPath(admitted, gateParentRunPath);
463
541
  admitted = { ...admitted, sourceRunPath: gateParentRunPath };
464
542
  }
543
+ // #1166 J11: review-body branch must merge the same file-flag delivery as
544
+ // resolveInitialPrompt / resumeTurnRequestProjectionOptions — never body alone.
545
+ const reviewBody = env.reviewReask ?? env.gateReviewInstruction;
465
546
  const turnProjection = roleTurnOptions(env, admitted, {
466
547
  kind: "initial",
467
- prompt: (env.reviewReask ?? env.gateReviewInstruction)
468
- ?? buildInstructionTransportPrompt(admitted),
548
+ prompt: reviewBody !== undefined
549
+ ? appendCallerFileFlagPaths(reviewBody, admitted.attachments)
550
+ : buildInstructionTransportPrompt(admitted),
469
551
  });
470
552
  const turnRequest = buildInstructionSeatTurnRequest(admitted, turnProjection);
471
553
  const result = await runPostAdmissionOneShot({
@@ -555,10 +637,10 @@ export async function runPublicInstructionSeat(argv, env, io, role, parseArgv) {
555
637
  return { exitCode: 2 };
556
638
  const sourceDirectory = auditorSource;
557
639
  const summons = {
558
- ...sameParentInstruction(env, {
640
+ ...(await sameParentDialogue(env, {
559
641
  instruction: parsed.instruction ?? "",
560
642
  instructionEmpty: (parsed.instruction ?? "").length === 0,
561
- }),
643
+ }, sourceDirectory, projectRoot)),
562
644
  attachmentPaths: parsed.attachmentPaths ?? [],
563
645
  };
564
646
  const resumed = await withAuditorSoulEnv({
@@ -576,15 +658,30 @@ export async function runPublicInstructionSeat(argv, env, io, role, parseArgv) {
576
658
  if (resumed != null)
577
659
  return resumed;
578
660
  }
579
- if (record.sameParent === "gate-pointer") {
580
- const parentRunPath = parentRunPathFromGatePointerInstruction(parsed.instruction ?? "");
581
- if (parentRunPath !== undefined) {
661
+ if (record.sameParent === "source-run") {
662
+ // #1166: structured --source-run only. Instruction bytes stay opaque caller/peer text.
663
+ if (parsed.sourceRun !== undefined) {
664
+ let parentRunPath;
665
+ try {
666
+ parentRunPath = (await resolveNotarySourceRunLocator({
667
+ projectRoot,
668
+ sourceRun: parsed.sourceRun,
669
+ home: env.home,
670
+ })).runDirectory;
671
+ }
672
+ catch (error) {
673
+ if (error instanceof NotarySourceRunError) {
674
+ presentStructuralRejection(new CliUsageError(error.message, { cause: error }), io);
675
+ return { exitCode: 2 };
676
+ }
677
+ throw error;
678
+ }
582
679
  const summons = {
583
680
  sourceRunPath: parentRunPath,
584
- ...sameParentInstruction(env, {
681
+ ...(await sameParentDialogue(env, {
585
682
  instruction: parsed.instruction ?? "",
586
683
  instructionEmpty: (parsed.instruction ?? "").length === 0,
587
- }),
684
+ }, parentRunPath, projectRoot)),
588
685
  attachmentPaths: parsed.attachmentPaths ?? [],
589
686
  };
590
687
  const resumed = await resumeSameParentInstructionSeat({
@@ -615,13 +712,10 @@ export async function runPublicInstructionSeat(argv, env, io, role, parseArgv) {
615
712
  }
616
713
  throw error;
617
714
  }
618
- const resumeInstruction = env.reviewReask ?? env.gateReviewInstruction;
619
715
  const summons = {
620
716
  sourceRunPath: source.runDirectory,
621
717
  sourceRun: source,
622
- ...(resumeInstruction === undefined
623
- ? {}
624
- : { instruction: resumeInstruction, instructionEmpty: false }),
718
+ ...(await sameParentDialogue(env, { instruction: "", instructionEmpty: true }, source.runDirectory, projectRoot)),
625
719
  };
626
720
  resolvedNotarySource = source;
627
721
  const resumed = await resumeSameParentInstructionSeat({
@@ -649,16 +743,18 @@ export async function runPublicInstructionSeat(argv, env, io, role, parseArgv) {
649
743
  return rejected;
650
744
  throw error;
651
745
  }
652
- if (record.sameParent === "gate-pointer") {
653
- const parentRunPath = parentRunPathFromGatePointerInstruction(parsed.instruction ?? "");
654
- if (parentRunPath !== undefined) {
655
- await persistAdmittedSourceRunPath(admitted, parentRunPath);
656
- const sourcePatch = { sourceRunPath: parentRunPath };
657
- admitted = { ...admitted, ...sourcePatch };
658
- }
746
+ if (record.sameParent === "source-run" && parsed.sourceRun !== undefined) {
747
+ const parentRunPath = (await resolveNotarySourceRunLocator({
748
+ projectRoot,
749
+ sourceRun: parsed.sourceRun,
750
+ home: env.home,
751
+ })).runDirectory;
752
+ await persistAdmittedSourceRunPath(admitted, parentRunPath);
753
+ admitted = { ...admitted, sourceRunPath: parentRunPath };
659
754
  }
660
755
  if (record.sameParent === "subject-source" && auditorSource !== undefined) {
661
756
  await persistAdmittedSourceRunPath(admitted, auditorSource, auditorSubject);
757
+ admitted = { ...admitted, sourceRunPath: auditorSource };
662
758
  }
663
759
  const runAdmitted = async () => {
664
760
  await markRunAdmitted(admitted, env.principalAuthority);
@@ -997,8 +1093,7 @@ async function auditSubmittedRole(turn, env, io, resumedOfficer, passedReceipt)
997
1093
  summonAuditor: async (subject, sourceRunDirectory, signal, reask, submission) => {
998
1094
  const summoned = await summonPublicRole({
999
1095
  role: "auditor",
1000
- argv: ["--subject", subject, "--source-run", sourceRunDirectory,
1001
- `${AUDITOR_DOSSIER_PROMPT}${sourceRunDirectory}`],
1096
+ argv: ["--subject", subject, "--source-run", sourceRunDirectory],
1002
1097
  cwd: admitted.projectRoot, home: env.home, packageRoot: env.packageRoot,
1003
1098
  principalAuthority: env.principalAuthority,
1004
1099
  correlationId: admitted.runId,
@@ -1084,19 +1084,35 @@ function admittedTransportPromptKind(admitted) {
1084
1084
  return record.transportPrompt;
1085
1085
  return "instruction";
1086
1086
  }
1087
+ /** Append opaque caller file-flag paths after dialogue (#1165 / #1166 J11 / #1168). */
1088
+ export function appendCallerFileFlagPaths(body, attachments, requestManifestPath, prerequisitesPath) {
1089
+ const flaggedPaths = [
1090
+ ...attachments.map((attachment) => `--attach ${attachment.path}`),
1091
+ ...(requestManifestPath === undefined
1092
+ ? []
1093
+ : [`--request-manifest ${requestManifestPath}`]),
1094
+ ...(prerequisitesPath === undefined
1095
+ ? []
1096
+ : [`--prerequisites ${prerequisitesPath}`]),
1097
+ ];
1098
+ if (flaggedPaths.length === 0)
1099
+ return body;
1100
+ // ADR 0087 / #1165 / #1166 J13: after caller words, only necessary file flags
1101
+ // and original paths — no package-authored title or list wrapper.
1102
+ return [body, "", ...flaggedPaths].join("\n");
1103
+ }
1087
1104
  /**
1088
1105
  * One initial prompt transport. The registry `transportPrompt` leaf selects
1089
- * a fixed kickoff, a bound baseline, or frozen skill args. Absent means the
1090
- * caller instruction plus caller attachment paths as-is (#1165).
1106
+ * a fixed kickoff, a bound baseline, or skill args. Absent means the caller
1107
+ * instruction plus caller file-flag paths (ADR 0087).
1091
1108
  * Engine / outsourcing material rides startup readingMaterial (#1167), not here.
1092
1109
  */
1093
1110
  export function buildInstructionTransportPrompt(admitted) {
1094
1111
  const kind = admittedTransportPromptKind(admitted);
1095
1112
  if (kind === "fixed-kickoff") {
1096
- if (admitted.sourceRunPath === undefined || admitted.sourceRunPath.trim() === "") {
1097
- throw new Error("fixed-kickoff transport prompt is missing the source run pointer");
1098
- }
1099
- return admitted.sourceRunPath;
1113
+ // #1166 / ADR 0087: audited-run identity rides startup materials; dialogue
1114
+ // prompt is peer body / reask only — never a package-computed directory path.
1115
+ return "";
1100
1116
  }
1101
1117
  if (kind === "baseline") {
1102
1118
  if (admitted.baseRevision === undefined) {
@@ -1126,26 +1142,7 @@ export function buildInstructionTransportPrompt(admitted) {
1126
1142
  }
1127
1143
  return lines.join("\n");
1128
1144
  }
1129
- // #1165 J3 / #1168: assemble from the admitted instruction bytes themselves.
1130
- const lines = [admitted.instruction];
1131
- // #1164/#1165/#1168: each caller path keeps its file-flag provenance.
1132
- const flaggedPaths = [
1133
- ...admitted.attachments.map((attachment) => `--attach ${attachment.path}`),
1134
- ...(admitted.requestManifestPath === undefined
1135
- ? []
1136
- : [`--request-manifest ${admitted.requestManifestPath}`]),
1137
- ...(admitted.prerequisitesPath === undefined
1138
- ? []
1139
- : [`--prerequisites ${admitted.prerequisitesPath}`]),
1140
- ];
1141
- if (flaggedPaths.length > 0) {
1142
- lines.push("");
1143
- lines.push("已受理附件:");
1144
- for (const entry of flaggedPaths) {
1145
- lines.push(`- ${entry}`);
1146
- }
1147
- }
1148
- return lines.join("\n");
1145
+ return appendCallerFileFlagPaths(admitted.instruction, admitted.attachments, admitted.requestManifestPath, admitted.prerequisitesPath);
1149
1146
  }
1150
1147
  /** Persist a deferred Countersign admission after same-ticket lookup found no retained run. */
1151
1148
  export async function materializeCountersignInvocation(admitted, options) {