@akagilnc/pi-workflow-roles 0.1.4035 → 0.1.4193

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 (108) hide show
  1. package/dist/acp-host/production-host.js +2368 -1155
  2. package/dist/archivist-record-entry.js +204 -20
  3. package/dist/archivist-record-topology.js +36 -16
  4. package/dist/auditor-dossier-tool.js +2 -1
  5. package/dist/diarist-contracts.js +96 -0
  6. package/dist/doctor-auditor.js +1 -1
  7. package/dist/doctor-evidence.js +3 -2
  8. package/dist/dossier-resolution.js +21 -8
  9. package/dist/gatekeeper-role.js +34 -27
  10. package/dist/headless-host/description.js +7 -8
  11. package/dist/headless-host/production-host.js +2375 -1149
  12. package/dist/host-contracts.js +16 -0
  13. package/dist/inspector-contracts.js +8 -0
  14. package/dist/migrate-book-topology.js +278917 -0
  15. package/dist/navigator-public-session.js +22 -25
  16. package/dist/notary-source-run.js +7 -4
  17. package/dist/packaged-role-registry.js +1 -1
  18. package/dist/pi/durable-principal.js +9 -6
  19. package/dist/pi/role-turn-host.js +43 -13
  20. package/dist/public-cli/auto-resume.js +2 -5
  21. package/dist/public-cli/case-dossier-delivery.js +60 -1
  22. package/dist/public-cli/diarist-run.js +27 -25
  23. package/dist/public-cli/inspector-run.js +17 -3
  24. package/dist/public-cli/instruction-seat-run.js +17 -17
  25. package/dist/public-cli/invocation.js +127 -63
  26. package/dist/public-cli/main.js +1685 -696
  27. package/dist/public-cli/notary-run.js +7 -4
  28. package/dist/public-cli/option-definitions.js +2 -2
  29. package/dist/public-cli/post-admission.js +113 -71
  30. package/dist/public-cli/run-lifecycle.js +209 -58
  31. package/dist/public-cli/seat-ticket-binding.js +3 -6
  32. package/dist/public-cli/settlement.js +29 -10
  33. package/dist/public-role-summons.js +8 -0
  34. package/dist/role-run-placement.js +84 -0
  35. package/dist/role-run-relocation.js +358 -0
  36. package/dist/run-terminal-artifacts.js +2 -1
  37. package/dist/run-ticket-number.js +51 -32
  38. package/dist/sitian-appender.js +11 -26
  39. package/dist/submission-ledger.js +106 -25
  40. package/dist/ticket-provenance.js +3 -1
  41. package/dist/user-dialogue-stdin.js +33 -0
  42. package/extensions/role-runtime.ts +1 -0
  43. package/package.json +3 -2
  44. package/resources/836-deleted-machine-instruction-inventory.md +1 -1
  45. package/scripts/build-package.mjs +34 -2
  46. package/souls/fixer.md +3 -2
  47. package/src/analyst-ledger.ts +14 -15
  48. package/src/archivist-record-entry.ts +285 -38
  49. package/src/archivist-record-topology.ts +43 -18
  50. package/src/auditor-dossier-tool.ts +2 -1
  51. package/src/book-topology-migration-placement.ts +493 -0
  52. package/src/book-topology-migration.ts +220 -0
  53. package/src/book-topology-migrators-t11.ts +856 -0
  54. package/src/book-topology-mixed-volume-migrators.ts +470 -0
  55. package/src/book-topology-partition-migrators.ts +25 -0
  56. package/src/book-topology-record-class-migrators.ts +779 -0
  57. package/src/book-topology-runs-migrator.ts +244 -0
  58. package/src/diarist-contracts.ts +116 -0
  59. package/src/diarist-role.ts +6 -0
  60. package/src/diarist.ts +2 -0
  61. package/src/doctor-auditor.ts +1 -1
  62. package/src/doctor-evidence.ts +4 -1
  63. package/src/doctor-role.ts +1 -1
  64. package/src/dossier-resolution.ts +26 -8
  65. package/src/external-host-turn-loop.ts +9 -0
  66. package/src/gatekeeper-pass-envelope.ts +6 -0
  67. package/src/gatekeeper-role.ts +47 -28
  68. package/src/headless-host/description.ts +8 -11
  69. package/src/headless-host/role-turn-host.ts +20 -5
  70. package/src/host-contracts.ts +22 -3
  71. package/src/inspector-contracts.ts +7 -0
  72. package/src/judge-role.ts +4 -0
  73. package/src/navigator-public-session.ts +33 -30
  74. package/src/navigator-work-context.ts +3 -4
  75. package/src/notary-role.ts +1 -0
  76. package/src/notary-source-run.ts +9 -4
  77. package/src/packaged-role-registry.ts +1 -1
  78. package/src/pi/adapter.ts +19 -4
  79. package/src/pi/durable-principal.ts +9 -13
  80. package/src/pi/role-turn-host.ts +48 -14
  81. package/src/public-cli/auto-resume.ts +2 -6
  82. package/src/public-cli/case-dossier-delivery.ts +86 -1
  83. package/src/public-cli/countersign-run.ts +182 -32
  84. package/src/public-cli/diarist-run.ts +34 -26
  85. package/src/public-cli/inspector-run.ts +26 -2
  86. package/src/public-cli/instruction-seat-run.ts +24 -20
  87. package/src/public-cli/invocation.ts +194 -58
  88. package/src/public-cli/notary-run.ts +13 -4
  89. package/src/public-cli/option-definitions.ts +2 -2
  90. package/src/public-cli/post-admission.ts +147 -78
  91. package/src/public-cli/run-lifecycle.ts +258 -65
  92. package/src/public-cli/seat-ticket-binding.ts +3 -6
  93. package/src/public-cli/settlement.ts +38 -10
  94. package/src/public-role-summons.ts +31 -7
  95. package/src/role-envelope.ts +9 -30
  96. package/src/role-run-placement.ts +128 -0
  97. package/src/role-run-relocation.ts +491 -0
  98. package/src/role-runtime-dependencies.ts +1 -0
  99. package/src/role-runtime.ts +106 -24
  100. package/src/run-terminal-artifacts.ts +3 -1
  101. package/src/run-ticket-number.ts +80 -20
  102. package/src/sitian-appender.ts +25 -28
  103. package/src/submission-ledger.ts +148 -30
  104. package/src/ticket-provenance.ts +4 -1
  105. package/src/ticket-trajectory.ts +22 -35
  106. package/src/user-dialogue-stdin.ts +37 -0
  107. package/src/worker-role.ts +8 -4
  108. package/src/worker-submission-gates.ts +6 -6
@@ -52,10 +52,10 @@ export async function runPublicNotary(argv, env, io, parseNotaryArgv) {
52
52
  throw error;
53
53
  }
54
54
  // #747: officer resume key is this parent source-run path (not ticket number).
55
- // #753/#786: gate re-ask and verbatim submission body share summons.instruction
56
- // (reask wins when both present; no parallel stack).
55
+ // #753/#879: gate re-ask and verbatim submission body share summons.instruction
56
+ // (reask wins when both present; no parallel stack). Binding stays sourceRunPath.
57
57
  {
58
- const resumeInstruction = env.reviewReask;
58
+ const resumeInstruction = env.reviewReask ?? env.gateReviewInstruction;
59
59
  const summons = {
60
60
  sourceRunPath: source.runDirectory,
61
61
  sourceRun: source,
@@ -112,7 +112,10 @@ export async function runPublicNotary(argv, env, io, parseNotaryArgv) {
112
112
  : { correlationId: env.correlationId }),
113
113
  continuation: {
114
114
  kind: "initial",
115
- prompt: buildNotaryTransportPrompt(admitted, engineMaterial),
115
+ // #879: gate path first mint carries parent payload as dialogue content;
116
+ // external zero-prompt kickoff unchanged when no body/reask.
117
+ prompt: (env.reviewReask ?? env.gateReviewInstruction)
118
+ ?? buildNotaryTransportPrompt(admitted, engineMaterial),
116
119
  },
117
120
  });
118
121
  return await runPostAdmissionOneShot({
@@ -529,8 +529,8 @@ const DOCTOR_OPTIONS = [
529
529
  repeatable: false,
530
530
  form: "option",
531
531
  description: {
532
- en: "Optional project-relative .ak-roles/books/<book>/issues/<n>/runs override matching --issue.",
533
- zh: "可选项目相对 .ak-roles/books/<book>/issues/<n>/runs 覆盖,且须匹配 --issue。",
532
+ en: "Optional project-relative .ak-roles/books/<book>/<n>/runs override matching --issue.",
533
+ zh: "可选项目相对 .ak-roles/books/<book>/<n>/runs 覆盖,且须匹配 --issue。",
534
534
  },
535
535
  },
536
536
  ];
@@ -8,13 +8,14 @@
8
8
  import { randomUUID } from "node:crypto";
9
9
  import { readFile, writeFile } from "node:fs/promises";
10
10
  import { isAbsolute, join, resolve } from "node:path";
11
- import { buildResumeContinuationPrompt, GATE_DOSSIER_POINTER_PREFIX, RESUME_TRANSPORT_ENVELOPE, } from "./run-lifecycle.js";
11
+ import { buildResumeContinuationPrompt, RESUME_TRANSPORT_ENVELOPE, } from "./run-lifecycle.js";
12
12
  import { CliUsageError } from "./cli-errors.js";
13
13
  import { buildInstructionTransportPrompt, freezeAttachmentsIntoRun, } from "./invocation.js";
14
14
  import { pathContainedIn } from "../activation-ledger-topology.js";
15
15
  import { pickEngineAxis } from "../package-resources/engine-material.js";
16
16
  import { resolveHostAwareSessionAvailability } from "../session-identity.js";
17
- import { projectCaseDossierPointerSection } from "./case-dossier-delivery.js";
17
+ import { isOfficerReviewSeat } from "../host-contracts.js";
18
+ import { deliverCaseDossierAsAttachment, projectCaseDossierPointerSection, } from "./case-dossier-delivery.js";
18
19
  /** Original error bytes, never relabeled — a secondary fact riding beside a classified cause. */
19
20
  function describeCaughtError(error) {
20
21
  if (error instanceof Error) {
@@ -30,6 +31,14 @@ function appendContinuationSection(continuation, section) {
30
31
  ? { kind: "initial", prompt }
31
32
  : { kind: "resume", prompt };
32
33
  }
34
+ /**
35
+ * Nested gate summons (station child) on an officer seat: dialogue content is
36
+ * peer words only (#879). ADR 0081 case dossier still hangs via the existing
37
+ * attachments freeze seam — never into the peer body, never RoleTurnRequest.materials.
38
+ */
39
+ function isStationChildOfficerDialogue(role, env) {
40
+ return env.stationChild === true && isOfficerReviewSeat(role);
41
+ }
33
42
  import { projectHostTransitionPriorNative } from "../host-transition-prior-native.js";
34
43
  import { missingCredentialPreDispatchFailure, postRunMissingCredentialFailure, } from "./public-run-credentials.js";
35
44
  import { acquireRunWriterLease, clearCurrentCourt, clearTypedProviderHttpObservation, describeErrorIdentity, markRunRunning, readCurrentCourt, recordCurrentCourt, renderResumeCommand, RunWriterLeaseHeldError, } from "./run-lifecycle.js";
@@ -53,10 +62,10 @@ function withOnceSuccessfulBeforeDispatch(adapters) {
53
62
  let succeeded = false;
54
63
  return {
55
64
  ...adapters,
56
- beforeDispatch: async (admitted) => {
65
+ beforeDispatch: async (admitted, lease) => {
57
66
  if (succeeded)
58
67
  return;
59
- await hook(admitted);
68
+ await hook(admitted, lease);
60
69
  succeeded = true;
61
70
  },
62
71
  };
@@ -250,6 +259,41 @@ export async function dispatchPostAdmissionTurn(input) {
250
259
  const persistRunState = input.persistRunState !== false;
251
260
  const deferredPersist = persistRunState ? {} : { needsPersist: true };
252
261
  const shouldPresent = adapters.shouldPresentSettled ?? ((terminal) => isLawfulTypedTerminalOutcome(terminal.roleOutcome));
262
+ /**
263
+ * Once-only post-host-turn hook (Diarist bind/relocate, etc.) under the still-held
264
+ * writer lease. Every exit after the host turn has started must pass here before
265
+ * lease release — success and failure alike. When a primary failure terminal already
266
+ * exists, keep that cause and leave relocate failure on the shared diagnostic channel.
267
+ */
268
+ let afterDispatchApplied = false;
269
+ const finishAfterTurn = async (result) => {
270
+ if (adapters.afterDispatch === undefined || afterDispatchApplied)
271
+ return result;
272
+ afterDispatchApplied = true;
273
+ try {
274
+ await adapters.afterDispatch(admitted, lease);
275
+ return result;
276
+ }
277
+ catch (error) {
278
+ const primaryFailure = result.terminal !== undefined
279
+ && !isLawfulTypedTerminalOutcome(result.terminal.roleOutcome);
280
+ if (primaryFailure) {
281
+ await recordBestEffortPostDispatchDiagnostic(admitted, env, `afterDispatch failed beside primary terminal (best-effort continue): ${describeErrorIdentity(error)}`, io);
282
+ return result;
283
+ }
284
+ return {
285
+ ...(await presentControlledFailure(admitted, {
286
+ timedOut: false,
287
+ code: null,
288
+ stderr: "",
289
+ thrown: error,
290
+ }, adapters, env.principalAuthority, io, persistRunState)),
291
+ ...(result.turnDispatched === true ? { turnDispatched: true } : {}),
292
+ ...(result.skipAutoResume === true ? { skipAutoResume: true } : {}),
293
+ ...deferredPersist,
294
+ };
295
+ }
296
+ };
253
297
  try {
254
298
  const missingCredential = missingCredentialPreDispatchFailure(env.model, env.credentials);
255
299
  if (missingCredential !== undefined) {
@@ -306,7 +350,7 @@ export async function dispatchPostAdmissionTurn(input) {
306
350
  // (#840 父子不层叠).
307
351
  if (adapters.beforeDispatch !== undefined) {
308
352
  try {
309
- await adapters.beforeDispatch(admitted);
353
+ await adapters.beforeDispatch(admitted, lease);
310
354
  }
311
355
  catch (error) {
312
356
  const settled = (await presentControlledFailure(admitted, {
@@ -324,9 +368,9 @@ export async function dispatchPostAdmissionTurn(input) {
324
368
  // Turn request is assembled after beforeDispatch so this turn sees whatever it
325
369
  // settled — the seat's ticket bind re-projection and any court diarist station
326
370
  // writes (#742). Case dossier delivery (ADR 0081 / #709) rides here once for
327
- // every public entry: first call, same-ticket re-summons and manual resume
328
- // alike. System refs append their own neutral section; caller frozen
329
- // attachments and the seat's own prompt bytes are never rewritten.
371
+ // every public entry. #879: station-child officer dialogue keeps peer body
372
+ // intact — 起居录 hangs via existing attachments freeze (not prompt wrap,
373
+ // not RoleTurnRequest.materials). Other entries keep the neutral prompt section.
330
374
  let turnRequest = env.signal === undefined ? request : { ...request, signal: env.signal };
331
375
  if (env.stationChild !== undefined) {
332
376
  turnRequest = { ...turnRequest, stationChild: env.stationChild };
@@ -334,16 +378,31 @@ export async function dispatchPostAdmissionTurn(input) {
334
378
  if (hostTransition !== undefined) {
335
379
  turnRequest = { ...turnRequest, hostTransition };
336
380
  }
337
- const dossierSection = await projectCaseDossierPointerSection({
338
- ticketNumber: admitted.ticketNumber,
339
- projectRoot: admitted.projectRoot,
340
- home: env.home,
341
- });
342
- if (dossierSection !== undefined) {
343
- turnRequest = {
344
- ...turnRequest,
345
- continuation: appendContinuationSection(turnRequest.continuation, dossierSection),
346
- };
381
+ if (isStationChildOfficerDialogue(admitted.role, env)) {
382
+ // 0081 non-body face: freeze pointer section under run/attachments/.
383
+ // Peer dialogue continuation.prompt stays parent payload only — the seat
384
+ // consumes the freeze via loadCaseDossierReadingMaterial → existing
385
+ // agent-start readingMaterial / systemPrompt.materials fold (not prompt splice,
386
+ // not RoleTurnRequest.materials).
387
+ await deliverCaseDossierAsAttachment({
388
+ ticketNumber: admitted.ticketNumber,
389
+ projectRoot: admitted.projectRoot,
390
+ home: env.home,
391
+ runDirectory: admitted.runDirectory,
392
+ });
393
+ }
394
+ else {
395
+ const dossierSection = await projectCaseDossierPointerSection({
396
+ ticketNumber: admitted.ticketNumber,
397
+ projectRoot: admitted.projectRoot,
398
+ home: env.home,
399
+ });
400
+ if (dossierSection !== undefined) {
401
+ turnRequest = {
402
+ ...turnRequest,
403
+ continuation: appendContinuationSection(turnRequest.continuation, dossierSection),
404
+ };
405
+ }
347
406
  }
348
407
  // Authoritative host write happens here, at the real dispatch boundary —
349
408
  // immediately before the turn actually starts, after every retryable
@@ -360,7 +419,7 @@ export async function dispatchPostAdmissionTurn(input) {
360
419
  stderr: "",
361
420
  thrown: error,
362
421
  }, adapters, env.principalAuthority, io, persistRunState);
363
- return { ...settled, turnDispatched: true, ...deferredPersist };
422
+ return await finishAfterTurn({ ...settled, turnDispatched: true, ...deferredPersist });
364
423
  }
365
424
  // `result.stderr` stays live in memory for the real classification below
366
425
  // regardless of whether this durable mirror write succeeds. A write
@@ -527,7 +586,7 @@ export async function dispatchPostAdmissionTurn(input) {
527
586
  stderr: result.stderr,
528
587
  thrown: error,
529
588
  }, adapters, env.principalAuthority, io, persistRunState);
530
- return { ...settledFailure, turnDispatched: true, ...deferredPersist };
589
+ return await finishAfterTurn({ ...settledFailure, turnDispatched: true, ...deferredPersist });
531
590
  }
532
591
  if (settledOutcome !== undefined) {
533
592
  if (persistRunState) {
@@ -552,12 +611,12 @@ export async function dispatchPostAdmissionTurn(input) {
552
611
  thrown: error,
553
612
  skipRunStateWrite: true,
554
613
  }, adapters, env.principalAuthority, io, persistRunState);
555
- return { ...failed, turnDispatched: true, ...deferredPersist };
614
+ return await finishAfterTurn({ ...failed, turnDispatched: true, ...deferredPersist });
556
615
  }
557
616
  }
558
617
  // Lawful persist + present is the caller's stop seam (auto-resume loop /
559
618
  // manual resume), not this retried host-turn function.
560
- return { ...settledOutcome, ...deferredPersist };
619
+ return await finishAfterTurn({ ...settledOutcome, ...deferredPersist });
561
620
  }
562
621
  // Host/runner true failure coexists with already-recorded payloads — never wash as accepted.
563
622
  if (hostSignalFailed) {
@@ -584,7 +643,7 @@ export async function dispatchPostAdmissionTurn(input) {
584
643
  }
585
644
  : { knownDetails: stderrLogWriteDetails }),
586
645
  }, adapters, env.principalAuthority, io, persistRunState);
587
- return { ...failed, turnDispatched: true, ...deferredPersist };
646
+ return await finishAfterTurn({ ...failed, turnDispatched: true, ...deferredPersist });
588
647
  }
589
648
  // Nothing else was wrong, but the durable stderr mirror itself failed to
590
649
  // write — that is the real (infrastructure) problem in this case, not a
@@ -596,7 +655,7 @@ export async function dispatchPostAdmissionTurn(input) {
596
655
  stderr: result.stderr,
597
656
  thrown: stderrLogWriteFailure,
598
657
  }, adapters, env.principalAuthority, io, persistRunState);
599
- return { ...failed, turnDispatched: true, ...deferredPersist };
658
+ return await finishAfterTurn({ ...failed, turnDispatched: true, ...deferredPersist });
600
659
  }
601
660
  const noReceipt = await attachRecordedSubmissions(admitted, await settleHostEndedNoReceipt(admitted, env.principalAuthority), courtScope);
602
661
  if (persistRunState) {
@@ -616,16 +675,16 @@ export async function dispatchPostAdmissionTurn(input) {
616
675
  thrown: error,
617
676
  skipRunStateWrite: true,
618
677
  }, adapters, env.principalAuthority, io, persistRunState);
619
- return { ...failed, turnDispatched: true, ...deferredPersist };
678
+ return await finishAfterTurn({ ...failed, turnDispatched: true, ...deferredPersist });
620
679
  }
621
680
  }
622
- return {
681
+ return await finishAfterTurn({
623
682
  exitCode: exitCodeForTerminalOutcome(noReceipt.roleOutcome),
624
683
  admitted,
625
684
  terminal: noReceipt,
626
685
  turnDispatched: true,
627
686
  ...deferredPersist,
628
- };
687
+ });
629
688
  }
630
689
  finally {
631
690
  try {
@@ -643,46 +702,40 @@ export async function dispatchPostAdmissionTurn(input) {
643
702
  }
644
703
  }
645
704
  /**
646
- * Shared resume continuation projection (#471 / #600 / #633 / #637 / #755):
705
+ * Shared resume continuation projection (#471 / #600 / #633 / #637 / #755 / #879):
647
706
  * seat-table model/engine/timeout axes, restored correlation, and either
648
707
  * - manual resume (no same-ticket summons): package envelope / optional caller
649
708
  * message, with engine-axis handbook via buildResumeContinuationPrompt, or
650
709
  * - same-ticket summons (审核循环续话): caller/peer words + optional frozen
651
- * attachment paths only — no「重新读」、no engine handbook packaging
652
- * (#750/#755), whether or not attachments are present.
710
+ * attachment paths only — no「请重读」、no code-authored content substitute,
711
+ * no engine handbook packaging (#750/#755/#879).
653
712
  * Caller message wins as prompt base when supplied (bytes unchanged, including
654
- * blank/whitespace); else summons instruction. Attachment projection must not
655
- * re-interpret the caller message as instructionEmpty.
713
+ * blank/whitespace); else summons instruction (parent payload or reask).
714
+ * Binding pointer stays on summons.sourceRunPath / activation — not dialogue content.
656
715
  * Seats add only their activation projection. Call prepareSummonsResumeMaterials
657
716
  * first when request.summons carries instruction or attachment paths.
658
717
  */
659
718
  export function resumeTurnRequestProjectionOptions(admitted, request, env, summonsPrepared) {
660
- const officerSourcePath = request.summons?.sourceRunPath;
661
- const withReread = (body) => {
662
- if (officerSourcePath === undefined
663
- || (admitted.role !== "notary"
664
- && admitted.role !== "inspector"
665
- && admitted.role !== "auditor")) {
666
- return body;
667
- }
668
- if (body.startsWith("请重读"))
669
- return body;
670
- return `请重读\n${body}`;
671
- };
719
+ // #879: officer dialogue content is caller/peer words only — no「请重读」,
720
+ // no code-authored constant substitute, no attachment-list wrap of peer body.
721
+ // Binding pointer stays on summons sourceRunPath / activation / attachments.
722
+ const officerDialogue = isStationChildOfficerDialogue(admitted.role, env);
672
723
  let prompt;
673
724
  if (request.message !== undefined) {
674
725
  if (summonsPrepared !== undefined) {
675
- // #755: same-ticket review / open-court — caller words + optional paths.
676
- // Attachments are not a gate: message-only summons must stay plain too.
677
- prompt = withReread(buildInstructionTransportPrompt({
678
- instruction: request.message,
679
- instructionEmpty: false,
680
- attachments: summonsPrepared.attachments,
681
- }));
726
+ // #755: same-ticket review / open-court — caller words.
727
+ // #879 station-child officer: words only (attachments are independent freeze).
728
+ prompt = officerDialogue
729
+ ? request.message
730
+ : buildInstructionTransportPrompt({
731
+ instruction: request.message,
732
+ instructionEmpty: false,
733
+ attachments: summonsPrepared.attachments,
734
+ });
682
735
  }
683
736
  else if (request.summons !== undefined) {
684
737
  // #755: same-ticket summons without prepared materials — caller words only.
685
- prompt = withReread(request.message);
738
+ prompt = request.message;
686
739
  }
687
740
  else {
688
741
  // Bare manual resume — outsourcing engine axis keeps handbook (#600/#736).
@@ -694,27 +747,16 @@ export function resumeTurnRequestProjectionOptions(admitted, request, env, summo
694
747
  }
695
748
  }
696
749
  else if (summonsPrepared !== undefined) {
697
- // #755: same-ticket review summons — instruction/attachments only.
698
- prompt = withReread(buildInstructionTransportPrompt(summonsPrepared));
750
+ // #879 station-child officer: instruction bytes === peer body/reask (no wrap).
751
+ // Other seats keep #755 instruction + optional attachment path listing.
752
+ prompt = officerDialogue
753
+ ? (summonsPrepared.instructionEmpty ? "" : summonsPrepared.instruction)
754
+ : buildInstructionTransportPrompt(summonsPrepared);
699
755
  }
700
756
  else if (request.summons !== undefined) {
701
- // #755: same-ticket summons with no instruction/attachments (e.g. notary
702
- // source-run pointer). #836: officer resume opening adds「请重读」+ path pointer.
703
- const path = request.summons.sourceRunPath;
704
- if (path !== undefined &&
705
- (admitted.role === "notary" ||
706
- admitted.role === "inspector" ||
707
- admitted.role === "auditor")) {
708
- prompt = `请重读\n${GATE_DOSSIER_POINTER_PREFIX}${path}`;
709
- }
710
- else if (admitted.role === "notary" ||
711
- admitted.role === "inspector" ||
712
- admitted.role === "auditor") {
713
- prompt = "请重读";
714
- }
715
- else {
716
- prompt = "";
717
- }
757
+ // #879: same-ticket summons with no instruction (e.g. notary source-run binding
758
+ // only). Pointer is activation/sourceRun material — not dialogue content.
759
+ prompt = "";
718
760
  }
719
761
  else {
720
762
  // Bare manual resume — outsourcing engine axis keeps handbook (#600/#736).