@akagilnc/pi-workflow-roles 0.1.4800 → 0.1.4870

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 (143) 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/souls/coder.md +1 -2
  64. package/src/acp-host/role-turn-host.ts +4 -1
  65. package/src/analyst-metric-families/acceptance-success-rework.ts +3 -2
  66. package/src/auditor-role.ts +1 -2
  67. package/src/auditor-soul.ts +1 -1
  68. package/src/collector-role.ts +2 -2
  69. package/src/countersign-contracts.ts +0 -1
  70. package/src/countersign-role.ts +1 -1
  71. package/src/diarist-contracts.ts +0 -1
  72. package/src/diarist-role.ts +0 -1
  73. package/src/doctor-auditor.ts +1 -2
  74. package/src/doctor-contracts.ts +1 -1
  75. package/src/doctor-role.ts +3 -2
  76. package/src/external-host-turn-loop.ts +1 -1
  77. package/src/factory-board.ts +10 -7
  78. package/src/gatekeeper-role.ts +16 -10
  79. package/src/gleaner-left-contracts.ts +0 -1
  80. package/src/gleaner-left-role.ts +0 -1
  81. package/src/headless-host/role-turn-host.ts +7 -1
  82. package/src/host-contracts.ts +10 -6
  83. package/src/inspector-contracts.ts +0 -1
  84. package/src/inspector-role.ts +0 -2
  85. package/src/institutional-resolution.ts +6 -4
  86. package/src/judge-role.ts +3 -3
  87. package/src/merger-contracts.ts +0 -1
  88. package/src/merger-role.ts +2 -2
  89. package/src/navigator-public-session.ts +7 -6
  90. package/src/navigator-work-context.ts +6 -8
  91. package/src/notary-contracts.ts +0 -1
  92. package/src/notary-role.ts +2 -3
  93. package/src/package-contracts/auditor-output.ts +0 -1
  94. package/src/package-contracts/collector-output.ts +0 -1
  95. package/src/package-contracts/fixer-output.ts +0 -1
  96. package/src/package-contracts/gatekeeper-output.ts +0 -1
  97. package/src/package-contracts/judge-output.ts +0 -1
  98. package/src/package-contracts/navigator-output.ts +0 -1
  99. package/src/package-contracts/reviewer-output.ts +0 -1
  100. package/src/package-contracts/terminating-tools.ts +27 -99
  101. package/src/package-contracts/worker-output.ts +0 -2
  102. package/src/packaged-role-registry.ts +604 -35
  103. package/src/pi/role-turn-host.ts +2 -1
  104. package/src/public-cli/cli.ts +64 -259
  105. package/src/public-cli/config.ts +18 -10
  106. package/src/public-cli/countersign-run.ts +14 -449
  107. package/src/public-cli/instruction-seat-run.ts +758 -277
  108. package/src/public-cli/invocation.ts +1097 -2051
  109. package/src/public-cli/option-definitions.ts +62 -127
  110. package/src/public-cli/post-admission.ts +47 -2
  111. package/src/public-cli/run-lifecycle.ts +303 -613
  112. package/src/public-cli/seat-ticket-binding.ts +6 -0
  113. package/src/public-cli/settlement.ts +399 -1185
  114. package/src/public-cli/turn-request.ts +92 -1
  115. package/src/public-role-summons.ts +44 -128
  116. package/src/reviewer-role.ts +3 -2
  117. package/src/role-activation-flags.ts +20 -41
  118. package/src/role-runtime-dependencies.ts +25 -26
  119. package/src/role-runtime.ts +121 -232
  120. package/src/secretariat-contracts.ts +0 -1
  121. package/src/secretariat-role.ts +0 -2
  122. package/src/session-identity.ts +23 -8
  123. package/src/session-opening-materials.ts +2 -1
  124. package/src/worker-role.ts +3 -4
  125. package/dist/doctor-auditor.js +0 -25
  126. package/dist/public-cli/diarist-run.js +0 -130
  127. package/dist/public-cli/doctor-run.js +0 -87
  128. package/dist/public-cli/inspector-run.js +0 -151
  129. package/dist/public-cli/judge-run.js +0 -114
  130. package/dist/public-cli/notary-run.js +0 -174
  131. package/dist/public-cli/reviewer-run.js +0 -339
  132. package/src/public-cli/coder-run.ts +0 -255
  133. package/src/public-cli/collector-run.ts +0 -189
  134. package/src/public-cli/diarist-run.ts +0 -233
  135. package/src/public-cli/doctor-run.ts +0 -167
  136. package/src/public-cli/fixer-run.ts +0 -265
  137. package/src/public-cli/gleaner-left-run.ts +0 -167
  138. package/src/public-cli/inspector-run.ts +0 -261
  139. package/src/public-cli/judge-run.ts +0 -196
  140. package/src/public-cli/merger-run.ts +0 -294
  141. package/src/public-cli/notary-run.ts +0 -279
  142. package/src/public-cli/reviewer-run.ts +0 -480
  143. package/src/public-cli/secretariat-run.ts +0 -265
@@ -11,8 +11,6 @@ import { readSitianRecords, resolveSitianRecordPath, sitianReport } from "../sit
11
11
  import { hasFreshAttemptSubmission, readAttemptScopedSubmissionRows, readRecordedSubmissionRows, readRecordedSubmissions, } from "../submission-ledger.js";
12
12
  import { isAuditEscalationResult } from "../audit-escalation.js";
13
13
  import { AUDITOR_SOUL_ROLES } from "../auditor-soul.js";
14
- import { DOCTOR_AUDIT_TOOL_NAME } from "../doctor-auditor.js";
15
- import { JUDGE_AUDIT_TOOL_NAME } from "../judge-auditor.js";
16
14
  import { knownFailureFromProviderStop } from "../pi/known-failure.js";
17
15
  import { isV1ResumableProvider, readLatestTypedProviderHttpObservation, readTypedHttp429Observation, } from "./run-lifecycle.js";
18
16
  import { AUDITOR_COMPLIANCE_FAILURE_ENTRY_TYPE, AUDITOR_PARENT_ATTEMPT_BINDING_ENTRY_TYPE, COMPLIANCE_RESPONSE_ENTRY_TYPE, readComplianceCandidate, } from "../compliance-transport.js";
@@ -27,17 +25,9 @@ import { CODER_OUTPUT_TOOL_NAME, FIXER_OUTPUT_TOOL_NAME, } from "../package-cont
27
25
  import { DOCTOR_OUTPUT_TOOL_NAME, } from "../doctor-contracts.js";
28
26
  import { DOCTOR_CANDIDATE_ENTRY_TYPE } from "../dossier-resolution.js";
29
27
  import { REVIEWER_OUTPUT_TOOL_NAME, } from "../package-contracts/reviewer-output.js";
30
- import { MERGER_OUTPUT_TOOL_NAME, } from "../merger-contracts.js";
31
- import { NOTARY_OUTPUT_TOOL_NAME, } from "../notary-contracts.js";
32
- import { COUNTERSIGN_OUTPUT_TOOL_NAME, } from "../countersign-contracts.js";
33
- import { GLEANER_LEFT_OUTPUT_TOOL_NAME, } from "../gleaner-left-contracts.js";
34
- import { DIARIST_OUTPUT_TOOL_NAME, } from "../diarist-contracts.js";
35
- import { SECRETARIAT_COUNTERSIGN_TERMINAL_FACT_KEY, SECRETARIAT_GATE_OFFICER_ENTRY_TYPE, SECRETARIAT_OUTPUT_TOOL_NAME, } from "../secretariat-contracts.js";
36
- import { INSPECTOR_OUTPUT_TOOL_NAME, } from "../inspector-contracts.js";
37
- import { GATEKEEPER_OUTPUT_TOOL_NAME, } from "../package-contracts/gatekeeper-output.js";
38
- import { NAVIGATOR_OUTPUT_TOOL_NAME, } from "../package-contracts/navigator-output.js";
39
- import { AUDITOR_OUTPUT_TOOL_NAME, } from "../package-contracts/auditor-output.js";
40
- import { observePackagedMethodSkillInvocation, } from "../package-resources/method-skill.js";
28
+ import { packagedAuditToolName, packagedDurableOfficerEntry, packagedProjectsTargetBindRejection, packagedRoleAcceptedOutputTool, packagedRoleMetadata, packagedSkipsGateOnInfrastructureStage, } from "../packaged-role-registry.js";
29
+ import { SECRETARIAT_COUNTERSIGN_TERMINAL_FACT_KEY, SECRETARIAT_GATE_OFFICER_ENTRY_TYPE, } from "../secretariat-contracts.js";
30
+ import { observePackagedMethodSkillInvocation, resolvePackagedMethodSkillPath, } from "../package-resources/method-skill.js";
41
31
  import { classifyPackagedRoleTerminalResult, findLatestDurablePackagedRoleTerminal, hasNavigatorInfrastructureFailureBase, isAcceptedPackagedRoleTerminalResult, isReceiptSettlementBindingClear, NAVIGATOR_INVOCATION_ENTRY, parseInvocationMarkerIdentity, } from "../navigator-invocation-identity.js";
42
32
  import { NO_RECEIPT_LIFECYCLE_ENTRY_TYPE, RECEIPT_DELIVERY_TURN_LIMIT, noReceiptLifecycleFacts, parseNoReceiptLifecycleFacts, } from "../receipt-delivery-policy.js";
43
33
  import { roleRunArtifactsDirectory } from "../role-run-placement.js";
@@ -160,9 +150,6 @@ export async function settleHostEndedNoReceipt(admitted, authority, scope) {
160
150
  runId: admitted.runId,
161
151
  }, coordinates.sessionDirectory, detourGateContext(admitted, scope));
162
152
  }
163
- async function closedLedgerOutcome(admitted, role, scope) {
164
- return sealedLedgerOutcome(admitted, role, scope);
165
- }
166
153
  /** Transitional host-session reads remain only for non-sealed failure and audit evidence. */
167
154
  function coordinatesFromAdmitted(authority, admitted) {
168
155
  return authority.decode(admitted.principal);
@@ -1153,13 +1140,52 @@ export function extractEngineDetourInfrastructureFailure(entries) {
1153
1140
  export async function readEngineDetourInfrastructureFailure(sessionFile) {
1154
1141
  return readInfrastructureToolFailure(sessionFile, ENGINE_DETOUR_INFRASTRUCTURE_FAILURE_SPEC);
1155
1142
  }
1143
+ function knownFailureFromControlled(failure) {
1144
+ return {
1145
+ ...(failure.cause === undefined ? {} : { cause: failure.cause }),
1146
+ diagnostic: failure.diagnostic,
1147
+ ...(failure.identity === undefined ? {} : { identity: failure.identity }),
1148
+ };
1149
+ }
1150
+ const RUNNER_FAILURE_POLICY = {
1151
+ "engine-detour-known-first": {
1152
+ read: readEngineDetourInfrastructureFailure,
1153
+ rank: "known-first",
1154
+ },
1155
+ "engine-detour-record-first": {
1156
+ read: readEngineDetourInfrastructureFailure,
1157
+ rank: "record-first",
1158
+ },
1159
+ "collector-known-first": {
1160
+ read: readCollectorInfrastructureFailure,
1161
+ rank: "known-first",
1162
+ },
1163
+ };
1164
+ /**
1165
+ * Runner-failure rank for one seat. The composition-root `runnerFailure`
1166
+ * leaf is the only seat difference; absent means the runner knownFailure stands.
1167
+ */
1168
+ export function seatKnownFailureResolver(role) {
1169
+ const record = packagedRoleMetadata(role);
1170
+ if (record === undefined || !("runnerFailure" in record))
1171
+ return undefined;
1172
+ const policy = RUNNER_FAILURE_POLICY[record.runnerFailure];
1173
+ return async ({ result, sessionFile }) => {
1174
+ const infrastructureFailure = await policy.read(sessionFile);
1175
+ if (policy.rank === "record-first") {
1176
+ return infrastructureFailure === undefined
1177
+ ? result.knownFailure
1178
+ : knownFailureFromControlled(infrastructureFailure);
1179
+ }
1180
+ return result.knownFailure ?? (infrastructureFailure === undefined ? undefined : knownFailureFromControlled(infrastructureFailure));
1181
+ };
1182
+ }
1156
1183
  function auditToolNameForRole(role) {
1157
- switch (role) {
1158
- case "judge":
1159
- return JUDGE_AUDIT_TOOL_NAME;
1160
- case "doctor":
1161
- return DOCTOR_AUDIT_TOOL_NAME;
1184
+ const name = packagedAuditToolName(role);
1185
+ if (name === undefined) {
1186
+ throw new Error(`audit tool is not declared for ${role}`);
1162
1187
  }
1188
+ return name;
1163
1189
  }
1164
1190
  function boundRoleToolCallForResult(entries, resultIndex, message, outputToolName) {
1165
1191
  const callId = message.toolCallId;
@@ -1560,9 +1586,7 @@ async function withOptionalGateProjection(base, sessionDirectory, gateContext =
1560
1586
  : undefined;
1561
1587
  const skipGate = isRecord(secondaryEvidence)
1562
1588
  && secondaryEvidence.kind === "role_infrastructure_failure"
1563
- && (secondaryEvidence.stage === "gatekeeper"
1564
- || secondaryEvidence.stage === "inspector"
1565
- || secondaryEvidence.stage === "notary");
1589
+ && packagedSkipsGateOnInfrastructureStage(secondaryEvidence.stage);
1566
1590
  let next = base;
1567
1591
  if (!skipGate) {
1568
1592
  // Defaults live solely in extractGateFactFromSessionDirectory — do not re-derive.
@@ -1744,48 +1768,9 @@ async function publishAcceptedTerminalArtifacts(admitted, roleOutcome, coordinat
1744
1768
  { kind: "evidence", path: evidencePath },
1745
1769
  ];
1746
1770
  }
1747
- export async function publishJudgeArtifacts(admitted, roleOutcome, coordinates) {
1748
- return publishAcceptedTerminalArtifacts(admitted, roleOutcome, coordinates, {
1749
- report: {
1750
- role: "judge",
1751
- runId: admitted.runId,
1752
- outcome: roleOutcome,
1753
- },
1754
- evidence: {
1755
- runId: admitted.runId,
1756
- sessionDirectory: coordinates.sessionDirectory,
1757
- sessionFile: coordinates.sessionFile,
1758
- admittedRequestPath: admitted.admittedRequestPath,
1759
- attachments: acceptedArtifactAttachmentRefs(admitted.attachments),
1760
- },
1761
- });
1762
- }
1763
- /**
1764
- * Publish lawful Coder success Artifacts on the shared #106 success interface.
1765
- * Evidence records package method provenance without ambient home Skill paths.
1766
- */
1767
- export async function publishCoderArtifacts(admitted, roleOutcome, coordinates, options = {}) {
1768
- return publishAcceptedTerminalArtifacts(admitted, roleOutcome, coordinates, {
1769
- report: {
1770
- role: "coder",
1771
- runId: admitted.runId,
1772
- phase: admitted.phase,
1773
- outcome: roleOutcome,
1774
- },
1775
- evidence: {
1776
- runId: admitted.runId,
1777
- role: "coder",
1778
- phase: admitted.phase,
1779
- sessionDirectory: coordinates.sessionDirectory,
1780
- sessionFile: coordinates.sessionFile,
1781
- admittedRequestPath: admitted.admittedRequestPath,
1782
- taskPath: admitted.taskPath,
1783
- attachments: acceptedArtifactAttachmentRefs(admitted.attachments),
1784
- ...(options.methodProvenance === undefined
1785
- ? {}
1786
- : { methodProvenance: options.methodProvenance }),
1787
- },
1788
- });
1771
+ /** Publish one accepted seat's report/evidence face from the shared leaf table. */
1772
+ export async function publishSeatAcceptedArtifacts(admitted, roleOutcome, coordinates, entries = [], options = {}) {
1773
+ return publishDeclaredSeatArtifacts(admitted, roleOutcome, coordinates, entries, options);
1789
1774
  }
1790
1775
  /**
1791
1776
  * Read session entries for lawful settlement. Missing path → undefined (absence).
@@ -1807,85 +1792,105 @@ async function readLawfulSettlementEntries(sessionFile) {
1807
1792
  }
1808
1793
  }
1809
1794
  /**
1810
- * Lawful Judge outcome presence only — no artifact publication.
1811
- * Returns undefined for genuine absence (missing path / no lawful verdict).
1812
- * Session-read failures propagate with typed identity.
1795
+ * Sealed-ledger seats that publish on a lawful outcome and do not scan a
1796
+ * residual tool or attach run-scoped submission history.
1797
+ * Absence stays undefined. Session-read and publication errors keep their identity.
1798
+ * Outcome is read before publication so a later write error cannot erase it.
1813
1799
  */
1814
- export async function readLawfulJudgeRoleOutcome(admitted, authority, scope) {
1815
- return sealedLedgerOutcome(admitted, "judge", scope);
1816
- }
1817
- /**
1818
- * Single lawful-settlement implementation (session → outcome/Navigator/artifacts).
1819
- *
1820
- * - Returns undefined only for genuine absence (missing session path, or no
1821
- * lawful verdict in an otherwise readable session).
1822
- * - Malformed JSONL / other session-read failures throw with knownCause=session
1823
- * and original identity (SyntaxError name retained).
1824
- * - Artifact publication failures propagate with their original typed identity.
1825
- * - Lawful outcome presence is decided before publication so a later write error
1826
- * cannot erase the fact that a lawful result already exists.
1827
- */
1828
- async function settleLawfulJudgeTerminalResult(admitted, authority, scope) {
1829
- const roleOutcome = await readLawfulJudgeRoleOutcome(admitted, authority, scope);
1800
+ async function settleSealedLedgerTerminal(admitted, authority, scope, publish, accept) {
1801
+ const roleOutcome = await sealedLedgerOutcome(admitted, admitted.role, scope);
1830
1802
  if (roleOutcome === undefined)
1831
1803
  return undefined;
1804
+ if (accept !== undefined && !accept(roleOutcome))
1805
+ return undefined;
1832
1806
  const coordinates = coordinatesFromAdmitted(authority, admitted);
1833
1807
  const entries = await readLawfulSettlementEntries(coordinates.sessionFile) ?? [];
1834
- const navigator = extractNavigatorFact(entries);
1835
- // Lawful outcome exists — artifact publication keeps original errno/name.
1836
- const artifacts = await publishJudgeArtifacts(admitted, roleOutcome, coordinates);
1808
+ const artifacts = await publish(roleOutcome, coordinates, entries);
1837
1809
  return withOptionalGateProjection({
1838
1810
  roleOutcome,
1839
- navigator,
1811
+ navigator: extractNavigatorFact(entries),
1840
1812
  artifacts,
1841
1813
  runId: admitted.runId,
1842
1814
  }, coordinates.sessionDirectory, detourGateContext(admitted, scope));
1843
1815
  }
1844
1816
  /**
1845
- * Settle a lawful typed terminal result from the admitted session.
1846
- * Throws when no lawful outcome is present (tests/callers that require success).
1847
- * Session-read and publication failures retain their typed identity.
1817
+ * Sealed accepted outcome publishes. Any other ledger face falls through to
1818
+ * the latest bound errored tool result in the scan window, which settles as
1819
+ * output failure. Both faces attach run-scoped submissions. Absence of both
1820
+ * stays undefined. Session is read first so a read failure keeps its identity
1821
+ * even when the ledger has no accepted row.
1848
1822
  */
1849
- export async function settleJudgeTerminalResult(admitted, authority, scope) {
1850
- const settled = await settleLawfulJudgeTerminalResult(admitted, authority, scope);
1851
- if (settled === undefined) {
1852
- throw new Error("Judge Role run completed without a lawful typed terminal result");
1823
+ async function settleSealedAcceptedOrToolResidual(admitted, authority, scope, role, residualToolName, scan, publish) {
1824
+ const coordinates = coordinatesFromAdmitted(authority, admitted);
1825
+ const { sessionDirectory, sessionFile } = coordinates;
1826
+ const entries = await readLawfulSettlementEntries(sessionFile) ?? [];
1827
+ const roleOutcome = await sealedLedgerOutcome(admitted, role, scope);
1828
+ if (roleOutcome?.role !== role || roleOutcome.kind !== "accepted") {
1829
+ const scanStart = scan === "current-attempt" ? currentAttemptStartIndex(entries) : 0;
1830
+ for (let index = entries.length - 1; index >= scanStart; index -= 1) {
1831
+ const message = entries[index]?.message;
1832
+ if (message?.role !== "toolResult")
1833
+ continue;
1834
+ const residual = boundErroredToolCandidate(entries, index, message, residualToolName);
1835
+ if (residual === undefined)
1836
+ continue;
1837
+ const candidate = residual.candidate;
1838
+ const details = isRecord(candidate) ? candidate : { candidate };
1839
+ const failed = await settleFailureTerminalResult(admitted, {
1840
+ cause: "output",
1841
+ diagnostic: residual.diagnostic,
1842
+ details,
1843
+ }, authority, scope ?? {});
1844
+ return attachRecordedSubmissions(admitted, failed, scope);
1845
+ }
1846
+ return undefined;
1853
1847
  }
1854
- return settled;
1848
+ const artifacts = await publish(roleOutcome, coordinates, entries);
1849
+ return attachRecordedSubmissions(admitted, await withOptionalGateProjection({
1850
+ roleOutcome,
1851
+ navigator: extractNavigatorFact(entries),
1852
+ artifacts,
1853
+ runId: admitted.runId,
1854
+ }, sessionDirectory, detourGateContext(admitted, scope)), scope);
1855
1855
  }
1856
1856
  /**
1857
- * Try to settle a lawful typed terminal result from the admitted session.
1858
- * Returns undefined only for genuine absence (no lawful verdict / missing path).
1859
- * Session malformation and publication exceptions propagate with typed identity.
1857
+ * One settlement for every registered seat. The registry `settlement` leaf
1858
+ * picks sealed ledger, sealed-or-residual, or the accepted-tool scan.
1859
+ * Seat evidence and the observed-method tail stay on the artifact face.
1860
1860
  */
1861
- export async function trySettleJudgeTerminalResult(admitted, authority, scope) {
1862
- return settleLawfulJudgeTerminalResult(admitted, authority, scope);
1861
+ async function settleSeat(admitted, authority, scope, options) {
1862
+ const record = packagedRoleMetadata(admitted.role);
1863
+ if (record === undefined) {
1864
+ throw new Error(`no settlement for ${admitted.role}`);
1865
+ }
1866
+ if (record.settlement === "accepted") {
1867
+ return trySettleAcceptedSeatTerminalResult(admitted, authority, scope);
1868
+ }
1869
+ const publish = (roleOutcome, coordinates, entries) => publishDeclaredSeatArtifacts(admitted, roleOutcome, coordinates, entries, options);
1870
+ if (record.settlement === "residual") {
1871
+ return settleSealedAcceptedOrToolResidual(admitted, authority, scope, admitted.role, record.residualTool, record.residualScan, publish);
1872
+ }
1873
+ const accept = "sealedAcceptedOnly" in record && record.sealedAcceptedOnly === true
1874
+ ? (roleOutcome) => roleOutcome.role === admitted.role && roleOutcome.kind === "accepted"
1875
+ : undefined;
1876
+ return settleSealedLedgerTerminal(admitted, authority, scope, publish, accept);
1863
1877
  }
1864
- async function settleLawfulCoderTerminalResult(admitted, authority, options = {}, scope) {
1865
- const ledgerOutcome = await closedLedgerOutcome(admitted, "coder", scope);
1866
- if (ledgerOutcome === undefined)
1867
- return undefined;
1868
- const roleOutcome = ledgerOutcome;
1869
- const coordinates = coordinatesFromAdmitted(authority, admitted);
1870
- const entries = await readLawfulSettlementEntries(coordinates.sessionFile) ?? [];
1871
- const navigator = extractNavigatorFact(entries);
1872
- const artifacts = await publishCoderArtifacts(admitted, roleOutcome, coordinates, {
1873
- ...(options.methodProvenance === undefined
1874
- ? {}
1875
- : { methodProvenance: options.methodProvenance }),
1876
- });
1877
- return withOptionalGateProjection({
1878
- roleOutcome,
1879
- navigator,
1880
- artifacts,
1881
- runId: admitted.runId,
1882
- }, coordinates.sessionDirectory, detourGateContext(admitted, scope));
1878
+ /**
1879
+ * Try to settle any registered seat. Undefined only for genuine absence.
1880
+ * Session malformation and publication exceptions keep their typed identity.
1881
+ */
1882
+ export async function trySettleSeatTerminalResult(admitted, authority, options = {}, scope) {
1883
+ return settleSeat(admitted, authority, scope, options);
1883
1884
  }
1884
- /** Settle a lawful Coder Terminal from the admitted session (shared #106 success interface). */
1885
- export async function settleCoderTerminalResult(admitted, authority, options = {}, scope) {
1886
- const settled = await settleLawfulCoderTerminalResult(admitted, authority, options, scope);
1885
+ /**
1886
+ * Settle any registered seat. Throws when no lawful outcome is present.
1887
+ * Session-read and publication failures retain their typed identity.
1888
+ */
1889
+ export async function settleSeatTerminalResult(admitted, authority, options = {}, scope) {
1890
+ const settled = await settleSeat(admitted, authority, scope, options);
1887
1891
  if (settled === undefined) {
1888
- throw new Error("Coder Role run completed without a lawful typed terminal result");
1892
+ const label = admitted.role.charAt(0).toUpperCase() + admitted.role.slice(1);
1893
+ throw new Error(`${label} Role run completed without a lawful typed terminal result`);
1889
1894
  }
1890
1895
  return settled;
1891
1896
  }
@@ -1909,10 +1914,21 @@ function sessionMessageText(message) {
1909
1914
  return parts.join("\n");
1910
1915
  }
1911
1916
  /**
1912
- * Observe optional Fixer diagnosing-bugs Skill expansions from the session.
1913
- * Availability is always package-bound; invocation is recorded only when observed.
1917
+ * Locations a loaded packaged method may be observed at.
1918
+ * The name is the loaded material; the configured path is the package copy.
1914
1919
  */
1915
- export function extractFixerMethodInvocations(entries, options) {
1920
+ export function observedMethodSkillOptions(packageRoot, material) {
1921
+ return {
1922
+ methodProvenance: material.provenance,
1923
+ methodSkillPath: material.skillPath,
1924
+ methodSkillConfiguredPath: resolvePackagedMethodSkillPath(packageRoot, material.name),
1925
+ };
1926
+ }
1927
+ /**
1928
+ * Observe packaged method Skill expansions from the session.
1929
+ * The skill name is the caller's packaged method; home locations never count.
1930
+ */
1931
+ function extractObservedMethodInvocations(entries, options) {
1916
1932
  const observed = [];
1917
1933
  for (const entry of entries) {
1918
1934
  if (entry?.type !== "message")
@@ -1924,7 +1940,7 @@ export function extractFixerMethodInvocations(entries, options) {
1924
1940
  if (text.length === 0)
1925
1941
  continue;
1926
1942
  const hit = observePackagedMethodSkillInvocation(text, {
1927
- name: "diagnosing-bugs",
1943
+ name: options.name,
1928
1944
  allowedLocations: options.allowedLocations,
1929
1945
  });
1930
1946
  if (hit !== undefined)
@@ -1933,240 +1949,117 @@ export function extractFixerMethodInvocations(entries, options) {
1933
1949
  return Object.freeze(observed);
1934
1950
  }
1935
1951
  /**
1936
- * Publish lawful Fixer success Artifacts on the shared #106 success interface.
1937
- * Evidence records package diagnosis provenance and optional observed invocation.
1952
+ * #836: cost and the auditor's no-receipt facts ride beside the role's
1953
+ * testimony on the current attempt's candidate entry. Absence is omitted,
1954
+ * never invented. Both facts come from that one entry.
1938
1955
  */
1939
- export async function publishFixerArtifacts(admitted, roleOutcome, coordinates, options) {
1940
- return publishAcceptedTerminalArtifacts(admitted, roleOutcome, coordinates, {
1941
- report: {
1942
- role: "fixer",
1943
- runId: admitted.runId,
1944
- phase: admitted.phase,
1945
- outcome: roleOutcome,
1946
- },
1947
- evidence: {
1948
- runId: admitted.runId,
1949
- role: "fixer",
1950
- phase: admitted.phase,
1951
- sessionDirectory: coordinates.sessionDirectory,
1952
- sessionFile: coordinates.sessionFile,
1953
- admittedRequestPath: admitted.admittedRequestPath,
1954
- packetPath: admitted.packetPath,
1955
- ...(admitted.prerequisitesPath === undefined
1956
- ? {}
1957
- : { prerequisitesPath: admitted.prerequisitesPath }),
1958
- prerequisites: admitted.prerequisites,
1959
- attachments: acceptedArtifactAttachmentRefs(admitted.attachments),
1960
- methodProvenance: options.methodProvenance,
1961
- // Optional diagnosis: availability is package-bound; invocation only when observed.
1962
- methodInvocationObserved: (options.methodInvocations ?? []).length > 0,
1963
- methodInvocations: options.methodInvocations ?? [],
1964
- },
1965
- });
1966
- }
1967
- async function settleLawfulFixerTerminalResult(admitted, authority, options, scope) {
1968
- const ledgerOutcome = await closedLedgerOutcome(admitted, "fixer", scope);
1969
- if (ledgerOutcome === undefined)
1970
- return undefined;
1971
- const roleOutcome = ledgerOutcome;
1972
- const coordinates = coordinatesFromAdmitted(authority, admitted);
1973
- const { sessionDirectory, sessionFile } = coordinates;
1974
- const entries = await readLawfulSettlementEntries(sessionFile) ?? [];
1975
- const navigator = extractNavigatorFact(entries);
1976
- const methodInvocations = extractFixerMethodInvocations(entries, {
1977
- allowedLocations: [
1978
- options.methodSkillPath,
1979
- options.methodSkillConfiguredPath,
1980
- ],
1981
- });
1982
- const artifacts = await publishFixerArtifacts(admitted, roleOutcome, coordinates, {
1983
- methodProvenance: options.methodProvenance,
1984
- methodInvocations,
1985
- });
1986
- return withOptionalGateProjection({
1987
- roleOutcome,
1988
- navigator,
1989
- artifacts,
1990
- runId: admitted.runId,
1991
- }, sessionDirectory, detourGateContext(admitted, scope));
1992
- }
1993
- /** Settle a lawful Fixer Terminal from the admitted session (shared #106 success interface). */
1994
- export async function settleFixerTerminalResult(admitted, authority, options, scope) {
1995
- const settled = await settleLawfulFixerTerminalResult(admitted, authority, options, scope);
1996
- if (settled === undefined) {
1997
- throw new Error("Fixer Role run completed without a lawful typed terminal result");
1998
- }
1999
- return settled;
2000
- }
2001
- export async function publishCollectorArtifacts(admitted, roleOutcome, coordinates) {
2002
- return publishAcceptedTerminalArtifacts(admitted, roleOutcome, coordinates, {
2003
- report: {
2004
- role: "collector",
2005
- runId: admitted.runId,
2006
- outcome: roleOutcome,
2007
- },
2008
- evidence: {
2009
- runId: admitted.runId,
2010
- role: "collector",
2011
- ...(admitted.prNumber === undefined ? {} : { prNumber: admitted.prNumber }),
2012
- repository: admitted.repository.canonical,
2013
- manifestDigest: admitted.manifestDigest,
2014
- sessionDirectory: coordinates.sessionDirectory,
2015
- sessionFile: coordinates.sessionFile,
2016
- admittedRequestPath: admitted.admittedRequestPath,
2017
- attachments: acceptedArtifactAttachmentRefs(admitted.attachments),
2018
- },
2019
- });
2020
- }
2021
- async function settleLawfulCollectorTerminalResult(admitted, authority, scope) {
2022
- const coordinates = coordinatesFromAdmitted(authority, admitted);
2023
- const { sessionDirectory, sessionFile } = coordinates;
2024
- const entries = await readLawfulSettlementEntries(sessionFile) ?? [];
2025
- const roleOutcome = await sealedLedgerOutcome(admitted, "collector", scope);
2026
- if (roleOutcome?.role !== "collector" || roleOutcome.kind !== "accepted") {
2027
- // Bounded to the current attempt so multi-attempt resume timeout/no-output
2028
- // is not masked by a prior wait-tool residual (#633).
2029
- const scanStart = currentAttemptStartIndex(entries);
2030
- for (let index = entries.length - 1; index >= scanStart; index -= 1) {
2031
- const message = entries[index]?.message;
2032
- if (message?.role !== "toolResult")
2033
- continue;
2034
- const residual = boundErroredToolCandidate(entries, index, message, COLLECTOR_WAIT_TOOL);
2035
- if (residual === undefined)
2036
- continue;
2037
- const candidate = residual.candidate;
2038
- const details = isRecord(candidate) ? candidate : { candidate };
2039
- const failed = await settleFailureTerminalResult(admitted, {
2040
- cause: "output",
2041
- diagnostic: residual.diagnostic,
2042
- details,
2043
- }, authority, scope ?? {});
2044
- return attachRecordedSubmissions(admitted, failed, scope);
1956
+ function extractDoctorCandidateFacts(entries) {
1957
+ const scanStart = currentAttemptStartIndex(entries);
1958
+ for (let i = entries.length - 1; i >= scanStart; i -= 1) {
1959
+ const entry = entries[i];
1960
+ if (entry?.type !== "custom" || entry.customType !== DOCTOR_CANDIDATE_ENTRY_TYPE) {
1961
+ continue;
2045
1962
  }
2046
- return undefined;
1963
+ const data = entry.data;
1964
+ if (!isRecord(data))
1965
+ return {};
1966
+ return {
1967
+ ...(data.cost === undefined ? {} : { cost: data.cost }),
1968
+ ...(data.auditNoReceipt === undefined ? {} : { auditNoReceipt: data.auditNoReceipt }),
1969
+ };
2047
1970
  }
2048
- const accepted = roleOutcome;
2049
- const navigator = extractNavigatorFact(entries);
2050
- const artifacts = await publishCollectorArtifacts(admitted, accepted, coordinates);
2051
- return attachRecordedSubmissions(admitted, await withOptionalGateProjection({
2052
- roleOutcome: accepted,
2053
- navigator,
2054
- artifacts,
2055
- runId: admitted.runId,
2056
- }, sessionDirectory, detourGateContext(admitted, scope)), scope);
1971
+ return {};
2057
1972
  }
2058
- /** Settle a lawful Collector Terminal from the admitted session. */
2059
- export async function settleCollectorTerminalResult(admitted, authority, scope) {
2060
- const settled = await settleLawfulCollectorTerminalResult(admitted, authority, scope);
2061
- if (settled === undefined) {
2062
- throw new Error("Collector Role run completed without a lawful typed terminal result");
1973
+ const EMPTY_ARTIFACT_FACE = { leaves: [] };
1974
+ /** Artifact face for one seat. Absent means report/evidence carry only shared leaves. */
1975
+ function seatArtifactFace(role) {
1976
+ const record = packagedRoleMetadata(role);
1977
+ if (record !== undefined && "artifactFace" in record && record.artifactFace !== undefined) {
1978
+ return record.artifactFace;
2063
1979
  }
2064
- return settled;
1980
+ return EMPTY_ARTIFACT_FACE;
2065
1981
  }
2066
- /** Try to settle a lawful Collector Terminal; undefined only for genuine absence. */
2067
- export async function trySettleCollectorTerminalResult(admitted, authority, scope) {
2068
- return settleLawfulCollectorTerminalResult(admitted, authority, scope);
1982
+ function readAdmittedPath(source, path) {
1983
+ let current = source;
1984
+ for (const part of path.split(".")) {
1985
+ if (typeof current !== "object" || current === null)
1986
+ return undefined;
1987
+ current = current[part];
1988
+ }
1989
+ return current;
2069
1990
  }
2070
- /**
2071
- * #836: runtime cost is a machine fact recorded beside the role's original
2072
- * testimony (`ak_doctor_audit_candidate` custom entry), never merged into the
2073
- * accepted payload itself. Absence (no candidate entry, or entry without a
2074
- * cost sibling) reads as undefined — never invented.
2075
- */
2076
- function extractDoctorCandidateCostFact(entries) {
2077
- const scanStart = currentAttemptStartIndex(entries);
2078
- for (let i = entries.length - 1; i >= scanStart; i -= 1) {
2079
- const entry = entries[i];
2080
- if (entry?.type === "custom" && entry.customType === DOCTOR_CANDIDATE_ENTRY_TYPE) {
2081
- const data = entry.data;
2082
- return isRecord(data) ? data.cost : undefined;
1991
+ function evidenceLeaves(admitted, leaves) {
1992
+ const evidence = {};
1993
+ for (const leaf of leaves) {
1994
+ if (leaf.callerProvenance === true) {
1995
+ if (!admitted.instructionEmpty)
1996
+ evidence[leaf.key] = admitted.instruction;
1997
+ continue;
2083
1998
  }
1999
+ const value = readAdmittedPath(admitted, leaf.from ?? leaf.key);
2000
+ if (value === undefined && leaf.omitUndefined === true)
2001
+ continue;
2002
+ evidence[leaf.key] = leaf.copyArray === true && Array.isArray(value) ? [...value] : value;
2084
2003
  }
2085
- return undefined;
2004
+ return evidence;
2086
2005
  }
2087
- /**
2088
- * #836: the auditor's own no-receipt lifecycle facts are a machine fact about
2089
- * the audit leg, recorded beside (never merged into) the role's accepted
2090
- * testimony. Absence reads as undefined — never invented.
2091
- */
2092
- function extractDoctorCandidateAuditNoReceiptFact(entries) {
2093
- const scanStart = currentAttemptStartIndex(entries);
2094
- for (let i = entries.length - 1; i >= scanStart; i -= 1) {
2095
- const entry = entries[i];
2096
- if (entry?.type === "custom" && entry.customType === DOCTOR_CANDIDATE_ENTRY_TYPE) {
2097
- const data = entry.data;
2098
- return isRecord(data) ? data.auditNoReceipt : undefined;
2099
- }
2006
+ function doctorReportFacts(face, roleOutcome, entries) {
2007
+ if (face.doctorReportFacts !== true || roleOutcome.kind === "audit_escalation")
2008
+ return {};
2009
+ const facts = extractDoctorCandidateFacts(entries);
2010
+ return {
2011
+ ...(facts.cost === undefined ? {} : { cost: facts.cost }),
2012
+ ...(facts.auditNoReceipt === undefined ? {} : { auditNoReceipt: facts.auditNoReceipt }),
2013
+ };
2014
+ }
2015
+ function observedMethodTail(face, entries, options) {
2016
+ if (face.method === undefined)
2017
+ return {};
2018
+ if (face.method === "optional") {
2019
+ return options.methodProvenance === undefined
2020
+ ? {}
2021
+ : { methodProvenance: options.methodProvenance };
2100
2022
  }
2101
- return undefined;
2023
+ if (options.methodProvenance === undefined
2024
+ || options.methodSkillPath === undefined
2025
+ || options.methodSkillConfiguredPath === undefined) {
2026
+ throw new Error("observed method publication is missing packaged method coordinates");
2027
+ }
2028
+ const methodInvocations = extractObservedMethodInvocations(entries, {
2029
+ name: options.methodProvenance.name,
2030
+ allowedLocations: [options.methodSkillPath, options.methodSkillConfiguredPath],
2031
+ });
2032
+ return {
2033
+ methodProvenance: options.methodProvenance,
2034
+ methodInvocationObserved: methodInvocations.length > 0,
2035
+ methodInvocations,
2036
+ };
2102
2037
  }
2103
- export async function publishDoctorArtifacts(admitted, roleOutcome, coordinates, options = {}) {
2038
+ async function publishDeclaredSeatArtifacts(admitted, roleOutcome, coordinates, entries, options = {}) {
2039
+ const face = seatArtifactFace(admitted.role);
2040
+ const phase = face.reportPhase === true
2041
+ ? { phase: readAdmittedPath(admitted, "phase") }
2042
+ : {};
2104
2043
  return publishAcceptedTerminalArtifacts(admitted, roleOutcome, coordinates, {
2105
2044
  report: {
2106
- role: "doctor",
2045
+ role: admitted.role,
2107
2046
  runId: admitted.runId,
2047
+ ...phase,
2108
2048
  outcome: roleOutcome,
2109
- ...(options.cost === undefined ? {} : { cost: options.cost }),
2110
- ...(options.auditNoReceipt === undefined
2111
- ? {}
2112
- : { auditNoReceipt: options.auditNoReceipt }),
2049
+ ...doctorReportFacts(face, roleOutcome, entries),
2113
2050
  },
2114
2051
  evidence: {
2115
2052
  runId: admitted.runId,
2116
- role: "doctor",
2117
- issueNumber: admitted.issueNumber,
2118
- caseRunsPath: admitted.caseRunsPath,
2119
- caseIdentity: admitted.caseIdentity,
2053
+ ...(face.evidenceRole === true ? { role: admitted.role } : {}),
2054
+ ...evidenceLeaves(admitted, face.leaves),
2120
2055
  sessionDirectory: coordinates.sessionDirectory,
2121
2056
  sessionFile: coordinates.sessionFile,
2122
2057
  admittedRequestPath: admitted.admittedRequestPath,
2123
2058
  attachments: acceptedArtifactAttachmentRefs(admitted.attachments),
2059
+ ...observedMethodTail(face, entries, options),
2124
2060
  },
2125
2061
  });
2126
2062
  }
2127
- async function settleLawfulDoctorTerminalResult(admitted, authority, scope) {
2128
- const sealed = await sealedLedgerOutcome(admitted, "doctor", scope);
2129
- const coordinates = coordinatesFromAdmitted(authority, admitted);
2130
- const { sessionDirectory, sessionFile } = coordinates;
2131
- const entries = await readLawfulSettlementEntries(sessionFile) ?? [];
2132
- if (sealed === undefined)
2133
- return undefined;
2134
- if (sealed.kind === "audit_escalation") {
2135
- const artifacts = await publishDoctorArtifacts(admitted, sealed, coordinates);
2136
- return withOptionalGateProjection({
2137
- roleOutcome: sealed,
2138
- navigator: extractNavigatorFact(entries),
2139
- artifacts,
2140
- runId: admitted.runId,
2141
- }, sessionDirectory, detourGateContext(admitted, scope));
2142
- }
2143
- const roleOutcome = sealed;
2144
- const navigator = extractNavigatorFact(entries);
2145
- const cost = extractDoctorCandidateCostFact(entries);
2146
- const auditNoReceipt = extractDoctorCandidateAuditNoReceiptFact(entries);
2147
- const artifacts = await publishDoctorArtifacts(admitted, roleOutcome, coordinates, {
2148
- ...(cost === undefined ? {} : { cost }),
2149
- ...(auditNoReceipt === undefined ? {} : { auditNoReceipt }),
2150
- });
2151
- return withOptionalGateProjection({
2152
- roleOutcome,
2153
- navigator,
2154
- artifacts,
2155
- runId: admitted.runId,
2156
- }, sessionDirectory, detourGateContext(admitted, scope));
2157
- }
2158
- /** Settle a lawful Doctor Terminal from the admitted session. */
2159
- export async function settleDoctorTerminalResult(admitted, authority, scope) {
2160
- const settled = await settleLawfulDoctorTerminalResult(admitted, authority, scope);
2161
- if (settled === undefined) {
2162
- throw new Error("Doctor Role run completed without a lawful typed terminal result");
2163
- }
2164
- return settled;
2165
- }
2166
- /** Try to settle a lawful Doctor Terminal; undefined only for genuine absence. */
2167
- export async function trySettleDoctorTerminalResult(admitted, authority, scope) {
2168
- return settleLawfulDoctorTerminalResult(admitted, authority, scope);
2169
- }
2170
2063
  /** Latest top-level user message index; 0 when the session has none (initial attempt). */
2171
2064
  function currentAttemptStartIndex(entries) {
2172
2065
  for (let i = entries.length - 1; i >= 0; i -= 1) {
@@ -2177,25 +2070,6 @@ function currentAttemptStartIndex(entries) {
2177
2070
  }
2178
2071
  return 0;
2179
2072
  }
2180
- /**
2181
- * Filed-seat success face via the sole accepted publisher (#953).
2182
- */
2183
- async function publishSeatAcceptedArtifacts(admitted, roleOutcome, coordinates) {
2184
- return publishAcceptedTerminalArtifacts(admitted, roleOutcome, coordinates, {
2185
- report: {
2186
- role: admitted.role,
2187
- runId: admitted.runId,
2188
- outcome: roleOutcome,
2189
- },
2190
- evidence: {
2191
- runId: admitted.runId,
2192
- sessionDirectory: coordinates.sessionDirectory,
2193
- sessionFile: coordinates.sessionFile,
2194
- admittedRequestPath: admitted.admittedRequestPath,
2195
- attachments: acceptedArtifactAttachmentRefs(admitted.attachments),
2196
- },
2197
- });
2198
- }
2199
2073
  async function settleLawfulSeatAcceptedTerminalResult(admitted, authority, spec, scope) {
2200
2074
  const coordinates = coordinatesFromAdmitted(authority, admitted);
2201
2075
  const { sessionDirectory, sessionFile } = coordinates;
@@ -2230,10 +2104,10 @@ async function settleLawfulSeatAcceptedTerminalResult(admitted, authority, spec,
2230
2104
  residual = boundErroredToolCandidate(entries, index, message, spec.toolName);
2231
2105
  }
2232
2106
  }
2233
- const roleOutcome = await closedLedgerOutcome(admitted, spec.role, scope);
2107
+ const roleOutcome = await sealedLedgerOutcome(admitted, spec.role, scope);
2234
2108
  if (roleOutcome !== undefined && (thisAttemptHasSeatSuccess || residual === undefined)) {
2235
2109
  const navigator = extractNavigatorFact(entries);
2236
- const artifacts = await publishSeatAcceptedArtifacts(admitted, roleOutcome, coordinates);
2110
+ const artifacts = await publishDeclaredSeatArtifacts(admitted, roleOutcome, coordinates, entries);
2237
2111
  return withSubmissions(await withOptionalGateProjection({
2238
2112
  roleOutcome,
2239
2113
  navigator,
@@ -2254,70 +2128,36 @@ async function settleLawfulSeatAcceptedTerminalResult(admitted, authority, spec,
2254
2128
  }
2255
2129
  return undefined;
2256
2130
  }
2257
- async function settleLawfulNotaryTerminalResult(admitted, authority, scope) {
2258
- // #757: default sealed pass-through — no projectAccepted identity wrapper.
2259
- return settleLawfulSeatAcceptedTerminalResult(admitted, authority, {
2260
- role: "notary",
2261
- toolName: NOTARY_OUTPUT_TOOL_NAME,
2262
- }, scope);
2263
- }
2264
- /** Settle a lawful Notary Terminal from the admitted session. */
2265
- export async function settleNotaryTerminalResult(admitted, authority, scope) {
2266
- const settled = await settleLawfulNotaryTerminalResult(admitted, authority, scope);
2267
- if (settled === undefined) {
2268
- throw new Error("Notary Role run completed without a lawful typed terminal result");
2131
+ /** Accepted-tool seats: one scan, tool name from the composition-root record. */
2132
+ export async function trySettleAcceptedSeatTerminalResult(admitted, authority, scope) {
2133
+ const toolName = packagedRoleAcceptedOutputTool(admitted.role);
2134
+ if (toolName === undefined) {
2135
+ throw new Error(`accepted-seat settlement is not declared for ${admitted.role}`);
2269
2136
  }
2270
- return settled;
2271
- }
2272
- /** Try to settle a lawful Notary Terminal; undefined only for genuine absence. */
2273
- export async function trySettleNotaryTerminalResult(admitted, authority, scope) {
2274
- return settleLawfulNotaryTerminalResult(admitted, authority, scope);
2275
- }
2276
- async function settleLawfulCountersignTerminalResult(admitted, authority, scope) {
2277
- return settleLawfulSeatAcceptedTerminalResult(admitted, authority, {
2278
- role: "countersign",
2279
- toolName: COUNTERSIGN_OUTPUT_TOOL_NAME,
2280
- }, scope);
2281
- }
2282
- /** Settle a lawful Countersign Terminal from the admitted session. */
2283
- export async function settleCountersignTerminalResult(admitted, authority, scope) {
2284
- const settled = await settleLawfulCountersignTerminalResult(admitted, authority, scope);
2285
- if (settled === undefined) {
2286
- throw new Error("Countersign Role run completed without a lawful typed terminal result");
2287
- }
2288
- return settled;
2289
- }
2290
- /** Try to settle a lawful Countersign Terminal; undefined only for genuine absence. */
2291
- export async function trySettleCountersignTerminalResult(admitted, authority, scope) {
2292
- return settleLawfulCountersignTerminalResult(admitted, authority, scope);
2293
- }
2294
- async function settleLawfulGleanerLeftTerminalResult(admitted, authority, scope) {
2295
- return settleLawfulSeatAcceptedTerminalResult(admitted, authority, {
2296
- role: "gleaner-left",
2297
- toolName: GLEANER_LEFT_OUTPUT_TOOL_NAME,
2137
+ const settled = await settleLawfulSeatAcceptedTerminalResult(admitted, authority, {
2138
+ role: admitted.role,
2139
+ toolName,
2298
2140
  }, scope);
2299
- }
2300
- /** Settle a lawful Gleaner-Left Terminal from the admitted session. */
2301
- export async function settleGleanerLeftTerminalResult(admitted, authority, scope) {
2302
- const settled = await settleLawfulGleanerLeftTerminalResult(admitted, authority, scope);
2303
- if (settled === undefined) {
2304
- throw new Error("Gleaner-Left Role run completed without a lawful typed terminal result");
2141
+ const record = packagedRoleMetadata(admitted.role);
2142
+ if (settled === undefined
2143
+ || record === undefined
2144
+ || !("projectCountersignTerminal" in record)
2145
+ || record.projectCountersignTerminal !== true) {
2146
+ return settled;
2305
2147
  }
2306
- return settled;
2148
+ return applySecretariatCountersignTerminal(admitted, authority, settled);
2307
2149
  }
2308
- /** Try to settle a lawful Gleaner-Left Terminal; undefined only for genuine absence. */
2309
- export async function trySettleGleanerLeftTerminalResult(admitted, authority, scope) {
2310
- return settleLawfulGleanerLeftTerminalResult(admitted, authority, scope);
2311
- }
2312
- async function settleLawfulDiaristTerminalResult(admitted, authority, scope) {
2313
- return settleLawfulSeatAcceptedTerminalResult(admitted, authority, {
2314
- role: "diarist",
2315
- toolName: DIARIST_OUTPUT_TOOL_NAME,
2316
- }, scope);
2317
- }
2318
- /** Try to settle a lawful Diarist Terminal; undefined only for genuine absence. */
2319
- export async function trySettleDiaristTerminalResult(admitted, authority, scope) {
2320
- return settleLawfulDiaristTerminalResult(admitted, authority, scope);
2150
+ /** One settlement dispatch. The registry `settlement` leaf selects the path. */
2151
+ export async function trySettlePublicSeat(admitted, authority, scope, material, packageRoot) {
2152
+ const face = seatArtifactFace(admitted.role);
2153
+ if (face.method === "observed" && material === undefined)
2154
+ return undefined;
2155
+ const options = face.method === "observed" && material !== undefined
2156
+ ? observedMethodSkillOptions(packageRoot, material)
2157
+ : face.method === "optional" && material !== undefined
2158
+ ? { methodProvenance: material.provenance }
2159
+ : {};
2160
+ return settleSeat(admitted, authority, scope, options);
2321
2161
  }
2322
2162
  /**
2323
2163
  * #969 seat projection sole authority: 给事中 terminal (署|上呈) booked as a
@@ -2337,7 +2177,7 @@ function countersignTerminalFromEntries(entries) {
2337
2177
  const data = entry.data !== null && typeof entry.data === "object" && !Array.isArray(entry.data)
2338
2178
  ? entry.data
2339
2179
  : undefined;
2340
- if (data?.officer !== "countersign")
2180
+ if (data === undefined || !packagedDurableOfficerEntry(data.officer))
2341
2181
  continue;
2342
2182
  if (data.receipt === undefined)
2343
2183
  continue;
@@ -2382,13 +2222,7 @@ function acceptedSecretariatDefinesOfficerProjection(roleOutcome) {
2382
2222
  }
2383
2223
  return false;
2384
2224
  }
2385
- async function settleLawfulSecretariatTerminalResult(admitted, authority, scope) {
2386
- const settled = await settleLawfulSeatAcceptedTerminalResult(admitted, authority, {
2387
- role: "secretariat",
2388
- toolName: SECRETARIAT_OUTPUT_TOOL_NAME,
2389
- }, scope);
2390
- if (settled === undefined)
2391
- return undefined;
2225
+ async function applySecretariatCountersignTerminal(admitted, authority, settled) {
2392
2226
  const coordinates = coordinatesFromAdmitted(authority, admitted);
2393
2227
  const entries = await readLawfulSettlementEntries(coordinates.sessionFile) ?? [];
2394
2228
  const officer = countersignTerminalFromEntries(entries);
@@ -2418,254 +2252,6 @@ async function settleLawfulSecretariatTerminalResult(admitted, authority, scope)
2418
2252
  }
2419
2253
  return settled;
2420
2254
  }
2421
- /** Try to settle a lawful Secretariat Terminal; undefined only for genuine absence. */
2422
- export async function trySettleSecretariatTerminalResult(admitted, authority, scope) {
2423
- return settleLawfulSecretariatTerminalResult(admitted, authority, scope);
2424
- }
2425
- async function settleLawfulInspectorTerminalResult(admitted, authority, scope) {
2426
- return settleLawfulSeatAcceptedTerminalResult(admitted, authority, {
2427
- role: "inspector",
2428
- toolName: INSPECTOR_OUTPUT_TOOL_NAME,
2429
- }, scope);
2430
- }
2431
- export async function trySettleInspectorTerminalResult(admitted, authority, scope) {
2432
- return settleLawfulInspectorTerminalResult(admitted, authority, scope);
2433
- }
2434
- async function settleLawfulGatekeeperTerminalResult(admitted, authority, scope) {
2435
- return settleLawfulSeatAcceptedTerminalResult(admitted, authority, {
2436
- role: "gatekeeper",
2437
- toolName: GATEKEEPER_OUTPUT_TOOL_NAME,
2438
- }, scope);
2439
- }
2440
- /** Try to settle a lawful Gatekeeper Terminal; undefined only for genuine absence. */
2441
- export async function trySettleGatekeeperTerminalResult(admitted, authority, scope) {
2442
- return settleLawfulGatekeeperTerminalResult(admitted, authority, scope);
2443
- }
2444
- async function settleLawfulNavigatorTerminalResult(admitted, authority, scope) {
2445
- return settleLawfulSeatAcceptedTerminalResult(admitted, authority, {
2446
- role: "navigator",
2447
- toolName: NAVIGATOR_OUTPUT_TOOL_NAME,
2448
- }, scope);
2449
- }
2450
- /** Try to settle a lawful Navigator Terminal; undefined only for genuine absence. */
2451
- export async function trySettleNavigatorTerminalResult(admitted, authority, scope) {
2452
- return settleLawfulNavigatorTerminalResult(admitted, authority, scope);
2453
- }
2454
- async function settleLawfulAuditorTerminalResult(admitted, authority, scope) {
2455
- return settleLawfulSeatAcceptedTerminalResult(admitted, authority, {
2456
- role: "auditor",
2457
- toolName: AUDITOR_OUTPUT_TOOL_NAME,
2458
- }, scope);
2459
- }
2460
- export async function trySettleAuditorTerminalResult(admitted, authority, scope) {
2461
- return settleLawfulAuditorTerminalResult(admitted, authority, scope);
2462
- }
2463
- /** Try to settle a lawful Coder Terminal; undefined only for genuine absence. */
2464
- export async function trySettleCoderTerminalResult(admitted, authority, options = {}, scope) {
2465
- return settleLawfulCoderTerminalResult(admitted, authority, options, scope);
2466
- }
2467
- /** Try to settle a lawful Fixer Terminal; undefined only for genuine absence. */
2468
- export async function trySettleFixerTerminalResult(admitted, authority, options, scope) {
2469
- return settleLawfulFixerTerminalResult(admitted, authority, options, scope);
2470
- }
2471
- /**
2472
- * Observe forced Reviewer ak-cross-m-review Skill expansions from the session.
2473
- * Expansion evidence is package-path only; ambient home locations never count.
2474
- */
2475
- export function extractReviewerMethodInvocations(entries, options) {
2476
- const observed = [];
2477
- for (const entry of entries) {
2478
- if (entry?.type !== "message")
2479
- continue;
2480
- const message = entry.message;
2481
- if (message?.role !== "user")
2482
- continue;
2483
- const text = sessionMessageText(message);
2484
- if (text.length === 0)
2485
- continue;
2486
- const hit = observePackagedMethodSkillInvocation(text, {
2487
- name: "ak-cross-m-review",
2488
- allowedLocations: options.allowedLocations,
2489
- });
2490
- if (hit !== undefined)
2491
- observed.push(hit);
2492
- }
2493
- return Object.freeze(observed);
2494
- }
2495
- /**
2496
- * Publish lawful Reviewer success Artifacts on the shared #106 success interface.
2497
- * Evidence records package ak-cross-m-review provenance and typed expansion
2498
- * observation without ambient home Skill paths.
2499
- */
2500
- export async function publishReviewerArtifacts(admitted, roleOutcome, coordinates, options) {
2501
- return publishAcceptedTerminalArtifacts(admitted, roleOutcome, coordinates, {
2502
- report: {
2503
- role: "reviewer",
2504
- runId: admitted.runId,
2505
- outcome: roleOutcome,
2506
- },
2507
- evidence: {
2508
- runId: admitted.runId,
2509
- role: "reviewer",
2510
- sessionDirectory: coordinates.sessionDirectory,
2511
- sessionFile: coordinates.sessionFile,
2512
- admittedRequestPath: admitted.admittedRequestPath,
2513
- baseRevision: admitted.baseRevision,
2514
- lens: admitted.lens,
2515
- authorityRefs: [...admitted.authorityRefs],
2516
- ...(admitted.instructionEmpty
2517
- ? {}
2518
- : { callerProvenance: admitted.instruction }),
2519
- attachments: acceptedArtifactAttachmentRefs(admitted.attachments),
2520
- methodProvenance: options.methodProvenance,
2521
- // Forced package method: availability is package-bound; expansion only when observed.
2522
- methodInvocationObserved: (options.methodInvocations ?? []).length > 0,
2523
- methodInvocations: options.methodInvocations ?? [],
2524
- },
2525
- });
2526
- }
2527
- async function settleLawfulReviewerTerminalResult(admitted, authority, options, scope) {
2528
- const sealed = await sealedLedgerOutcome(admitted, "reviewer", scope);
2529
- if (sealed?.role !== "reviewer" || sealed.kind !== "accepted")
2530
- return undefined;
2531
- const coordinates = coordinatesFromAdmitted(authority, admitted);
2532
- const { sessionDirectory, sessionFile } = coordinates;
2533
- const entries = await readLawfulSettlementEntries(sessionFile) ?? [];
2534
- const roleOutcome = sealed;
2535
- const navigator = extractNavigatorFact(entries);
2536
- const methodInvocations = extractReviewerMethodInvocations(entries, {
2537
- allowedLocations: [
2538
- options.methodSkillPath,
2539
- options.methodSkillConfiguredPath,
2540
- ],
2541
- });
2542
- const artifacts = await publishReviewerArtifacts(admitted, roleOutcome, coordinates, {
2543
- methodProvenance: options.methodProvenance,
2544
- methodInvocations,
2545
- });
2546
- return withOptionalGateProjection({
2547
- roleOutcome,
2548
- navigator,
2549
- artifacts,
2550
- runId: admitted.runId,
2551
- }, sessionDirectory, detourGateContext(admitted, scope));
2552
- }
2553
- /** Settle a lawful Reviewer Terminal from the admitted session (shared #106 success interface). */
2554
- export async function settleReviewerTerminalResult(admitted, authority, options, scope) {
2555
- const settled = await settleLawfulReviewerTerminalResult(admitted, authority, options, scope);
2556
- if (settled === undefined) {
2557
- throw new Error("Reviewer Role run completed without a lawful typed terminal result");
2558
- }
2559
- return settled;
2560
- }
2561
- /** Try to settle a lawful Reviewer Terminal; undefined only for genuine absence. */
2562
- export async function trySettleReviewerTerminalResult(admitted, authority, options, scope) {
2563
- return settleLawfulReviewerTerminalResult(admitted, authority, options, scope);
2564
- }
2565
- /**
2566
- * Observe forced Merger resolving-merge-conflicts Skill expansions from the session.
2567
- * Expansion evidence is package-path only; ambient home locations never count.
2568
- */
2569
- export function extractMergerMethodInvocations(entries, options) {
2570
- const observed = [];
2571
- for (const entry of entries) {
2572
- if (entry?.type !== "message")
2573
- continue;
2574
- const message = entry.message;
2575
- if (message?.role !== "user")
2576
- continue;
2577
- const text = sessionMessageText(message);
2578
- if (text.length === 0)
2579
- continue;
2580
- const hit = observePackagedMethodSkillInvocation(text, {
2581
- name: "resolving-merge-conflicts",
2582
- allowedLocations: options.allowedLocations,
2583
- });
2584
- if (hit !== undefined)
2585
- observed.push(hit);
2586
- }
2587
- return Object.freeze(observed);
2588
- }
2589
- /**
2590
- * Publish lawful Merger success Artifacts on the shared #106 success interface.
2591
- * Evidence records package method provenance, forced expansion observation, and
2592
- * adapter-derived mechanical envelope facts without ambient home Skill paths.
2593
- */
2594
- export async function publishMergerArtifacts(admitted, roleOutcome, coordinates, options) {
2595
- return publishAcceptedTerminalArtifacts(admitted, roleOutcome, coordinates, {
2596
- report: {
2597
- role: "merger",
2598
- runId: admitted.runId,
2599
- outcome: roleOutcome,
2600
- },
2601
- evidence: {
2602
- runId: admitted.runId,
2603
- role: "merger",
2604
- sessionDirectory: coordinates.sessionDirectory,
2605
- sessionFile: coordinates.sessionFile,
2606
- admittedRequestPath: admitted.admittedRequestPath,
2607
- mergerInputPath: admitted.mergerInputPath,
2608
- derived: admitted.derived,
2609
- attachments: acceptedArtifactAttachmentRefs(admitted.attachments),
2610
- methodProvenance: options.methodProvenance,
2611
- methodInvocationObserved: (options.methodInvocations ?? []).length > 0,
2612
- methodInvocations: options.methodInvocations ?? [],
2613
- },
2614
- });
2615
- }
2616
- async function settleLawfulMergerTerminalResult(admitted, authority, options, scope) {
2617
- const coordinates = coordinatesFromAdmitted(authority, admitted);
2618
- const { sessionDirectory, sessionFile } = coordinates;
2619
- const entries = await readLawfulSettlementEntries(sessionFile) ?? [];
2620
- const roleOutcome = await sealedLedgerOutcome(admitted, "merger", scope);
2621
- if (roleOutcome?.role !== "merger" || roleOutcome.kind !== "accepted") {
2622
- // #836: non-sole-round barrier deleted; residual path is host/session only.
2623
- for (let index = entries.length - 1; index >= 0; index -= 1) {
2624
- const message = entries[index]?.message;
2625
- if (message?.role !== "toolResult")
2626
- continue;
2627
- const residual = boundErroredToolCandidate(entries, index, message, MERGER_OUTPUT_TOOL_NAME);
2628
- if (residual === undefined)
2629
- continue;
2630
- const candidate = residual.candidate;
2631
- const details = isRecord(candidate) ? candidate : { candidate };
2632
- const failed = await settleFailureTerminalResult(admitted, {
2633
- cause: "output",
2634
- diagnostic: residual.diagnostic,
2635
- details,
2636
- }, authority, scope ?? {});
2637
- return attachRecordedSubmissions(admitted, failed, scope);
2638
- }
2639
- return undefined;
2640
- }
2641
- const accepted = roleOutcome;
2642
- const navigator = extractNavigatorFact(entries);
2643
- const methodInvocations = extractMergerMethodInvocations(entries, {
2644
- allowedLocations: [options.methodSkillPath, options.methodSkillConfiguredPath],
2645
- });
2646
- const artifacts = await publishMergerArtifacts(admitted, accepted, coordinates, {
2647
- methodProvenance: options.methodProvenance,
2648
- methodInvocations,
2649
- });
2650
- return attachRecordedSubmissions(admitted, await withOptionalGateProjection({
2651
- roleOutcome: accepted,
2652
- navigator,
2653
- artifacts,
2654
- runId: admitted.runId,
2655
- }, sessionDirectory, detourGateContext(admitted, scope)), scope);
2656
- }
2657
- /** Settle a lawful Merger Terminal from the admitted session (shared #106 success interface). */
2658
- export async function settleMergerTerminalResult(admitted, authority, options, scope) {
2659
- const settled = await settleLawfulMergerTerminalResult(admitted, authority, options, scope);
2660
- if (settled === undefined) {
2661
- throw new Error("Merger Role run completed without a lawful typed terminal result");
2662
- }
2663
- return settled;
2664
- }
2665
- /** Try to settle a lawful Merger Terminal; undefined only for genuine absence. */
2666
- export async function trySettleMergerTerminalResult(admitted, authority, options, scope) {
2667
- return settleLawfulMergerTerminalResult(admitted, authority, options, scope);
2668
- }
2669
2255
  function publicationAttemptFromError(path, error) {
2670
2256
  if (error instanceof Error) {
2671
2257
  const identity = {
@@ -2871,7 +2457,7 @@ export async function settleFailureTerminalResult(admitted, failure, authority,
2871
2457
  facts.attemptPointer === `current:${admitted.runDirectory}`) {
2872
2458
  let decisiveFacts = facts;
2873
2459
  // #676 D1/J3: project durable bind-target rejection onto public no_receipt facts.
2874
- if (admitted.role === "collector") {
2460
+ if (packagedProjectsTargetBindRejection(admitted.role)) {
2875
2461
  const bindRejection = extractCollectorTargetBindRejection(entries.slice(attemptStart));
2876
2462
  if (bindRejection !== undefined) {
2877
2463
  decisiveFacts = {