@akagilnc/pi-workflow-roles 0.1.5593 → 0.1.5598

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.
@@ -370,8 +370,8 @@ const FIXER_OPTIONS = [
370
370
  repeatable: false,
371
371
  form: "option",
372
372
  description: {
373
- en: "JSON array of {id, requirement} prerequisite objects.",
374
- zh: "{id, requirement} 前置条件 JSON 数组路径。",
373
+ 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.",
374
+ zh: "调用方前置条件文件路径原样递给衙门。包不读、不复制、不校验;调用方当前目录与 --project 不同时请给绝对路径。",
375
375
  },
376
376
  },
377
377
  ];
@@ -49,12 +49,12 @@ function projectRelocatedTurnIdentity(request, result, admitted, relocation) {
49
49
  mutableRequest.principal = admitted.principal;
50
50
  const activation = mutableRequest.activation;
51
51
  if (isRecord(activation)) {
52
- for (const field of ["taskPath", "packetPath", "prerequisitesPath", "inputPath"]) {
52
+ for (const field of ["inputPath"]) {
53
53
  const record = activation;
54
54
  if (field in record)
55
55
  record[field] = rewrite(record[field]);
56
56
  }
57
- // #1165: activation.requestManifestPath is a caller path — do not rewrite.
57
+ // #1165/#1168: caller file-flag paths are not activation fields to rewrite.
58
58
  }
59
59
  if (result.terminal !== undefined) {
60
60
  for (const artifact of result.terminal.artifacts) {
@@ -766,10 +766,7 @@ async function loadResumableRunRecord(home, runId, authority) {
766
766
  let instructionEmpty = true;
767
767
  let attachments = [];
768
768
  let phase;
769
- let taskPath;
770
- let packetPath;
771
769
  let prerequisitesPath;
772
- let prerequisites;
773
770
  let baseRevision;
774
771
  let lens;
775
772
  let authorityRefs;
@@ -813,19 +810,10 @@ async function loadResumableRunRecord(home, runId, authority) {
813
810
  if (record.phase === "plan" || record.phase === "apply") {
814
811
  phase = record.phase;
815
812
  }
816
- if (typeof record.taskPath === "string" && record.taskPath.trim() !== "") {
817
- taskPath = record.taskPath;
818
- }
819
- if (typeof record.packetPath === "string" && record.packetPath.trim() !== "") {
820
- packetPath = record.packetPath;
821
- }
822
- if (typeof record.prerequisitesPath === "string" &&
823
- record.prerequisitesPath.trim() !== "") {
813
+ // #1168: opaque caller path on resume — do not trim-filter provided values.
814
+ if (typeof record.prerequisitesPath === "string") {
824
815
  prerequisitesPath = record.prerequisitesPath;
825
816
  }
826
- if (Array.isArray(record.prerequisites)) {
827
- prerequisites = record.prerequisites;
828
- }
829
817
  if (typeof record.baseRevision === "string" &&
830
818
  record.baseRevision.trim() !== "") {
831
819
  baseRevision = record.baseRevision;
@@ -974,10 +962,7 @@ async function loadResumableRunRecord(home, runId, authority) {
974
962
  instructionEmpty,
975
963
  attachments,
976
964
  ...(phase === undefined ? {} : { phase }),
977
- ...(taskPath === undefined ? {} : { taskPath }),
978
- ...(packetPath === undefined ? {} : { packetPath }),
979
965
  ...(prerequisitesPath === undefined ? {} : { prerequisitesPath }),
980
- ...(prerequisites === undefined ? {} : { prerequisites }),
981
966
  ...(baseRevision === undefined ? {} : { baseRevision }),
982
967
  ...(lens === undefined ? {} : { lens }),
983
968
  ...(authorityRefs === undefined ? {} : { authorityRefs }),
@@ -1079,10 +1064,6 @@ function admitResumedRole(loaded) {
1079
1064
  }
1080
1065
  case "worker-task": {
1081
1066
  const phase = resumedWorkerPhase(fields.phase ?? loaded.run.phase, record.phases, role, runId);
1082
- const taskPath = fields.taskPath;
1083
- if (taskPath === undefined) {
1084
- throw new CliUsageError(`role run admitted coder task path is missing: ${runId}`);
1085
- }
1086
1067
  if (fields.instruction.trim() === "") {
1087
1068
  throw new CliUsageError(`role run admitted coder task is blank: ${runId}`);
1088
1069
  }
@@ -1091,30 +1072,22 @@ function admitResumedRole(loaded) {
1091
1072
  phase,
1092
1073
  ...base,
1093
1074
  instructionEmpty: false,
1094
- taskPath,
1095
1075
  };
1096
1076
  return admitted;
1097
1077
  }
1098
1078
  case "worker-packet": {
1099
1079
  const phase = resumedWorkerPhase(fields.phase ?? loaded.run.phase, record.phases, role, runId);
1100
- const packetPath = fields.packetPath;
1101
- if (packetPath === undefined) {
1102
- throw new CliUsageError(`role run admitted fixer packet path is missing: ${runId}`);
1103
- }
1104
1080
  if (fields.instruction.trim() === "") {
1105
1081
  throw new CliUsageError(`role run admitted fixer instruction is blank: ${runId}`);
1106
1082
  }
1107
- const prerequisites = fields.prerequisites ?? Object.freeze([]);
1108
1083
  const admitted = {
1109
1084
  role: "fixer",
1110
1085
  phase,
1111
1086
  ...base,
1112
1087
  instructionEmpty: false,
1113
- packetPath,
1114
1088
  ...(fields.prerequisitesPath === undefined
1115
1089
  ? {}
1116
1090
  : { prerequisitesPath: fields.prerequisitesPath }),
1117
- prerequisites,
1118
1091
  };
1119
1092
  return admitted;
1120
1093
  }
@@ -19,10 +19,9 @@ const ADMITTED_PAGE_FIELDS = [
19
19
  "admittedRequestPath", // pre-#1161 pages only
20
20
  "sessionDirectory",
21
21
  "sessionFile",
22
- "taskPath",
23
- "packetPath",
24
- "prerequisitesPath",
25
- // #1165: requestManifestPath is a caller path — never rewrite.
22
+ // #1165/#1168: caller file-flag paths (requestManifestPath, prerequisitesPath)
23
+ // stay as given. Obsolete copy fields (taskPath/packetPath) are not rewritten —
24
+ // stock volumes keep their bytes; live relocate no longer maintains them.
26
25
  "mergerInputPath",
27
26
  "sourceRunPath",
28
27
  ];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@akagilnc/pi-workflow-roles",
3
- "version": "0.1.5593",
3
+ "version": "0.1.5598",
4
4
  "description": "Soul-bound workflow roles for Pi",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",
@@ -55,7 +55,6 @@ const entries = [
55
55
  "open-tool-schema",
56
56
  "package-contracts/collector-output",
57
57
  "package-contracts/fixer-output",
58
- "package-contracts/fixer-packet",
59
58
  "package-contracts/gatekeeper-output",
60
59
  "package-contracts/judge-output",
61
60
  "package-contracts/navigator-output",
@@ -87,13 +87,10 @@ export type RoleTurnActivation =
87
87
  | {
88
88
  readonly role: "coder";
89
89
  readonly phase: string;
90
- readonly taskPath: string;
91
90
  }
92
91
  | {
93
92
  readonly role: "fixer";
94
93
  readonly phase: string;
95
- readonly packetPath: string;
96
- readonly prerequisitesPath?: string;
97
94
  }
98
95
  | {
99
96
  readonly role: "reviewer";
@@ -11,7 +11,8 @@ export const mergerInputSchema = Type.Object({
11
11
  attemptId: Type.String({ minLength: 1, description: "对账 attempt 身份(transport)" }),
12
12
  targetObjectId: Type.String({ description: "材料:target parent OID;可空" }),
13
13
  sourceObjectId: Type.String({ description: "材料:source parent OID;可空" }),
14
- materials: Type.Object({ task: materialSchema, authority: materialSchema, targetIntent: materialSchema, sourceIntent: materialSchema }),
14
+ // #1168: task/authority dispatch copies removed; git-fact intents remain.
15
+ materials: Type.Object({ targetIntent: materialSchema, sourceIntent: materialSchema }),
15
16
  expectedConflictPaths: Type.Array(Type.String(), { description: "材料:当前未合并路径;可空" }),
16
17
  resolutionScope: Type.Array(Type.String(), { description: "材料:解析范围提示;可空" }),
17
18
  authorizedChecks: Type.Array(checkSchema),
@@ -62,7 +63,10 @@ function readMaterial(value: unknown, label: string): MergerMaterial {
62
63
  export function validateMergerInput(value: unknown): MergerInput {
63
64
  if (!isRecord(value) || blank(value.attemptId)) fail("Merger input requires a non-empty attemptId for accounting");
64
65
  if (!isRecord(value.materials)) fail("Merger materials are missing");
65
- const materials = { task: readMaterial(value.materials.task, "task"), authority: readMaterial(value.materials.authority, "authority"), targetIntent: readMaterial(value.materials.targetIntent, "targetIntent"), sourceIntent: readMaterial(value.materials.sourceIntent, "sourceIntent") };
66
+ const materials = {
67
+ targetIntent: readMaterial(value.materials.targetIntent, "targetIntent"),
68
+ sourceIntent: readMaterial(value.materials.sourceIntent, "sourceIntent"),
69
+ };
66
70
  const authorizedChecks = Array.isArray(value.authorizedChecks) ? value.authorizedChecks.filter((check): check is Record<string, unknown> => isRecord(check)).map(c => ({ name: asString(c.name), argv: asStringArray(c.argv).filter(a => a.trim().length > 0) })).filter(c => c.name.trim().length > 0 && c.argv.length > 0) : [];
67
71
  return deepFreeze(structuredClone({ attemptId: (value.attemptId as string).trim(), targetObjectId: asString(value.targetObjectId), sourceObjectId: asString(value.sourceObjectId), materials, expectedConflictPaths: asStringArray(value.expectedConflictPaths), resolutionScope: asStringArray(value.resolutionScope), authorizedChecks }) as MergerInput);
68
72
  }
@@ -21,6 +21,7 @@ function materialText(input: MergerInput, key: keyof MergerInput["materials"]):
21
21
  * Merger (校书郎) role runtime.
22
22
  * Submission tool records every call (#836); host end is the final.
23
23
  * Git state / completion verification are not attendance or rejection gates (#827).
24
+ * #1168: dispatch text is the first message; assignment carries git facts only.
24
25
  */
25
26
  export function createMergerRoleRuntime(pi: RoleHost, dependencies: MergerRoleDependencies) {
26
27
  let activation: { soul: string; input: Readonly<MergerInput> } | undefined;
@@ -41,7 +42,16 @@ export function createMergerRoleRuntime(pi: RoleHost, dependencies: MergerRoleDe
41
42
  });
42
43
  pi.on("before_agent_start", (event) => {
43
44
  if (!activation) throw new Error("校书郎未激活");
44
- const admitted = { attemptId: activation.input.attemptId, targetObjectId: activation.input.targetObjectId, sourceObjectId: activation.input.sourceObjectId, task: materialText(activation.input, "task"), authority: materialText(activation.input, "authority"), targetIntent: materialText(activation.input, "targetIntent"), sourceIntent: materialText(activation.input, "sourceIntent"), expectedConflictPaths: activation.input.expectedConflictPaths, resolutionScope: activation.input.resolutionScope, authorizedChecks: activation.input.authorizedChecks };
45
+ const admitted = {
46
+ attemptId: activation.input.attemptId,
47
+ targetObjectId: activation.input.targetObjectId,
48
+ sourceObjectId: activation.input.sourceObjectId,
49
+ targetIntent: materialText(activation.input, "targetIntent"),
50
+ sourceIntent: materialText(activation.input, "sourceIntent"),
51
+ expectedConflictPaths: activation.input.expectedConflictPaths,
52
+ resolutionScope: activation.input.resolutionScope,
53
+ authorizedChecks: activation.input.authorizedChecks,
54
+ };
45
55
  return { systemPrompt: `${event.systemPrompt}\n\n<merger_soul>\n${activation.soul}\n</merger_soul>\n\n<merger_assignment>\n${JSON.stringify(admitted)}\n</merger_assignment>` };
46
56
  });
47
57
  }
@@ -229,14 +229,14 @@ export function navigatorSubjectKey(
229
229
  /**
230
230
  * Role inputs for one ad-hoc work item live below role-specific run folders.
231
231
  * The folder and filename are transport, not identity: the shared work root
232
- * keeps task.md, fix-packet.json, and other natural inputs on one subject.
232
+ * keeps natural inputs on one subject.
233
233
  */
234
234
  export function navigatorSubjectKeyForInput(subjectRoot: string, reference: string, cwd = process.cwd()): string {
235
235
  if (issueRoot(subjectRoot) !== undefined || !subjectRoot.includes("/.ak/work/")) return subjectRoot;
236
236
  const resolvedReference = resolve(cwd, reference);
237
237
  const marker = "/runs/";
238
238
  if (resolvedReference.includes(marker)) {
239
- // The work root, not task.md/fix-packet.json/etc., is the stable subject.
239
+ // The work root, not a role-input filename, is the stable subject.
240
240
  // Different roots remain isolated without inventing a filename convention.
241
241
  return subjectRoot;
242
242
  }
@@ -13,26 +13,18 @@ import {
13
13
  type FixerOutput,
14
14
  type FixerPhase,
15
15
  } from "./fixer-output.ts";
16
- import { fixerPrerequisiteSchema, fixerPrerequisitesSchema, parseFixerPrerequisites, validateFixerPrerequisites } from "./fixer-packet.ts";
17
- import type { FixerInvocationInput, FixerPrerequisite } from "./fixer-packet.ts";
18
16
  import { withTerminatingOutputDeclarations } from "./terminating-infrastructure.ts";
19
17
 
20
18
  export {
21
19
  FIXER_OUTPUT_TOOL_NAME,
22
20
  fixerOutputSchema,
23
21
  validateFixerOutput,
24
- fixerPrerequisiteSchema,
25
- fixerPrerequisitesSchema,
26
- parseFixerPrerequisites,
27
- validateFixerPrerequisites,
28
22
  };
29
23
  export type {
30
24
  FixerBlocker,
31
25
  FixerClassResult,
32
26
  FixerOutput,
33
27
  FixerPhase,
34
- FixerInvocationInput,
35
- FixerPrerequisite,
36
28
  };
37
29
 
38
30
  export const CODER_OUTPUT_TOOL_NAME = "ak_coder_output";
@@ -115,10 +115,10 @@ export const PUBLIC_ROLE_RECORDS = [
115
115
  reportPhase: true,
116
116
  },
117
117
  boardPlacement: "marshal",
118
+ /** #1168: dispatch is first message; navigator reads admitted instruction. */
119
+ navigatorSubject: "public-instruction",
118
120
  activationFlags: [
119
- { field: "packetPath", flag: "ak-fix-packet", binds: "input" },
120
121
  { field: "phase", flag: "ak-fixer-phase", binds: "phase" },
121
- { field: "prerequisitesPath", flag: "ak-fixer-prerequisites" },
122
122
  ],
123
123
  activationStage: "load-and-install",
124
124
  sessionMaterials: [
@@ -145,8 +145,9 @@ export const PUBLIC_ROLE_RECORDS = [
145
145
  artifactFace: {
146
146
  reportPhase: true,
147
147
  },
148
+ /** #1168: dispatch is first message; navigator reads admitted instruction. */
149
+ navigatorSubject: "public-instruction",
148
150
  activationFlags: [
149
- { field: "taskPath", flag: "ak-coder-task", binds: "input" },
150
151
  { field: "phase", flag: "ak-coder-phase", binds: "phase" },
151
152
  ],
152
153
  activationStage: "load-and-install",
@@ -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";
@@ -204,20 +199,14 @@ export type AdmittedCoderInvocation = AdmittedRoleInvocationBase & {
204
199
  readonly role: "coder";
205
200
  /** Explicit plan or default apply — preserved through admission and continuation. */
206
201
  readonly phase: CoderPhase;
207
- /** Durable task file path consumed by internal --ak-coder-task. */
208
- readonly taskPath: string;
209
202
  };
210
203
 
211
204
  export type AdmittedFixerInvocation = AdmittedRoleInvocationBase & {
212
205
  readonly role: "fixer";
213
206
  /** Explicit plan or default apply — preserved through admission and continuation. */
214
207
  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. */
208
+ /** Optional caller --prerequisites path as-is (#1168; package does not read it). */
218
209
  readonly prerequisitesPath?: string;
219
- /** Structurally validated prerequisite declarations frozen at admission. */
220
- readonly prerequisites: readonly FixerPrerequisite[];
221
210
  };
222
211
 
223
212
  export type AdmittedCollectorInvocation = AdmittedRoleInvocationBase & {
@@ -622,15 +611,13 @@ export async function relocateAdmittedRunToTicket(
622
611
  admittedRecord,
623
612
  [
624
613
  "runDirectory",
625
- "taskPath",
626
- "packetPath",
627
- "prerequisitesPath",
628
614
  "mergerInputPath",
629
615
  ],
630
616
  oldRunDirectory,
631
617
  target.runDirectory,
632
618
  );
633
- // #1165: caller --attach / --request-manifest paths stay as given; do not rewrite.
619
+ // #1165/#1168: caller file-flag paths stay as given. Obsolete copy fields
620
+ // (taskPath/packetPath) are not rewritten — stock volumes keep their bytes.
634
621
  (admitted as { principal: DurablePrincipal }).principal = principal;
635
622
 
636
623
  // current.json projects host.original from this run directory. Ownership is
@@ -876,7 +863,8 @@ function assignPublicSeatOption(
876
863
  fields.authorityRefs.push(requireAuthorityRef(value));
877
864
  return;
878
865
  case "prerequisites":
879
- fields.prerequisitesPath = requireOptionPath(taken.def.canonical, value);
866
+ // #1168: same opaque file-flag rule as --attach.
867
+ fields.prerequisitesPath = requireProvidedOptionValue(taken.def.canonical, value);
880
868
  return;
881
869
  case "pr":
882
870
  fields.prNumber = parsePositivePrOption(value);
@@ -1324,16 +1312,13 @@ export async function admitPublicRole(
1324
1312
  if (!record.phases.some((item) => item === phase)) {
1325
1313
  throw new CliUsageError("coder phase must be plan or apply");
1326
1314
  }
1315
+ // #1168: dispatch text is the first message only — no task.md copy.
1327
1316
  return admitStandardMaterialInvocation("coder", {
1328
1317
  ...shared,
1329
1318
  instruction,
1330
1319
  attachmentPaths,
1331
1320
  ...project,
1332
- placedFields: async (placed) => {
1333
- const taskPath = join(placed.runDirectory, "task.md");
1334
- await writeFile(taskPath, instruction, "utf8");
1335
- return { phase, taskPath };
1336
- },
1321
+ placedFields: async () => ({ phase }),
1337
1322
  });
1338
1323
  }
1339
1324
  case "worker-packet": {
@@ -1344,53 +1329,18 @@ export async function admitPublicRole(
1344
1329
  if (!record.phases.some((item) => item === phase)) {
1345
1330
  throw new CliUsageError("fixer phase must be plan or apply");
1346
1331
  }
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
- }
1332
+ // #1168: dispatch once as first message; --prerequisites path as-is.
1370
1333
  return admitStandardMaterialInvocation("fixer", {
1371
1334
  ...shared,
1372
1335
  instruction,
1373
1336
  attachmentPaths,
1374
1337
  ...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
- },
1338
+ placedFields: async () => ({
1339
+ phase,
1340
+ ...(parsed.prerequisitesPath === undefined
1341
+ ? {}
1342
+ : { prerequisitesPath: parsed.prerequisitesPath }),
1343
+ }),
1394
1344
  });
1395
1345
  }
1396
1346
  case "collect-target": {
@@ -1579,13 +1529,12 @@ export async function admitPublicRole(
1579
1529
  placedFields: async (placed) => {
1580
1530
  const targetLabel = derived.targetObjectId === "" ? "(none observed)" : derived.targetObjectId;
1581
1531
  const sourceLabel = derived.sourceObjectId === "" ? "(none observed)" : derived.sourceObjectId;
1532
+ // #1168: git facts stay; do not encode dispatch text as task/authority copies.
1582
1533
  const mergerInput = validateMergerInput({
1583
1534
  attemptId: placed.runId,
1584
1535
  targetObjectId: derived.targetObjectId,
1585
1536
  sourceObjectId: derived.sourceObjectId,
1586
1537
  materials: {
1587
- task: mergerMaterialFromUtf8(instruction),
1588
- authority: mergerMaterialFromUtf8(instruction),
1589
1538
  targetIntent: mergerMaterialFromUtf8(
1590
1539
  `Investigate primary sources for target parent ${targetLabel}. Do not invent intent.`,
1591
1540
  ),
@@ -1767,7 +1716,7 @@ async function persistPlacedAdmission(
1767
1716
  * before materializeCountersignInvocation writes the page.
1768
1717
  * Seats whose extra facts are known before placement pass them as admittedFields.
1769
1718
  * 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).
1719
+ * (merger writes merger-input.json with git facts; coder/fixer dispatch is first-message only, #1168).
1771
1720
  */
1772
1721
  async function admitStandardMaterialInvocation<
1773
1722
  R extends PackagedRole,
@@ -1849,9 +1798,10 @@ export type AdmitAuditorInvocationOptions = AdmitInspectorInvocationOptions;
1849
1798
  type InstructionTransportSource = {
1850
1799
  readonly role?: string;
1851
1800
  readonly instruction: string;
1852
- readonly instructionEmpty: boolean;
1801
+ readonly instructionEmpty?: boolean;
1853
1802
  readonly attachments: readonly { readonly path: string }[];
1854
1803
  readonly requestManifestPath?: string;
1804
+ readonly prerequisitesPath?: string;
1855
1805
  readonly baseRevision?: string;
1856
1806
  readonly lens?: ReviewerLens;
1857
1807
  readonly authorityRefs?: readonly string[];
@@ -1913,14 +1863,17 @@ export function buildInstructionTransportPrompt(
1913
1863
  }
1914
1864
  return lines.join("\n");
1915
1865
  }
1916
- // #1165 J3: assemble from the admitted instruction bytes themselves.
1866
+ // #1165 J3 / #1168: assemble from the admitted instruction bytes themselves.
1917
1867
  const lines: string[] = [admitted.instruction];
1918
- // #1164/#1165: each caller path keeps its file-flag provenance.
1868
+ // #1164/#1165/#1168: each caller path keeps its file-flag provenance.
1919
1869
  const flaggedPaths: string[] = [
1920
1870
  ...admitted.attachments.map((attachment) => `--attach ${attachment.path}`),
1921
1871
  ...(admitted.requestManifestPath === undefined
1922
1872
  ? []
1923
1873
  : [`--request-manifest ${admitted.requestManifestPath}`]),
1874
+ ...(admitted.prerequisitesPath === undefined
1875
+ ? []
1876
+ : [`--prerequisites ${admitted.prerequisitesPath}`]),
1924
1877
  ];
1925
1878
  if (flaggedPaths.length > 0) {
1926
1879
  lines.push("");
@@ -2022,7 +1975,7 @@ export type AdmitFixerInvocationOptions = {
2022
1975
  phase: FixerPhase;
2023
1976
  instruction: string;
2024
1977
  attachmentPaths: readonly string[];
2025
- /** Optional caller path to prerequisite JSON array; malformed grammar rejects here. */
1978
+ /** Optional caller --prerequisites path as-is (#1168). */
2026
1979
  prerequisitesPath?: string;
2027
1980
  project?: string;
2028
1981
  createRunId?: () => string;
@@ -2198,7 +2151,7 @@ export function buildReviewerSkillArgProjection(
2198
2151
  ].join(" ");
2199
2152
  }
2200
2153
 
2201
- function mergerMaterialFromUtf8(text: string): MergerInput["materials"]["task"] {
2154
+ function mergerMaterialFromUtf8(text: string): MergerInput["materials"]["targetIntent"] {
2202
2155
  const bytes = Buffer.from(text, "utf8");
2203
2156
  return Object.freeze({
2204
2157
  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[];
@@ -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) {
@@ -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";
@@ -992,10 +991,7 @@ type LoadedAdmittedRequestFields = {
992
991
  readonly instructionEmpty: boolean;
993
992
  readonly attachments: FrozenAttachment[];
994
993
  readonly phase?: CoderPhase | FixerPhase;
995
- readonly taskPath?: string;
996
- readonly packetPath?: string;
997
994
  readonly prerequisitesPath?: string;
998
- readonly prerequisites?: readonly FixerPrerequisite[];
999
995
  readonly baseRevision?: string;
1000
996
  readonly lens?: ReviewerLens;
1001
997
  readonly authorityRefs?: readonly string[];
@@ -1081,10 +1077,7 @@ async function loadResumableRunRecord(
1081
1077
  let instructionEmpty = true;
1082
1078
  let attachments: FrozenAttachment[] = [];
1083
1079
  let phase: CoderPhase | FixerPhase | undefined;
1084
- let taskPath: string | undefined;
1085
- let packetPath: string | undefined;
1086
1080
  let prerequisitesPath: string | undefined;
1087
- let prerequisites: readonly FixerPrerequisite[] | undefined;
1088
1081
  let baseRevision: string | undefined;
1089
1082
  let lens: ReviewerLens | undefined;
1090
1083
  let authorityRefs: readonly string[] | undefined;
@@ -1128,21 +1121,10 @@ async function loadResumableRunRecord(
1128
1121
  if (record.phase === "plan" || record.phase === "apply") {
1129
1122
  phase = record.phase;
1130
1123
  }
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
- ) {
1124
+ // #1168: opaque caller path on resume — do not trim-filter provided values.
1125
+ if (typeof record.prerequisitesPath === "string") {
1141
1126
  prerequisitesPath = record.prerequisitesPath;
1142
1127
  }
1143
- if (Array.isArray(record.prerequisites)) {
1144
- prerequisites = record.prerequisites as FixerPrerequisite[];
1145
- }
1146
1128
  if (
1147
1129
  typeof record.baseRevision === "string" &&
1148
1130
  record.baseRevision.trim() !== ""
@@ -1319,10 +1301,7 @@ async function loadResumableRunRecord(
1319
1301
  instructionEmpty,
1320
1302
  attachments,
1321
1303
  ...(phase === undefined ? {} : { phase }),
1322
- ...(taskPath === undefined ? {} : { taskPath }),
1323
- ...(packetPath === undefined ? {} : { packetPath }),
1324
1304
  ...(prerequisitesPath === undefined ? {} : { prerequisitesPath }),
1325
- ...(prerequisites === undefined ? {} : { prerequisites }),
1326
1305
  ...(baseRevision === undefined ? {} : { baseRevision }),
1327
1306
  ...(lens === undefined ? {} : { lens }),
1328
1307
  ...(authorityRefs === undefined ? {} : { authorityRefs }),
@@ -1453,12 +1432,6 @@ function admitResumedRole(loaded: {
1453
1432
  }
1454
1433
  case "worker-task": {
1455
1434
  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
1435
  if (fields.instruction.trim() === "") {
1463
1436
  throw new CliUsageError(
1464
1437
  `role run admitted coder task is blank: ${runId}`,
@@ -1469,34 +1442,24 @@ function admitResumedRole(loaded: {
1469
1442
  phase,
1470
1443
  ...base,
1471
1444
  instructionEmpty: false,
1472
- taskPath,
1473
1445
  };
1474
1446
  return admitted;
1475
1447
  }
1476
1448
  case "worker-packet": {
1477
1449
  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
1450
  if (fields.instruction.trim() === "") {
1485
1451
  throw new CliUsageError(
1486
1452
  `role run admitted fixer instruction is blank: ${runId}`,
1487
1453
  );
1488
1454
  }
1489
- const prerequisites = fields.prerequisites ?? Object.freeze([]);
1490
1455
  const admitted: AdmittedFixerInvocation = {
1491
1456
  role: "fixer",
1492
1457
  phase,
1493
1458
  ...base,
1494
1459
  instructionEmpty: false,
1495
- packetPath,
1496
1460
  ...(fields.prerequisitesPath === undefined
1497
1461
  ? {}
1498
1462
  : { prerequisitesPath: fields.prerequisitesPath }),
1499
- prerequisites,
1500
1463
  };
1501
1464
  return admitted;
1502
1465
  }
@@ -23,10 +23,9 @@ const ADMITTED_PAGE_FIELDS = [
23
23
  "admittedRequestPath", // pre-#1161 pages only
24
24
  "sessionDirectory",
25
25
  "sessionFile",
26
- "taskPath",
27
- "packetPath",
28
- "prerequisitesPath",
29
- // #1165: requestManifestPath is a caller path — never rewrite.
26
+ // #1165/#1168: caller file-flag paths (requestManifestPath, prerequisitesPath)
27
+ // stay as given. Obsolete copy fields (taskPath/packetPath) are not rewritten —
28
+ // stock volumes keep their bytes; live relocate no longer maintains them.
30
29
  "mergerInputPath",
31
30
  "sourceRunPath",
32
31
  ] as const;