@akagilnc/pi-workflow-roles 0.1.3644 → 0.1.3652

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 (92) hide show
  1. package/dist/acp-host/production-host.js +3089 -2187
  2. package/dist/activation-ledger-session.js +105 -0
  3. package/dist/activation-ledger.js +139 -0
  4. package/dist/activation-trace.js +33 -0
  5. package/dist/agent-start-materials.js +11 -0
  6. package/dist/audit-escalation.js +5 -5
  7. package/dist/auditor-role.js +12 -0
  8. package/dist/canonical-skill-binding.js +64 -0
  9. package/dist/collector-identity.js +151 -0
  10. package/dist/collector-receipt.js +95 -0
  11. package/dist/collector-role.js +441 -0
  12. package/dist/compliance-transport.js +11 -57
  13. package/dist/countersign-role.js +28 -0
  14. package/dist/diarist-contracts.js +0 -12
  15. package/dist/diarist-role.js +29 -0
  16. package/dist/doctor-contracts.js +0 -2
  17. package/dist/doctor-role.js +74 -0
  18. package/dist/fixer-bash-seatbelt.js +13 -0
  19. package/dist/gatekeeper-pass-envelope.js +72 -0
  20. package/dist/gleaner-left-contracts.js +0 -7
  21. package/dist/gleaner-left-role.js +26 -0
  22. package/dist/inspector-contracts.js +0 -4
  23. package/dist/inspector-role.js +29 -0
  24. package/dist/judge-role.js +106 -0
  25. package/dist/merger-role.js +66 -0
  26. package/dist/navigator-public-session.js +1 -5
  27. package/dist/navigator-role.js +12 -0
  28. package/dist/notary-contracts.js +0 -18
  29. package/dist/notary-role.js +137 -0
  30. package/dist/oauth-keepalive.js +158 -0
  31. package/dist/package-contracts/auditor-output.js +0 -13
  32. package/dist/package-contracts/gatekeeper-output.js +0 -10
  33. package/dist/package-contracts/judge-output.js +0 -2
  34. package/dist/package-contracts/navigator-output.js +0 -4
  35. package/dist/package-contracts/terminating-tools.js +2 -16
  36. package/dist/packaged-role-registry.js +1 -18
  37. package/dist/pi/adapter.js +211 -0
  38. package/dist/pi/role-turn-host.js +0 -2
  39. package/dist/public-cli/instruction-seat-run.js +2 -6
  40. package/dist/public-cli/invocation.js +0 -7
  41. package/dist/public-cli/main.js +138 -735
  42. package/dist/public-cli/option-definitions.js +0 -14
  43. package/dist/public-cli/registry.js +1 -2
  44. package/dist/public-cli/run-lifecycle.js +1 -3
  45. package/dist/public-cli/settlement.js +66 -537
  46. package/dist/public-role-summons.js +0 -14
  47. package/dist/reviewer-child-executor.js +163 -70
  48. package/dist/reviewer-construction.js +2 -2
  49. package/dist/reviewer-role.js +159 -0
  50. package/dist/reviewer-settlement.js +66 -0
  51. package/dist/role-runtime.js +1394 -0
  52. package/dist/stderr-jsonl.js +26 -0
  53. package/dist/tool-execution-observation.js +141 -0
  54. package/dist/worker-role.js +343 -0
  55. package/dist/worker-submission-gates.js +305 -0
  56. package/extensions/role-runtime.ts +1 -2
  57. package/package.json +1 -1
  58. package/src/acp-host/production-host.ts +0 -1
  59. package/src/audit-escalation.ts +9 -9
  60. package/src/compliance-transport.ts +28 -94
  61. package/src/diarist-contracts.ts +0 -12
  62. package/src/doctor-contracts.ts +0 -1
  63. package/src/doctor-role.ts +2 -2
  64. package/src/gleaner-left-contracts.ts +0 -9
  65. package/src/host-contracts.ts +0 -2
  66. package/src/inspector-contracts.ts +0 -8
  67. package/src/judge-role.ts +4 -5
  68. package/src/navigator-public-session.ts +4 -5
  69. package/src/notary-contracts.ts +0 -18
  70. package/src/package-contracts/auditor-output.ts +0 -11
  71. package/src/package-contracts/gatekeeper-output.ts +0 -11
  72. package/src/package-contracts/judge-output.ts +0 -1
  73. package/src/package-contracts/navigator-output.ts +0 -3
  74. package/src/package-contracts/terminating-tools.ts +1 -19
  75. package/src/packaged-role-registry.ts +1 -19
  76. package/src/pi/role-turn-host.ts +0 -2
  77. package/src/public-cli/cli.ts +1 -5
  78. package/src/public-cli/instruction-seat-run.ts +5 -14
  79. package/src/public-cli/invocation.ts +3 -21
  80. package/src/public-cli/option-definitions.ts +0 -16
  81. package/src/public-cli/registry.ts +1 -2
  82. package/src/public-cli/run-lifecycle.ts +0 -6
  83. package/src/public-cli/settlement.ts +58 -572
  84. package/src/public-cli/terminal.ts +0 -1
  85. package/src/public-role-summons.ts +0 -15
  86. package/src/reviewer-child-executor.ts +199 -98
  87. package/src/reviewer-construction.ts +3 -3
  88. package/src/role-runtime.ts +1 -33
  89. package/dist/package-contracts/evidence-child-output.js +0 -34
  90. package/souls/evidence-child.md +0 -1
  91. package/src/evidence-child-role.ts +0 -22
  92. package/src/package-contracts/evidence-child-output.ts +0 -51
@@ -13,7 +13,6 @@ import { isAuditEscalationResult } from "../audit-escalation.js";
13
13
  import { AUDITOR_SOUL_ROLES } from "../auditor-soul.js";
14
14
  import { DOCTOR_AUDIT_TOOL_NAME } from "../doctor-auditor.js";
15
15
  import { JUDGE_AUDIT_TOOL_NAME } from "../judge-auditor.js";
16
- import { stampShapeUnreadableDetails } from "../shape-unreadable-failure.js";
17
16
  import { knownFailureFromProviderStop } from "../pi/known-failure.js";
18
17
  import { readReviewerDispatchRejection } from "./reviewer-dispatch-rejection.js";
19
18
  import { RESUME_TRANSPORT_ENVELOPE, isV1ResumableProvider, readLatestTypedProviderHttpObservation, readTypedHttp429Observation, } from "./run-lifecycle.js";
@@ -23,21 +22,20 @@ import { AUDITOR_COMPLIANCE_FAILURE_ENTRY_TYPE, AUDITOR_PARENT_ATTEMPT_BINDING_E
23
22
  import { COLLECTOR_OBSERVE_TOOL, COLLECTOR_READ_TOOL, COLLECTOR_REQUEST_TOOL, COLLECTOR_WAIT_TOOL, } from "../collector-ledger.js";
24
23
  import { ENGINE_DETOUR_TOOL_NAME } from "../engine-detour.js";
25
24
  import { JUDGE_OUTPUT_TOOL_NAME, } from "../package-contracts/judge-output.js";
26
- import { COLLECTOR_OUTPUT_TOOL, validateAcceptedCollectorReceipt, } from "../package-contracts/collector-output.js";
27
- import { CODER_OUTPUT_TOOL_NAME, FIXER_OUTPUT_TOOL_NAME, validateAcceptedCoderDetails, validateFixerOutput, } from "../package-contracts/worker-output.js";
25
+ import { COLLECTOR_OUTPUT_TOOL, } from "../package-contracts/collector-output.js";
26
+ import { CODER_OUTPUT_TOOL_NAME, FIXER_OUTPUT_TOOL_NAME, } from "../package-contracts/worker-output.js";
28
27
  import { validateAcceptedDetails } from "../package-contracts/terminating-tools.js";
29
- import { DOCTOR_OUTPUT_TOOL_NAME, validateRecordedDoctorOutput, } from "../doctor-contracts.js";
30
- import { REVIEWER_OUTPUT_TOOL_NAME, validateRuntimeReviewerReceipt, } from "../package-contracts/reviewer-output.js";
31
- import { MERGER_OUTPUT_TOOL_NAME, validateMergerOutput, } from "../merger-contracts.js";
32
- import { NOTARY_OUTPUT_TOOL_NAME, notaryDecisiveFacts, validateRecordedNotaryOutput, } from "../notary-contracts.js";
33
- import { COUNTERSIGN_OUTPUT_TOOL_NAME, validateRecordedCountersignOutput, } from "../countersign-contracts.js";
34
- import { GLEANER_LEFT_OUTPUT_TOOL_NAME, gleanerLeftDecisiveFacts, validateRecordedGleanerLeftOutput, } from "../gleaner-left-contracts.js";
35
- import { DIARIST_OUTPUT_TOOL_NAME, diaristDecisiveFacts, validateRecordedDiaristOutput, } from "../diarist-contracts.js";
36
- import { INSPECTOR_OUTPUT_TOOL_NAME, inspectorDecisiveFacts, validateRecordedInspectorOutput, } from "../inspector-contracts.js";
37
- import { GATEKEEPER_OUTPUT_TOOL_NAME, gatekeeperDecisiveFacts, validateRecordedGatekeeperOutput, } from "../package-contracts/gatekeeper-output.js";
38
- import { NAVIGATOR_OUTPUT_TOOL_NAME, navigatorDecisiveFacts, validateRecordedNavigatorOutput, } from "../package-contracts/navigator-output.js";
39
- import { AUDITOR_OUTPUT_TOOL_NAME, auditorDecisiveFacts, projectLawfulAuditorOutput, validateRecordedAuditorOutput, } from "../package-contracts/auditor-output.js";
40
- import { EVIDENCE_CHILD_OUTPUT_TOOL_NAME, evidenceChildDecisiveFacts, validateRecordedEvidenceChildOutput, } from "../package-contracts/evidence-child-output.js";
28
+ import { DOCTOR_OUTPUT_TOOL_NAME, } from "../doctor-contracts.js";
29
+ 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 { INSPECTOR_OUTPUT_TOOL_NAME, } from "../inspector-contracts.js";
36
+ import { GATEKEEPER_OUTPUT_TOOL_NAME, } from "../package-contracts/gatekeeper-output.js";
37
+ import { NAVIGATOR_OUTPUT_TOOL_NAME, } from "../package-contracts/navigator-output.js";
38
+ import { AUDITOR_OUTPUT_TOOL_NAME, } from "../package-contracts/auditor-output.js";
41
39
  import { observePackagedMethodSkillInvocation, } from "../package-resources/method-skill.js";
42
40
  import { classifyPackagedRoleTerminalResult, findLatestDurablePackagedRoleTerminal, hasNavigatorInfrastructureFailureBase, isAcceptedPackagedRoleTerminalResult, isReceiptSettlementBindingClear, NAVIGATOR_INVOCATION_ENTRY, parseInvocationMarkerIdentity, } from "../navigator-invocation-identity.js";
43
41
  import { NO_RECEIPT_LIFECYCLE_ENTRY_TYPE, parseNoReceiptLifecycleFacts } from "../receipt-delivery-policy.js";
@@ -843,7 +841,7 @@ function typedFailedTerminatingToolKnownFailure(entries) {
843
841
  // Durable details already carry fact + typed evidence from envelope one-shot projection (#475).
844
842
  // Do not re-parse retained compliance responses here.
845
843
  // Host infrastructure must NOT map to cause=output — that cause is reserved for
846
- // shape-unreadable retained candidates (ADR 0055 / #675 producer→consumer diversion).
844
+ // role-output failures (isError residual / no sealed receipt), not host infra.
847
845
  const details = isRecord(message.details) ? message.details : classification.fact;
848
846
  return {
849
847
  cause: "activation",
@@ -1058,304 +1056,12 @@ function auditNoReceiptDecisiveFact(candidate) {
1058
1056
  return {};
1059
1057
  }
1060
1058
  }
1061
- /** Typed unreadable audit leg beside accepted parent candidate (ADR 0055 / #675). */
1062
- function auditUnreadableDecisiveFact(candidate) {
1063
- const projected = safelyRead(candidate, "auditUnreadable");
1064
- if (!projected.readable || projected.value === undefined)
1065
- return {};
1066
- if (typeof projected.value !== "object" || projected.value === null || Array.isArray(projected.value)) {
1067
- return { auditUnreadable: projected.value };
1068
- }
1069
- return { auditUnreadable: projected.value };
1070
- }
1071
- /** Countersign terminal projection — escalate keeps decisionGate; continue keeps fix (#572 / ADR 0074). */
1072
- function countersignDecisiveFacts(verdict, countersignStatus) {
1073
- const facts = { countersignStatus };
1074
- if (countersignStatus === "continue") {
1075
- const fix = safelyRead(verdict, "fix");
1076
- if (fix.readable && isRecord(fix.value)) {
1077
- const summary = safelyRead(fix.value, "summary");
1078
- if (summary.readable && typeof summary.value === "string") {
1079
- facts.fixSummary = summary.value;
1080
- }
1081
- }
1082
- }
1083
- if (countersignStatus === "escalate") {
1084
- const gate = safelyRead(verdict, "decisionGate");
1085
- if (gate.readable && isRecord(gate.value)) {
1086
- const question = safelyRead(gate.value, "question");
1087
- const options = safelyRead(gate.value, "options");
1088
- if (question.readable && typeof question.value === "string") {
1089
- facts.decisionQuestion = question.value;
1090
- }
1091
- if (options.readable && Array.isArray(options.value)) {
1092
- facts.decisionOptions = [...options.value];
1093
- }
1094
- }
1095
- }
1096
- const note = safelyRead(verdict, "note");
1097
- if (note.readable && note.value !== undefined)
1098
- facts.note = note.value;
1099
- const evidence = safelyRead(verdict, "evidence");
1100
- if (evidence.readable && evidence.value !== undefined)
1101
- facts.evidence = evidence.value;
1102
- return facts;
1103
- }
1104
- function judgeDecisiveFacts(verdict, judgeStatus) {
1105
- const facts = {
1106
- judgeStatus,
1107
- ...auditNoReceiptDecisiveFact(verdict),
1108
- ...auditUnreadableDecisiveFact(verdict),
1109
- };
1110
- const statusBase = judgeStatus;
1111
- if (statusBase === "continue") {
1112
- const fix = safelyRead(verdict, "fix");
1113
- if (fix.readable && isRecord(fix.value)) {
1114
- const summary = safelyRead(fix.value, "summary");
1115
- if (summary.readable && typeof summary.value === "string") {
1116
- facts.fixSummary = summary.value;
1117
- }
1118
- }
1119
- const classes = safelyRead(verdict, "classes");
1120
- if (classes.readable && Array.isArray(classes.value)) {
1121
- try {
1122
- facts.classes = classes.value.map((entry) => {
1123
- if (!isRecord(entry))
1124
- throw new Error("unreadable Judge class");
1125
- return {
1126
- name: entry.name,
1127
- owner: entry.owner,
1128
- boundary: entry.boundary,
1129
- disposition: entry.disposition,
1130
- };
1131
- });
1132
- facts.classCount = classes.value.length;
1133
- }
1134
- catch {
1135
- // Optional class material is omitted as a unit when any row is unreadable.
1136
- }
1137
- }
1138
- }
1139
- if (statusBase === "escalate") {
1140
- const gate = safelyRead(verdict, "decisionGate");
1141
- if (gate.readable && isRecord(gate.value)) {
1142
- const question = safelyRead(gate.value, "question");
1143
- const options = safelyRead(gate.value, "options");
1144
- if (question.readable && typeof question.value === "string") {
1145
- facts.decisionQuestion = question.value;
1146
- }
1147
- if (options.readable && Array.isArray(options.value)) {
1148
- facts.decisionOptions = [...options.value];
1149
- }
1150
- }
1151
- }
1152
- const note = safelyRead(verdict, "note");
1153
- if (note.readable && note.value !== undefined)
1154
- facts.note = note.value;
1155
- const evidence = safelyRead(verdict, "evidence");
1156
- if (evidence.readable && evidence.value !== undefined)
1157
- facts.evidence = evidence.value;
1158
- return facts;
1159
- }
1160
- function coderDecisiveFacts(output) {
1161
- const candidate = output;
1162
- const status = safelyRead(candidate, "status");
1163
- const facts = {};
1164
- if (status.readable && typeof status.value === "string")
1165
- facts.coderStatus = status.value;
1166
- const statusBase = status.readable && typeof status.value === "string"
1167
- ? (status.value)
1168
- : undefined;
1169
- const remainingScope = safelyRead(candidate, "remainingScope");
1170
- if (statusBase === "unfinished" && remainingScope.readable && typeof remainingScope.value === "string")
1171
- facts.remainingScope = remainingScope.value;
1172
- const reason = safelyRead(candidate, "reason");
1173
- if (statusBase === "unfinished" && reason.readable && typeof reason.value === "string" && reason.value.trim().length > 0) {
1174
- facts.reason = reason.value;
1175
- }
1176
- const report = safelyRead(candidate, "report");
1177
- if (report.readable && typeof report.value === "string")
1178
- facts.reportPresent = report.value.trim().length > 0;
1179
- return facts;
1180
- }
1181
- function fixerDecisiveFacts(output) {
1182
- const candidate = output;
1183
- const status = safelyRead(candidate, "status");
1184
- const facts = {};
1185
- if (status.readable && typeof status.value === "string")
1186
- facts.fixerStatus = status.value;
1187
- const statusBase = status.readable && typeof status.value === "string"
1188
- ? (status.value)
1189
- : undefined;
1190
- const remainingScope = safelyRead(candidate, "remainingScope");
1191
- if ((statusBase === "unfinished" || statusBase === "refused") && remainingScope.readable && typeof remainingScope.value === "string")
1192
- facts.remainingScope = remainingScope.value;
1193
- const reason = safelyRead(candidate, "reason");
1194
- if (statusBase === "unfinished" && reason.readable && typeof reason.value === "string" && reason.value.trim().length > 0) {
1195
- facts.reason = reason.value;
1196
- }
1197
- const blockerRead = safelyRead(candidate, "blocker");
1198
- if (statusBase === "refused" && blockerRead.readable && isRecord(blockerRead.value)) {
1199
- const cause = safelyRead(blockerRead.value, "cause");
1200
- if (cause.readable && typeof cause.value === "string")
1201
- facts.blockerCause = cause.value;
1202
- const prerequisiteId = safelyRead(blockerRead.value, "prerequisiteId");
1203
- if (cause.readable && cause.value === "prerequisite_unmet" && prerequisiteId.readable && typeof prerequisiteId.value === "string")
1204
- facts.prerequisiteId = prerequisiteId.value;
1205
- }
1206
- const classResults = safelyRead(candidate, "classResults");
1207
- if (classResults.readable && Array.isArray(classResults.value)) {
1208
- const rows = [];
1209
- const blockers = [];
1210
- try {
1211
- for (const entry of classResults.value) {
1212
- if (!isRecord(entry))
1213
- throw new Error("unreadable class result");
1214
- const name = safelyRead(entry, "name");
1215
- const disposition = safelyRead(entry, "disposition");
1216
- if (!name.readable || !disposition.readable)
1217
- throw new Error("unreadable class result");
1218
- rows.push({ name: name.value, disposition: disposition.value });
1219
- const blocker = safelyRead(entry, "blocker");
1220
- if (disposition.value === "refused" && blocker.readable && isRecord(blocker.value))
1221
- blockers.push(blocker.value);
1222
- }
1223
- facts.classResultCount = rows.length;
1224
- facts.classDispositions = rows;
1225
- const causes = blockers.flatMap((blocker) => {
1226
- const cause = safelyRead(blocker, "cause");
1227
- return cause.readable && typeof cause.value === "string" ? [cause.value] : [];
1228
- });
1229
- if (causes.length > 0)
1230
- facts.blockerCauses = causes;
1231
- const prerequisiteIds = blockers.flatMap((blocker) => {
1232
- const cause = safelyRead(blocker, "cause");
1233
- const id = safelyRead(blocker, "prerequisiteId");
1234
- return cause.readable && cause.value === "prerequisite_unmet" && id.readable && typeof id.value === "string" ? [id.value] : [];
1235
- });
1236
- if (prerequisiteIds.length > 0)
1237
- facts.prerequisiteIds = prerequisiteIds;
1238
- }
1239
- catch {
1240
- // Optional class projection is omitted as a unit when any row is unreadable.
1241
- }
1242
- }
1243
- const report = safelyRead(candidate, "report");
1244
- if (report.readable && typeof report.value === "string")
1245
- facts.reportPresent = report.value.trim().length > 0;
1246
- return facts;
1247
- }
1248
- function collectorDecisiveFacts(receipt) {
1249
- const candidate = receipt;
1250
- const facts = {};
1251
- for (const key of ["repository", "prNumber", "targetHead", "manifestDigest"]) {
1252
- const value = safelyRead(candidate, key);
1253
- if (value.readable && value.value !== undefined)
1254
- facts[key] = value.value;
1255
- }
1256
- const groups = safelyRead(candidate, "groups");
1257
- if (groups.readable && Array.isArray(groups.value)) {
1258
- try {
1259
- facts.groups = groups.value.map((group) => {
1260
- if (!isRecord(group))
1261
- throw new Error("unreadable Collector group");
1262
- const identity = safelyRead(group, "identity");
1263
- const attendance = safelyRead(group, "attendance");
1264
- const materials = safelyRead(group, "materials");
1265
- const findings = safelyRead(group, "findings");
1266
- if (!identity.readable || !attendance.readable ||
1267
- !materials.readable || !Array.isArray(materials.value) ||
1268
- !findings.readable || !Array.isArray(findings.value)) {
1269
- throw new Error("unreadable Collector group");
1270
- }
1271
- return {
1272
- identity: identity.value,
1273
- attendance: attendance.value,
1274
- materialCount: materials.value.length,
1275
- findingCount: findings.value.length,
1276
- };
1277
- });
1278
- }
1279
- catch { /* omit unreadable optional projection */ }
1280
- }
1281
- return facts;
1282
- }
1283
- function doctorDecisiveFacts(output) {
1284
- const candidate = output;
1285
- const status = safelyRead(candidate, "status");
1286
- const facts = {
1059
+ /** Keep optional auditNoReceipt parallel fact when present on sealed details. */
1060
+ function withAuditNoReceiptFacts(candidate) {
1061
+ return {
1062
+ ...candidate,
1287
1063
  ...auditNoReceiptDecisiveFact(candidate),
1288
- ...auditUnreadableDecisiveFact(candidate),
1289
1064
  };
1290
- if (status.readable && typeof status.value === "string")
1291
- facts.doctorStatus = status.value;
1292
- const statusBase = status.readable && typeof status.value === "string"
1293
- ? (status.value)
1294
- : undefined;
1295
- if (statusBase === "refused") {
1296
- const reason = safelyRead(candidate, "reason");
1297
- if (reason.readable && reason.value !== undefined)
1298
- facts.reason = reason.value;
1299
- const missing = safelyRead(candidate, "missingEvidence");
1300
- if (missing.readable && Array.isArray(missing.value))
1301
- facts.missingEvidenceCount = missing.value.length;
1302
- return facts;
1303
- }
1304
- const caseValue = safelyRead(candidate, "case");
1305
- if (caseValue.readable && isRecord(caseValue.value)) {
1306
- const issueNumber = safelyRead(caseValue.value, "issueNumber");
1307
- const runsPath = safelyRead(caseValue.value, "runsPath");
1308
- if (issueNumber.readable && issueNumber.value !== undefined)
1309
- facts.issueNumber = issueNumber.value;
1310
- if (runsPath.readable && runsPath.value !== undefined)
1311
- facts.runsPath = runsPath.value;
1312
- }
1313
- const findings = safelyRead(candidate, "findings");
1314
- if (findings.readable && Array.isArray(findings.value))
1315
- facts.findingsCount = findings.value.length;
1316
- return facts;
1317
- }
1318
- function reviewerAxes(value) {
1319
- if (!isRecord(value))
1320
- return [];
1321
- return ["standards", "spec"].filter((axis) => {
1322
- const projected = safelyRead(value, axis);
1323
- return projected.readable && projected.value !== undefined;
1324
- });
1325
- }
1326
- function reviewerDecisiveFacts(output) {
1327
- const candidate = output;
1328
- const status = safelyRead(candidate, "status");
1329
- const outcomes = safelyRead(candidate, "outcomes");
1330
- const reports = safelyRead(candidate, "reports");
1331
- const amendments = safelyRead(candidate, "amendments");
1332
- const axes = reviewerAxes(outcomes.readable ? outcomes.value : undefined);
1333
- const reportAxes = reviewerAxes(reports.readable ? reports.value : undefined);
1334
- // Typed presence only — never copy amendment prose into public facts.
1335
- const amendmentAxes = reviewerAxes(amendments.readable ? amendments.value : undefined);
1336
- const acceptedBatch = safelyRead(candidate, "acceptedBatch");
1337
- const specDisposition = safelyRead(candidate, "specDisposition");
1338
- const facts = {
1339
- axes,
1340
- reportAxes,
1341
- amendmentAxes,
1342
- acceptedBatchPresent: acceptedBatch.readable && acceptedBatch.value !== undefined,
1343
- ...auditNoReceiptDecisiveFact(candidate),
1344
- };
1345
- if (status.readable && typeof status.value === "string")
1346
- facts.reviewerStatus = status.value;
1347
- if (specDisposition.readable &&
1348
- (specDisposition.value === "launched" || specDisposition.value === "skipped-missing")) {
1349
- facts.specDisposition = specDisposition.value;
1350
- }
1351
- const diagnostic = safelyRead(candidate, "diagnostic");
1352
- const statusBase = status.readable && typeof status.value === "string"
1353
- ? (status.value)
1354
- : undefined;
1355
- if (statusBase === "refused" && diagnostic.readable) {
1356
- facts.diagnosticPresent = typeof diagnostic.value === "string" && diagnostic.value.trim().length > 0;
1357
- }
1358
- return facts;
1359
1065
  }
1360
1066
  /**
1361
1067
  * ADR 0037: a shape-valid Collector receipt may still name the wrong live target.
@@ -2057,7 +1763,8 @@ export async function readLawfulJudgeRoleOutcome(admitted, authority) {
2057
1763
  kind: "accepted",
2058
1764
  role: "judge",
2059
1765
  status: sealed.status,
2060
- decisiveFacts: judgeDecisiveFacts(details, sealed.status),
1766
+ // #757: sealed details pass through (judgeStatus already on the receipt).
1767
+ decisiveFacts: withAuditNoReceiptFacts(details),
2061
1768
  };
2062
1769
  }
2063
1770
  // Non-final: consume ledger audit-escalation projection (no JSONL accepted rebuild).
@@ -2114,17 +1821,11 @@ async function settleLawfulCoderTerminalResult(admitted, authority, options = {}
2114
1821
  const ledgerOutcome = await closedLedgerOutcome(admitted, "coder");
2115
1822
  if (ledgerOutcome === undefined)
2116
1823
  return undefined;
2117
- let roleOutcome = ledgerOutcome;
2118
- let output;
2119
- if (ledgerOutcome.kind === "accepted") {
2120
- output = validateAcceptedCoderDetails(ledgerOutcome.decisiveFacts);
2121
- roleOutcome = {
2122
- kind: "accepted",
2123
- role: "coder",
2124
- status: ledgerOutcome.status,
2125
- decisiveFacts: coderDecisiveFacts(output),
2126
- };
2127
- }
1824
+ // #757: sealed facts pass through — no shape re-project / field drop.
1825
+ const roleOutcome = ledgerOutcome;
1826
+ const output = ledgerOutcome.kind === "accepted"
1827
+ ? ledgerOutcome.decisiveFacts
1828
+ : undefined;
2128
1829
  const coordinates = coordinatesFromAdmitted(authority, admitted);
2129
1830
  const entries = await readLawfulSettlementEntries(coordinates.sessionFile) ?? [];
2130
1831
  const navigator = extractNavigatorFact(entries);
@@ -2242,17 +1943,11 @@ async function settleLawfulFixerTerminalResult(admitted, authority, options) {
2242
1943
  const ledgerOutcome = await closedLedgerOutcome(admitted, "fixer");
2243
1944
  if (ledgerOutcome === undefined)
2244
1945
  return undefined;
2245
- let roleOutcome = ledgerOutcome;
2246
- let output;
2247
- if (ledgerOutcome.kind === "accepted") {
2248
- output = validateFixerOutput(ledgerOutcome.decisiveFacts);
2249
- roleOutcome = {
2250
- kind: "accepted",
2251
- role: "fixer",
2252
- status: ledgerOutcome.status,
2253
- decisiveFacts: fixerDecisiveFacts(output),
2254
- };
2255
- }
1946
+ // #757: sealed facts pass through — no shape re-project / field drop.
1947
+ const roleOutcome = ledgerOutcome;
1948
+ const output = ledgerOutcome.kind === "accepted"
1949
+ ? ledgerOutcome.decisiveFacts
1950
+ : undefined;
2256
1951
  const coordinates = coordinatesFromAdmitted(authority, admitted);
2257
1952
  const { sessionDirectory, sessionFile } = coordinates;
2258
1953
  const entries = await readLawfulSettlementEntries(sessionFile) ?? [];
@@ -2351,13 +2046,15 @@ async function settleLawfulCollectorTerminalResult(admitted, authority) {
2351
2046
  }
2352
2047
  return undefined;
2353
2048
  }
2354
- const receipt = validateAcceptedCollectorReceipt(roleOutcome.decisiveFacts);
2049
+ // #757: sealed facts pass through — no groups rebuild / field drop.
2050
+ // ADR 0037 identity binding stays (external admitted facts, not shape).
2051
+ const receipt = roleOutcome.decisiveFacts;
2355
2052
  assertCollectorReceiptMatchesAdmitted(receipt, admitted);
2356
2053
  const accepted = {
2357
2054
  kind: "accepted",
2358
2055
  role: "collector",
2359
2056
  status: roleOutcome.status,
2360
- decisiveFacts: collectorDecisiveFacts(receipt),
2057
+ decisiveFacts: { ...roleOutcome.decisiveFacts },
2361
2058
  };
2362
2059
  const navigator = extractNavigatorFact(entries);
2363
2060
  const artifacts = await publishCollectorArtifacts(admitted, accepted, coordinates, { collectorReceipt: receipt });
@@ -2431,14 +2128,15 @@ async function settleLawfulDoctorTerminalResult(admitted, authority) {
2431
2128
  runId: admitted.runId,
2432
2129
  }, sessionDirectory);
2433
2130
  }
2434
- const output = validateRecordedDoctorOutput(sealed.decisiveFacts);
2131
+ // #757: sealed facts pass through — no validateRecordedDoctorOutput shape gate.
2132
+ const output = sealed.decisiveFacts;
2435
2133
  const roleOutcome = {
2436
2134
  kind: "accepted",
2437
2135
  role: "doctor",
2438
2136
  status: sealed.status,
2439
- decisiveFacts: doctorDecisiveFacts(output),
2137
+ decisiveFacts: { ...sealed.decisiveFacts },
2440
2138
  };
2441
- // Bind completed receipt case identity to the admitted Issue evidence case.
2139
+ // Bind completed receipt case identity to the admitted Issue evidence case (external fact).
2442
2140
  if (String(output.status) === "completed") {
2443
2141
  const completedCase = output.case;
2444
2142
  if (completedCase.issueNumber !== admitted.caseIdentity.issueNumber ||
@@ -2495,50 +2193,33 @@ async function settleLawfulSeatAcceptedTerminalResult(admitted, authority, spec,
2495
2193
  }, sessionDirectory);
2496
2194
  }
2497
2195
  if (roleOutcome?.role !== spec.role) {
2498
- // No usable release → existing non-zero failure channel with candidate (#475 / ADR 0055).
2499
- // One reverse pass: prefer errored residual; else latest accepted-once non-usable details.
2196
+ // No sealed ledger outcome for this seat/court. Prefer a real isError residual
2197
+ // (transport/lifecycle failure). Accepted-once without seal is absence — seal is
2198
+ // the sole acceptance authority (#637); do not promote session bytes to success.
2500
2199
  // Bounded to the current attempt so multi-attempt resume timeout/no-output
2501
2200
  // is not masked by a prior residual (#599 / #633).
2502
2201
  const scanStart = currentAttemptStartIndex(entries);
2503
- let acceptedNonUsable;
2504
2202
  for (let index = entries.length - 1; index >= scanStart; index -= 1) {
2505
2203
  const message = entries[index]?.message;
2506
2204
  if (message?.role !== "toolResult")
2507
2205
  continue;
2508
2206
  const residual = boundErroredToolCandidate(entries, index, message, spec.toolName);
2509
2207
  if (residual !== undefined) {
2208
+ // isError residual: retain candidate bytes as details (no shape stamp).
2209
+ const details = isRecord(residual.candidate)
2210
+ ? residual.candidate
2211
+ : { candidate: residual.candidate };
2510
2212
  return settleFailureTerminalResult(admitted, {
2511
2213
  cause: "output",
2512
2214
  diagnostic: residual.diagnostic,
2513
- details: stampShapeUnreadableDetails(residual.candidate),
2215
+ details,
2514
2216
  }, authority);
2515
2217
  }
2516
- if (acceptedNonUsable === undefined &&
2517
- message.toolName === spec.toolName &&
2518
- isAcceptedPackagedRoleTerminalResult(message)) {
2519
- // Accepted once but not a lawful seat release — hold as fallback.
2520
- if (!spec.tryAcceptDetails(message.details)) {
2521
- acceptedNonUsable = message.details;
2522
- }
2523
- }
2524
- }
2525
- if (acceptedNonUsable !== undefined) {
2526
- return settleFailureTerminalResult(admitted, {
2527
- cause: "output",
2528
- diagnostic: spec.nonUsableDiagnostic,
2529
- details: stampShapeUnreadableDetails(acceptedNonUsable),
2530
- }, authority);
2531
2218
  }
2532
2219
  return undefined;
2533
2220
  }
2534
- if (!spec.tryAcceptDetails(roleOutcome.decisiveFacts)) {
2535
- return settleFailureTerminalResult(admitted, {
2536
- cause: "output",
2537
- diagnostic: spec.nonUsableDiagnostic,
2538
- details: stampShapeUnreadableDetails(roleOutcome.decisiveFacts),
2539
- }, authority);
2540
- }
2541
- const acceptedOutcome = spec.projectAccepted(roleOutcome);
2221
+ // Sealed ledger outcome: pass through full decisiveFacts (#757).
2222
+ const acceptedOutcome = roleOutcome;
2542
2223
  const navigator = extractNavigatorFact(entries);
2543
2224
  return withOptionalGateProjection({
2544
2225
  roleOutcome: acceptedOutcome,
@@ -2547,33 +2228,11 @@ async function settleLawfulSeatAcceptedTerminalResult(admitted, authority, spec,
2547
2228
  runId: admitted.runId,
2548
2229
  }, sessionDirectory);
2549
2230
  }
2550
- function tryAcceptWithValidator(validate) {
2551
- return (details) => {
2552
- try {
2553
- validate(details);
2554
- return true;
2555
- }
2556
- catch {
2557
- return false;
2558
- }
2559
- };
2560
- }
2561
2231
  async function settleLawfulNotaryTerminalResult(admitted, authority, scope) {
2232
+ // #757: default sealed pass-through — no projectAccepted identity wrapper.
2562
2233
  return settleLawfulSeatAcceptedTerminalResult(admitted, authority, {
2563
2234
  role: "notary",
2564
2235
  toolName: NOTARY_OUTPUT_TOOL_NAME,
2565
- nonUsableDiagnostic: "符宝郎回执无显式 pass/bounce/escalate",
2566
- tryAcceptDetails: tryAcceptWithValidator(validateRecordedNotaryOutput),
2567
- projectAccepted: (sealed) => {
2568
- const output = validateRecordedNotaryOutput(sealed.decisiveFacts);
2569
- const accepted = {
2570
- kind: "accepted",
2571
- role: "notary",
2572
- status: sealed.status,
2573
- decisiveFacts: notaryDecisiveFacts(output),
2574
- };
2575
- return accepted;
2576
- },
2577
2236
  }, scope);
2578
2237
  }
2579
2238
  /** Settle a lawful Notary Terminal from the admitted session. */
@@ -2592,18 +2251,6 @@ async function settleLawfulCountersignTerminalResult(admitted, authority, scope)
2592
2251
  return settleLawfulSeatAcceptedTerminalResult(admitted, authority, {
2593
2252
  role: "countersign",
2594
2253
  toolName: COUNTERSIGN_OUTPUT_TOOL_NAME,
2595
- nonUsableDiagnostic: "给事中回执无显式 署/封驳/上呈",
2596
- tryAcceptDetails: tryAcceptWithValidator(validateRecordedCountersignOutput),
2597
- projectAccepted: (sealed) => {
2598
- const verdict = validateRecordedCountersignOutput(sealed.decisiveFacts);
2599
- const accepted = {
2600
- kind: "accepted",
2601
- role: "countersign",
2602
- status: sealed.status,
2603
- decisiveFacts: countersignDecisiveFacts(verdict, sealed.status),
2604
- };
2605
- return accepted;
2606
- },
2607
2254
  }, scope);
2608
2255
  }
2609
2256
  /** Settle a lawful Countersign Terminal from the admitted session. */
@@ -2622,18 +2269,6 @@ async function settleLawfulGleanerLeftTerminalResult(admitted, authority, scope)
2622
2269
  return settleLawfulSeatAcceptedTerminalResult(admitted, authority, {
2623
2270
  role: "gleaner-left",
2624
2271
  toolName: GLEANER_LEFT_OUTPUT_TOOL_NAME,
2625
- nonUsableDiagnostic: "左拾遗回执无显式 completed",
2626
- tryAcceptDetails: tryAcceptWithValidator(validateRecordedGleanerLeftOutput),
2627
- projectAccepted: (sealed) => {
2628
- const output = validateRecordedGleanerLeftOutput(sealed.decisiveFacts);
2629
- const accepted = {
2630
- kind: "accepted",
2631
- role: "gleaner-left",
2632
- status: sealed.status,
2633
- decisiveFacts: gleanerLeftDecisiveFacts(output),
2634
- };
2635
- return accepted;
2636
- },
2637
2272
  }, scope);
2638
2273
  }
2639
2274
  /** Settle a lawful Gleaner-Left Terminal from the admitted session. */
@@ -2652,18 +2287,6 @@ async function settleLawfulDiaristTerminalResult(admitted, authority, scope) {
2652
2287
  return settleLawfulSeatAcceptedTerminalResult(admitted, authority, {
2653
2288
  role: "diarist",
2654
2289
  toolName: DIARIST_OUTPUT_TOOL_NAME,
2655
- nonUsableDiagnostic: "起居郎回执无显式 completed",
2656
- tryAcceptDetails: tryAcceptWithValidator(validateRecordedDiaristOutput),
2657
- projectAccepted: (sealed) => {
2658
- const output = validateRecordedDiaristOutput(sealed.decisiveFacts);
2659
- const accepted = {
2660
- kind: "accepted",
2661
- role: "diarist",
2662
- status: sealed.status,
2663
- decisiveFacts: diaristDecisiveFacts(output),
2664
- };
2665
- return accepted;
2666
- },
2667
2290
  }, scope);
2668
2291
  }
2669
2292
  /** Try to settle a lawful Diarist Terminal; undefined only for genuine absence. */
@@ -2674,18 +2297,6 @@ async function settleLawfulInspectorTerminalResult(admitted, authority, scope) {
2674
2297
  return settleLawfulSeatAcceptedTerminalResult(admitted, authority, {
2675
2298
  role: "inspector",
2676
2299
  toolName: INSPECTOR_OUTPUT_TOOL_NAME,
2677
- nonUsableDiagnostic: "察院回执无显式 pass/bounce/escalate",
2678
- tryAcceptDetails: tryAcceptWithValidator(validateRecordedInspectorOutput),
2679
- projectAccepted: (sealed) => {
2680
- const output = validateRecordedInspectorOutput(sealed.decisiveFacts);
2681
- const accepted = {
2682
- kind: "accepted",
2683
- role: "inspector",
2684
- status: sealed.status,
2685
- decisiveFacts: inspectorDecisiveFacts(output),
2686
- };
2687
- return accepted;
2688
- },
2689
2300
  }, scope);
2690
2301
  }
2691
2302
  export async function trySettleInspectorTerminalResult(admitted, authority, scope) {
@@ -2695,18 +2306,6 @@ async function settleLawfulGatekeeperTerminalResult(admitted, authority, scope)
2695
2306
  return settleLawfulSeatAcceptedTerminalResult(admitted, authority, {
2696
2307
  role: "gatekeeper",
2697
2308
  toolName: GATEKEEPER_OUTPUT_TOOL_NAME,
2698
- nonUsableDiagnostic: "门下省决议无显式 dispatch/pass",
2699
- tryAcceptDetails: tryAcceptWithValidator(validateRecordedGatekeeperOutput),
2700
- projectAccepted: (sealed) => {
2701
- const output = validateRecordedGatekeeperOutput(sealed.decisiveFacts);
2702
- const accepted = {
2703
- kind: "accepted",
2704
- role: "gatekeeper",
2705
- status: output.status,
2706
- decisiveFacts: gatekeeperDecisiveFacts(output),
2707
- };
2708
- return accepted;
2709
- },
2710
2309
  }, scope);
2711
2310
  }
2712
2311
  /** Try to settle a lawful Gatekeeper Terminal; undefined only for genuine absence. */
@@ -2717,18 +2316,6 @@ async function settleLawfulNavigatorTerminalResult(admitted, authority, scope) {
2717
2316
  return settleLawfulSeatAcceptedTerminalResult(admitted, authority, {
2718
2317
  role: "navigator",
2719
2318
  toolName: NAVIGATOR_OUTPUT_TOOL_NAME,
2720
- nonUsableDiagnostic: "游奕使回执无显式路线建议",
2721
- tryAcceptDetails: tryAcceptWithValidator(validateRecordedNavigatorOutput),
2722
- projectAccepted: (sealed) => {
2723
- const output = validateRecordedNavigatorOutput(sealed.decisiveFacts);
2724
- const accepted = {
2725
- kind: "accepted",
2726
- role: "navigator",
2727
- status: "advice",
2728
- decisiveFacts: navigatorDecisiveFacts(output),
2729
- };
2730
- return accepted;
2731
- },
2732
2319
  }, scope);
2733
2320
  }
2734
2321
  /** Try to settle a lawful Navigator Terminal; undefined only for genuine absence. */
@@ -2739,49 +2326,11 @@ async function settleLawfulAuditorTerminalResult(admitted, authority, scope) {
2739
2326
  return settleLawfulSeatAcceptedTerminalResult(admitted, authority, {
2740
2327
  role: "auditor",
2741
2328
  toolName: AUDITOR_OUTPUT_TOOL_NAME,
2742
- nonUsableDiagnostic: "审刑院回执无显式 pass/bounce/escalate",
2743
- // Only pass/bounce/escalate are lawful releases. Unreadable mystery status
2744
- // fails closed with candidate retained for parent ComplianceCandidateUnreadableError.
2745
- tryAcceptDetails: (details) => projectLawfulAuditorOutput(details) !== undefined,
2746
- projectAccepted: (sealed) => {
2747
- const lawful = projectLawfulAuditorOutput(sealed.decisiveFacts);
2748
- if (lawful === undefined) {
2749
- throw new Error("auditor projectAccepted requires lawful pass/bounce/escalate");
2750
- }
2751
- const accepted = {
2752
- kind: "accepted",
2753
- role: "auditor",
2754
- status: lawful.status,
2755
- decisiveFacts: auditorDecisiveFacts(lawful),
2756
- };
2757
- return accepted;
2758
- },
2759
2329
  }, scope);
2760
2330
  }
2761
2331
  export async function trySettleAuditorTerminalResult(admitted, authority, scope) {
2762
2332
  return settleLawfulAuditorTerminalResult(admitted, authority, scope);
2763
2333
  }
2764
- async function settleLawfulEvidenceChildTerminalResult(admitted, authority, scope) {
2765
- return settleLawfulSeatAcceptedTerminalResult(admitted, authority, {
2766
- role: "evidence-child",
2767
- toolName: EVIDENCE_CHILD_OUTPUT_TOOL_NAME,
2768
- nonUsableDiagnostic: "取证回执无报告正文",
2769
- tryAcceptDetails: tryAcceptWithValidator(validateRecordedEvidenceChildOutput),
2770
- projectAccepted: (sealed) => {
2771
- const output = validateRecordedEvidenceChildOutput(sealed.decisiveFacts);
2772
- const accepted = {
2773
- kind: "accepted",
2774
- role: "evidence-child",
2775
- status: "report",
2776
- decisiveFacts: evidenceChildDecisiveFacts(output),
2777
- };
2778
- return accepted;
2779
- },
2780
- }, scope);
2781
- }
2782
- export async function trySettleEvidenceChildTerminalResult(admitted, authority, scope) {
2783
- return settleLawfulEvidenceChildTerminalResult(admitted, authority, scope);
2784
- }
2785
2334
  /** Try to settle a lawful Coder Terminal; undefined only for genuine absence. */
2786
2335
  export async function trySettleCoderTerminalResult(admitted, authority, options = {}) {
2787
2336
  return settleLawfulCoderTerminalResult(admitted, authority, options);
@@ -2870,12 +2419,13 @@ async function settleLawfulReviewerTerminalResult(admitted, authority, options)
2870
2419
  const coordinates = coordinatesFromAdmitted(authority, admitted);
2871
2420
  const { sessionDirectory, sessionFile } = coordinates;
2872
2421
  const entries = await readLawfulSettlementEntries(sessionFile) ?? [];
2873
- const receipt = validateRuntimeReviewerReceipt(sealed.decisiveFacts);
2422
+ // #757: sealed facts pass through — no validateRuntimeReviewerReceipt shape gate.
2423
+ const receipt = sealed.decisiveFacts;
2874
2424
  const roleOutcome = {
2875
2425
  kind: "accepted",
2876
2426
  role: "reviewer",
2877
2427
  status: sealed.status,
2878
- decisiveFacts: reviewerDecisiveFacts(receipt),
2428
+ decisiveFacts: { ...sealed.decisiveFacts },
2879
2429
  };
2880
2430
  const navigator = extractNavigatorFact(entries);
2881
2431
  const methodInvocations = extractReviewerMethodInvocations(entries, {
@@ -2908,24 +2458,6 @@ export async function settleReviewerTerminalResult(admitted, authority, options)
2908
2458
  export async function trySettleReviewerTerminalResult(admitted, authority, options) {
2909
2459
  return settleLawfulReviewerTerminalResult(admitted, authority, options);
2910
2460
  }
2911
- function mergerDecisiveFacts(output) {
2912
- const candidate = output;
2913
- const facts = {};
2914
- const status = safelyRead(candidate, "status");
2915
- const attemptId = safelyRead(candidate, "attemptId");
2916
- if (status.readable && typeof status.value === "string")
2917
- facts.mergerStatus = status.value;
2918
- if (attemptId.readable && attemptId.value !== undefined)
2919
- facts.attemptId = attemptId.value;
2920
- const statusBase = status.readable && typeof status.value === "string"
2921
- ? (status.value)
2922
- : undefined;
2923
- const decisiveKey = statusBase === "completed" ? "mergeCommitId" : "diagnosis";
2924
- const decisive = safelyRead(candidate, decisiveKey);
2925
- if (decisive.readable && decisive.value !== undefined)
2926
- facts[decisiveKey] = decisive.value;
2927
- return facts;
2928
- }
2929
2461
  /**
2930
2462
  * Observe forced Merger resolving-merge-conflicts Skill expansions from the session.
2931
2463
  * Expansion evidence is package-path only; ambient home locations never count.
@@ -3015,32 +2547,29 @@ async function settleLawfulMergerTerminalResult(admitted, authority, options) {
3015
2547
  ? safelyRead(residual.candidate, "attemptId")
3016
2548
  : { readable: true, value: undefined };
3017
2549
  // Admitted-attempt identity binding only (ADR 0037) — not sole-final cardinality.
2550
+ // isError residual with matching attemptId is incomplete; no shape re-judge (#757).
3018
2551
  if (!attemptId.readable || attemptId.value !== admitted.runId)
3019
2552
  continue;
3020
- try {
3021
- validateMergerOutput(residual.candidate, admitted.runId);
3022
- }
3023
- catch {
3024
- return {
3025
- roleOutcome: buildResidualIncompleteTerminalOutcome({
3026
- role: "merger",
3027
- candidate: residual.candidate,
3028
- diagnostic: residual.diagnostic,
3029
- }),
3030
- navigator: { disposition: "no-advice" },
3031
- artifacts: [],
3032
- runId: admitted.runId,
3033
- };
3034
- }
2553
+ return {
2554
+ roleOutcome: buildResidualIncompleteTerminalOutcome({
2555
+ role: "merger",
2556
+ candidate: residual.candidate,
2557
+ diagnostic: residual.diagnostic,
2558
+ }),
2559
+ navigator: { disposition: "no-advice" },
2560
+ artifacts: [],
2561
+ runId: admitted.runId,
2562
+ };
3035
2563
  }
3036
2564
  return undefined;
3037
2565
  }
3038
- const output = validateMergerOutput(roleOutcome.decisiveFacts, admitted.runId);
2566
+ // #757: sealed facts pass through — no validateMergerOutput shape gate.
2567
+ const output = roleOutcome.decisiveFacts;
3039
2568
  const accepted = {
3040
2569
  kind: "accepted",
3041
2570
  role: "merger",
3042
2571
  status: roleOutcome.status,
3043
- decisiveFacts: mergerDecisiveFacts(output),
2572
+ decisiveFacts: { ...roleOutcome.decisiveFacts },
3044
2573
  };
3045
2574
  const methodInvocations = extractMergerMethodInvocations(entries, {
3046
2575
  allowedLocations: [