@akagilnc/pi-workflow-roles 0.1.4321 → 0.1.4363

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 (37) hide show
  1. package/dist/acp-host/production-host.js +81 -99
  2. package/dist/doctor-contracts.js +2 -2
  3. package/dist/headless-host/production-host.js +81 -99
  4. package/dist/merger-contracts.js +2 -2
  5. package/dist/migrate-book-topology.js +13 -8
  6. package/dist/notary-contracts.js +2 -2
  7. package/dist/package-contracts/auditor-output.js +2 -2
  8. package/dist/package-contracts/fixer-output.js +2 -2
  9. package/dist/package-contracts/gatekeeper-output.js +2 -2
  10. package/dist/package-contracts/navigator-output.js +2 -2
  11. package/dist/package-contracts/terminating-infrastructure.js +7 -2
  12. package/dist/public-cli/case-dossier-delivery.js +45 -28
  13. package/dist/public-cli/main.js +71 -89
  14. package/dist/public-cli/post-admission.js +41 -41
  15. package/dist/public-cli/settlement.js +3 -53
  16. package/dist/sitian-appender.js +21 -4
  17. package/package.json +1 -1
  18. package/src/collector-tool-schemas.ts +2 -2
  19. package/src/countersign-role.ts +2 -2
  20. package/src/diarist-role.ts +2 -2
  21. package/src/doctor-contracts.ts +2 -2
  22. package/src/gleaner-left-role.ts +2 -2
  23. package/src/inspector-role.ts +2 -2
  24. package/src/judge-role.ts +2 -2
  25. package/src/merger-contracts.ts +2 -2
  26. package/src/notary-contracts.ts +2 -2
  27. package/src/package-contracts/auditor-output.ts +2 -2
  28. package/src/package-contracts/fixer-output.ts +2 -2
  29. package/src/package-contracts/gatekeeper-output.ts +2 -2
  30. package/src/package-contracts/navigator-output.ts +2 -2
  31. package/src/package-contracts/terminating-infrastructure.ts +13 -3
  32. package/src/public-cli/case-dossier-delivery.ts +48 -29
  33. package/src/public-cli/post-admission.ts +42 -50
  34. package/src/public-cli/settlement.ts +3 -53
  35. package/src/reviewer-role.ts +2 -2
  36. package/src/sitian-appender.ts +36 -3
  37. package/src/worker-role.ts +2 -2
@@ -1,55 +1,69 @@
1
1
  /**
2
- * 系统随案递送本票起居录的中立指针段(ADR 0081:公共入口直接挂案卷,Soul 只说明用途不负责派送;
3
- * #709 公共入口通用递送与 #742 给事中受理链路同源;
4
- * 指针输入沿 ADR 0079(指针是绑定材料由代码精准递送),不把卷宗正文塞进提示词)。
5
- * 只读已有案卷:不刷新、不生成、不校验内容、不新增拒收或停工条件。
2
+ * 系统随案递送起居录路径的中立指针段(ADR 0081:公共入口直接挂案卷,Soul 只说明用途不负责派送;
3
+ * #709 公共入口通用递送与 #742 给事中受理链路同源;#858 告诉 LLM 路径,不另建取号/lookup)。
4
+ * 指针输入沿 ADR 0079(指针是绑定材料由代码精准递送),不把卷宗正文塞进提示词。
5
+ * 只告诉路径:不刷新、不生成、不校验内容、不新增拒收或停工条件、不从 instruction 抽票号。
6
6
  * 机器文本仅中立标识材料(ADR 0073),用途说明归角色材料所有。
7
7
  *
8
8
  * 递送挂载点唯一:`post-admission` 在 beforeDispatch 之后为每个公共入口挂载。
9
- * 普通入口把本段追加进 continuation;station-child 审核轮次走 attachments
10
- * 冻结 + role-runtime `loadCaseDossierReadingMaterial` → readingMaterial →
11
- * systemPrompt.materials fold(#879:对话 instruction 保持父腿 payload 原文;
12
- * 起居录作独立附件面,不新造 RoleTurnRequest.materials)。
9
+ * 全部公共入口(ordinary 已绑定/未绑定与 station-child)统一走 attachments 冻结 +
10
+ * role-runtime `loadCaseDossierReadingMaterial` → readingMaterial →
11
+ * systemPrompt.materials fold(#879 / #858:对话 instruction、空请求、resume
12
+ * message 保持调用者原文;起居录作独立附件面,不新造 RoleTurnRequest.materials,
13
+ * 不拼进 user-dialogue continuation)。
14
+ *
15
+ * #858: deliver returns typed FrozenAttachment[]; load currently re-derives the
16
+ * freeze leaf under runDirectory because agent-start only has HostContext.runDirectory.
17
+ * Consuming the typed frozenPath across that process boundary needs a design
18
+ * revision of the existing envelope/persistence seam — not a local replica of
19
+ * freezeAttachments' `00-` naming, not a drift throw, not readdir guessing.
13
20
  */
14
21
  import { mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
15
22
  import { tmpdir } from "node:os";
16
23
  import { join } from "node:path";
24
+ import { projectTicketRecordsPathShape } from "../sitian-facade.js";
17
25
  import { resolveTicketProvenanceVolume } from "../ticket-provenance.js";
18
26
  import { freezeAttachmentsIntoRun, } from "./invocation.js";
19
- /** Section heading of the system-delivered dossier pointer (presentation only). */
27
+ /** Bound-ticket section heading (presentation only). */
20
28
  const CASE_DOSSIER_SECTION_HEADING = "## 本票起居录(系统随案提供)";
29
+ /** Unbound path-only heading — no 本票 claim when no typed ticket is on the run. */
30
+ const UNBOUND_DOSSIER_PATH_HEADING = "## 起居录路径(系统随案提供)";
21
31
  /** Stable freeze key under run/attachments/ for station-child 0081 delivery. */
22
32
  const CASE_DOSSIER_ATTACH_KEY = "case-dossier";
23
33
  /** Leaf name of the frozen pointer section (content = purpose + paths). */
24
34
  const CASE_DOSSIER_ATTACH_FILE = "case-dossier-pointer.md";
25
- /** Pointer only — presence/absence is for the role to observe at the path. */
26
- function describeDossierFile(path) {
27
- return path;
28
- }
29
35
  /**
30
- * Pointer section for a bound ticket's existing 起居录, or undefined when the
31
- * run carries no ticket identity (unbound calls stay legal and get no dossier).
32
- * A bound ticket whose volume is missing or unreadable is stated as such —
33
- * the section never claims a dossier that is not there.
36
+ * Neutral 起居录 path pointer for every public entry (ADR 0081 delivery seam).
37
+ * Always tells the canonical path shape so the seat LLM can read the diary
38
+ * itself (陛下 2026-09-15: 只需要告诉llm这个路径). When a typed ticket identity is
39
+ * already on the run, also project the concrete resolved file. Never claims a
40
+ * volume or「本票」exists when unbound; never extracts a ticket from instruction.
41
+ * Under-book shape comes only from sitian writer joins — no local replica.
34
42
  */
35
43
  export async function projectCaseDossierPointerSection(input) {
36
- if (input.ticketNumber === undefined)
37
- return undefined;
44
+ if (input.ticketNumber === undefined) {
45
+ return [
46
+ UNBOUND_DOSSIER_PATH_HEADING,
47
+ "",
48
+ `记录卷宗:${projectTicketRecordsPathShape()}`,
49
+ ].join("\n");
50
+ }
38
51
  const volume = resolveTicketProvenanceVolume(input.ticketNumber, input.projectRoot, input.home);
39
52
  return [
40
53
  CASE_DOSSIER_SECTION_HEADING,
41
54
  "",
42
55
  `票号:#${input.ticketNumber}`,
43
- `记录卷宗:${describeDossierFile(volume.recordFile)}`,
56
+ `记录卷宗:${volume.recordFile}`,
44
57
  ].join("\n");
45
58
  }
46
59
  /**
47
- * ADR 0081 delivery for station-child officer turns (#879): freeze the same
48
- * pointer section through the existing attachments seam. Role-runtime loads
49
- * that freeze via loadCaseDossierReadingMaterial onto readingMaterial; the
50
- * envelope then folds it into systemPrompt.materials. Peer dialogue instruction
51
- * stays the parent payload; never RoleTurnRequest.materials.
52
- * Returns frozen attachments, or undefined when unbound (no dossier).
60
+ * ADR 0081 delivery for every public entry (#879 / #858): freeze the pointer
61
+ * section through the existing attachments seam. Role-runtime loads that freeze
62
+ * via loadCaseDossierReadingMaterial onto readingMaterial; the envelope then
63
+ * folds it into systemPrompt.materials. Caller / peer dialogue instruction stays
64
+ * opaque; never RoleTurnRequest.materials, never user-dialogue continuation.
65
+ * Always freezes the path pointer (canonical shape, or concrete file when a
66
+ * typed ticket is already bound).
53
67
  */
54
68
  export async function deliverCaseDossierAsAttachment(input) {
55
69
  const section = await projectCaseDossierPointerSection({
@@ -57,8 +71,6 @@ export async function deliverCaseDossierAsAttachment(input) {
57
71
  projectRoot: input.projectRoot,
58
72
  home: input.home,
59
73
  });
60
- if (section === undefined)
61
- return undefined;
62
74
  // Stage in OS temp only — never leave a run-local .case-dossier-stage copy.
63
75
  const stagingDir = await mkdtemp(join(tmpdir(), "ak-case-dossier-"));
64
76
  try {
@@ -74,6 +86,11 @@ export async function deliverCaseDossierAsAttachment(input) {
74
86
  * Load a previously frozen case-dossier attachment as reading material
75
87
  * (existing agent-start / systemPrompt.materials fold — not dialogue prompt,
76
88
  * not RoleTurnRequest.materials). Undefined when the run has no such freeze.
89
+ *
90
+ * #858: this join re-derives freezeAttachments' leaf naming because the
91
+ * agent-start handler only receives runDirectory. Replacing it requires
92
+ * threading deliver's typed frozenPath across the existing envelope seam
93
+ * (design revision) — do not copy freeze's `00-` algorithm here again.
77
94
  */
78
95
  export async function loadCaseDossierReadingMaterial(runDirectory) {
79
96
  const frozenPath = join(runDirectory, "attachments", CASE_DOSSIER_ATTACH_KEY, `00-${CASE_DOSSIER_ATTACH_FILE}`);
@@ -8465,10 +8465,15 @@ var init_open_tool_schema = __esm({
8465
8465
  });
8466
8466
 
8467
8467
  // src/package-contracts/terminating-infrastructure.ts
8468
- function withInfrastructureFailureDeclaration(schema) {
8468
+ function withTerminatingOutputDeclarations(schema) {
8469
8469
  const baseProperties = schema.properties;
8470
8470
  const properties = {
8471
8471
  ...baseProperties ?? {},
8472
+ ...baseProperties?.ticketNumber === void 0 ? {
8473
+ ticketNumber: typebox_exports.Unknown({
8474
+ description: "\u53EF\u9009\u672C\u7968\u53F7\uFF1A\u5C1A\u672A\u7ED1\u5B9A\u65F6\u7531\u89D2\u8272\u5728\u65E2\u6709\u56DE\u6267\u4E2D\u7533\u62A5\uFF1B\u673A\u68B0\u5C42\u53EA\u8BB0\u5F55\u5408\u6CD5\u6B63\u6574\u6570\uFF0C\u4E0D\u4ECE\u6563\u6587\u63A8\u5BFC\u3001\u4E0D\u9A8C\u771F\u3002\u7F3A\u5931\u6216\u9519\u5F62\u4E0D\u62D2\u6536\u3002"
8475
+ })
8476
+ } : {},
8472
8477
  [INFRASTRUCTURE_FAILURE_DECLARATION_KEY]: infrastructureFailureDeclarationSchema.properties[INFRASTRUCTURE_FAILURE_DECLARATION_KEY]
8473
8478
  };
8474
8479
  const object = typebox_exports.Object(properties, { additionalProperties: true });
@@ -8525,7 +8530,7 @@ var init_gatekeeper_output = __esm({
8525
8530
  })
8526
8531
  })
8527
8532
  );
8528
- gatekeeperOutputSchema = withInfrastructureFailureDeclaration(
8533
+ gatekeeperOutputSchema = withTerminatingOutputDeclarations(
8529
8534
  gatekeeperDecisionSchema
8530
8535
  );
8531
8536
  }
@@ -8540,7 +8545,7 @@ var init_navigator_output = __esm({
8540
8545
  init_open_tool_schema();
8541
8546
  init_terminating_infrastructure();
8542
8547
  NAVIGATOR_OUTPUT_TOOL_NAME = "ak_navigator_output";
8543
- navigatorOutputSchema = withInfrastructureFailureDeclaration(
8548
+ navigatorOutputSchema = withTerminatingOutputDeclarations(
8544
8549
  openToolObject(
8545
8550
  typebox_exports.Object({
8546
8551
  status: typebox_exports.Unknown({
@@ -8616,7 +8621,7 @@ var init_fixer_output = __esm({
8616
8621
  typebox_exports.Object({ status: typebox_exports.Unknown({ description: FIXER_STATUS_DESCRIPTION }), report: typebox_exports.String({ description: "\u5982\u5B9E\u7ED3\u679C\u62A5\u544A" }), classResults: typebox_exports.Array(classResultSchema, { description: "\u5404\u7C7B\u62D2\u7EDD\u7ED3\u7B97" }) }),
8617
8622
  typebox_exports.Object({ status: typebox_exports.Unknown({ description: FIXER_STATUS_DESCRIPTION }), report: typebox_exports.String({ description: "\u5982\u5B9E\u7ED3\u679C\u62A5\u544A" }), classResults: typebox_exports.Array(classResultSchema, { description: "\u5404\u7C7B\u5B8C\u6210\u6216\u62D2\u7EDD\u7ED3\u7B97" }), testEvidence: typebox_exports.Optional(testEvidenceSchema) })
8618
8623
  ]);
8619
- fixerOutputSchema = withInfrastructureFailureDeclaration(
8624
+ fixerOutputSchema = withTerminatingOutputDeclarations(
8620
8625
  openToolObjectFromUnion(fixerOutputVariants)
8621
8626
  );
8622
8627
  }
@@ -14676,7 +14681,7 @@ var init_doctor_contracts = __esm({
14676
14681
  missingEvidence: typebox_exports.Array(typebox_exports.Object({ need: nonblank, targetKeys: evidenceIds }, { additionalProperties: true }), { description: "\u5982\u5B9E\u8BC1\u8BCD\u6240\u9700\u800C\u5C1A\u7F3A\u7684\u8BC1\u636E" })
14677
14682
  }, { additionalProperties: false, description: "\u8BC1\u636E\u4E0D\u8DB3\u4EE5\u652F\u6491\u5982\u5B9E\u6848\u8BC1\u8BCD" })
14678
14683
  ]);
14679
- doctorSubmissionSchema = withInfrastructureFailureDeclaration(
14684
+ doctorSubmissionSchema = withTerminatingOutputDeclarations(
14680
14685
  openToolObjectFromUnion(doctorSubmissionVariants)
14681
14686
  );
14682
14687
  doctorEvidenceReadSchema = typebox_exports.Object({ evidenceId: typebox_exports.String({ minLength: 1, description: "\u5F85\u8BFB\u7559\u5B58\u8BC1\u636E\u6807\u8BC6" }), offset: typebox_exports.Optional(typebox_exports.Integer({ minimum: 0, description: "\u8D77\u59CB\u5B57\u8282\u504F\u79FB\uFF08\u4ECE 0 \u8BA1\uFF09" })), limit: typebox_exports.Optional(typebox_exports.Integer({ minimum: 1, description: "\u8FD4\u56DE\u5B57\u8282\u6570\uFF08\u65E0\u4E0A\u9650\uFF09" })) }, { additionalProperties: true });
@@ -14748,7 +14753,7 @@ var init_merger_contracts = __esm({
14748
14753
  typebox_exports.Object({ status: typebox_exports.Unknown({ description: MERGER_STATUS_DESCRIPTION }), attemptId: typebox_exports.String({ description: "\u5DF2\u53D7\u7406\u5408\u5E76 attempt \u8EAB\u4EFD" }), report: typebox_exports.String({ description: "\u5982\u5B9E\u7ED3\u679C\u62A5\u544A" }), mergeCommitId: typebox_exports.String({ description: "\u5B8C\u6210\u5408\u5E76 commit object ID" }) }, { additionalProperties: false }),
14749
14754
  typebox_exports.Object({ status: typebox_exports.Unknown({ description: MERGER_STATUS_DESCRIPTION }), attemptId: typebox_exports.String({ description: "\u5DF2\u53D7\u7406\u5408\u5E76 attempt \u8EAB\u4EFD" }), diagnosis: typebox_exports.String({ description: "\u5408\u5E76\u65E0\u6CD5\u6216\u4E0D\u5E94\u7531\u672C\u5E2D\u5B8C\u6210\u7684\u539F\u56E0\uFF08\u542B\u65E0\u8FDB\u884C\u4E2D\u5408\u5E76\u3001\u65E0\u6D3B\u53EF\u5E72\u3001\u9700\u65B0\u7684\u4EA7\u54C1/\u6743\u529B\u51B3\u5B9A\uFF09" }), report: typebox_exports.String({ description: "\u5982\u5B9E\u7ED3\u679C\u62A5\u544A" }) }, { additionalProperties: false })
14750
14755
  ]);
14751
- mergerOutputSchema = withInfrastructureFailureDeclaration(openToolObjectFromUnion(mergerOutputVariants));
14756
+ mergerOutputSchema = withTerminatingOutputDeclarations(openToolObjectFromUnion(mergerOutputVariants));
14752
14757
  MERGER_OUTPUT_TOOL_NAME = "ak_merger_output";
14753
14758
  record = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
14754
14759
  blank = (v) => typeof v !== "string" || v.trim().length === 0;
@@ -14773,7 +14778,7 @@ var init_notary_contracts = __esm({
14773
14778
  init_terminating_infrastructure();
14774
14779
  NOTARY_OUTPUT_TOOL_NAME = "ak_notary_output";
14775
14780
  NOTARY_FIXED_KICKOFF = "\u7B26\u5B9D\u90CE\u6848\u5377\u5DF2\u53D7\u7406\uFF1B\u6765\u6E90 run \u5B9A\u4F4D\u89C1\u4F1A\u8BDD\u6750\u6599\u3002";
14776
- notaryOutputSchema = withInfrastructureFailureDeclaration(
14781
+ notaryOutputSchema = withTerminatingOutputDeclarations(
14777
14782
  openToolObject(
14778
14783
  typebox_exports.Object({
14779
14784
  status: typebox_exports.Unknown({
@@ -14827,7 +14832,7 @@ var init_auditor_output = __esm({
14827
14832
  init_open_tool_schema();
14828
14833
  init_terminating_infrastructure();
14829
14834
  AUDITOR_OUTPUT_TOOL_NAME = "ak_auditor_output";
14830
- auditorOutputSchema = withInfrastructureFailureDeclaration(
14835
+ auditorOutputSchema = withTerminatingOutputDeclarations(
14831
14836
  openToolObject(
14832
14837
  typebox_exports.Object({
14833
14838
  status: typebox_exports.Unknown({
@@ -16360,25 +16365,40 @@ function resolveSitianVolumeCategory(kind) {
16360
16365
  }
16361
16366
  return kind;
16362
16367
  }
16368
+ function ticketProvenanceUnderBookPaths(ledgerHome, bookKey, ticketId) {
16369
+ const sessionDir = join9(activationBookDirectory(ledgerHome, bookKey), ticketId);
16370
+ return { sessionDir, recordFile: join9(sessionDir, SITIAN_RECORDS_LEAF) };
16371
+ }
16363
16372
  function resolveSitianRecordPathInLedger(input, ledgerHome) {
16364
16373
  const category = resolveSitianVolumeCategory(input.kind);
16365
16374
  const ticketNumber = category === "ticket-provenance" ? typeof input.subject === "string" && /^[1-9][0-9]*$/.test(input.subject) ? input.subject : typeof input.subject === "object" && typeof input.subject.ticketNumber === "number" && Number.isSafeInteger(input.subject.ticketNumber) && input.subject.ticketNumber > 0 ? String(input.subject.ticketNumber) : void 0 : void 0;
16366
16375
  let sessionDir;
16376
+ let recordFile;
16367
16377
  if (ticketNumber !== void 0) {
16368
- const bookDir = activationBookDirectory(
16378
+ const paths = ticketProvenanceUnderBookPaths(
16369
16379
  ledgerHome,
16370
- resolveBookKeyFromGit(input.cwd ?? process.cwd())
16380
+ resolveBookKeyFromGit(input.cwd ?? process.cwd()),
16381
+ ticketNumber
16371
16382
  );
16372
- sessionDir = join9(bookDir, ticketNumber);
16383
+ sessionDir = paths.sessionDir;
16384
+ recordFile = paths.recordFile;
16373
16385
  } else {
16374
16386
  if (input.sessionParent === void 0 || input.sessionParent.length === 0 || !physicallyContainedIn(ledgerHome, input.sessionParent)) {
16375
16387
  throw new Error("Sitian record ownership requires a parent session inside the ledger home");
16376
16388
  }
16377
16389
  sessionDir = join9(dirname5(input.sessionParent), category);
16390
+ recordFile = join9(sessionDir, SITIAN_RECORDS_LEAF);
16378
16391
  }
16379
- const recordFile = join9(sessionDir, "records.jsonl");
16380
16392
  return { sessionDir, recordFile, ledgerHome };
16381
16393
  }
16394
+ function projectTicketRecordsPathShape() {
16395
+ const { recordFile } = ticketProvenanceUnderBookPaths(
16396
+ join9("~", ".ak-roles"),
16397
+ "<\u7C3F>",
16398
+ "<\u7968\u53F7>"
16399
+ );
16400
+ return recordFile.replace(/\\/g, "/");
16401
+ }
16382
16402
  function resolveSitianRecordPath(input) {
16383
16403
  const ledgerHome = input.home !== void 0 && input.home.length > 0 ? resolveActivationLedgerHome(input.home) : resolveActivationLedgerHomeForPath(input.sessionParent);
16384
16404
  return resolveSitianRecordPathInLedger(input, ledgerHome);
@@ -16415,7 +16435,7 @@ function appendSitianRecord(input) {
16415
16435
  );
16416
16436
  }
16417
16437
  }
16418
- var S4_SUBMISSION_LEDGER_KINDS;
16438
+ var S4_SUBMISSION_LEDGER_KINDS, SITIAN_RECORDS_LEAF;
16419
16439
  var init_sitian_appender = __esm({
16420
16440
  "src/sitian-appender.ts"() {
16421
16441
  "use strict";
@@ -16429,6 +16449,7 @@ var init_sitian_appender = __esm({
16429
16449
  "sealed",
16430
16450
  "post-seal-anomaly"
16431
16451
  ]);
16452
+ SITIAN_RECORDS_LEAF = "records.jsonl";
16432
16453
  }
16433
16454
  });
16434
16455
 
@@ -24871,7 +24892,6 @@ __export(settlement_exports, {
24871
24892
  publishMergerArtifacts: () => publishMergerArtifacts,
24872
24893
  publishReviewerArtifacts: () => publishReviewerArtifacts,
24873
24894
  raceNavigatorGrace: () => raceNavigatorGrace,
24874
- readBoundAuditorKnownFailure: () => readBoundAuditorKnownFailure,
24875
24895
  readBoundEvidenceChildKnownFailure: () => readBoundEvidenceChildKnownFailure,
24876
24896
  readCollectorInfrastructureFailure: () => readCollectorInfrastructureFailure,
24877
24897
  readEngineDetourInfrastructureFailure: () => readEngineDetourInfrastructureFailure,
@@ -25415,32 +25435,6 @@ async function loadBoundAuditorVolumes(sessionFile) {
25415
25435
  }
25416
25436
  const parentId = parentEntries.find((entry) => entry.type === "session")?.id;
25417
25437
  if (parentId === void 0) return void 0;
25418
- const isResumeEnvelopeBytes = (value) => {
25419
- if (typeof value !== "string") return false;
25420
- if (value.length === 0) return true;
25421
- const nl = value.indexOf("\n");
25422
- const firstLine = nl === -1 ? value : value.slice(0, nl);
25423
- const body = firstLine === "" && nl !== -1 ? value.slice(nl + 1) : value;
25424
- return body.startsWith("\u672C\u6B21\u914D\u7F6E\u7684\u52B3\u52A1\u5F15\u64CE\u53CA\u5176\u624B\u518C\uFF1A") || body.startsWith("- engine:");
25425
- };
25426
- const isResumeEnvelope = (msg) => {
25427
- if (!isRecord10(msg) || msg.role !== "user") return false;
25428
- const text = typeof msg.text === "string" ? msg.text : typeof msg.content === "string" ? msg.content : void 0;
25429
- if (isResumeEnvelopeBytes(text)) return true;
25430
- const content = msg.content;
25431
- if (Array.isArray(content)) {
25432
- return content.some((p) => isRecord10(p) && (isResumeEnvelopeBytes(p.text) || isResumeEnvelopeBytes(p.content)));
25433
- }
25434
- return false;
25435
- };
25436
- let latestParentUserIndex = -1;
25437
- for (let i = parentEntries.length - 1; i >= 0; i -= 1) {
25438
- const entry = parentEntries[i];
25439
- if (entry?.type !== "message" || entry.message?.role !== "user") continue;
25440
- if (isResumeEnvelope(entry.message)) continue;
25441
- latestParentUserIndex = i;
25442
- break;
25443
- }
25444
25438
  const childDirectories = [join25(dirname13(sessionFile), "auditor-roles")];
25445
25439
  const valid = [];
25446
25440
  let sawAnyDirectory = false;
@@ -25477,12 +25471,9 @@ async function loadBoundAuditorVolumes(sessionFile) {
25477
25471
  for (const { entry: bindingEntry, start, end } of bindingPasses) {
25478
25472
  const bindingParent = bindingEntry !== void 0 && isRecord10(bindingEntry.data) && isRecord10(bindingEntry.data.parent) ? bindingEntry.data.parent : void 0;
25479
25473
  const attemptEntryId = typeof bindingParent?.attemptEntryId === "string" ? bindingParent.attemptEntryId : void 0;
25480
- const attemptEntryIndex = attemptEntryId === void 0 ? -1 : parentEntries.findIndex((entry) => entry.id === attemptEntryId);
25481
25474
  const boundSessionFile = typeof bindingParent?.sessionFile === "string" ? bindingParent.sessionFile : typeof header.parentSession === "string" ? header.parentSession : void 0;
25482
25475
  if (boundSessionFile !== sessionFile) continue;
25483
- if (bindingParent !== void 0 && (bindingParent.sessionId !== parentId || attemptEntryIndex < latestParentUserIndex)) {
25484
- continue;
25485
- }
25476
+ if (bindingParent !== void 0 && bindingParent.sessionId !== parentId) continue;
25486
25477
  if (bindingParent === void 0 && header.parentSession !== sessionFile) continue;
25487
25478
  valid.push({
25488
25479
  entries: entries.slice(start, end),
@@ -25537,11 +25528,6 @@ function providerStopFallbackFromAuditorVolumes(volumes) {
25537
25528
  }
25538
25529
  return void 0;
25539
25530
  }
25540
- async function readBoundAuditorKnownFailure(sessionFile) {
25541
- const volumes = await loadBoundAuditorVolumes(sessionFile);
25542
- if (volumes === void 0) return void 0;
25543
- return complianceFailureFromAuditorVolumes(volumes) ?? providerStopFallbackFromAuditorVolumes(volumes);
25544
- }
25545
25531
  async function readBoundAuditorComplianceFailure(sessionFile) {
25546
25532
  const volumes = await loadBoundAuditorVolumes(sessionFile);
25547
25533
  if (volumes === void 0) return void 0;
@@ -27568,11 +27554,14 @@ var init_ticket_provenance = __esm({
27568
27554
  import { mkdtemp, readFile as readFile19, rm, writeFile as writeFile8 } from "node:fs/promises";
27569
27555
  import { tmpdir } from "node:os";
27570
27556
  import { join as join27 } from "node:path";
27571
- function describeDossierFile(path) {
27572
- return path;
27573
- }
27574
27557
  async function projectCaseDossierPointerSection(input) {
27575
- if (input.ticketNumber === void 0) return void 0;
27558
+ if (input.ticketNumber === void 0) {
27559
+ return [
27560
+ UNBOUND_DOSSIER_PATH_HEADING,
27561
+ "",
27562
+ `\u8BB0\u5F55\u5377\u5B97\uFF1A${projectTicketRecordsPathShape()}`
27563
+ ].join("\n");
27564
+ }
27576
27565
  const volume = resolveTicketProvenanceVolume(
27577
27566
  input.ticketNumber,
27578
27567
  input.projectRoot,
@@ -27582,7 +27571,7 @@ async function projectCaseDossierPointerSection(input) {
27582
27571
  CASE_DOSSIER_SECTION_HEADING,
27583
27572
  "",
27584
27573
  `\u7968\u53F7\uFF1A#${input.ticketNumber}`,
27585
- `\u8BB0\u5F55\u5377\u5B97\uFF1A${describeDossierFile(volume.recordFile)}`
27574
+ `\u8BB0\u5F55\u5377\u5B97\uFF1A${volume.recordFile}`
27586
27575
  ].join("\n");
27587
27576
  }
27588
27577
  async function deliverCaseDossierAsAttachment(input) {
@@ -27591,7 +27580,6 @@ async function deliverCaseDossierAsAttachment(input) {
27591
27580
  projectRoot: input.projectRoot,
27592
27581
  home: input.home
27593
27582
  });
27594
- if (section === void 0) return void 0;
27595
27583
  const stagingDir = await mkdtemp(join27(tmpdir(), "ak-case-dossier-"));
27596
27584
  try {
27597
27585
  const stagingPath = join27(stagingDir, CASE_DOSSIER_ATTACH_FILE);
@@ -27606,13 +27594,15 @@ async function deliverCaseDossierAsAttachment(input) {
27606
27594
  await rm(stagingDir, { recursive: true, force: true });
27607
27595
  }
27608
27596
  }
27609
- var CASE_DOSSIER_SECTION_HEADING, CASE_DOSSIER_ATTACH_KEY, CASE_DOSSIER_ATTACH_FILE;
27597
+ var CASE_DOSSIER_SECTION_HEADING, UNBOUND_DOSSIER_PATH_HEADING, CASE_DOSSIER_ATTACH_KEY, CASE_DOSSIER_ATTACH_FILE;
27610
27598
  var init_case_dossier_delivery = __esm({
27611
27599
  "src/public-cli/case-dossier-delivery.ts"() {
27612
27600
  "use strict";
27601
+ init_sitian_facade();
27613
27602
  init_ticket_provenance();
27614
27603
  init_invocation();
27615
27604
  CASE_DOSSIER_SECTION_HEADING = "## \u672C\u7968\u8D77\u5C45\u5F55\uFF08\u7CFB\u7EDF\u968F\u6848\u63D0\u4F9B\uFF09";
27605
+ UNBOUND_DOSSIER_PATH_HEADING = "## \u8D77\u5C45\u5F55\u8DEF\u5F84\uFF08\u7CFB\u7EDF\u968F\u6848\u63D0\u4F9B\uFF09";
27616
27606
  CASE_DOSSIER_ATTACH_KEY = "case-dossier";
27617
27607
  CASE_DOSSIER_ATTACH_FILE = "case-dossier-pointer.md";
27618
27608
  }
@@ -28111,12 +28101,6 @@ function describeCaughtError(error) {
28111
28101
  }
28112
28102
  return { message: String(error) };
28113
28103
  }
28114
- function appendContinuationSection(continuation, section) {
28115
- const prompt = `${continuation.prompt}
28116
-
28117
- ${section}`;
28118
- return continuation.kind === "initial" ? { kind: "initial", prompt } : { kind: "resume", prompt };
28119
- }
28120
28104
  function isStationChildOfficerDialogue(role, env) {
28121
28105
  return env.stationChild === true && isOfficerReviewSeat(role);
28122
28106
  }
@@ -28278,10 +28262,24 @@ async function dispatchPostAdmissionTurn(input) {
28278
28262
  const shouldPresent = adapters.shouldPresentSettled ?? ((terminal) => isLawfulTypedTerminalOutcome(terminal.roleOutcome));
28279
28263
  let afterDispatchApplied = false;
28280
28264
  const finishAfterTurn = async (result2) => {
28281
- if (adapters.afterDispatch === void 0 || afterDispatchApplied) return result2;
28265
+ if (afterDispatchApplied) return result2;
28282
28266
  afterDispatchApplied = true;
28283
28267
  try {
28284
- await adapters.afterDispatch(admitted, lease);
28268
+ if (admitted.ticketNumber === void 0) {
28269
+ const rows = await readRecordedSubmissionRows(
28270
+ admitted.projectRoot,
28271
+ admitted.runId,
28272
+ { home: homeFromRunDirectory(admitted.runDirectory), sessionParent: join30(admitted.runDirectory, "session", "session.jsonl") }
28273
+ );
28274
+ const asserted = rows.filter((row) => row.kind === "accepted" && row.role === admitted.role).map((row) => row.accepted).find((payload) => {
28275
+ if (payload === null || typeof payload !== "object" || Array.isArray(payload)) return false;
28276
+ const value = payload.ticketNumber;
28277
+ return typeof value === "number" && Number.isSafeInteger(value) && value > 0;
28278
+ });
28279
+ const ticketNumber = asserted === void 0 ? void 0 : asserted.ticketNumber;
28280
+ if (ticketNumber !== void 0) await bindAdmittedTicketNumber(admitted, ticketNumber);
28281
+ }
28282
+ if (adapters.afterDispatch !== void 0) await adapters.afterDispatch(admitted, lease);
28285
28283
  return result2;
28286
28284
  } catch (error) {
28287
28285
  const primaryFailure = result2.terminal !== void 0 && !isLawfulTypedTerminalOutcome(result2.terminal.roleOutcome);
@@ -28396,29 +28394,12 @@ async function dispatchPostAdmissionTurn(input) {
28396
28394
  if (typeof liveHost === "string" && liveHost.trim() !== "") {
28397
28395
  turnRequest = { ...turnRequest, host: liveHost.trim() };
28398
28396
  }
28399
- if (isStationChildOfficerDialogue(admitted.role, env)) {
28400
- await deliverCaseDossierAsAttachment({
28401
- ticketNumber: admitted.ticketNumber,
28402
- projectRoot: admitted.projectRoot,
28403
- home: env.home,
28404
- runDirectory: admitted.runDirectory
28405
- });
28406
- } else {
28407
- const dossierSection = await projectCaseDossierPointerSection({
28408
- ticketNumber: admitted.ticketNumber,
28409
- projectRoot: admitted.projectRoot,
28410
- home: env.home
28411
- });
28412
- if (dossierSection !== void 0) {
28413
- turnRequest = {
28414
- ...turnRequest,
28415
- continuation: appendContinuationSection(
28416
- turnRequest.continuation,
28417
- dossierSection
28418
- )
28419
- };
28420
- }
28421
- }
28397
+ await deliverCaseDossierAsAttachment({
28398
+ ticketNumber: admitted.ticketNumber,
28399
+ projectRoot: admitted.projectRoot,
28400
+ home: env.home,
28401
+ runDirectory: admitted.runDirectory
28402
+ });
28422
28403
  await markRunRunning(
28423
28404
  admitted.runDirectory,
28424
28405
  env.model,
@@ -29006,6 +28987,7 @@ var init_post_admission = __esm({
29006
28987
  init_run_lifecycle();
29007
28988
  init_cli_errors();
29008
28989
  init_invocation();
28990
+ init_submission_ledger();
29009
28991
  init_activation_ledger_topology();
29010
28992
  init_engine_material();
29011
28993
  init_session_identity();
@@ -30623,8 +30605,8 @@ async function summonPublicRole(options) {
30623
30605
  async function summonGateOfficer(options) {
30624
30606
  let home = options.home;
30625
30607
  if (home === void 0) {
30626
- const { homeFromRunDirectory: homeFromRunDirectory3 } = await Promise.resolve().then(() => (init_activation_ledger_topology(), activation_ledger_topology_exports));
30627
- home = homeFromRunDirectory3(options.sourceRunDirectory);
30608
+ const { homeFromRunDirectory: homeFromRunDirectory2 } = await Promise.resolve().then(() => (init_activation_ledger_topology(), activation_ledger_topology_exports));
30609
+ home = homeFromRunDirectory2(options.sourceRunDirectory);
30628
30610
  }
30629
30611
  let gateReviewInstruction;
30630
30612
  if (options.reask === void 0 && options.submission !== void 0) {
@@ -10,12 +10,13 @@ import { writeFile } from "node:fs/promises";
10
10
  import { isAbsolute, join, resolve } from "node:path";
11
11
  import { buildResumeContinuationPrompt, RESUME_TRANSPORT_ENVELOPE, } from "./run-lifecycle.js";
12
12
  import { CliUsageError } from "./cli-errors.js";
13
- import { buildInstructionTransportPrompt, freezeAttachmentsIntoRun, } from "./invocation.js";
13
+ import { bindAdmittedTicketNumber, buildInstructionTransportPrompt, freezeAttachmentsIntoRun, } from "./invocation.js";
14
+ import { readRecordedSubmissionRows } from "../submission-ledger.js";
14
15
  import { pathContainedIn } from "../activation-ledger-topology.js";
15
16
  import { pickEngineAxis } from "../package-resources/engine-material.js";
16
17
  import { resolveHostAwareSessionAvailability } from "../session-identity.js";
17
18
  import { isOfficerReviewSeat } from "../host-contracts.js";
18
- import { deliverCaseDossierAsAttachment, projectCaseDossierPointerSection, } from "./case-dossier-delivery.js";
19
+ import { deliverCaseDossierAsAttachment } from "./case-dossier-delivery.js";
19
20
  /** Original error bytes, never relabeled — a secondary fact riding beside a classified cause. */
20
21
  function describeCaughtError(error) {
21
22
  if (error instanceof Error) {
@@ -24,13 +25,6 @@ function describeCaughtError(error) {
24
25
  }
25
26
  return { message: String(error) };
26
27
  }
27
- /** Append one system section to a continuation prompt, keeping its kind. */
28
- function appendContinuationSection(continuation, section) {
29
- const prompt = `${continuation.prompt}\n\n${section}`;
30
- return continuation.kind === "initial"
31
- ? { kind: "initial", prompt }
32
- : { kind: "resume", prompt };
33
- }
34
28
  /**
35
29
  * Nested gate summons (station child) on an officer seat: dialogue content is
36
30
  * peer words only (#879). ADR 0081 case dossier still hangs via the existing
@@ -262,11 +256,32 @@ export async function dispatchPostAdmissionTurn(input) {
262
256
  */
263
257
  let afterDispatchApplied = false;
264
258
  const finishAfterTurn = async (result) => {
265
- if (adapters.afterDispatch === undefined || afterDispatchApplied)
259
+ if (afterDispatchApplied)
266
260
  return result;
267
261
  afterDispatchApplied = true;
268
262
  try {
269
- await adapters.afterDispatch(admitted, lease);
263
+ // #858: an unbound seat may assert its ticket on the existing receipt.
264
+ // Read the original accepted payload; do not rewrite it, infer from prose,
265
+ // or reject missing/malformed declarations. An existing binding wins.
266
+ if (admitted.ticketNumber === undefined) {
267
+ const rows = await readRecordedSubmissionRows(admitted.projectRoot, admitted.runId, { home: homeFromRunDirectory(admitted.runDirectory), sessionParent: join(admitted.runDirectory, "session", "session.jsonl") });
268
+ const asserted = rows
269
+ .filter((row) => row.kind === "accepted" && row.role === admitted.role)
270
+ .map((row) => row.accepted)
271
+ .find((payload) => {
272
+ if (payload === null || typeof payload !== "object" || Array.isArray(payload))
273
+ return false;
274
+ const value = payload.ticketNumber;
275
+ return typeof value === "number" && Number.isSafeInteger(value) && value > 0;
276
+ });
277
+ const ticketNumber = asserted === undefined
278
+ ? undefined
279
+ : asserted.ticketNumber;
280
+ if (ticketNumber !== undefined)
281
+ await bindAdmittedTicketNumber(admitted, ticketNumber);
282
+ }
283
+ if (adapters.afterDispatch !== undefined)
284
+ await adapters.afterDispatch(admitted, lease);
270
285
  return result;
271
286
  }
272
287
  catch (error) {
@@ -362,10 +377,11 @@ export async function dispatchPostAdmissionTurn(input) {
362
377
  }
363
378
  // Turn request is assembled after beforeDispatch so this turn sees whatever it
364
379
  // settled — the seat's ticket bind re-projection and any court diarist station
365
- // writes (#742). Case dossier delivery (ADR 0081 / #709) rides here once for
366
- // every public entry. #879: station-child officer dialogue keeps peer body
367
- // intact — 起居录 hangs via existing attachments freeze (not prompt wrap,
368
- // not RoleTurnRequest.materials). Other entries keep the neutral prompt section.
380
+ // writes (#742). Case dossier delivery (ADR 0081 / #709 / #858) rides here once
381
+ // for every public entry on the existing attachments → readingMaterial face
382
+ // (station-child and ordinary share one seam). Dialogue continuation stays
383
+ // caller/peer opaque — never splice system path sections into user dialogue.
384
+ // No package-resume parallel face or typed resume identity.
369
385
  let turnRequest = env.signal === undefined ? request : { ...request, signal: env.signal };
370
386
  if (env.stationChild !== undefined) {
371
387
  turnRequest = { ...turnRequest, stationChild: env.stationChild };
@@ -378,32 +394,16 @@ export async function dispatchPostAdmissionTurn(input) {
378
394
  if (typeof liveHost === "string" && liveHost.trim() !== "") {
379
395
  turnRequest = { ...turnRequest, host: liveHost.trim() };
380
396
  }
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
- }
406
- }
397
+ // 0081 non-dialogue face: freeze pointer section under run/attachments/.
398
+ // Seat consumes via loadCaseDossierReadingMaterial → existing agent-start
399
+ // readingMaterial / systemPrompt.materials fold. Caller instruction, empty
400
+ // request, and resume --message stay verbatim.
401
+ await deliverCaseDossierAsAttachment({
402
+ ticketNumber: admitted.ticketNumber,
403
+ projectRoot: admitted.projectRoot,
404
+ home: env.home,
405
+ runDirectory: admitted.runDirectory,
406
+ });
407
407
  // Authoritative host write happens here, at the real dispatch boundary —
408
408
  // immediately before the turn actually starts, after every retryable
409
409
  // pre-turn step above has succeeded on this attempt (#840 r9 判词 class 2).