@akagilnc/pi-workflow-roles 0.1.4802 → 0.1.4874

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 (142) hide show
  1. package/dist/acp-host/production-host.js +19434 -18218
  2. package/dist/analyst-book-key.js +63 -0
  3. package/dist/analyst-cohort.js +167 -0
  4. package/dist/analyst-entry.js +320 -0
  5. package/dist/analyst-index.js +247 -0
  6. package/dist/analyst-ledger.js +561 -0
  7. package/dist/analyst-median.js +16 -0
  8. package/dist/analyst-metric-families/acceptance-success-rework.js +249 -0
  9. package/dist/analyst-metric-families/b2-frame-buckets-actions.js +189 -0
  10. package/dist/analyst-metric-families/gate-cycles.js +77 -0
  11. package/dist/analyst-metric-families/leg-wall-clock.js +56 -0
  12. package/dist/analyst-metric-families/round-timeline.js +126 -0
  13. package/dist/analyst-metric-families.js +23 -0
  14. package/dist/analyst-metric-family.js +11 -0
  15. package/dist/analyst-model-groups.js +135 -0
  16. package/dist/analyst-page.js +182 -0
  17. package/dist/atomic-write.js +23 -0
  18. package/dist/auditor-soul.js +1 -1
  19. package/dist/countersign-contracts.js +0 -2
  20. package/dist/diarist-contracts.js +0 -1
  21. package/dist/doctor-contracts.js +2 -2
  22. package/dist/gatekeeper-role.js +15 -16
  23. package/dist/gleaner-left-contracts.js +0 -2
  24. package/dist/headless-host/production-host.js +16967 -15749
  25. package/dist/host-contracts.js +0 -4
  26. package/dist/inspector-contracts.js +0 -2
  27. package/dist/institutional-resolution.js +4 -2
  28. package/dist/merger-contracts.js +0 -2
  29. package/dist/migrate-book-topology.js +3908 -3089
  30. package/dist/navigator-public-session.js +4 -3
  31. package/dist/notary-contracts.js +0 -2
  32. package/dist/package-contracts/auditor-output.js +0 -1
  33. package/dist/package-contracts/collector-output.js +0 -2
  34. package/dist/package-contracts/fixer-output.js +0 -2
  35. package/dist/package-contracts/gatekeeper-output.js +0 -2
  36. package/dist/package-contracts/judge-output.js +0 -2
  37. package/dist/package-contracts/navigator-output.js +0 -2
  38. package/dist/package-contracts/reviewer-output.js +0 -2
  39. package/dist/package-contracts/terminating-tools.js +32 -92
  40. package/dist/package-contracts/worker-output.js +0 -4
  41. package/dist/packaged-role-registry.js +518 -36
  42. package/dist/pi/role-turn-host.js +2 -1
  43. package/dist/public-cli/analyst-run.js +185 -0
  44. package/dist/public-cli/cli.js +885 -0
  45. package/dist/public-cli/config.js +12 -9
  46. package/dist/public-cli/countersign-run.js +4 -311
  47. package/dist/public-cli/instruction-seat-run.js +628 -158
  48. package/dist/public-cli/invocation.js +806 -1550
  49. package/dist/public-cli/main.js +6962 -9882
  50. package/dist/public-cli/option-definitions.js +51 -99
  51. package/dist/public-cli/post-admission.js +30 -2
  52. package/dist/public-cli/run-lifecycle.js +234 -353
  53. package/dist/public-cli/seat-ticket-binding.js +6 -0
  54. package/dist/public-cli/settlement.js +261 -675
  55. package/dist/public-cli/turn-request.js +76 -0
  56. package/dist/public-role-summons.js +38 -112
  57. package/dist/role-activation-flags.js +23 -45
  58. package/dist/secretariat-contracts.js +0 -2
  59. package/dist/session-identity.js +17 -8
  60. package/dist/session-opening-materials.js +3 -2
  61. package/extensions/role-runtime.ts +6 -80
  62. package/package.json +1 -1
  63. package/src/acp-host/role-turn-host.ts +4 -1
  64. package/src/analyst-metric-families/acceptance-success-rework.ts +3 -2
  65. package/src/auditor-role.ts +1 -2
  66. package/src/auditor-soul.ts +1 -1
  67. package/src/collector-role.ts +2 -2
  68. package/src/countersign-contracts.ts +0 -1
  69. package/src/countersign-role.ts +1 -1
  70. package/src/diarist-contracts.ts +0 -1
  71. package/src/diarist-role.ts +0 -1
  72. package/src/doctor-auditor.ts +1 -2
  73. package/src/doctor-contracts.ts +1 -1
  74. package/src/doctor-role.ts +3 -2
  75. package/src/external-host-turn-loop.ts +1 -1
  76. package/src/factory-board.ts +10 -7
  77. package/src/gatekeeper-role.ts +16 -10
  78. package/src/gleaner-left-contracts.ts +0 -1
  79. package/src/gleaner-left-role.ts +0 -1
  80. package/src/headless-host/role-turn-host.ts +7 -1
  81. package/src/host-contracts.ts +10 -6
  82. package/src/inspector-contracts.ts +0 -1
  83. package/src/inspector-role.ts +0 -2
  84. package/src/institutional-resolution.ts +6 -4
  85. package/src/judge-role.ts +3 -3
  86. package/src/merger-contracts.ts +0 -1
  87. package/src/merger-role.ts +2 -2
  88. package/src/navigator-public-session.ts +7 -6
  89. package/src/navigator-work-context.ts +6 -8
  90. package/src/notary-contracts.ts +0 -1
  91. package/src/notary-role.ts +2 -3
  92. package/src/package-contracts/auditor-output.ts +0 -1
  93. package/src/package-contracts/collector-output.ts +0 -1
  94. package/src/package-contracts/fixer-output.ts +0 -1
  95. package/src/package-contracts/gatekeeper-output.ts +0 -1
  96. package/src/package-contracts/judge-output.ts +0 -1
  97. package/src/package-contracts/navigator-output.ts +0 -1
  98. package/src/package-contracts/reviewer-output.ts +0 -1
  99. package/src/package-contracts/terminating-tools.ts +27 -99
  100. package/src/package-contracts/worker-output.ts +0 -2
  101. package/src/packaged-role-registry.ts +604 -35
  102. package/src/pi/role-turn-host.ts +2 -1
  103. package/src/public-cli/cli.ts +64 -259
  104. package/src/public-cli/config.ts +18 -10
  105. package/src/public-cli/countersign-run.ts +14 -449
  106. package/src/public-cli/instruction-seat-run.ts +758 -277
  107. package/src/public-cli/invocation.ts +1097 -2051
  108. package/src/public-cli/option-definitions.ts +62 -127
  109. package/src/public-cli/post-admission.ts +47 -2
  110. package/src/public-cli/run-lifecycle.ts +303 -613
  111. package/src/public-cli/seat-ticket-binding.ts +6 -0
  112. package/src/public-cli/settlement.ts +399 -1185
  113. package/src/public-cli/turn-request.ts +92 -1
  114. package/src/public-role-summons.ts +44 -128
  115. package/src/reviewer-role.ts +3 -2
  116. package/src/role-activation-flags.ts +20 -41
  117. package/src/role-runtime-dependencies.ts +25 -26
  118. package/src/role-runtime.ts +121 -232
  119. package/src/secretariat-contracts.ts +0 -1
  120. package/src/secretariat-role.ts +0 -2
  121. package/src/session-identity.ts +23 -8
  122. package/src/session-opening-materials.ts +2 -1
  123. package/src/worker-role.ts +3 -4
  124. package/dist/doctor-auditor.js +0 -25
  125. package/dist/public-cli/diarist-run.js +0 -130
  126. package/dist/public-cli/doctor-run.js +0 -87
  127. package/dist/public-cli/inspector-run.js +0 -151
  128. package/dist/public-cli/judge-run.js +0 -114
  129. package/dist/public-cli/notary-run.js +0 -174
  130. package/dist/public-cli/reviewer-run.js +0 -339
  131. package/src/public-cli/coder-run.ts +0 -255
  132. package/src/public-cli/collector-run.ts +0 -189
  133. package/src/public-cli/diarist-run.ts +0 -233
  134. package/src/public-cli/doctor-run.ts +0 -167
  135. package/src/public-cli/fixer-run.ts +0 -265
  136. package/src/public-cli/gleaner-left-run.ts +0 -167
  137. package/src/public-cli/inspector-run.ts +0 -261
  138. package/src/public-cli/judge-run.ts +0 -196
  139. package/src/public-cli/merger-run.ts +0 -294
  140. package/src/public-cli/notary-run.ts +0 -279
  141. package/src/public-cli/reviewer-run.ts +0 -480
  142. package/src/public-cli/secretariat-run.ts +0 -265
@@ -10,7 +10,6 @@ import {
10
10
  } from "./diarist-contracts.ts";
11
11
 
12
12
  export {
13
- DIARIST_ACCEPTED_TEXT,
14
13
  DIARIST_OUTPUT_TOOL_NAME,
15
14
  } from "./diarist-contracts.ts";
16
15
  export type { DiaristOutput };
@@ -10,8 +10,7 @@ import {
10
10
  resolveAuditDossier,
11
11
  } from "./dossier-resolution.ts";
12
12
  import type { HostContext } from "./host-contracts.ts";
13
-
14
- export const DOCTOR_AUDIT_TOOL_NAME = "ak_doctor_audit_decision";
13
+ export { DOCTOR_AUDIT_TOOL_NAME } from "./doctor-contracts.ts";
15
14
 
16
15
  export type DoctorAuditOptions = {
17
16
  context: HostContext;
@@ -5,7 +5,7 @@ import { withTerminatingOutputDeclarations } from "./package-contracts/terminati
5
5
 
6
6
  export const DOCTOR_EVIDENCE_TOOL_NAME = "ak_doctor_evidence";
7
7
  export const DOCTOR_OUTPUT_TOOL_NAME = "ak_doctor_output";
8
- export const DOCTOR_ACCEPTED_TEXT = "太医署回执已接受";
8
+ export const DOCTOR_AUDIT_TOOL_NAME = "ak_doctor_audit_decision";
9
9
  export const DOCTOR_ACCEPTED_AUDIT_NO_RECEIPT_TEXT = "太医署回执已接受;审计无回执";
10
10
  export const DOCTOR_OUTPUT_TOOL_DESCRIPTION = "提交唯一终局单案证词;completed 允许空 findings。";
11
11
  export const DOCTOR_TARGET_KINDS = ["law", "gate", "template", "station", "seat"] as const;
@@ -3,7 +3,8 @@ import { disposeComplianceDecision } from "./audit-escalation.ts";
3
3
  import { ComplianceResponseRetentionError, type ComplianceDecision } from "./compliance-transport.ts";
4
4
  import { GatekeeperDecisionError } from "./submission-errors.ts";
5
5
  import { DOCTOR_CANDIDATE_ENTRY_TYPE } from "./dossier-resolution.ts";
6
- import { DOCTOR_ACCEPTED_AUDIT_NO_RECEIPT_TEXT, DOCTOR_ACCEPTED_TEXT, DOCTOR_EVIDENCE_TOOL_NAME, DOCTOR_OUTPUT_TOOL_DESCRIPTION, DOCTOR_OUTPUT_TOOL_NAME, DoctorEvidenceStore, doctorEvidenceReadSchema, doctorSubmissionSchema, validateDoctorOutput, type DoctorCase } from "./doctor-contracts.ts";
6
+ import { packagedRoleAcceptedText } from "./packaged-role-registry.ts";
7
+ import { DOCTOR_ACCEPTED_AUDIT_NO_RECEIPT_TEXT, DOCTOR_EVIDENCE_TOOL_NAME, DOCTOR_OUTPUT_TOOL_DESCRIPTION, DOCTOR_OUTPUT_TOOL_NAME, DoctorEvidenceStore, doctorEvidenceReadSchema, doctorSubmissionSchema, validateDoctorOutput, type DoctorCase } from "./doctor-contracts.ts";
7
8
 
8
9
  import { sitianReport } from "./sitian-facade.ts";
9
10
 
@@ -36,7 +37,7 @@ export function createDoctorRoleRuntime(pi: RoleHost, dependencies: DoctorRoleDe
36
37
  let activation: { soul: string; patient: DoctorCase; store: DoctorEvidenceStore } | undefined; let registered = false; pi.registerFlag(DOCTOR_CASE_FLAG.name, DOCTOR_CASE_FLAG.definition);
37
38
  return { async activate() { const path = pi.getFlag(DOCTOR_CASE_FLAG.name); if (typeof path !== "string" || !path.trim()) throw new Error("Doctor requires --ak-doctor-case"); const soul = (await dependencies.loadSoul()).trim(); if (!soul) throw new Error("Doctor soul is empty"); const patient = await dependencies.loadCase(path); activation = { soul, patient, store: new DoctorEvidenceStore(patient) };
38
39
  if (!registered) { registered = true; pi.registerTool({ name: DOCTOR_EVIDENCE_TOOL_NAME, label: "太医署证据", description: "分页读取留存的 Pi session 字节。", parameters: doctorEvidenceReadSchema, async execute(_id: string, params: { evidenceId: string; offset?: number; limit?: number }) { if (!activation) throw new Error("太医署未激活"); const details = activation.store.read(params.evidenceId, params.offset, params.limit); return { content: [{ type: "text" as const, text: JSON.stringify(details) }], details }; } });
39
- pi.registerTool({ name: DOCTOR_OUTPUT_TOOL_NAME, label: "太医署输出", description: DOCTOR_OUTPUT_TOOL_DESCRIPTION, parameters: doctorSubmissionSchema, async execute(id: string, params: unknown, signal: AbortSignal | undefined, _update: unknown, ctx: HostContext): Promise<HostToolResult<unknown>> { if (!activation) throw new Error("太医署未激活"); const active = activation; const testimony = validateDoctorOutput(params, active.patient, active.store); try { appendCandidate(ctx, { version: 1, testimony, cost: active.patient.cost, readRecord: active.store.readRecord(), patientIdentity: active.patient.identity }); } catch (error) { host.failInfrastructure(error, ctx, id); } let audit: ComplianceDecision; try { audit = await dependencies.auditCompliance(signal === undefined ? { context: ctx } : { context: ctx, signal }); } catch (error) { host.failInfrastructure(error, ctx, id); } const acceptedDetails = testimony; return disposeComplianceDecision<HostToolResult<unknown>>(audit, { pass: (usage) => ({ content: [{ type: "text" as const, text: DOCTOR_ACCEPTED_TEXT }], details: acceptedDetails, terminate: true as const, ...(usage === undefined ? {} : { usage }) }), noReceipt: (auditNoReceipt, usageProjection) => { try { appendCandidate(ctx, { version: 1, testimony, cost: active.patient.cost, auditNoReceipt, readRecord: active.store.readRecord(), patientIdentity: active.patient.identity }); } catch (error) { host.failInfrastructure(error, ctx, id); } return { content: [{ type: "text" as const, text: DOCTOR_ACCEPTED_AUDIT_NO_RECEIPT_TEXT }], details: acceptedDetails, terminate: true as const, ...usageProjection }; }, received: () => { throw new Error("审刑院非三态应交 runComplianceAudit 重问说话者"); }, bounce: (violations) => { throw new GatekeeperDecisionError({ status: "bounce", officer: "auditor", receipt: violations }); }, escalate: (result) => result, transportFailure: (facts) => { host.failInfrastructure(Object.assign(new Error(facts.diagnostic), { name: "ComplianceTransportFailure", ...(facts.submissions === undefined && facts.terminal === undefined ? {} : { submission: facts.submissions ?? facts.terminal }) }), ctx, id); } }, acceptedDetails); } });
40
+ pi.registerTool({ name: DOCTOR_OUTPUT_TOOL_NAME, label: "太医署输出", description: DOCTOR_OUTPUT_TOOL_DESCRIPTION, parameters: doctorSubmissionSchema, async execute(id: string, params: unknown, signal: AbortSignal | undefined, _update: unknown, ctx: HostContext): Promise<HostToolResult<unknown>> { if (!activation) throw new Error("太医署未激活"); const active = activation; const testimony = validateDoctorOutput(params, active.patient, active.store); try { appendCandidate(ctx, { version: 1, testimony, cost: active.patient.cost, readRecord: active.store.readRecord(), patientIdentity: active.patient.identity }); } catch (error) { host.failInfrastructure(error, ctx, id); } let audit: ComplianceDecision; try { audit = await dependencies.auditCompliance(signal === undefined ? { context: ctx } : { context: ctx, signal }); } catch (error) { host.failInfrastructure(error, ctx, id); } const acceptedDetails = testimony; return disposeComplianceDecision<HostToolResult<unknown>>(audit, { pass: (usage) => ({ content: [{ type: "text" as const, text: packagedRoleAcceptedText("doctor") }], details: acceptedDetails, terminate: true as const, ...(usage === undefined ? {} : { usage }) }), noReceipt: (auditNoReceipt, usageProjection) => { try { appendCandidate(ctx, { version: 1, testimony, cost: active.patient.cost, auditNoReceipt, readRecord: active.store.readRecord(), patientIdentity: active.patient.identity }); } catch (error) { host.failInfrastructure(error, ctx, id); } return { content: [{ type: "text" as const, text: DOCTOR_ACCEPTED_AUDIT_NO_RECEIPT_TEXT }], details: acceptedDetails, terminate: true as const, ...usageProjection }; }, received: () => { throw new Error("审刑院非三态应交 runComplianceAudit 重问说话者"); }, bounce: (violations) => { throw new GatekeeperDecisionError({ status: "bounce", officer: "auditor", receipt: violations }); }, escalate: (result) => result, transportFailure: (facts) => { host.failInfrastructure(Object.assign(new Error(facts.diagnostic), { name: "ComplianceTransportFailure", ...(facts.submissions === undefined && facts.terminal === undefined ? {} : { submission: facts.submissions ?? facts.terminal }) }), ctx, id); } }, acceptedDetails); } });
40
41
  pi.on("before_agent_start", (event) => { if (!activation) throw new Error("太医署未激活"); const catalog = { version: activation.patient.version, identity: activation.patient.identity, admittedMetrics: { cost: activation.patient.cost }, lawfulTargetKeys: ["case", ...activation.patient.cost.invocations.sources], evidence: activation.patient.evidence.map(({ id, kind, sha256, byteLength, contentLength }) => ({ id, kind, sha256, byteLength, contentLength })) }; return { systemPrompt: `${event.systemPrompt}\n\n<doctor_soul>\n${activation.soul}\n</doctor_soul>\n\n<doctor_case>\n${JSON.stringify(catalog)}\n</doctor_case>` }; }); }
41
42
  const required = [DOCTOR_EVIDENCE_TOOL_NAME, DOCTOR_OUTPUT_TOOL_NAME]; const names = pi.getAllTools().map((tool) => tool.name); for (const name of required) if (names.filter((item) => item === name).length !== 1) throw new Error(`Doctor required tool collision or missing: ${name}`); pi.setActiveTools(required); const active = pi.getActiveTools?.() ?? required; if (active.length !== 2 || !required.every((name) => active.includes(name))) throw new Error("Doctor active tool narrowing failed"); } };
42
43
  }
@@ -9,7 +9,7 @@ import type {
9
9
  RoleTurnRequest,
10
10
  RoleTurnResult,
11
11
  } from "./host-contracts.ts";
12
- import { isOfficerReviewSeat } from "./host-contracts.ts";
12
+ import { isOfficerReviewSeat } from "./packaged-role-registry.ts";
13
13
 
14
14
  export const EXTERNAL_ROLE_TURN_ROUND_LIMIT = 8 as const;
15
15
 
@@ -20,6 +20,7 @@ import { randomUUID } from "node:crypto";
20
20
  import { lstat, mkdir, realpath, rename, rm, writeFile } from "node:fs/promises";
21
21
  import { basename, dirname, join, relative, resolve, sep } from "node:path";
22
22
 
23
+ import { packagedBoardPlacement } from "./packaged-role-registry.ts";
23
24
  import {
24
25
  formatDurationZh,
25
26
  formatLocalDateTime,
@@ -187,16 +188,18 @@ function placeTicket(prepared: PreparedTicket): BoardPlacement {
187
188
  const sorted = sortRunsByStart(prepared.runs);
188
189
  const latest = sorted.at(-1)!;
189
190
  if (latest.station === "unknown") return "unknown";
190
- if (latest.station === "judge") {
191
+ // ADR 0053: marshal-driven runs land in 尚书省. Marshal is not a packaged seat.
192
+ if (latest.station === "marshal") return "marshal";
193
+ const placement = packagedBoardPlacement(latest.station);
194
+ if (placement === "judge-history") {
191
195
  // Unknown history never counts as construction evidence.
192
- const started = sorted.some((run) => run.station !== "unknown" && run.station !== "judge");
196
+ const started = sorted.some((run) => {
197
+ if (run.station === "unknown") return false;
198
+ return packagedBoardPlacement(run.station) !== "judge-history";
199
+ });
193
200
  return started ? "marshal" : "court";
194
201
  }
195
- if (latest.station === "coder") return "coder";
196
- if (latest.station === "fixer" || latest.station === "reviewer") return "marshal";
197
- // ADR 0053: marshal-driven runs land in 尚书省 once the seat ships (station maps now).
198
- if (latest.station === "marshal") return "marshal";
199
- if (latest.station === "collector") return "collector";
202
+ if (placement !== undefined) return placement;
200
203
  return `other:${latest.station}`;
201
204
  }
202
205
 
@@ -2,6 +2,7 @@ import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
2
2
  import type { HostContext } from "./host-contracts.ts";
3
3
 
4
4
  import { auditorRunDirectory } from "./auditor-dossier-tool.ts";
5
+ import { packagedGateDecision, packagedGateStageLabel } from "./packaged-role-registry.ts";
5
6
  import type { NoReceiptLifecycleFacts } from "./receipt-delivery-policy.ts";
6
7
  import { GatekeeperDecisionError } from "./submission-errors.ts";
7
8
  import { INSPECTOR_OUTPUT_TOOL_NAME } from "./inspector-contracts.ts";
@@ -82,18 +83,21 @@ export type GatekeeperNonPassResult = Extract<
82
83
  >;
83
84
 
84
85
  function gateSeatLabel(stage: GateOfficer): string {
85
- if (stage === "inspector") return "台院";
86
- if (stage === "auditor") return "审刑院";
87
- if (stage === "countersign") return "给事中";
88
- return "符宝郎";
86
+ return packagedGateStageLabel(stage) ?? stage;
89
87
  }
90
88
 
89
+ /** Subject kind → review officer. One table; default is notary. */
90
+ const GATE_OFFICER_BY_SUBJECT = {
91
+ worker_completion: "inspector",
92
+ judge_compliance: "auditor",
93
+ judge_draft: "notary",
94
+ countersign_verdict: "notary",
95
+ secretariat_verdict: "countersign",
96
+ } as const satisfies Record<GatekeeperSubject["kind"], GateOfficer>;
97
+
91
98
  /** Subject kind → review officer (#753 countersign/notary, #756 judge/auditor + worker/inspector, #969 secretariat/countersign). */
92
99
  export function gateOfficerForSubject(subject: GatekeeperSubject): GateOfficer {
93
- if (subject.kind === "worker_completion") return "inspector";
94
- if (subject.kind === "judge_compliance") return "auditor";
95
- if (subject.kind === "secretariat_verdict") return "countersign";
96
- return "notary";
100
+ return GATE_OFFICER_BY_SUBJECT[subject.kind];
97
101
  }
98
102
 
99
103
  export { GatekeeperDecisionError } from "./submission-errors.ts";
@@ -222,7 +226,7 @@ function projectOfficerDecision(
222
226
  const record = readRecord(decision);
223
227
  // 给事中: only countersignStatus, strict three-word map; never generic status,
224
228
  // never unmapped raw word, never fallbackStatus (#969 / ADR 0040/0055).
225
- if (officer === "countersign") {
229
+ if (packagedGateDecision(officer) === "countersign-status") {
226
230
  const countersignStatus =
227
231
  record !== undefined && typeof record.countersignStatus === "string"
228
232
  ? record.countersignStatus
@@ -417,7 +421,9 @@ export const COUNTERSIGN_CONCLUSION_REASK =
417
421
 
418
422
  /** Pick the re-ask line for the officer under review. */
419
423
  export function officerConclusionReask(officer: GateOfficer): string {
420
- return officer === "countersign" ? COUNTERSIGN_CONCLUSION_REASK : OFFICER_CONCLUSION_REASK;
424
+ return packagedGateDecision(officer) === "countersign-status"
425
+ ? COUNTERSIGN_CONCLUSION_REASK
426
+ : OFFICER_CONCLUSION_REASK;
421
427
  }
422
428
 
423
429
  /**
@@ -5,7 +5,6 @@
5
5
  */
6
6
 
7
7
  export const GLEANER_LEFT_OUTPUT_TOOL_NAME = "ak_gleaner_left_output";
8
- export const GLEANER_LEFT_ACCEPTED_TEXT = "左拾遗回执已接受";
9
8
 
10
9
  /** Internal transport: comparison-base revision for the unanchored merge-candidate diff. */
11
10
  export const GLEANER_LEFT_BASE_FLAG = {
@@ -10,7 +10,6 @@ import {
10
10
  } from "./gleaner-left-contracts.ts";
11
11
 
12
12
  export {
13
- GLEANER_LEFT_ACCEPTED_TEXT,
14
13
  GLEANER_LEFT_OUTPUT_TOOL_NAME,
15
14
  } from "./gleaner-left-contracts.ts";
16
15
  export type { GleanerLeftOutput };
@@ -464,7 +464,13 @@ export function createHeadlessRoleTurnHost(config: HeadlessRoleTurnHostConfig):
464
464
  let outcome: RoleTurnResult = failure("session", "HeadlessNoOutcome", "no-outcome");
465
465
  try {
466
466
  // Claude mints a package UUID for --session-id; codex waits for thread.started.
467
- let sessionId = await config.sessionIdentity.load(request.principal);
467
+ // Public explicit resume already read the stored native id. Auto-resume omits it.
468
+ const explicitHostSessionId = request.continuation.kind === "resume"
469
+ ? request.continuation.hostSessionId
470
+ : undefined;
471
+ let sessionId = explicitHostSessionId !== undefined && explicitHostSessionId !== ""
472
+ ? explicitHostSessionId
473
+ : await config.sessionIdentity.load(request.principal);
468
474
  let sessionKind: "new" | "resume" =
469
475
  request.continuation.kind === "resume" && sessionId !== undefined && sessionId !== ""
470
476
  ? "resume"
@@ -140,7 +140,16 @@ export type RoleTurnActivation =
140
140
 
141
141
  export type RoleTurnContinuation =
142
142
  | { readonly kind: "initial"; readonly prompt: string }
143
- | { readonly kind: "resume"; readonly prompt: string };
143
+ | {
144
+ readonly kind: "resume";
145
+ readonly prompt: string;
146
+ /**
147
+ * Stored native host session/thread id for a public explicit resume.
148
+ * Absent on in-call auto-resume and in-gate retries; those still load
149
+ * through the host adapter. Never the package run id.
150
+ */
151
+ readonly hostSessionId?: string;
152
+ };
144
153
 
145
154
  /** Seat model consumed by the turn host (provider/model/thinking). */
146
155
  export type RoleTurnModelConfig = {
@@ -162,11 +171,6 @@ export type RoleTurnHostTransition = {
162
171
  readonly priorNativePaths: readonly string[];
163
172
  };
164
173
 
165
- /** Gate review officers (台院 / 符宝郎 / 审刑院). Single authority for seat checks. */
166
- export function isOfficerReviewSeat(role: string): boolean {
167
- return role === "notary" || role === "inspector" || role === "auditor";
168
- }
169
-
170
174
  /** One main-session turn request over the host-neutral execution seam. */
171
175
  export type RoleTurnRequest = {
172
176
  readonly principal: DurablePrincipal;
@@ -5,7 +5,6 @@
5
5
  */
6
6
 
7
7
  export const INSPECTOR_OUTPUT_TOOL_NAME = "ak_inspector_output" as const;
8
- export const INSPECTOR_ACCEPTED_TEXT = "台院回执已接受";
9
8
  export const INSPECTOR_SOURCE_RUN_FLAG = {
10
9
  name: "ak-inspector-source-run",
11
10
  definition: {
@@ -4,14 +4,12 @@ import { Type } from "typebox";
4
4
  import { openToolObject } from "./open-tool-schema.ts";
5
5
  import { withTerminatingOutputDeclarations } from "./package-contracts/terminating-infrastructure.ts";
6
6
  import {
7
- INSPECTOR_ACCEPTED_TEXT,
8
7
  INSPECTOR_OUTPUT_TOOL_NAME,
9
8
  validateRecordedInspectorOutput,
10
9
  type InspectorOutput,
11
10
  } from "./inspector-contracts.ts";
12
11
 
13
12
  export {
14
- INSPECTOR_ACCEPTED_TEXT,
15
13
  INSPECTOR_OUTPUT_TOOL_NAME,
16
14
  };
17
15
  export { INSPECTOR_OUTPUT_TOOL_NAME as INSPECTOR_OUTPUT_TOOL };
@@ -5,10 +5,11 @@
5
5
  * is the live public seat table (model/host/engine).
6
6
  */
7
7
  import type {
8
- GateOfficerSeat,
9
8
  PublicCliConfig,
10
9
  SeatModelConfig,
11
10
  } from "./public-cli/config.ts";
11
+ import type { PublicConfigurableSeat } from "./public-cli/registry.ts";
12
+ import { packagedModelParent } from "./packaged-role-registry.ts";
12
13
  import { seatModelOnly } from "./public-cli/registry.ts";
13
14
 
14
15
  /**
@@ -29,16 +30,17 @@ export type ConfiguredProvinceOfficerResolution = {
29
30
  */
30
31
  export function resolveConfiguredProvinceOfficer(
31
32
  config: PublicCliConfig,
32
- officer: GateOfficerSeat,
33
+ officer: PublicConfigurableSeat,
33
34
  ): ConfiguredProvinceOfficerResolution {
34
35
  const ownModel = seatModelOnly(config.seats[officer]);
35
36
  if (ownModel !== undefined) {
36
37
  return { selection: ownModel, source: "persistent" };
37
38
  }
38
- if (officer === "gatekeeper") {
39
+ const parent = packagedModelParent(officer);
40
+ if (parent === undefined) {
39
41
  return { source: "unconfigured" };
40
42
  }
41
- const gatekeeperModel = seatModelOnly(config.seats.gatekeeper);
43
+ const gatekeeperModel = seatModelOnly(config.seats[parent]);
42
44
  if (gatekeeperModel !== undefined) {
43
45
  return { selection: gatekeeperModel, source: "inherit-gatekeeper" };
44
46
  }
package/src/judge-role.ts CHANGED
@@ -4,8 +4,8 @@ import { Type, type Static } from "typebox";
4
4
  import { withTerminatingOutputDeclarations } from "./package-contracts/terminating-infrastructure.ts";
5
5
  import { ParentQueueReaskError } from "./submission-errors.ts";
6
6
 
7
+ import { packagedRoleAcceptedText } from "./packaged-role-registry.ts";
7
8
  import {
8
- JUDGE_ACCEPTED_TEXT,
9
9
  JUDGE_OUTPUT_TOOL_NAME,
10
10
  validateAcceptedJudgeDetails,
11
11
  type JudgeVerdict,
@@ -107,7 +107,7 @@ export function createJudgeRoleRuntime(
107
107
  // Parent escalate → throw to caller as-is; officers do not attend (#753 / #756).
108
108
  const verdict = validateVerdict(parameters);
109
109
  return {
110
- content: [{ type: "text" as const, text: JUDGE_ACCEPTED_TEXT }],
110
+ content: [{ type: "text" as const, text: packagedRoleAcceptedText("judge") }],
111
111
  details: verdict,
112
112
  terminate: true as const,
113
113
  };
@@ -138,7 +138,7 @@ export function createJudgeRoleRuntime(
138
138
  submission: parameters,
139
139
  });
140
140
  return {
141
- content: [{ type: "text" as const, text: JUDGE_ACCEPTED_TEXT }],
141
+ content: [{ type: "text" as const, text: packagedRoleAcceptedText("judge") }],
142
142
  details: verdict,
143
143
  terminate: true as const,
144
144
  };
@@ -34,7 +34,6 @@ export type MergerOutput =
34
34
  | { status: "completed"; attemptId: string; report: string; mergeCommitId: string }
35
35
  | { status: "escalate"; attemptId: string; diagnosis: string; report: string };
36
36
  export const MERGER_OUTPUT_TOOL_NAME = "ak_merger_output";
37
- export const MERGER_ACCEPTED_TEXT = "合并回执已接受";
38
37
 
39
38
  const record = (v: unknown): v is Record<string, unknown> => typeof v === "object" && v !== null && !Array.isArray(v);
40
39
  const blank = (v: unknown) => typeof v !== "string" || v.trim().length === 0;
@@ -1,6 +1,6 @@
1
1
  import type { RoleHost, HostContext } from "./host-contracts.ts";
2
+ import { packagedRoleAcceptedText } from "./packaged-role-registry.ts";
2
3
  import {
3
- MERGER_ACCEPTED_TEXT,
4
4
  MERGER_OUTPUT_TOOL_NAME,
5
5
  mergerOutputSchema,
6
6
  validateMergerInput,
@@ -40,7 +40,7 @@ export function createMergerRoleRuntime(pi: RoleHost, dependencies: MergerRoleDe
40
40
  name: MERGER_OUTPUT_TOOL_NAME, label: "合并输出", description: "提交合并结果;输出分支为 completed 与 escalate。", promptSnippet: "提交合并结果", parameters: mergerOutputSchema,
41
41
  async execute(_id: string, params: unknown, _signal: AbortSignal | undefined, _update: unknown, _ctx: HostContext) {
42
42
  if (!activation) throw new Error("校书郎未激活");
43
- return { content: [{ type: "text" as const, text: MERGER_ACCEPTED_TEXT }], details: params, terminate: true as const };
43
+ return { content: [{ type: "text" as const, text: packagedRoleAcceptedText("merger") }], details: params, terminate: true as const };
44
44
  },
45
45
  });
46
46
  pi.on("before_agent_start", (event) => {
@@ -22,6 +22,7 @@ import type { NoReceiptLifecycleFacts } from "./receipt-delivery-policy.ts";
22
22
  import { runDirectoryFromHostContext, type HostContext } from "./host-contracts.ts";
23
23
  import type { PublicSummonResult } from "./public-role-summons.ts";
24
24
  import { CliUsageError } from "./public-cli/cli-errors.ts";
25
+ import { isNavigatorSeat } from "./packaged-role-registry.ts";
25
26
 
26
27
  /**
27
28
  * Ledger process home for navigator attendance: admitted HostContext.runDirectory
@@ -76,16 +77,16 @@ export function readNavigatorHostRunPointer(entries: readonly unknown[]): string
76
77
 
77
78
  /**
78
79
  * Typed preflight via public CLI load path: can this run reopen as navigator?
79
- * CliUsageError (code AK_ROLE_USAGE) from loadResumableInstructionSeatRun means
80
- * unknown id / principal unavailable / non-instruction seat — not resumable.
81
- * Other throws propagate. Never reads stderr prose.
80
+ * CliUsageError (code AK_ROLE_USAGE) from loadResumablePublicRole means
81
+ * unknown id or principal unavailable — not resumable. Any other disk role
82
+ * is not this navigator host run. Other throws propagate. Never reads stderr prose.
82
83
  */
83
84
  export async function navigatorHostRunResumable(home: string, runId: string): Promise<boolean> {
84
85
  const { piDurablePrincipalAuthority } = await import("./pi/durable-principal.ts");
85
- const { loadResumableInstructionSeatRun } = await import("./public-cli/run-lifecycle.ts");
86
+ const { loadResumablePublicRole } = await import("./public-cli/run-lifecycle.ts");
86
87
  try {
87
- const loaded = await loadResumableInstructionSeatRun(home, runId, piDurablePrincipalAuthority);
88
- return loaded.admitted.role === "navigator";
88
+ const loaded = await loadResumablePublicRole(home, runId, piDurablePrincipalAuthority);
89
+ return isNavigatorSeat(loaded.admitted.role);
89
90
  } catch (error) {
90
91
  if (error instanceof CliUsageError) return false;
91
92
  throw error;
@@ -17,7 +17,7 @@ import {
17
17
  type NavigatorWorkContext,
18
18
  } from "./navigator-attendance.ts";
19
19
  import { loadNotarySourceRunLocator } from "./notary-source-run.ts";
20
- import { packagedRoleInputFlag } from "./packaged-role-registry.ts";
20
+ import { packagedNavigatorSubject, packagedRoleInputFlag } from "./packaged-role-registry.ts";
21
21
  import { loadAdmittedJudgeRequest } from "./public-cli/invocation.ts";
22
22
 
23
23
  export type NavigatorWorkContextLoaderOptions = {
@@ -44,7 +44,8 @@ export async function loadNavigatorWorkContext(
44
44
  options: NavigatorWorkContextLoaderOptions,
45
45
  ): Promise<NavigatorWorkContext> {
46
46
  const reference = navigatorInputReference(options.getFlag, options.role);
47
- const input = reference === undefined || options.role === "doctor" || options.role === "notary"
47
+ const subjectMode = packagedNavigatorSubject(options.role);
48
+ const input = reference === undefined || subjectMode === "case" || subjectMode === "source-run"
48
49
  ? undefined
49
50
  : await readFile(reference, "utf8");
50
51
  const subjectRoot = subjectPath(reference ?? options.context.sessionManager.getSessionDir(), options.context.cwd);
@@ -53,12 +54,12 @@ export async function loadNavigatorWorkContext(
53
54
  : navigatorSubjectKeyForInput(subjectRoot, reference, options.context.cwd);
54
55
  let subject = input ?? `work subject: ${subjectKey}`;
55
56
  let subjectProvenance: NavigatorSubjectProvenance = input === undefined ? "placeholder" : "role_input";
56
- if (options.role === "doctor" && reference !== undefined) {
57
+ if (subjectMode === "case" && reference !== undefined) {
57
58
  const patient = await loadDoctorCase(reference);
58
59
  subject = JSON.stringify({ identity: patient.identity, cost: patient.cost });
59
60
  subjectProvenance = "role_input";
60
61
  }
61
- if (options.role === "notary" && reference !== undefined) {
62
+ if (subjectMode === "source-run" && reference !== undefined) {
62
63
  const locator = await loadNotarySourceRunLocator(reference);
63
64
  subject = JSON.stringify({ sourceRun: locator });
64
65
  subjectProvenance = "role_input";
@@ -68,10 +69,7 @@ export async function loadNavigatorWorkContext(
68
69
  const currentSessionDir = options.context.sessionManager.getSessionDir();
69
70
  const isBoundPublicRun = publicRunDir !== undefined
70
71
  && resolve(currentSessionDir) === resolve(publicRunDir, "session");
71
- if (
72
- options.role === "judge" &&
73
- isBoundPublicRun
74
- ) {
72
+ if (subjectMode === "public-instruction" && isBoundPublicRun) {
75
73
  let admitted;
76
74
  try {
77
75
  admitted = await loadAdmittedJudgeRequest(publicRunDir);
@@ -9,7 +9,6 @@ import { openToolObject } from "./open-tool-schema.ts";
9
9
  import { withTerminatingOutputDeclarations } from "./package-contracts/terminating-infrastructure.ts";
10
10
 
11
11
  export const NOTARY_OUTPUT_TOOL_NAME = "ak_notary_output";
12
- export const NOTARY_ACCEPTED_TEXT = "符宝郎回执已接受";
13
12
  export const NOTARY_SOURCE_RUN_FLAG = {
14
13
  name: "ak-notary-source-run",
15
14
  definition: {
@@ -6,8 +6,8 @@ import type { RoleHost, HostContext, HostToolResult } from "./host-contracts.ts"
6
6
  * This module keeps evidence assembly + projection only.
7
7
  */
8
8
 
9
+ import { packagedRoleAcceptedText } from "./packaged-role-registry.ts";
9
10
  import {
10
- NOTARY_ACCEPTED_TEXT,
11
11
  NOTARY_OUTPUT_TOOL_NAME,
12
12
  NOTARY_SOURCE_RUN_FLAG,
13
13
  NOTARY_TICKET_FLAG,
@@ -16,7 +16,6 @@ import {
16
16
  } from "./notary-contracts.ts";
17
17
 
18
18
  export {
19
- NOTARY_ACCEPTED_TEXT,
20
19
  NOTARY_OUTPUT_TOOL_NAME,
21
20
  NOTARY_SOURCE_RUN_FLAG,
22
21
  NOTARY_TICKET_FLAG,
@@ -171,7 +170,7 @@ export function createNotaryRoleRuntime(
171
170
  // #753: handler only records — params as submitted, no findings/disposition rewrite.
172
171
  // #541 infra declaration + sole-final barrier are ledger-owned (#575).
173
172
  return {
174
- content: [{ type: "text" as const, text: NOTARY_ACCEPTED_TEXT }],
173
+ content: [{ type: "text" as const, text: packagedRoleAcceptedText("notary") }],
175
174
  details: parameters,
176
175
  terminate: true as const,
177
176
  };
@@ -8,7 +8,6 @@ import { openToolObject } from "../open-tool-schema.ts";
8
8
  import { withTerminatingOutputDeclarations } from "./terminating-infrastructure.ts";
9
9
 
10
10
  export const AUDITOR_OUTPUT_TOOL_NAME = "ak_auditor_output" as const;
11
- export const AUDITOR_ACCEPTED_TEXT = "审刑院回执已接受";
12
11
 
13
12
  export const auditorOutputSchema = withTerminatingOutputDeclarations(
14
13
  openToolObject(
@@ -1,7 +1,6 @@
1
1
  /** Package-owned Collector receipt leaf — no role registration surface. */
2
2
 
3
3
  export const COLLECTOR_OUTPUT_TOOL = "ak_collector_output";
4
- export const COLLECTOR_ACCEPTED_TEXT = "通进司回执已接受";
5
4
  export const COLLECTOR_HOST = "github.com";
6
5
 
7
6
  export type CollectorIdentityGroup = {
@@ -3,7 +3,6 @@ import { openToolObjectFromUnion } from "../open-tool-schema.ts";
3
3
  import { withTerminatingOutputDeclarations } from "./terminating-infrastructure.ts";
4
4
 
5
5
  export const FIXER_OUTPUT_TOOL_NAME = "ak_fixer_output";
6
- export const FIXER_ACCEPTED_TEXT = "修内司回执已接受";
7
6
 
8
7
  // #836 r16 class 1: these are LLM/human-read narrative content — the candidate
9
8
  // row lands on the ledger as submitted (src/submission-ledger.ts:351-390) and no
@@ -9,7 +9,6 @@ import { openToolObject } from "../open-tool-schema.ts";
9
9
  import { withTerminatingOutputDeclarations } from "./terminating-infrastructure.ts";
10
10
 
11
11
  export const GATEKEEPER_OUTPUT_TOOL_NAME = "ak_gatekeeper_output";
12
- export const GATEKEEPER_ACCEPTED_TEXT = "门下省决议已受理";
13
12
 
14
13
  /** Same open decision shape the province uses inside audit sessions. */
15
14
  export const gatekeeperDecisionSchema = openToolObject(
@@ -2,7 +2,6 @@
2
2
 
3
3
 
4
4
  export const JUDGE_OUTPUT_TOOL_NAME = "ak_judge_output";
5
- export const JUDGE_ACCEPTED_TEXT = "大理寺回执已接受";
6
5
 
7
6
  export type JudgeClass = {
8
7
  name: string;
@@ -11,7 +11,6 @@ import { openToolObject } from "../open-tool-schema.ts";
11
11
  import { withTerminatingOutputDeclarations } from "./terminating-infrastructure.ts";
12
12
 
13
13
  export const NAVIGATOR_OUTPUT_TOOL_NAME = "ak_navigator_output";
14
- export const NAVIGATOR_ACCEPTED_TEXT = "游奕使建议已受理";
15
14
 
16
15
  export const navigatorOutputSchema = withTerminatingOutputDeclarations(
17
16
  openToolObject(
@@ -1,7 +1,6 @@
1
1
  /** Package-owned Reviewer intent — original role payload only (#836 删 8). */
2
2
 
3
3
  export const REVIEWER_OUTPUT_TOOL_NAME = "ak_reviewer_output";
4
- export const REVIEWER_ACCEPTED_TEXT = "御史台回执已接受";
5
4
 
6
5
  /** Seat-owned per-lens finding body text (completeness / correctness). */
7
6
  export type ReviewerAmendments = Readonly<