@akagilnc/pi-workflow-roles 0.1.5583 → 0.1.5593

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.
@@ -261,7 +261,7 @@ const SHARED_PROJECT_SEMANTICS = {
261
261
  },
262
262
  };
263
263
  /**
264
- * Immutable shared semantics for the common frozen-file `--attach` face.
264
+ * Immutable shared semantics for the common `--attach` face (#1165).
265
265
  * Role rows bind owner only. Reviewer has no attach face; analyst sweep attach
266
266
  * keeps its own modes/selectsMode/description and must not use this binding.
267
267
  */
@@ -274,8 +274,8 @@ const SHARED_ATTACH_SEMANTICS = {
274
274
  repeatable: true,
275
275
  form: "option",
276
276
  description: {
277
- en: "Attach a regular file; frozen at admission (repeatable).",
278
- zh: "附加普通文件;受理即冻结(可重复)。",
277
+ en: "Caller file path passed as-is to the role (repeatable). Package does not read, copy, or validate; use an absolute path when cwd differs from --project.",
278
+ zh: "调用方文件路径原样递给衙门(可重复)。包不读、不复制、不校验;调用方当前目录与 --project 不同时请给绝对路径。",
279
279
  },
280
280
  };
281
281
  /** Minimal owner-binding: one immutable semantic row → one role table entry. */
@@ -461,8 +461,8 @@ const COLLECTOR_OPTIONS = [
461
461
  repeatable: false,
462
462
  form: "option",
463
463
  description: {
464
- en: "Optional request manifest JSON path ({requests:[{id,body}]}). Parsed for semantics and passed to the Collector as materials — not a machine collection directive.",
465
- zh: "可选 request manifest JSON 路径({requests:[{id,body}]})。按语义解析后作为材料递给通进司,不是机器代收 finding 的指令。",
464
+ en: "Caller path to a request manifest JSON file, passed as-is. Package does not read, copy, or validate; use an absolute path when cwd differs from --project.",
465
+ zh: "调用方 request manifest JSON 路径,原样传递。包不读、不复制、不校验;调用方当前目录与 --project 不同时请给绝对路径。",
466
466
  },
467
467
  },
468
468
  ];
@@ -7,14 +7,12 @@
7
7
  */
8
8
  import { randomUUID } from "node:crypto";
9
9
  import { writeFile } from "node:fs/promises";
10
- import { isAbsolute, join, resolve } from "node:path";
11
10
  import { buildAutoResumeContinuationPrompt, findRunDirectoryById, readRoleRunState, RESUME_TRANSPORT_ENVELOPE, } from "./run-lifecycle.js";
12
11
  import { CliUsageError } from "./cli-errors.js";
13
12
  import { projectPublicTurnAxes } from "./turn-request.js";
14
- import { bindAdmittedTicketNumber, buildInstructionTransportPrompt, freezeAttachmentsIntoRun, relocateAdmittedRunToTicket, } from "./invocation.js";
13
+ import { bindAdmittedTicketNumber, buildInstructionTransportPrompt, relocateAdmittedRunToTicket, } from "./invocation.js";
15
14
  import { readRecordedSubmissionRows } from "../submission-ledger.js";
16
15
  import { parseTicketNumber, readDeclaredTicketNumber } from "../run-ticket-number.js";
17
- import { pathContainedIn } from "../activation-ledger-topology.js";
18
16
  import { readStoredHostSessionId } from "../session-identity.js";
19
17
  import { reportRunRecord } from "../sitian-facade.js";
20
18
  import { createReceiptDeliveryPolicy, deliveryLimitFromConfig, } from "../receipt-delivery-policy.js";
@@ -51,11 +49,12 @@ function projectRelocatedTurnIdentity(request, result, admitted, relocation) {
51
49
  mutableRequest.principal = admitted.principal;
52
50
  const activation = mutableRequest.activation;
53
51
  if (isRecord(activation)) {
54
- for (const field of ["taskPath", "packetPath", "prerequisitesPath", "inputPath", "requestManifestPath"]) {
52
+ for (const field of ["taskPath", "packetPath", "prerequisitesPath", "inputPath"]) {
55
53
  const record = activation;
56
54
  if (field in record)
57
55
  record[field] = rewrite(record[field]);
58
56
  }
57
+ // #1165: activation.requestManifestPath is a caller path — do not rewrite.
59
58
  }
60
59
  if (result.terminal !== undefined) {
61
60
  for (const artifact of result.terminal.artifacts) {
@@ -925,7 +924,7 @@ export function resumeTurnRequestProjectionOptions(admitted, request, env, summo
925
924
  if (request.message !== undefined) {
926
925
  if (summonsPrepared !== undefined) {
927
926
  // #755: same-ticket review / open-court — caller words.
928
- // #879 station-child officer: words only (attachments are independent freeze).
927
+ // #879 station-child officer: words only (paths remain on summons materials).
929
928
  prompt = officerDialogue
930
929
  ? request.message
931
930
  : buildInstructionTransportPrompt({
@@ -945,8 +944,10 @@ export function resumeTurnRequestProjectionOptions(admitted, request, env, summo
945
944
  else if (summonsPrepared !== undefined) {
946
945
  // #879 station-child officer: instruction bytes === peer body/reask (no wrap).
947
946
  // Other seats keep #755 instruction + optional attachment path listing.
947
+ // #1165 J3: officer dialogue is raw instruction bytes; do not gate on
948
+ // instructionEmpty metadata (resume of older admitted pages).
948
949
  prompt = officerDialogue
949
- ? (summonsPrepared.instructionEmpty ? "" : summonsPrepared.instruction)
950
+ ? summonsPrepared.instruction
950
951
  : buildInstructionTransportPrompt(summonsPrepared);
951
952
  }
952
953
  else if (request.summons !== undefined) {
@@ -1046,34 +1047,18 @@ async function runSettledAutoResumeLoop(input) {
1046
1047
  }),
1047
1048
  });
1048
1049
  }
1049
- function isAlreadyFrozenSummonsAttachment(runDirectory, attachmentPath) {
1050
- const absolute = isAbsolute(attachmentPath)
1051
- ? attachmentPath
1052
- : resolve(attachmentPath);
1053
- return pathContainedIn(join(runDirectory, "attachments"), absolute);
1054
- }
1055
1050
  /**
1056
- * Freeze same-ticket summons attachments into the retained run directory (#637).
1057
- * No-op materials (no paths / instruction-only) skip the freeze.
1058
- * Paths already under this run's attachments/ are the accepted freeze identity —
1059
- * reuse them for the same internal re-summons flow.
1060
- * Manual resume never calls this — old attachment semantics stay intact.
1051
+ * Same-ticket summons materials: caller paths as-is (#1165). No copy or freeze.
1061
1052
  */
1062
- export async function prepareSummonsResumeMaterials(runDirectory, summons) {
1053
+ export async function prepareSummonsResumeMaterials(_runDirectory, summons) {
1063
1054
  if (summons === undefined)
1064
1055
  return undefined;
1065
1056
  if (summons.instruction === undefined && (summons.attachmentPaths?.length ?? 0) === 0) {
1066
1057
  return undefined;
1067
1058
  }
1068
1059
  const instruction = summons.instruction ?? "";
1069
- const instructionEmpty = summons.instructionEmpty ?? instruction.trim() === "";
1070
- let attachments = [];
1071
- if (summons.attachmentPaths !== undefined && summons.attachmentPaths.length > 0) {
1072
- const alreadyFrozen = summons.attachmentPaths.every((path) => isAlreadyFrozenSummonsAttachment(runDirectory, path));
1073
- attachments = alreadyFrozen
1074
- ? summons.attachmentPaths.map((frozenPath) => ({ frozenPath }))
1075
- : await freezeAttachmentsIntoRun(summons.attachmentPaths, runDirectory);
1076
- }
1060
+ const instructionEmpty = summons.instructionEmpty ?? instruction.length === 0;
1061
+ const attachments = (summons.attachmentPaths ?? []).map((path) => ({ path }));
1077
1062
  return { instruction, instructionEmpty, attachments };
1078
1063
  }
1079
1064
  /**
@@ -1137,20 +1122,6 @@ export async function runPostAdmissionSeatResume(input) {
1137
1122
  openCourtAttemptId = openCourt.courtAttemptId;
1138
1123
  }
1139
1124
  }
1140
- // Internal re-summons freezes external paths once and records that identity.
1141
- if (request.summons !== undefined) {
1142
- const prepared = await prepareSummonsResumeMaterials(admittedForBuild.runDirectory, request.summons);
1143
- if (prepared !== undefined &&
1144
- (request.summons.attachmentPaths?.length ?? 0) > 0) {
1145
- request = {
1146
- ...request,
1147
- summons: {
1148
- ...request.summons,
1149
- attachmentPaths: prepared.attachments.map((attachment) => attachment.frozenPath),
1150
- },
1151
- };
1152
- }
1153
- }
1154
1125
  // Public explicit resume: attach the stored native id when the caller
1155
1126
  // left it unset (399c3c8c). In-call auto-resume / 催交 / gate retry omit
1156
1127
  // the field; those load inside the host adapter (host-contracts).
@@ -14,7 +14,7 @@ import { CliUsageError } from "./cli-errors.js";
14
14
  import { parseCollectorRepository } from "../collector-config.js";
15
15
  import { retainedRunPathsMatch, rewriteAdmittedRoleRunPage, rewriteRunDirectoryPathValue, } from "../role-run-relocation.js";
16
16
  import { packagedResumeSourcePath, packagedRoleMetadata, } from "../packaged-role-registry.js";
17
- import { admittedReviewerBaseFault, recordEffectiveInvocationModel, requireAuthorityRef, isReviewerLens, } from "./invocation.js";
17
+ import { admittedReviewerBaseFault, recordEffectiveInvocationModel, requireAuthorityRef, isReviewerLens, normalizeAdmittedAttachment, } from "./invocation.js";
18
18
  import { readPageSync, writeSectionSync } from "../run-dossier.js";
19
19
  import { isRecord, errorText, isEnoent } from "../unknown-value.js";
20
20
  /** Default for the #422 configurable single-call auto-resume ceiling
@@ -51,7 +51,7 @@ function parseSameTicketSummonsMaterials(raw) {
51
51
  const instruction = typeof record.instruction === "string" ? record.instruction : undefined;
52
52
  const instructionEmpty = typeof record.instructionEmpty === "boolean" ? record.instructionEmpty : undefined;
53
53
  const attachmentPaths = Array.isArray(record.attachmentPaths)
54
- ? record.attachmentPaths.filter((p) => typeof p === "string" && p.length > 0)
54
+ ? record.attachmentPaths.filter((p) => typeof p === "string")
55
55
  : undefined;
56
56
  const sourceRunPath = typeof record.sourceRunPath === "string" && record.sourceRunPath.trim() !== ""
57
57
  ? record.sourceRunPath
@@ -781,7 +781,6 @@ async function loadResumableRunRecord(home, runId, authority) {
781
781
  let repository;
782
782
  let repositoryDisplay;
783
783
  let requestManifestPath;
784
- let manifestDigest;
785
784
  let waitWindowMs;
786
785
  let issueNumber;
787
786
  let caseRunsPath;
@@ -807,7 +806,9 @@ async function loadResumableRunRecord(home, runId, authority) {
807
806
  instructionEmpty = record.instructionEmpty;
808
807
  }
809
808
  if (Array.isArray(record.attachments)) {
810
- attachments = record.attachments;
809
+ attachments = record.attachments
810
+ .map((item) => normalizeAdmittedAttachment(item))
811
+ .filter((item) => item !== undefined);
811
812
  }
812
813
  if (record.phase === "plan" || record.phase === "apply") {
813
814
  phase = record.phase;
@@ -842,12 +843,10 @@ async function loadResumableRunRecord(home, runId, authority) {
842
843
  if (typeof record.repositoryDisplay === "string" && record.repositoryDisplay.trim() !== "") {
843
844
  repositoryDisplay = record.repositoryDisplay;
844
845
  }
845
- if (typeof record.requestManifestPath === "string" && record.requestManifestPath.trim() !== "") {
846
+ // #1165: opaque caller path on resume — do not trim-filter provided values.
847
+ if (typeof record.requestManifestPath === "string") {
846
848
  requestManifestPath = record.requestManifestPath;
847
849
  }
848
- if (typeof record.manifestDigest === "string" && record.manifestDigest.trim() !== "") {
849
- manifestDigest = record.manifestDigest;
850
- }
851
850
  if (typeof record.waitWindowMs === "number" && Number.isSafeInteger(record.waitWindowMs) && record.waitWindowMs >= 1) {
852
851
  waitWindowMs = record.waitWindowMs;
853
852
  }
@@ -990,7 +989,6 @@ async function loadResumableRunRecord(home, runId, authority) {
990
989
  ...(repository === undefined ? {} : { repository }),
991
990
  ...(repositoryDisplay === undefined ? {} : { repositoryDisplay }),
992
991
  ...(requestManifestPath === undefined ? {} : { requestManifestPath }),
993
- ...(manifestDigest === undefined ? {} : { manifestDigest }),
994
992
  ...(waitWindowMs === undefined ? {} : { waitWindowMs }),
995
993
  ...(issueNumber === undefined ? {} : { issueNumber }),
996
994
  ...(caseRunsPath === undefined ? {} : { caseRunsPath }),
@@ -1179,10 +1177,8 @@ function admitResumedRole(loaded) {
1179
1177
  return admitted;
1180
1178
  }
1181
1179
  case "collect-target": {
1182
- const { prNumber, repository, repositoryDisplay, manifestDigest } = fields;
1183
- if (repository === undefined ||
1184
- repositoryDisplay === undefined ||
1185
- manifestDigest === undefined) {
1180
+ const { prNumber, repository, repositoryDisplay } = fields;
1181
+ if (repository === undefined || repositoryDisplay === undefined) {
1186
1182
  throw new CliUsageError(`role run admitted collector repository identity is missing: ${runId}`);
1187
1183
  }
1188
1184
  let parsedRepository;
@@ -1205,7 +1201,6 @@ function admitResumedRole(loaded) {
1205
1201
  ? {}
1206
1202
  : { requestManifestPath: fields.requestManifestPath }),
1207
1203
  ...(fields.waitWindowMs === undefined ? {} : { waitWindowMs: fields.waitWindowMs }),
1208
- manifestDigest,
1209
1204
  };
1210
1205
  return admitted;
1211
1206
  }
@@ -249,7 +249,7 @@ async function summonPublicRole(options) {
249
249
  runId: resumeRunId,
250
250
  summons: {
251
251
  instruction,
252
- instructionEmpty: instruction.trim() === ""
252
+ instructionEmpty: instruction.length === 0
253
253
  }
254
254
  },
255
255
  env,
@@ -22,7 +22,7 @@ const ADMITTED_PAGE_FIELDS = [
22
22
  "taskPath",
23
23
  "packetPath",
24
24
  "prerequisitesPath",
25
- "requestManifestPath",
25
+ // #1165: requestManifestPath is a caller path — never rewrite.
26
26
  "mergerInputPath",
27
27
  "sourceRunPath",
28
28
  ];
@@ -150,28 +150,19 @@ function rewriteSourceRunLocator(value, rewrites) {
150
150
  return;
151
151
  rewriteRunDirectoryPathFieldsAgainstRewrites(value, SOURCE_RUN_LOCATOR_FIELDS, rewrites);
152
152
  }
153
- /** Same-ticket summons materials: typed source-run + frozen attachment pointers. */
153
+ /** Same-ticket summons materials: typed source-run; caller attach paths stay as-is (#1165). */
154
154
  function rewriteSummonsMaterials(value, rewrites) {
155
155
  if (!isRecord(value))
156
156
  return;
157
157
  rewriteRunDirectoryPathFieldsAgainstRewrites(value, SUMMONS_PATH_FIELDS, rewrites);
158
158
  rewriteSourceRunLocator(value.sourceRun, rewrites);
159
- // Bare-resume frozen attachment pointers (string[]), not free text / bytes.
160
- if (Array.isArray(value.attachmentPaths)) {
161
- value.attachmentPaths = value.attachmentPaths.map((path) => rewriteRunDirectoryPathValueAgainstRewrites(path, rewrites));
162
- }
159
+ // #1165: summons.attachmentPaths are caller paths — do not rewrite.
163
160
  }
164
161
  /** Project one admitted page in memory after its containing run moved. */
165
162
  export function rewriteAdmittedRoleRunPage(page, rewrites) {
166
163
  rewriteRunDirectoryPathFieldsAgainstRewrites(page, ADMITTED_PAGE_FIELDS, rewrites);
167
164
  rewriteSourceRunLocator(page.sourceRun, rewrites);
168
- if (Array.isArray(page.attachments)) {
169
- for (const attachment of page.attachments) {
170
- if (isRecord(attachment)) {
171
- rewriteRunDirectoryPathFieldsAgainstRewrites(attachment, ["frozenPath"], rewrites);
172
- }
173
- }
174
- }
165
+ // #1165: admitted attachments are caller paths outside the run directory — do not rewrite.
175
166
  if (isRecord(page.principal)) {
176
167
  rewriteRunDirectoryPathFieldsAgainstRewrites(page.principal, ["sessionDirectory", "sessionFile"], rewrites);
177
168
  }
@@ -347,12 +338,13 @@ async function rewriteNestedMachinePathPages(pagesDirectory, rewrites) {
347
338
  await walk(sessionRoot);
348
339
  }
349
340
  /**
350
- * Rewrite the admitted / invocation / runState fact rows (path fields: attachment
351
- * frozenPath / summons.attachmentPaths pointers only), then nested package-owned
352
- * session seams. Callers may rewrite before or after the filesystem move/copy:
353
- * `pagesDirectory` is where the pages currently live on disk; path strings that
354
- * still name `oldRunDirectory` become `newRunDirectory`. `crossRunRewrites`
355
- * covers officer/parent pointers that landed under a different final placement.
341
+ * Rewrite the admitted / invocation / runState fact rows (typed run placement
342
+ * paths only; caller --attach / --request-manifest paths stay as-is, #1165),
343
+ * then nested package-owned session seams. Callers may rewrite before or after
344
+ * the filesystem move/copy: `pagesDirectory` is where the pages currently live
345
+ * on disk; path strings that still name `oldRunDirectory` become
346
+ * `newRunDirectory`. `crossRunRewrites` covers officer/parent pointers that
347
+ * landed under a different final placement.
356
348
  */
357
349
  export async function rewriteRoleRunDurablePages(input) {
358
350
  const { pagesDirectory } = input;
@@ -366,7 +358,7 @@ export async function rewriteRoleRunDurablePages(input) {
366
358
  if (isRecord(page.principal)) {
367
359
  rewriteRunDirectoryPathFieldsAgainstRewrites(page.principal, ["sessionDirectory", "sessionFile"], rewrites);
368
360
  }
369
- // Open court summons: source-run locators + frozen attachment path pointers.
361
+ // Open court summons: source-run locators only; caller attach paths stay (#1165).
370
362
  if (isRecord(page.currentCourt)) {
371
363
  rewriteSummonsMaterials(page.currentCourt.summons, rewrites);
372
364
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@akagilnc/pi-workflow-roles",
3
- "version": "0.1.5583",
3
+ "version": "0.1.5593",
4
4
  "description": "Soul-bound workflow roles for Pi",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",
@@ -1,7 +1,3 @@
1
- import { readFile } from "node:fs/promises";
2
-
3
- import { sha256Hex } from "./sha256.ts";
4
- import { isRecord } from "./unknown-value.ts";
5
1
  import { isTicketNumberString, parseTicketNumber } from "./run-ticket-number.ts";
6
2
 
7
3
  export const COLLECTOR_OWNER_PATTERN = /^[A-Za-z0-9](?:[A-Za-z0-9-]{0,37}[A-Za-z0-9])?$/;
@@ -14,14 +10,6 @@ export type CollectorRepository = {
14
10
  repo: string;
15
11
  };
16
12
 
17
- export type CollectorRequestConfig = { id: string; requestBody: string };
18
- export type CollectorManifest = {
19
- requests: readonly CollectorRequestConfig[];
20
- canonicalJson: string;
21
- digest: string;
22
- sourcePath?: string;
23
- };
24
-
25
13
  function fail(message: string, cause?: unknown): never {
26
14
  throw new Error(message, cause === undefined ? undefined : { cause });
27
15
  }
@@ -54,33 +42,3 @@ export function parseCollectorPrNumber(raw: unknown): number {
54
42
  : "Collector pull request number must be a positive safe integer");
55
43
  return value;
56
44
  }
57
-
58
- function canonicalManifest(requests: readonly CollectorRequestConfig[]): string {
59
- return `${JSON.stringify({ requests: requests.map((request) => ({ id: request.id, body: request.requestBody })) })}\n`;
60
- }
61
-
62
- export function emptyCollectorManifest(): CollectorManifest {
63
- const canonicalJson = canonicalManifest([]);
64
- return { requests: [], canonicalJson, digest: sha256Hex(canonicalJson) };
65
- }
66
-
67
- /** Optional request configuration. It names requests, never expected observers. */
68
- export async function loadCollectorManifest(path: string): Promise<CollectorManifest> {
69
- let bytes: Buffer;
70
- try { bytes = await readFile(path); } catch (error) { fail(`Collector request manifest is unreadable at ${path}`, error); }
71
- let parsed: unknown;
72
- try { parsed = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(bytes)); } catch (error) { fail("Collector request manifest must be UTF-8 JSON", error); }
73
- if (!isRecord(parsed)) fail("Collector request manifest must be an object");
74
- const rawRequests = parsed.requests ?? [];
75
- if (!Array.isArray(rawRequests)) fail("Collector request manifest requests must be an array");
76
- const requests: CollectorRequestConfig[] = [];
77
- const ids = new Set<string>();
78
- for (const [index, item] of rawRequests.entries()) {
79
- if (!isRecord(item) || typeof item.id !== "string" || item.id.length === 0 || typeof item.body !== "string" || item.body.trim() === "") fail(`Collector request manifest requests[${index}] is invalid`);
80
- if (ids.has(item.id)) fail(`Collector request manifest has duplicate request id "${item.id}"`);
81
- ids.add(item.id);
82
- requests.push({ id: item.id, requestBody: item.body });
83
- }
84
- const canonicalJson = canonicalManifest(requests);
85
- return { requests, canonicalJson, digest: sha256Hex(canonicalJson), sourcePath: path };
86
- }
@@ -2,17 +2,15 @@
2
2
  * Collector business: soul/material assembly and sole submission tool.
3
3
  * #1088: code no longer observes/requests/merges GitHub findings — the LLM
4
4
  * uses host CLI tools. Envelope owns host-surface + construction seatbelt.
5
+ * #1165: --request-manifest is a caller path only; package does not load it.
5
6
  */
6
7
  import type { RoleHost, HostContext } from "./host-contracts.ts";
7
8
  import { registerFiledSubmissionTool } from "./filed-submission.ts";
8
9
  import { roleSubmissionDeclaration } from "./role-submission-declarations.ts";
9
10
 
10
11
  import {
11
- emptyCollectorManifest,
12
- loadCollectorManifest,
13
12
  parseCollectorPrNumber,
14
13
  parseCollectorRepository,
15
- type CollectorManifest,
16
14
  type CollectorRepository,
17
15
  } from "./collector-config.ts";
18
16
  import {
@@ -47,7 +45,7 @@ export const COLLECTOR_TRANSPORT_FLAGS = Object.freeze([
47
45
  name: "ak-collector-request-manifest",
48
46
  definition: Object.freeze({
49
47
  description:
50
- "Path to the Collector v1 request manifest JSON file (caller guidance; not a machine collection directive).",
48
+ "Caller path to a request manifest JSON file (passed as-is; package does not read or validate).",
51
49
  type: "string" as const,
52
50
  }),
53
51
  }),
@@ -62,7 +60,7 @@ export type CollectorActivation = {
62
60
  soul: string;
63
61
  repository: CollectorRepository;
64
62
  prNumber: number | undefined;
65
- manifest: CollectorManifest;
63
+ requestManifestPath?: string;
66
64
  };
67
65
 
68
66
  function buildMethodContext(activation: CollectorActivation): string {
@@ -71,19 +69,11 @@ function buildMethodContext(activation: CollectorActivation): string {
71
69
  `host: github.com`,
72
70
  `repository: ${activation.repository.canonical}`,
73
71
  `prNumber: ${activation.prNumber === undefined ? "未绑定" : String(activation.prNumber)}`,
74
- `requests: ${JSON.stringify(activation.manifest.requests.map((request) => ({ id: request.id })))}`,
75
- `manifestDigest: ${activation.manifest.digest}`,
72
+ ...(activation.requestManifestPath === undefined
73
+ ? []
74
+ : [`requestManifestPath: ${activation.requestManifestPath}`]),
76
75
  "</collector_method>",
77
76
  ];
78
- if (activation.manifest.requests.length > 0) {
79
- const payload = JSON.stringify({
80
- requests: activation.manifest.requests.map((request) => ({
81
- id: request.id,
82
- body: request.requestBody,
83
- })),
84
- }).replaceAll("<", "\\u003c");
85
- lines.push("", "<collector_request_manifest>", payload, "</collector_request_manifest>");
86
- }
87
77
  return lines.join("\n");
88
78
  }
89
79
 
@@ -123,15 +113,15 @@ export function createCollectorRoleRuntime(
123
113
  } else if (typeof prFlag === "number") {
124
114
  prNumber = parseCollectorPrNumber(prFlag);
125
115
  }
126
- const manifest = typeof requestManifestFlag === "string" && requestManifestFlag.trim().length > 0
127
- ? await loadCollectorManifest(requestManifestFlag)
128
- : emptyCollectorManifest();
116
+ // #1165: opaque caller path — keep spaces/"" when the flag was provided.
117
+ const requestManifestPath =
118
+ typeof requestManifestFlag === "string" ? requestManifestFlag : undefined;
129
119
 
130
120
  return {
131
121
  soul,
132
122
  repository,
133
123
  prNumber,
134
- manifest,
124
+ ...(requestManifestPath === undefined ? {} : { requestManifestPath }),
135
125
  };
136
126
  },
137
127
 
@@ -48,7 +48,6 @@ import {
48
48
  recordAdmittedCorrelation,
49
49
  recordChildDiaristRun,
50
50
  relocateAdmittedRunToTicket,
51
- withPreparedAttachments,
52
51
  type AdmittedCountersignInvocation,
53
52
  type AdmittedRoleInvocation,
54
53
  type PublicSeatParse,
@@ -618,7 +617,7 @@ async function runCountersignBody(
618
617
  summons: {
619
618
  sourceRunPath: gateParentRunPath,
620
619
  instruction: resumeInstruction,
621
- instructionEmpty: resumeInstruction.trim() === "",
620
+ instructionEmpty: resumeInstruction.length === 0,
622
621
  },
623
622
  });
624
623
  if (resumed != null) return resumed;
@@ -634,12 +633,12 @@ async function runCountersignBody(
634
633
  }
635
634
 
636
635
  try {
637
- return await withPreparedAttachments(parsed.attachmentPaths ?? [], async (preparedAttachments) => {
636
+ {
638
637
  const materializeAdmission = async (ticketNumber?: number): Promise<void> => {
639
638
  await materializeCountersignInvocation(admitted, {
640
639
  home: env.home,
641
640
  principalAuthority: env.principalAuthority,
642
- preparedAttachments,
641
+ attachmentPaths: parsed.attachmentPaths ?? [],
643
642
  ...(env.model === undefined ? {} : { model: env.model }),
644
643
  ...(ticketNumber === undefined ? {} : { ticketNumber }),
645
644
  });
@@ -676,7 +675,7 @@ async function runCountersignBody(
676
675
  });
677
676
  await relocateAdmittedRunToTicket(admitted, env.principalAuthority);
678
677
  return result;
679
- });
678
+ }
680
679
  } catch (error) {
681
680
  const rejected = usageExit(error, io);
682
681
  if (rejected !== undefined) return rejected;
@@ -749,7 +748,7 @@ export async function runPublicInstructionSeat(
749
748
  const summons: SameTicketSummonsMaterials = {
750
749
  ...sameParentInstruction(env, {
751
750
  instruction: parsed.instruction ?? "",
752
- instructionEmpty: (parsed.instruction ?? "").trim() === "",
751
+ instructionEmpty: (parsed.instruction ?? "").length === 0,
753
752
  }),
754
753
  attachmentPaths: parsed.attachmentPaths ?? [],
755
754
  };
@@ -775,7 +774,7 @@ export async function runPublicInstructionSeat(
775
774
  sourceRunPath: parentRunPath,
776
775
  ...sameParentInstruction(env, {
777
776
  instruction: parsed.instruction ?? "",
778
- instructionEmpty: (parsed.instruction ?? "").trim() === "",
777
+ instructionEmpty: (parsed.instruction ?? "").length === 0,
779
778
  }),
780
779
  attachmentPaths: parsed.attachmentPaths ?? [],
781
780
  };
@@ -865,7 +864,7 @@ export async function runPublicInstructionSeat(
865
864
  instruction: parsed.instruction ?? "",
866
865
  projectRoot: admitted.projectRoot,
867
866
  failureLabel: "secretariat unbound summons",
868
- attachmentPaths: admitted.attachments.map((attachment) => attachment.frozenPath),
867
+ attachmentPaths: admitted.attachments.map((attachment) => attachment.path),
869
868
  correlationId: admitted.runId,
870
869
  }, env, io);
871
870
  } catch (error) {