@akagilnc/pi-workflow-roles 0.1.5593 → 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 (58) hide show
  1. package/README.md +1 -1
  2. package/README.zh-CN.md +1 -1
  3. package/dist/acp-host/production-host.js +521 -707
  4. package/dist/compliance-transport.js +2 -5
  5. package/dist/doctor-auditor.js +1 -1
  6. package/dist/gatekeeper-role.js +1 -1
  7. package/dist/headless-host/production-host.js +505 -691
  8. package/dist/merger-contracts.js +6 -2
  9. package/dist/migrate-book-topology.js +5142 -10735
  10. package/dist/navigator-public-session.js +4 -4
  11. package/dist/navigator-work-base.js +5 -30
  12. package/dist/package-contracts/worker-output.js +1 -6
  13. package/dist/packaged-role-registry.js +9 -6
  14. package/dist/pi/role-turn-host.js +10 -1
  15. package/dist/public-cli/instruction-seat-run.js +133 -38
  16. package/dist/public-cli/invocation.js +38 -74
  17. package/dist/public-cli/main.js +18155 -18235
  18. package/dist/public-cli/option-definitions.js +21 -2
  19. package/dist/public-cli/post-admission.js +25 -24
  20. package/dist/public-cli/run-lifecycle.js +4 -43
  21. package/dist/public-cli/turn-request.js +4 -9
  22. package/dist/public-role-summons.js +5 -3
  23. package/dist/role-run-placement.js +7 -1
  24. package/dist/role-run-relocation.js +3 -4
  25. package/package.json +1 -1
  26. package/scripts/build-package.mjs +2 -4
  27. package/src/audited-run-identity.ts +30 -0
  28. package/src/compliance-transport.ts +1 -4
  29. package/src/doctor-auditor.ts +1 -1
  30. package/src/gatekeeper-role.ts +1 -1
  31. package/src/host-contracts.ts +6 -4
  32. package/src/merger-contracts.ts +6 -2
  33. package/src/merger-role.ts +11 -1
  34. package/src/navigator-attendance.ts +2 -2
  35. package/src/navigator-public-session.ts +9 -5
  36. package/src/navigator-work-base.ts +19 -34
  37. package/src/notary-role.ts +12 -21
  38. package/src/package-contracts/worker-output.ts +0 -8
  39. package/src/packaged-role-registry.ts +8 -7
  40. package/src/pi/role-turn-host.ts +11 -1
  41. package/src/public-cli/instruction-seat-run.ts +162 -42
  42. package/src/public-cli/invocation.ts +55 -93
  43. package/src/public-cli/option-definitions.ts +22 -2
  44. package/src/public-cli/post-admission.ts +30 -24
  45. package/src/public-cli/run-lifecycle.ts +4 -56
  46. package/src/public-cli/turn-request.ts +9 -8
  47. package/src/public-role-summons.ts +17 -6
  48. package/src/role-envelope.ts +4 -0
  49. package/src/role-run-placement.ts +10 -1
  50. package/src/role-run-relocation.ts +3 -4
  51. package/src/role-runtime-dependencies.ts +0 -2
  52. package/src/role-runtime.ts +54 -47
  53. package/src/worker-role.ts +11 -78
  54. package/dist/auditor-dossier-tool.js +0 -47
  55. package/dist/package-contracts/fixer-packet.js +0 -77
  56. package/packets/fixer-prerequisites.json +0 -6
  57. package/src/auditor-dossier-tool.ts +0 -63
  58. package/src/package-contracts/fixer-packet.ts +0 -91
@@ -65,11 +65,6 @@ import {
65
65
  type CollectorRepository,
66
66
  } from "../collector-config.ts";
67
67
  import { ownerRepoFromGitHubRemoteUrl } from "./github-remote.ts";
68
- import {
69
- FixerPacketValidationError,
70
- parseFixerPrerequisites,
71
- type FixerPrerequisite,
72
- } from "../package-contracts/fixer-packet.ts";
73
68
  import type { FixerPhase } from "../package-contracts/fixer-output.ts";
74
69
  import { createProductionMergerGitState } from "../merger-git-state.ts";
75
70
  import type { MergerGitState } from "../merger-git-state.ts";
@@ -188,6 +183,8 @@ export type AdmittedNavigatorInvocation = AdmittedRoleInvocationBase & {
188
183
 
189
184
  export type AdmittedAuditorInvocation = AdmittedRoleInvocationBase & {
190
185
  readonly role: "auditor";
186
+ /** Audited source-run directory (#1166 identity / ADR 0085 peer-body load). */
187
+ readonly sourceRunPath?: string;
191
188
  };
192
189
 
193
190
  export type AdmittedDiaristInvocation = AdmittedRoleInvocationBase & {
@@ -204,20 +201,14 @@ export type AdmittedCoderInvocation = AdmittedRoleInvocationBase & {
204
201
  readonly role: "coder";
205
202
  /** Explicit plan or default apply — preserved through admission and continuation. */
206
203
  readonly phase: CoderPhase;
207
- /** Durable task file path consumed by internal --ak-coder-task. */
208
- readonly taskPath: string;
209
204
  };
210
205
 
211
206
  export type AdmittedFixerInvocation = AdmittedRoleInvocationBase & {
212
207
  readonly role: "fixer";
213
208
  /** Explicit plan or default apply — preserved through admission and continuation. */
214
209
  readonly phase: FixerPhase;
215
- /** Durable opaque instruction path consumed by internal --ak-fix-packet. */
216
- readonly packetPath: string;
217
- /** Optional durable prerequisites JSON path for --ak-fixer-prerequisites. */
210
+ /** Optional caller --prerequisites path as-is (#1168; package does not read it). */
218
211
  readonly prerequisitesPath?: string;
219
- /** Structurally validated prerequisite declarations frozen at admission. */
220
- readonly prerequisites: readonly FixerPrerequisite[];
221
212
  };
222
213
 
223
214
  export type AdmittedCollectorInvocation = AdmittedRoleInvocationBase & {
@@ -622,15 +613,13 @@ export async function relocateAdmittedRunToTicket(
622
613
  admittedRecord,
623
614
  [
624
615
  "runDirectory",
625
- "taskPath",
626
- "packetPath",
627
- "prerequisitesPath",
628
616
  "mergerInputPath",
629
617
  ],
630
618
  oldRunDirectory,
631
619
  target.runDirectory,
632
620
  );
633
- // #1165: caller --attach / --request-manifest paths stay as given; do not rewrite.
621
+ // #1165/#1168: caller file-flag paths stay as given. Obsolete copy fields
622
+ // (taskPath/packetPath) are not rewritten — stock volumes keep their bytes.
634
623
  (admitted as { principal: DurablePrincipal }).principal = principal;
635
624
 
636
625
  // current.json projects host.original from this run directory. Ownership is
@@ -876,7 +865,8 @@ function assignPublicSeatOption(
876
865
  fields.authorityRefs.push(requireAuthorityRef(value));
877
866
  return;
878
867
  case "prerequisites":
879
- fields.prerequisitesPath = requireOptionPath(taken.def.canonical, value);
868
+ // #1168: same opaque file-flag rule as --attach.
869
+ fields.prerequisitesPath = requireProvidedOptionValue(taken.def.canonical, value);
880
870
  return;
881
871
  case "pr":
882
872
  fields.prNumber = parsePositivePrOption(value);
@@ -1324,16 +1314,13 @@ export async function admitPublicRole(
1324
1314
  if (!record.phases.some((item) => item === phase)) {
1325
1315
  throw new CliUsageError("coder phase must be plan or apply");
1326
1316
  }
1317
+ // #1168: dispatch text is the first message only — no task.md copy.
1327
1318
  return admitStandardMaterialInvocation("coder", {
1328
1319
  ...shared,
1329
1320
  instruction,
1330
1321
  attachmentPaths,
1331
1322
  ...project,
1332
- placedFields: async (placed) => {
1333
- const taskPath = join(placed.runDirectory, "task.md");
1334
- await writeFile(taskPath, instruction, "utf8");
1335
- return { phase, taskPath };
1336
- },
1323
+ placedFields: async () => ({ phase }),
1337
1324
  });
1338
1325
  }
1339
1326
  case "worker-packet": {
@@ -1344,53 +1331,18 @@ export async function admitPublicRole(
1344
1331
  if (!record.phases.some((item) => item === phase)) {
1345
1332
  throw new CliUsageError("fixer phase must be plan or apply");
1346
1333
  }
1347
- let prerequisites: readonly FixerPrerequisite[] = Object.freeze([]);
1348
- let prerequisitesSource: string | undefined;
1349
- if (parsed.prerequisitesPath !== undefined) {
1350
- const absolutePrereq = isAbsolute(parsed.prerequisitesPath)
1351
- ? parsed.prerequisitesPath
1352
- : resolve(parsed.prerequisitesPath);
1353
- try {
1354
- prerequisitesSource = await readFile(absolutePrereq, "utf8");
1355
- } catch (error) {
1356
- throw new CliUsageError(
1357
- `fixer prerequisites path is unreadable: ${parsed.prerequisitesPath}`,
1358
- { cause: error },
1359
- );
1360
- }
1361
- try {
1362
- prerequisites = parseFixerPrerequisites(prerequisitesSource);
1363
- } catch (error) {
1364
- if (error instanceof FixerPacketValidationError) {
1365
- throw new CliUsageError(error.message, { cause: error });
1366
- }
1367
- throw error;
1368
- }
1369
- }
1334
+ // #1168: dispatch once as first message; --prerequisites path as-is.
1370
1335
  return admitStandardMaterialInvocation("fixer", {
1371
1336
  ...shared,
1372
1337
  instruction,
1373
1338
  attachmentPaths,
1374
1339
  ...project,
1375
- placedFields: async (placed) => {
1376
- let prerequisitesPath: string | undefined;
1377
- if (prerequisitesSource !== undefined) {
1378
- prerequisitesPath = join(placed.runDirectory, "prerequisites.json");
1379
- await writeFile(
1380
- prerequisitesPath,
1381
- `${JSON.stringify(prerequisites, null, 2)}\n`,
1382
- "utf8",
1383
- );
1384
- }
1385
- const packetPath = join(placed.runDirectory, "fix-packet.md");
1386
- await writeFile(packetPath, instruction, "utf8");
1387
- return {
1388
- phase,
1389
- packetPath,
1390
- prerequisites,
1391
- ...(prerequisitesPath === undefined ? {} : { prerequisitesPath }),
1392
- };
1393
- },
1340
+ placedFields: async () => ({
1341
+ phase,
1342
+ ...(parsed.prerequisitesPath === undefined
1343
+ ? {}
1344
+ : { prerequisitesPath: parsed.prerequisitesPath }),
1345
+ }),
1394
1346
  });
1395
1347
  }
1396
1348
  case "collect-target": {
@@ -1579,13 +1531,12 @@ export async function admitPublicRole(
1579
1531
  placedFields: async (placed) => {
1580
1532
  const targetLabel = derived.targetObjectId === "" ? "(none observed)" : derived.targetObjectId;
1581
1533
  const sourceLabel = derived.sourceObjectId === "" ? "(none observed)" : derived.sourceObjectId;
1534
+ // #1168: git facts stay; do not encode dispatch text as task/authority copies.
1582
1535
  const mergerInput = validateMergerInput({
1583
1536
  attemptId: placed.runId,
1584
1537
  targetObjectId: derived.targetObjectId,
1585
1538
  sourceObjectId: derived.sourceObjectId,
1586
1539
  materials: {
1587
- task: mergerMaterialFromUtf8(instruction),
1588
- authority: mergerMaterialFromUtf8(instruction),
1589
1540
  targetIntent: mergerMaterialFromUtf8(
1590
1541
  `Investigate primary sources for target parent ${targetLabel}. Do not invent intent.`,
1591
1542
  ),
@@ -1767,7 +1718,7 @@ async function persistPlacedAdmission(
1767
1718
  * before materializeCountersignInvocation writes the page.
1768
1719
  * Seats whose extra facts are known before placement pass them as admittedFields.
1769
1720
  * Seats whose extra facts depend on the placed run pass placedFields
1770
- * (coder writes task.md; fixer writes fix-packet.md; merger writes merger-input.json).
1721
+ * (merger writes merger-input.json with git facts; coder/fixer dispatch is first-message only, #1168).
1771
1722
  */
1772
1723
  async function admitStandardMaterialInvocation<
1773
1724
  R extends PackagedRole,
@@ -1849,9 +1800,10 @@ export type AdmitAuditorInvocationOptions = AdmitInspectorInvocationOptions;
1849
1800
  type InstructionTransportSource = {
1850
1801
  readonly role?: string;
1851
1802
  readonly instruction: string;
1852
- readonly instructionEmpty: boolean;
1803
+ readonly instructionEmpty?: boolean;
1853
1804
  readonly attachments: readonly { readonly path: string }[];
1854
1805
  readonly requestManifestPath?: string;
1806
+ readonly prerequisitesPath?: string;
1855
1807
  readonly baseRevision?: string;
1856
1808
  readonly lens?: ReviewerLens;
1857
1809
  readonly authorityRefs?: readonly string[];
@@ -1867,10 +1819,32 @@ function admittedTransportPromptKind(
1867
1819
  return "instruction";
1868
1820
  }
1869
1821
 
1822
+ /** Append opaque caller file-flag paths after dialogue (#1165 / #1166 J11 / #1168). */
1823
+ export function appendCallerFileFlagPaths(
1824
+ body: string,
1825
+ attachments: readonly { readonly path: string }[],
1826
+ requestManifestPath?: string,
1827
+ prerequisitesPath?: string,
1828
+ ): string {
1829
+ const flaggedPaths = [
1830
+ ...attachments.map((attachment) => `--attach ${attachment.path}`),
1831
+ ...(requestManifestPath === undefined
1832
+ ? []
1833
+ : [`--request-manifest ${requestManifestPath}`]),
1834
+ ...(prerequisitesPath === undefined
1835
+ ? []
1836
+ : [`--prerequisites ${prerequisitesPath}`]),
1837
+ ];
1838
+ if (flaggedPaths.length === 0) return body;
1839
+ // ADR 0087 / #1165 / #1166 J13: after caller words, only necessary file flags
1840
+ // and original paths — no package-authored title or list wrapper.
1841
+ return [body, "", ...flaggedPaths].join("\n");
1842
+ }
1843
+
1870
1844
  /**
1871
1845
  * One initial prompt transport. The registry `transportPrompt` leaf selects
1872
- * a fixed kickoff, a bound baseline, or frozen skill args. Absent means the
1873
- * caller instruction plus caller attachment paths as-is (#1165).
1846
+ * a fixed kickoff, a bound baseline, or skill args. Absent means the caller
1847
+ * instruction plus caller file-flag paths (ADR 0087).
1874
1848
  * Engine / outsourcing material rides startup readingMaterial (#1167), not here.
1875
1849
  */
1876
1850
  export function buildInstructionTransportPrompt(
@@ -1878,10 +1852,9 @@ export function buildInstructionTransportPrompt(
1878
1852
  ): string {
1879
1853
  const kind = admittedTransportPromptKind(admitted);
1880
1854
  if (kind === "fixed-kickoff") {
1881
- if (admitted.sourceRunPath === undefined || admitted.sourceRunPath.trim() === "") {
1882
- throw new Error("fixed-kickoff transport prompt is missing the source run pointer");
1883
- }
1884
- return admitted.sourceRunPath;
1855
+ // #1166 / ADR 0087: audited-run identity rides startup materials; dialogue
1856
+ // prompt is peer body / reask only — never a package-computed directory path.
1857
+ return "";
1885
1858
  }
1886
1859
  if (kind === "baseline") {
1887
1860
  if (admitted.baseRevision === undefined) {
@@ -1913,23 +1886,12 @@ export function buildInstructionTransportPrompt(
1913
1886
  }
1914
1887
  return lines.join("\n");
1915
1888
  }
1916
- // #1165 J3: assemble from the admitted instruction bytes themselves.
1917
- const lines: string[] = [admitted.instruction];
1918
- // #1164/#1165: each caller path keeps its file-flag provenance.
1919
- const flaggedPaths: string[] = [
1920
- ...admitted.attachments.map((attachment) => `--attach ${attachment.path}`),
1921
- ...(admitted.requestManifestPath === undefined
1922
- ? []
1923
- : [`--request-manifest ${admitted.requestManifestPath}`]),
1924
- ];
1925
- if (flaggedPaths.length > 0) {
1926
- lines.push("");
1927
- lines.push("已受理附件:");
1928
- for (const entry of flaggedPaths) {
1929
- lines.push(`- ${entry}`);
1930
- }
1931
- }
1932
- return lines.join("\n");
1889
+ return appendCallerFileFlagPaths(
1890
+ admitted.instruction,
1891
+ admitted.attachments,
1892
+ admitted.requestManifestPath,
1893
+ admitted.prerequisitesPath,
1894
+ );
1933
1895
  }
1934
1896
 
1935
1897
  export type AdmitCountersignInvocationOptions = {
@@ -2022,7 +1984,7 @@ export type AdmitFixerInvocationOptions = {
2022
1984
  phase: FixerPhase;
2023
1985
  instruction: string;
2024
1986
  attachmentPaths: readonly string[];
2025
- /** Optional caller path to prerequisite JSON array; malformed grammar rejects here. */
1987
+ /** Optional caller --prerequisites path as-is (#1168). */
2026
1988
  prerequisitesPath?: string;
2027
1989
  project?: string;
2028
1990
  createRunId?: () => string;
@@ -2198,7 +2160,7 @@ export function buildReviewerSkillArgProjection(
2198
2160
  ].join(" ");
2199
2161
  }
2200
2162
 
2201
- function mergerMaterialFromUtf8(text: string): MergerInput["materials"]["task"] {
2163
+ function mergerMaterialFromUtf8(text: string): MergerInput["materials"]["targetIntent"] {
2202
2164
  const bytes = Buffer.from(text, "utf8");
2203
2165
  return Object.freeze({
2204
2166
  bytesBase64: bytes.toString("base64"),
@@ -463,8 +463,8 @@ const FIXER_OPTIONS = [
463
463
  repeatable: false,
464
464
  form: "option",
465
465
  description: {
466
- en: "JSON array of {id, requirement} prerequisite objects.",
467
- zh: "{id, requirement} 前置条件 JSON 数组路径。",
466
+ en: "Caller prerequisites path passed as-is to the role. Package does not read, copy, or validate; use an absolute path when cwd differs from --project.",
467
+ zh: "调用方前置条件文件路径原样递给衙门。包不读、不复制、不校验;调用方当前目录与 --project 不同时请给绝对路径。",
468
468
  },
469
469
  },
470
470
  ] as const satisfies readonly PublicOptionDefinition[];
@@ -612,6 +612,25 @@ const NOTARY_OPTIONS = [
612
612
  },
613
613
  ] as const satisfies readonly PublicOptionDefinition[];
614
614
 
615
+ /** 台院: optional --source-run binds the audited leg; gate summons always pass it (#1166). */
616
+ const INSPECTOR_OPTIONS = [
617
+ ...projectAndAttach("inspector"),
618
+ {
619
+ id: "source-run",
620
+ owner: "inspector",
621
+ canonical: "--source-run",
622
+ aliases: [],
623
+ valueMetavar: "runId@role|path",
624
+ required: false,
625
+ repeatable: false,
626
+ form: "option",
627
+ description: {
628
+ en: "Optional audited source-run locator (runId@role or path). Gate summons always supply it; identity rides startup materials.",
629
+ zh: "可选被审腿定位符(runId@role 或路径)。闸传召必带;身份在启动材料里。",
630
+ },
631
+ },
632
+ ] as const satisfies readonly PublicOptionDefinition[];
633
+
615
634
  const MERGER_OPTIONS = [
616
635
  // Merger project face: worktree whose Git materials are handed to the role.
617
636
  {
@@ -779,6 +798,7 @@ const SEAT_OPTION_ROWS: Partial<
779
798
  merger: MERGER_OPTIONS,
780
799
  notary: NOTARY_OPTIONS,
781
800
  auditor: AUDITOR_OPTIONS,
801
+ inspector: INSPECTOR_OPTIONS,
782
802
  };
783
803
 
784
804
  function seatOptionRows(role: PublicCallableRole): readonly PublicOptionDefinition[] {
@@ -19,8 +19,8 @@ import {
19
19
  import { CliUsageError } from "./cli-errors.ts";
20
20
  import { projectPublicTurnAxes, type RoleTurnRequestProjectionOptions } from "./turn-request.ts";
21
21
  import {
22
+ appendCallerFileFlagPaths,
22
23
  bindAdmittedTicketNumber,
23
- buildInstructionTransportPrompt,
24
24
  relocateAdmittedRunToTicket,
25
25
  } from "./invocation.ts";
26
26
  import { readRecordedSubmissionRows } from "../submission-ledger.ts";
@@ -132,11 +132,11 @@ function projectRelocatedTurnIdentity(
132
132
  mutableRequest.principal = admitted.principal;
133
133
  const activation = mutableRequest.activation;
134
134
  if (isRecord(activation)) {
135
- for (const field of ["taskPath", "packetPath", "prerequisitesPath", "inputPath"] as const) {
135
+ for (const field of ["inputPath"] as const) {
136
136
  const record = activation as Record<string, unknown>;
137
137
  if (field in record) record[field] = rewrite(record[field]);
138
138
  }
139
- // #1165: activation.requestManifestPath is a caller path — do not rewrite.
139
+ // #1165/#1168: caller file-flag paths are not activation fields to rewrite.
140
140
  }
141
141
  if (result.terminal !== undefined) {
142
142
  for (const artifact of result.terminal.artifacts) {
@@ -326,6 +326,11 @@ export type PostAdmissionEnv = {
326
326
  boundTicketNumber?: number;
327
327
  /** Station child role run (#840): omit automatic navigator attendance. */
328
328
  stationChild?: boolean;
329
+ /**
330
+ * Navigator nest work-context locator (#1166). Request-scoped; never folded
331
+ * into dialogue. Child spawn may mirror onto child env only.
332
+ */
333
+ navigatorWorkContextPath?: string;
329
334
  };
330
335
 
331
336
  /**
@@ -1458,8 +1463,8 @@ export async function dispatchPostAdmissionTurn<
1458
1463
  * Shared resume continuation projection (#471 / #600 / #633 / #637 / #755 / #879):
1459
1464
  * seat-table model/engine/timeout axes, restored correlation, and either
1460
1465
  * - manual resume (no same-ticket summons): caller message bytes, or
1461
- * - same-ticket summons (审核循环续话): caller/peer words + optional frozen
1462
- * attachment paths only — no「请重读」、no code-authored content substitute,
1466
+ * - same-ticket summons (审核循环续话): caller/peer words + optional caller file-flag
1467
+ * paths only — no「请重读」、no code-authored content substitute,
1463
1468
  * no engine handbook packaging (#750/#755/#879).
1464
1469
  * Caller message wins as prompt base when supplied (bytes unchanged, including
1465
1470
  * blank/whitespace); else summons instruction (parent payload or reask).
@@ -1477,22 +1482,17 @@ export function resumeTurnRequestProjectionOptions(
1477
1482
  readonly attachments: readonly { path: string }[];
1478
1483
  },
1479
1484
  ): RoleTurnRequestProjectionOptions {
1480
- // #879: officer dialogue content is caller/peer words only — no「请重读」,
1481
- // no code-authored constant substitute, no attachment-list wrap of peer body.
1482
- // Binding pointer stays on summons sourceRunPath / activation / attachments.
1485
+ // #879: officer dialogue is caller/peer words; #1166 J11 merges caller file-flag
1486
+ // paths when present. Gate with no file flags stays body-only (ADR 0085).
1483
1487
  const officerDialogue = isStationChildOfficerDialogue(admitted.role, env);
1488
+ const fileFlags = summonsPrepared?.attachments ?? [];
1484
1489
  let prompt: string;
1485
1490
  if (request.message !== undefined) {
1486
1491
  if (summonsPrepared !== undefined) {
1487
- // #755: same-ticket review / open-court — caller words.
1488
- // #879 station-child officer: words only (paths remain on summons materials).
1489
- prompt = officerDialogue
1492
+ // #755: same-ticket review / open-court — caller words + caller file flags.
1493
+ prompt = officerDialogue && fileFlags.length === 0
1490
1494
  ? request.message
1491
- : buildInstructionTransportPrompt({
1492
- instruction: request.message,
1493
- instructionEmpty: false,
1494
- attachments: summonsPrepared.attachments,
1495
- });
1495
+ : appendCallerFileFlagPaths(request.message, fileFlags);
1496
1496
  } else if (request.summons !== undefined) {
1497
1497
  // #755: same-ticket summons without prepared materials — caller words only.
1498
1498
  prompt = request.message;
@@ -1500,13 +1500,11 @@ export function resumeTurnRequestProjectionOptions(
1500
1500
  prompt = request.message;
1501
1501
  }
1502
1502
  } else if (summonsPrepared !== undefined) {
1503
- // #879 station-child officer: instruction bytes === peer body/reask (no wrap).
1504
- // Other seats keep #755 instruction + optional attachment path listing.
1505
- // #1165 J3: officer dialogue is raw instruction bytes; do not gate on
1506
- // instructionEmpty metadata (resume of older admitted pages).
1507
- prompt = officerDialogue
1508
- ? summonsPrepared.instruction
1509
- : buildInstructionTransportPrompt(summonsPrepared);
1503
+ const body = summonsPrepared.instruction;
1504
+ // No file flags: body alone (gate peer words). With flags: merge delivery.
1505
+ prompt = officerDialogue && fileFlags.length === 0
1506
+ ? body
1507
+ : appendCallerFileFlagPaths(body, fileFlags);
1510
1508
  } else if (request.summons !== undefined) {
1511
1509
  // #879: same-ticket summons with no instruction (e.g. notary source-run binding
1512
1510
  // only). Pointer is activation/sourceRun material — not dialogue content.
@@ -1527,6 +1525,10 @@ export function resumeTurnRequestProjectionOptions(
1527
1525
  ...(env.stationChild === undefined ? {} : { stationChild: env.stationChild }),
1528
1526
  // #1132: one configured ceiling, already resolved by the caller (#422).
1529
1527
  deliveryRequestLimit: deliveryLimitFromConfig(env.autoResumeLimit),
1528
+ ...(env.navigatorWorkContextPath === undefined
1529
+ || env.navigatorWorkContextPath.trim() === ""
1530
+ ? {}
1531
+ : { navigatorWorkContextPath: env.navigatorWorkContextPath }),
1530
1532
  };
1531
1533
  }
1532
1534
 
@@ -1547,6 +1549,10 @@ export function roleTurnOptions(
1547
1549
  ...(env.stationChild === undefined ? {} : { stationChild: env.stationChild }),
1548
1550
  // #1132: one configured ceiling, already resolved by the caller (#422).
1549
1551
  deliveryRequestLimit: deliveryLimitFromConfig(env.autoResumeLimit),
1552
+ ...(env.navigatorWorkContextPath === undefined
1553
+ || env.navigatorWorkContextPath.trim() === ""
1554
+ ? {}
1555
+ : { navigatorWorkContextPath: env.navigatorWorkContextPath }),
1550
1556
  };
1551
1557
  }
1552
1558
 
@@ -1668,7 +1674,7 @@ export async function prepareSummonsResumeMaterials(
1668
1674
  * validation, turn builder, and adapters stay on the seat.
1669
1675
  *
1670
1676
  * Court handling (#637): public manual resume reads only the open court's
1671
- * settlement identity; internal re-summons may freeze and record its materials.
1677
+ * settlement identity; internal re-summons passes caller file-flag paths as-is.
1672
1678
  */
1673
1679
  export async function runPostAdmissionSeatResume<
1674
1680
  A extends AdmittedRoleInvocation,
@@ -20,7 +20,6 @@ import { findRoleRunDirectory, listBookRunDirectories, parseRunLeaf, sessionFile
20
20
  import { isSafePositiveTicketNumber } from "../run-ticket-number.ts";
21
21
  import { CliUsageError } from "./cli-errors.ts";
22
22
  import type { FixerPhase } from "../package-contracts/fixer-output.ts";
23
- import type { FixerPrerequisite } from "../package-contracts/fixer-packet.ts";
24
23
  import { parseCollectorRepository } from "../collector-config.ts";
25
24
  import type { DoctorCaseIdentity } from "../doctor-contracts.ts";
26
25
  import type { NotarySourceRunLocator } from "../notary-contracts.ts";
@@ -886,21 +885,9 @@ export async function findRunDirectoryById(
886
885
  );
887
886
  }
888
887
 
889
- /** Code-owned gate inspector summons prefix (public-role-summons / #747). */
890
- export const GATE_DOSSIER_POINTER_PREFIX = "卷宗指针:" as const;
891
-
892
- /** Parent path from a code-owned inspector 卷宗指针 instruction; else undefined. */
893
- export function parentRunPathFromGatePointerInstruction(
894
- instruction: string,
895
- ): string | undefined {
896
- if (!instruction.startsWith(GATE_DOSSIER_POINTER_PREFIX)) return undefined;
897
- const path = instruction.slice(GATE_DOSSIER_POINTER_PREFIX.length).trim();
898
- return path === "" ? undefined : path;
899
- }
900
-
901
888
  /**
902
- * Parent-run binding on a retained officer run (#747).
903
- * Notary/auditor: typed sourceRunPath. Inspector: exact code-owned 卷宗指针 instruction.
889
+ * Parent-run binding on a retained officer run (#747 / #1166).
890
+ * Typed sourceRunPath only — instruction bytes are never a path protocol.
904
891
  * Missing page → undefined; damage / non-ENOENT IO propagates.
905
892
  */
906
893
  export async function readRunParentPath(
@@ -911,9 +898,6 @@ export async function readRunParentPath(
911
898
  if (typeof record.sourceRunPath === "string" && record.sourceRunPath.trim() !== "") {
912
899
  return record.sourceRunPath;
913
900
  }
914
- if (typeof record.instruction === "string") {
915
- return parentRunPathFromGatePointerInstruction(record.instruction);
916
- }
917
901
  return undefined;
918
902
  }
919
903
 
@@ -992,10 +976,7 @@ type LoadedAdmittedRequestFields = {
992
976
  readonly instructionEmpty: boolean;
993
977
  readonly attachments: FrozenAttachment[];
994
978
  readonly phase?: CoderPhase | FixerPhase;
995
- readonly taskPath?: string;
996
- readonly packetPath?: string;
997
979
  readonly prerequisitesPath?: string;
998
- readonly prerequisites?: readonly FixerPrerequisite[];
999
980
  readonly baseRevision?: string;
1000
981
  readonly lens?: ReviewerLens;
1001
982
  readonly authorityRefs?: readonly string[];
@@ -1081,10 +1062,7 @@ async function loadResumableRunRecord(
1081
1062
  let instructionEmpty = true;
1082
1063
  let attachments: FrozenAttachment[] = [];
1083
1064
  let phase: CoderPhase | FixerPhase | undefined;
1084
- let taskPath: string | undefined;
1085
- let packetPath: string | undefined;
1086
1065
  let prerequisitesPath: string | undefined;
1087
- let prerequisites: readonly FixerPrerequisite[] | undefined;
1088
1066
  let baseRevision: string | undefined;
1089
1067
  let lens: ReviewerLens | undefined;
1090
1068
  let authorityRefs: readonly string[] | undefined;
@@ -1128,21 +1106,10 @@ async function loadResumableRunRecord(
1128
1106
  if (record.phase === "plan" || record.phase === "apply") {
1129
1107
  phase = record.phase;
1130
1108
  }
1131
- if (typeof record.taskPath === "string" && record.taskPath.trim() !== "") {
1132
- taskPath = record.taskPath;
1133
- }
1134
- if (typeof record.packetPath === "string" && record.packetPath.trim() !== "") {
1135
- packetPath = record.packetPath;
1136
- }
1137
- if (
1138
- typeof record.prerequisitesPath === "string" &&
1139
- record.prerequisitesPath.trim() !== ""
1140
- ) {
1109
+ // #1168: opaque caller path on resume — do not trim-filter provided values.
1110
+ if (typeof record.prerequisitesPath === "string") {
1141
1111
  prerequisitesPath = record.prerequisitesPath;
1142
1112
  }
1143
- if (Array.isArray(record.prerequisites)) {
1144
- prerequisites = record.prerequisites as FixerPrerequisite[];
1145
- }
1146
1113
  if (
1147
1114
  typeof record.baseRevision === "string" &&
1148
1115
  record.baseRevision.trim() !== ""
@@ -1319,10 +1286,7 @@ async function loadResumableRunRecord(
1319
1286
  instructionEmpty,
1320
1287
  attachments,
1321
1288
  ...(phase === undefined ? {} : { phase }),
1322
- ...(taskPath === undefined ? {} : { taskPath }),
1323
- ...(packetPath === undefined ? {} : { packetPath }),
1324
1289
  ...(prerequisitesPath === undefined ? {} : { prerequisitesPath }),
1325
- ...(prerequisites === undefined ? {} : { prerequisites }),
1326
1290
  ...(baseRevision === undefined ? {} : { baseRevision }),
1327
1291
  ...(lens === undefined ? {} : { lens }),
1328
1292
  ...(authorityRefs === undefined ? {} : { authorityRefs }),
@@ -1453,12 +1417,6 @@ function admitResumedRole(loaded: {
1453
1417
  }
1454
1418
  case "worker-task": {
1455
1419
  const phase = resumedWorkerPhase(fields.phase ?? loaded.run.phase, record.phases, role, runId);
1456
- const taskPath = fields.taskPath;
1457
- if (taskPath === undefined) {
1458
- throw new CliUsageError(
1459
- `role run admitted coder task path is missing: ${runId}`,
1460
- );
1461
- }
1462
1420
  if (fields.instruction.trim() === "") {
1463
1421
  throw new CliUsageError(
1464
1422
  `role run admitted coder task is blank: ${runId}`,
@@ -1469,34 +1427,24 @@ function admitResumedRole(loaded: {
1469
1427
  phase,
1470
1428
  ...base,
1471
1429
  instructionEmpty: false,
1472
- taskPath,
1473
1430
  };
1474
1431
  return admitted;
1475
1432
  }
1476
1433
  case "worker-packet": {
1477
1434
  const phase = resumedWorkerPhase(fields.phase ?? loaded.run.phase, record.phases, role, runId);
1478
- const packetPath = fields.packetPath;
1479
- if (packetPath === undefined) {
1480
- throw new CliUsageError(
1481
- `role run admitted fixer packet path is missing: ${runId}`,
1482
- );
1483
- }
1484
1435
  if (fields.instruction.trim() === "") {
1485
1436
  throw new CliUsageError(
1486
1437
  `role run admitted fixer instruction is blank: ${runId}`,
1487
1438
  );
1488
1439
  }
1489
- const prerequisites = fields.prerequisites ?? Object.freeze([]);
1490
1440
  const admitted: AdmittedFixerInvocation = {
1491
1441
  role: "fixer",
1492
1442
  phase,
1493
1443
  ...base,
1494
1444
  instructionEmpty: false,
1495
- packetPath,
1496
1445
  ...(fields.prerequisitesPath === undefined
1497
1446
  ? {}
1498
1447
  : { prerequisitesPath: fields.prerequisitesPath }),
1499
- prerequisites,
1500
1448
  };
1501
1449
  return admitted;
1502
1450
  }
@@ -17,7 +17,6 @@ import {
17
17
  import type { SeatModelConfig } from "./config.ts";
18
18
  import type { AdmittedRoleInvocation } from "./invocation.ts";
19
19
  import { installedMethodSkillPath } from "./machine-method-skills.ts";
20
- import { parentRunPathFromGatePointerInstruction } from "./run-lifecycle.ts";
21
20
  import type { PublicThinkingLevel } from "./registry.ts";
22
21
 
23
22
  /** Structural model shape shared by the seam so seat/env sources fit. */
@@ -77,6 +76,11 @@ export type RoleTurnRequestProjectionOptions = {
77
76
  * execution seam count with the same configured number.
78
77
  */
79
78
  readonly deliveryRequestLimit?: number;
79
+ /**
80
+ * Navigator nest work-context locator (#1166). Request-scoped internal path —
81
+ * not dialogue content.
82
+ */
83
+ readonly navigatorWorkContextPath?: string;
80
84
  };
81
85
 
82
86
  export type AdmittedTurnInvocation = {
@@ -127,6 +131,10 @@ export function projectRoleTurnRequest(
127
131
  ...(options.deliveryRequestLimit === undefined
128
132
  ? {}
129
133
  : { deliveryRequestLimit: options.deliveryRequestLimit }),
134
+ ...(options.navigatorWorkContextPath === undefined
135
+ || options.navigatorWorkContextPath.trim() === ""
136
+ ? {}
137
+ : { navigatorWorkContextPath: options.navigatorWorkContextPath }),
130
138
  };
131
139
  }
132
140
 
@@ -163,13 +171,6 @@ function activationForAdmitted(admitted: AdmittedRoleInvocation): RoleTurnActiva
163
171
  const activation: Record<string, unknown> = { role: admitted.role };
164
172
  for (const spec of packagedRoleActivationFlags(admitted.role)) {
165
173
  let value = readAdmittedPath(admitted, spec.from ?? spec.field);
166
- if (spec.fallback === "gate-pointer") {
167
- const trimmed = typeof value === "string" ? value.trim() : "";
168
- value = trimmed !== ""
169
- ? trimmed
170
- : parentRunPathFromGatePointerInstruction(admitted.instruction);
171
- if (typeof value !== "string" || value === "") continue;
172
- }
173
174
  if (value === undefined) continue;
174
175
  if (spec.text === true) {
175
176
  if (typeof value !== "number") continue;