@akagilnc/pi-workflow-roles 0.1.4021 → 0.1.4035

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.
@@ -56,28 +56,22 @@ import {
56
56
  } from "../package-contracts/judge-output.ts";
57
57
  import {
58
58
  COLLECTOR_OUTPUT_TOOL,
59
- type CollectorReceipt,
60
59
  } from "../package-contracts/collector-output.ts";
61
60
  import {
62
61
  CODER_OUTPUT_TOOL_NAME,
63
62
  FIXER_OUTPUT_TOOL_NAME,
64
- type CoderOutput,
65
- type FixerOutput,
66
63
  } from "../package-contracts/worker-output.ts";
67
64
 
68
65
  import {
69
66
  DOCTOR_OUTPUT_TOOL_NAME,
70
67
  type DoctorCaseCost,
71
- type DoctorOutput,
72
68
  } from "../doctor-contracts.ts";
73
69
  import { DOCTOR_CANDIDATE_ENTRY_TYPE } from "../dossier-resolution.ts";
74
70
  import {
75
71
  REVIEWER_OUTPUT_TOOL_NAME,
76
- type ReviewerIntent,
77
72
  } from "../package-contracts/reviewer-output.ts";
78
73
  import {
79
74
  MERGER_OUTPUT_TOOL_NAME,
80
- type MergerOutput,
81
75
  } from "../merger-contracts.ts";
82
76
  import {
83
77
  NOTARY_OUTPUT_TOOL_NAME,
@@ -152,7 +146,7 @@ import {
152
146
  } from "./invocation.ts";
153
147
 
154
148
  /** Ledger reads use the run's machine home — not ambient process HOME (child write vs parent settle). */
155
- function sealedLedgerHome(admitted: AdmittedRoleInvocation): string {
149
+ function sealedLedgerHome(admitted: Pick<AdmittedRoleInvocation, "runDirectory">): string {
156
150
  return homeFromRunDirectory(admitted.runDirectory);
157
151
  }
158
152
 
@@ -165,7 +159,7 @@ export type SettlementCourtScope = {
165
159
  };
166
160
 
167
161
  function ledgerReadScope(
168
- admitted: AdmittedRoleInvocation,
162
+ admitted: Pick<AdmittedRoleInvocation, "runDirectory">,
169
163
  scope?: SettlementCourtScope,
170
164
  ): { home: string; attemptId?: string } {
171
165
  return {
@@ -178,12 +172,22 @@ function ledgerReadScope(
178
172
 
179
173
  function roleOutcomeFromRows(
180
174
  role: TerminalRoleName,
181
- rows: readonly { readonly role: TerminalRoleName; readonly kind: "accepted" | "audit-escalation"; readonly accepted: unknown }[],
175
+ rows: readonly {
176
+ readonly role?: TerminalRoleName;
177
+ readonly kind: "accepted" | "audit-escalation" | "correctable-rejection" | "infrastructure" | "candidate";
178
+ readonly accepted: unknown;
179
+ }[],
182
180
  ): Extract<TerminalRoleOutcome, { kind: "accepted" | "audit_escalation" }> | undefined {
183
181
  const mine = rows.filter((row) => row.role === role);
184
- if (mine.length === 0) return undefined;
182
+ // Terminal acceptance kind still only follows sealed / audit-escalation (#881):
183
+ // correctable-rejection / infrastructure / candidate stay payloads, not acceptance.
184
+ const terminal = mine.filter(
185
+ (row) => row.kind === "accepted" || row.kind === "audit-escalation",
186
+ );
187
+ if (terminal.length === 0) return undefined;
188
+ // Role-result block is the full recorded sequence for this seat, not a sole pick.
185
189
  const payloads = mine.map((row) => row.accepted);
186
- if (mine.some((row) => row.kind === "audit-escalation")) {
190
+ if (terminal.some((row) => row.kind === "audit-escalation")) {
187
191
  return { kind: "audit_escalation", role, status: "audit_escalation", payloads };
188
192
  }
189
193
  return { kind: "accepted", role, payloads };
@@ -227,7 +231,7 @@ export async function attemptProducedFreshSubmission(
227
231
 
228
232
  /** #836: every raw role payload in settle scope (调几次记几次). */
229
233
  export async function recordedSubmissionPayloads(
230
- admitted: AdmittedRoleInvocation,
234
+ admitted: Pick<AdmittedRoleInvocation, "projectRoot" | "runId" | "runDirectory">,
231
235
  scope?: SettlementCourtScope,
232
236
  ): Promise<readonly unknown[]> {
233
237
  return readRecordedSubmissions(
@@ -243,18 +247,18 @@ export function withSubmissions<T extends TerminalResult>(
243
247
  ): T {
244
248
  if (submissions.length === 0) return terminal;
245
249
  const roleOutcome = terminal.roleOutcome;
250
+ // Full ledger sequence always wins the role-result block (#881): do not keep a
251
+ // narrower pre-filtered payloads array when attach brings the complete set.
246
252
  const withPayloads =
247
- roleOutcome.kind === "accepted" || roleOutcome.kind === "audit_escalation"
248
- ? { ...roleOutcome, payloads: (roleOutcome.payloads ?? []).length > 0 ? roleOutcome.payloads : submissions }
249
- : roleOutcome.kind === "failure"
250
- ? { ...roleOutcome, payloads: roleOutcome.payloads ?? submissions }
251
- : roleOutcome;
253
+ roleOutcome.kind === "accepted" || roleOutcome.kind === "audit_escalation" || roleOutcome.kind === "failure"
254
+ ? { ...roleOutcome, payloads: submissions }
255
+ : roleOutcome;
252
256
  return { ...terminal, roleOutcome: withPayloads, submissions };
253
257
  }
254
258
 
255
259
  /** Attach full ledger submissions onto any settled terminal (#836). */
256
260
  export async function attachRecordedSubmissions<T extends TerminalResult>(
257
- admitted: AdmittedRoleInvocation,
261
+ admitted: Pick<AdmittedRoleInvocation, "projectRoot" | "runId" | "runDirectory">,
258
262
  terminal: T,
259
263
  scope?: SettlementCourtScope,
260
264
  ): Promise<T> {
@@ -313,7 +317,6 @@ import {
313
317
  exitCodeForTerminalOutcome,
314
318
  formatTerminalResult,
315
319
  isLawfulTypedTerminalOutcome,
316
- lastRolePayloadRecord,
317
320
  recommendationNavigatorFact,
318
321
  type ControlledFailureCause,
319
322
  type TerminalArtifactRef,
@@ -334,9 +337,10 @@ export {
334
337
  isLawfulTypedTerminalOutcome,
335
338
  };
336
339
 
337
- /** Preserved post-admission failure cause (not a role Receipt). */
340
+ /** Preserved post-admission failure (not a role Receipt). */
338
341
  export type ControlledFailure = {
339
- readonly cause: ControlledFailureCause;
342
+ /** Typed class only when confirmed; omitted when unknown (#881 — no fabricated label). */
343
+ readonly cause?: ControlledFailureCause;
340
344
  readonly diagnostic: string;
341
345
  readonly identity?: {
342
346
  readonly name?: string;
@@ -464,8 +468,7 @@ function isTypedActivationError(
464
468
  cause === "activation" ||
465
469
  cause === "session" ||
466
470
  cause === "output" ||
467
- cause === "timeout" ||
468
- cause === "unrecognized"
471
+ cause === "timeout"
469
472
  );
470
473
  }
471
474
 
@@ -494,21 +497,20 @@ export function projectThrownFailureLeaf(error: unknown): ControlledFailure {
494
497
  }
495
498
  return {
496
499
  cause: error.knownCause,
497
- diagnostic: error.message || error.name || "unrecognized exception",
500
+ diagnostic: error.message || error.name || "exception",
498
501
  identity,
499
502
  ...(error.details === undefined ? {} : { details: error.details }),
500
503
  };
501
504
  }
502
505
  if (error instanceof Error) {
503
506
  const identity = thrownIdentity(error);
507
+ // No typed confirmation → keep original diagnostic/identity; do not mint a class (#881).
504
508
  return {
505
- cause: "unrecognized",
506
- diagnostic: error.message || error.name || "unrecognized exception",
509
+ diagnostic: error.message || error.name || "exception",
507
510
  identity,
508
511
  };
509
512
  }
510
513
  return {
511
- cause: "unrecognized",
512
514
  diagnostic: String(error),
513
515
  };
514
516
  }
@@ -539,7 +541,7 @@ function classifyThrownFailure(error: unknown): ControlledFailure {
539
541
  ...leaves.slice(1).map((leaf) => {
540
542
  const secondary = projectThrownFailureLeaf(leaf);
541
543
  return {
542
- cause: secondary.cause,
544
+ ...(secondary.cause === undefined ? {} : { cause: secondary.cause }),
543
545
  diagnostic: secondary.diagnostic,
544
546
  ...(secondary.identity === undefined ? {} : { identity: secondary.identity }),
545
547
  ...(secondary.details === undefined ? {} : { details: secondary.details }),
@@ -547,7 +549,7 @@ function classifyThrownFailure(error: unknown): ControlledFailure {
547
549
  }),
548
550
  ];
549
551
  return {
550
- cause: primary.cause,
552
+ ...(primary.cause === undefined ? {} : { cause: primary.cause }),
551
553
  diagnostic: primary.diagnostic,
552
554
  ...(primary.identity === undefined ? {} : { identity: primary.identity }),
553
555
  details: {
@@ -574,7 +576,7 @@ function withKnownDetails(
574
576
  }
575
577
 
576
578
  /**
577
- * Classify a controlled post-admission failure without washing unrecognized identities.
579
+ * Classify a controlled post-admission failure without washing original identities.
578
580
  * Cause classes are closed; diagnostic text retains the original identity when known.
579
581
  *
580
582
  * Order: thrown → knownCause → timeout → activation (nonzero) → session → output.
@@ -588,7 +590,7 @@ export function classifyPostAdmissionFailure(input: {
588
590
  stderr: string;
589
591
  /**
590
592
  * Caught post-admission exception. Presence (own key) is distinct from value:
591
- * JavaScript permits `throw undefined`, which must stay unrecognized rather than
593
+ * JavaScript permits `throw undefined`, which must keep the original thrown fact rather than
592
594
  * being washed into activation/null-exit paths that treat missing thrown as absence.
593
595
  */
594
596
  thrown?: unknown;
@@ -642,6 +644,37 @@ export function classifyPostAdmissionFailure(input: {
642
644
  : { identity: input.knownIdentity }),
643
645
  };
644
646
  }
647
+ // #881: original failure testimony without a typed class — keep diagnostic/identity;
648
+ // do not fall through to activation/output wash that would mint a substitute class.
649
+ // Bare knownDetails alone is secondary evidence for later branches (withKnownDetails),
650
+ // not a stand-in primary failure record.
651
+ if (
652
+ (input.knownDiagnostic !== undefined && input.knownDiagnostic.trim() !== "") ||
653
+ input.knownIdentity !== undefined
654
+ ) {
655
+ const diagnostic =
656
+ input.knownDiagnostic !== undefined && input.knownDiagnostic.trim() !== ""
657
+ ? input.knownDiagnostic
658
+ : conciseChildDiagnostic(input.stderr, "role run failed");
659
+ const { timedOut: _knownTimedOut, ...knownDetails } =
660
+ input.knownDetails ?? {};
661
+ const remoteCode = knownDetails.code;
662
+ return withKnownDetails(
663
+ {
664
+ diagnostic,
665
+ details: {
666
+ ...knownDetails,
667
+ ...(remoteCode === undefined ? {} : { code: remoteCode }),
668
+ exitCode: input.code,
669
+ ...(input.timedOut ? { timedOut: true as const } : {}),
670
+ },
671
+ ...(input.knownIdentity === undefined
672
+ ? {}
673
+ : { identity: input.knownIdentity }),
674
+ },
675
+ undefined,
676
+ );
677
+ }
645
678
  if (input.timedOut) {
646
679
  return withKnownDetails(
647
680
  {
@@ -699,7 +732,7 @@ export function explicitInternalKnownFailureClassificationInput(
699
732
  ) {
700
733
  if (failure === undefined) return {};
701
734
  return {
702
- knownCause: failure.cause,
735
+ ...(failure.cause === undefined ? {} : { knownCause: failure.cause }),
703
736
  ...(failure.identity === undefined ? {} : { knownIdentity: failure.identity }),
704
737
  ...(failure.diagnostic === undefined ? {} : { knownDiagnostic: failure.diagnostic }),
705
738
  ...(failure.details === undefined ? {} : { knownDetails: failure.details }),
@@ -1137,10 +1170,20 @@ function complianceFailureFromAuditorVolumes(
1137
1170
  if (entry?.type !== "custom" || entry.customType !== AUDITOR_COMPLIANCE_FAILURE_ENTRY_TYPE || !isRecord(entry.data)) continue;
1138
1171
  const parent = isRecord(entry.data.parent) ? entry.data.parent : undefined;
1139
1172
  const failure = isRecord(entry.data.failure) ? entry.data.failure : undefined;
1140
- if (parent?.sessionId !== parentId || parent.sessionFile !== sessionFile || parent.attemptEntryId !== attemptEntryId || (failure?.cause !== "provider" && failure?.cause !== "unrecognized")) continue;
1173
+ if (parent?.sessionId !== parentId || parent.sessionFile !== sessionFile || parent.attemptEntryId !== attemptEntryId) continue;
1174
+ // #881: keep the recorded failure as written — typed cause when present, else raw diagnostic only.
1175
+ if (failure === undefined) continue;
1141
1176
  const identity = isRecord(failure.identity) ? failure.identity : undefined;
1177
+ const typedCause =
1178
+ failure.cause === "provider" ||
1179
+ failure.cause === "activation" ||
1180
+ failure.cause === "session" ||
1181
+ failure.cause === "output" ||
1182
+ failure.cause === "timeout"
1183
+ ? (failure.cause as ControlledFailureCause)
1184
+ : undefined;
1142
1185
  return {
1143
- cause: failure.cause === "provider" ? "provider" : "unrecognized",
1186
+ ...(typedCause === undefined ? {} : { cause: typedCause }),
1144
1187
  ...(identity === undefined ? {} : { identity: {
1145
1188
  ...(typeof identity.name === "string" ? { name: identity.name } : {}),
1146
1189
  ...(typeof identity.code === "string" || typeof identity.code === "number" ? { code: identity.code } : {}),
@@ -2314,7 +2357,6 @@ export async function publishCoderArtifacts(
2314
2357
  coordinates: DurablePrincipalCoordinates,
2315
2358
  options: {
2316
2359
  readonly methodProvenance?: PackagedMethodSkillProvenance;
2317
- readonly coderOutput?: CoderOutput;
2318
2360
  } = {},
2319
2361
  ): Promise<TerminalArtifactRef[]> {
2320
2362
  await appendRunAttemptHistory({ role: admitted.role, runId: admitted.runId, sessionFile: coordinates.sessionFile }, roleOutcome);
@@ -2329,9 +2371,6 @@ export async function publishCoderArtifacts(
2329
2371
  runId: admitted.runId,
2330
2372
  phase: admitted.phase,
2331
2373
  outcome: roleOutcome,
2332
- ...(options.coderOutput === undefined
2333
- ? {}
2334
- : { receipt: options.coderOutput }),
2335
2374
  },
2336
2375
  null,
2337
2376
  2,
@@ -2487,10 +2526,6 @@ async function settleLawfulCoderTerminalResult(
2487
2526
  const ledgerOutcome = await closedLedgerOutcome(admitted, "coder", scope);
2488
2527
  if (ledgerOutcome === undefined) return undefined;
2489
2528
  const roleOutcome: TerminalRoleOutcome = ledgerOutcome;
2490
- const output: CoderOutput | undefined =
2491
- ledgerOutcome.kind === "accepted"
2492
- ? (lastRolePayloadRecord(ledgerOutcome.payloads ?? []) as CoderOutput | undefined)
2493
- : undefined;
2494
2529
  const coordinates = coordinatesFromAdmitted(authority, admitted);
2495
2530
  const entries = await readLawfulSettlementEntries(coordinates.sessionFile) ?? [];
2496
2531
  const navigator = extractNavigatorFact(entries);
@@ -2499,7 +2534,6 @@ async function settleLawfulCoderTerminalResult(
2499
2534
  roleOutcome,
2500
2535
  coordinates,
2501
2536
  {
2502
- ...(output === undefined ? {} : { coderOutput: output }),
2503
2537
  ...(options.methodProvenance === undefined
2504
2538
  ? {}
2505
2539
  : { methodProvenance: options.methodProvenance }),
@@ -2590,7 +2624,6 @@ export async function publishFixerArtifacts(
2590
2624
  options: {
2591
2625
  readonly methodProvenance: PackagedMethodSkillProvenance;
2592
2626
  readonly methodInvocations?: readonly ObservedPackagedMethodSkillInvocation[];
2593
- readonly fixerOutput?: FixerOutput;
2594
2627
  },
2595
2628
  ): Promise<TerminalArtifactRef[]> {
2596
2629
  await appendRunAttemptHistory({ role: admitted.role, runId: admitted.runId, sessionFile: coordinates.sessionFile }, roleOutcome);
@@ -2605,9 +2638,6 @@ export async function publishFixerArtifacts(
2605
2638
  runId: admitted.runId,
2606
2639
  phase: admitted.phase,
2607
2640
  outcome: roleOutcome,
2608
- ...(options.fixerOutput === undefined
2609
- ? {}
2610
- : { receipt: options.fixerOutput }),
2611
2641
  },
2612
2642
  null,
2613
2643
  2,
@@ -2666,10 +2696,6 @@ async function settleLawfulFixerTerminalResult(
2666
2696
  const ledgerOutcome = await closedLedgerOutcome(admitted, "fixer", scope);
2667
2697
  if (ledgerOutcome === undefined) return undefined;
2668
2698
  const roleOutcome: TerminalRoleOutcome = ledgerOutcome;
2669
- const output: FixerOutput | undefined =
2670
- ledgerOutcome.kind === "accepted"
2671
- ? (lastRolePayloadRecord(ledgerOutcome.payloads ?? []) as FixerOutput | undefined)
2672
- : undefined;
2673
2699
  const coordinates = coordinatesFromAdmitted(authority, admitted);
2674
2700
  const { sessionDirectory, sessionFile } = coordinates;
2675
2701
  const entries = await readLawfulSettlementEntries(sessionFile) ?? [];
@@ -2685,7 +2711,6 @@ async function settleLawfulFixerTerminalResult(
2685
2711
  roleOutcome,
2686
2712
  coordinates,
2687
2713
  {
2688
- ...(output === undefined ? {} : { fixerOutput: output }),
2689
2714
  methodProvenance: options.methodProvenance,
2690
2715
  methodInvocations,
2691
2716
  },
@@ -2725,9 +2750,6 @@ export async function publishCollectorArtifacts(
2725
2750
  admitted: AdmittedCollectorInvocation,
2726
2751
  roleOutcome: TerminalRoleOutcome,
2727
2752
  coordinates: DurablePrincipalCoordinates,
2728
- options: {
2729
- readonly collectorReceipt?: CollectorReceipt;
2730
- } = {},
2731
2753
  ): Promise<TerminalArtifactRef[]> {
2732
2754
  await appendRunAttemptHistory({ role: admitted.role, runId: admitted.runId, sessionFile: coordinates.sessionFile }, roleOutcome);
2733
2755
  const artifactsDir = await ensureRunArtifactsDir(admitted.runDirectory);
@@ -2740,9 +2762,6 @@ export async function publishCollectorArtifacts(
2740
2762
  role: "collector",
2741
2763
  runId: admitted.runId,
2742
2764
  outcome: roleOutcome,
2743
- ...(options.collectorReceipt === undefined
2744
- ? {}
2745
- : { receipt: options.collectorReceipt }),
2746
2765
  },
2747
2766
  null,
2748
2767
  2,
@@ -2810,14 +2829,12 @@ async function settleLawfulCollectorTerminalResult(
2810
2829
  }
2811
2830
  return undefined;
2812
2831
  }
2813
- const receipt = (lastRolePayloadRecord(roleOutcome.payloads ?? []) ?? {}) as CollectorReceipt;
2814
2832
  const accepted: LawfulCollectorRoleOutcome = roleOutcome;
2815
2833
  const navigator = extractNavigatorFact(entries);
2816
2834
  const artifacts = await publishCollectorArtifacts(
2817
2835
  admitted,
2818
2836
  accepted,
2819
2837
  coordinates,
2820
- { collectorReceipt: receipt },
2821
2838
  );
2822
2839
  return attachRecordedSubmissions(
2823
2840
  admitted,
@@ -2902,7 +2919,6 @@ export async function publishDoctorArtifacts(
2902
2919
  roleOutcome: TerminalRoleOutcome,
2903
2920
  coordinates: DurablePrincipalCoordinates,
2904
2921
  options: {
2905
- readonly doctorOutput?: DoctorOutput;
2906
2922
  readonly cost?: DoctorCaseCost;
2907
2923
  readonly auditNoReceipt?: unknown;
2908
2924
  } = {},
@@ -2918,10 +2934,6 @@ export async function publishDoctorArtifacts(
2918
2934
  role: "doctor",
2919
2935
  runId: admitted.runId,
2920
2936
  outcome: roleOutcome,
2921
- ...(options.doctorOutput === undefined
2922
- ? {}
2923
- : { receipt: options.doctorOutput }),
2924
- // Independent machine fields beside the receipt — not merged into it.
2925
2937
  ...(options.cost === undefined ? {} : { cost: options.cost }),
2926
2938
  ...(options.auditNoReceipt === undefined ? {} : { auditNoReceipt: options.auditNoReceipt }),
2927
2939
  },
@@ -2987,7 +2999,6 @@ async function settleLawfulDoctorTerminalResult(
2987
2999
  sessionDirectory,
2988
3000
  );
2989
3001
  }
2990
- const output = (lastRolePayloadRecord(sealed.payloads ?? []) ?? {}) as DoctorOutput;
2991
3002
  const roleOutcome = sealed;
2992
3003
  const navigator = extractNavigatorFact(entries);
2993
3004
  const cost = extractDoctorCandidateCostFact(entries);
@@ -2997,7 +3008,6 @@ async function settleLawfulDoctorTerminalResult(
2997
3008
  roleOutcome,
2998
3009
  coordinates,
2999
3010
  {
3000
- doctorOutput: output,
3001
3011
  ...(cost === undefined ? {} : { cost }),
3002
3012
  ...(auditNoReceipt === undefined ? {} : { auditNoReceipt }),
3003
3013
  },
@@ -3433,7 +3443,6 @@ export async function publishReviewerArtifacts(
3433
3443
  options: {
3434
3444
  readonly methodProvenance: PackagedMethodSkillProvenance;
3435
3445
  readonly methodInvocations?: readonly ObservedPackagedMethodSkillInvocation[];
3436
- readonly reviewerReceipt?: ReviewerIntent;
3437
3446
  },
3438
3447
  ): Promise<TerminalArtifactRef[]> {
3439
3448
  await appendRunAttemptHistory({ role: admitted.role, runId: admitted.runId, sessionFile: coordinates.sessionFile }, roleOutcome);
@@ -3447,9 +3456,6 @@ export async function publishReviewerArtifacts(
3447
3456
  role: "reviewer",
3448
3457
  runId: admitted.runId,
3449
3458
  outcome: roleOutcome,
3450
- ...(options.reviewerReceipt === undefined
3451
- ? {}
3452
- : { receipt: options.reviewerReceipt }),
3453
3459
  },
3454
3460
  null,
3455
3461
  2,
@@ -3509,7 +3515,6 @@ async function settleLawfulReviewerTerminalResult(
3509
3515
  const coordinates = coordinatesFromAdmitted(authority, admitted);
3510
3516
  const { sessionDirectory, sessionFile } = coordinates;
3511
3517
  const entries = await readLawfulSettlementEntries(sessionFile) ?? [];
3512
- const receipt = lastRolePayloadRecord(sealed.payloads ?? []) as ReviewerIntent | undefined;
3513
3518
  const roleOutcome: LawfulReviewerRoleOutcome = sealed;
3514
3519
  const navigator = extractNavigatorFact(entries);
3515
3520
  const methodInvocations = extractReviewerMethodInvocations(entries, {
@@ -3523,7 +3528,6 @@ async function settleLawfulReviewerTerminalResult(
3523
3528
  roleOutcome,
3524
3529
  coordinates,
3525
3530
  {
3526
- ...(receipt === undefined ? {} : { reviewerReceipt: receipt }),
3527
3531
  methodProvenance: options.methodProvenance,
3528
3532
  methodInvocations,
3529
3533
  },
@@ -3612,7 +3616,6 @@ export async function publishMergerArtifacts(
3612
3616
  options: {
3613
3617
  readonly methodProvenance: PackagedMethodSkillProvenance;
3614
3618
  readonly methodInvocations?: readonly ObservedPackagedMethodSkillInvocation[];
3615
- readonly mergerOutput?: MergerOutput;
3616
3619
  },
3617
3620
  ): Promise<TerminalArtifactRef[]> {
3618
3621
  await appendRunAttemptHistory({ role: admitted.role, runId: admitted.runId, sessionFile: coordinates.sessionFile }, roleOutcome);
@@ -3626,9 +3629,6 @@ export async function publishMergerArtifacts(
3626
3629
  role: "merger",
3627
3630
  runId: admitted.runId,
3628
3631
  outcome: roleOutcome,
3629
- ...(options.mergerOutput === undefined
3630
- ? {}
3631
- : { receipt: options.mergerOutput }),
3632
3632
  },
3633
3633
  null,
3634
3634
  2,
@@ -3711,7 +3711,6 @@ async function settleLawfulMergerTerminalResult(
3711
3711
  accepted,
3712
3712
  coordinates,
3713
3713
  {
3714
- mergerOutput: (lastRolePayloadRecord(accepted.payloads ?? []) ?? {}) as MergerOutput,
3715
3714
  methodProvenance: options.methodProvenance,
3716
3715
  methodInvocations,
3717
3716
  },
@@ -3941,7 +3940,7 @@ export async function publishFailureArtifacts(
3941
3940
  kind: "error",
3942
3941
  role: admitted.role,
3943
3942
  runId: admitted.runId,
3944
- cause: failure.cause,
3943
+ ...(failure.cause === undefined ? {} : { cause: failure.cause }),
3945
3944
  diagnostic: failure.diagnostic,
3946
3945
  ...(failure.identity === undefined ? {} : { identity: failure.identity }),
3947
3946
  ...(failure.details === undefined ? {} : { details: failure.details }),
@@ -3966,7 +3965,7 @@ export async function publishFailureArtifacts(
3966
3965
  sha256: a.sha256,
3967
3966
  byteLength: a.byteLength,
3968
3967
  })),
3969
- failureCause: failure.cause,
3968
+ ...(failure.cause === undefined ? {} : { failureCause: failure.cause }),
3970
3969
  };
3971
3970
  const evidenceWrite = await writeFailureJsonRetainingCause(
3972
3971
  evidenceCandidates,
@@ -4045,7 +4044,7 @@ export async function settleFailureTerminalResult(
4045
4044
  // Private durable artifacts retain the original diagnostic identity (including run ID).
4046
4045
  const artifacts = await publishFailureArtifacts(admitted, failure, authority);
4047
4046
  const decisiveFacts: Record<string, unknown> = {
4048
- cause: failure.cause,
4047
+ ...(failure.cause === undefined ? {} : { cause: failure.cause }),
4049
4048
  diagnostic: failure.diagnostic,
4050
4049
  };
4051
4050
  if (failure.identity?.name !== undefined) {
@@ -4065,7 +4064,7 @@ export async function settleFailureTerminalResult(
4065
4064
  const roleOutcome: TerminalRoleOutcome = {
4066
4065
  kind: "failure",
4067
4066
  role: admitted.role,
4068
- cause: failure.cause,
4067
+ ...(failure.cause === undefined ? {} : { cause: failure.cause }),
4069
4068
  diagnostic: failure.diagnostic,
4070
4069
  decisiveFacts,
4071
4070
  };
@@ -4082,7 +4081,7 @@ export async function settleFailureTerminalResult(
4082
4081
  const roleOutcome: TerminalRoleOutcome = {
4083
4082
  kind: "failure",
4084
4083
  role: admitted.role,
4085
- cause: failure.cause,
4084
+ ...(failure.cause === undefined ? {} : { cause: failure.cause }),
4086
4085
  diagnostic: failure.diagnostic,
4087
4086
  decisiveFacts,
4088
4087
  };
@@ -4122,7 +4121,7 @@ export function presentFailureTerminal(
4122
4121
  io.stdout(formatTerminalResult(terminal));
4123
4122
  if (terminal.roleOutcome.kind === "failure") {
4124
4123
  io.stderr(formatFailureStderrDiagnostic({
4125
- cause: terminal.roleOutcome.cause,
4124
+ ...(terminal.roleOutcome.cause === undefined ? {} : { cause: terminal.roleOutcome.cause }),
4126
4125
  diagnostic: terminal.roleOutcome.diagnostic,
4127
4126
  }));
4128
4127
  return;
@@ -73,8 +73,12 @@ export type TerminalRoleOutcome =
73
73
  | {
74
74
  kind: "failure";
75
75
  role: TerminalRoleName;
76
- /** Typed cause class — never a fabricated role Receipt status. */
77
- cause: ControlledFailureCause;
76
+ /**
77
+ * Typed cause class when a typed fact confirms it.
78
+ * Omitted when unknown — original diagnostic + error artifact carry the fact (#881).
79
+ * Never a fabricated "unrecognized" label.
80
+ */
81
+ cause?: ControlledFailureCause;
78
82
  /** Original diagnostic identity retained for the caller. */
79
83
  diagnostic: string;
80
84
  decisiveFacts: Readonly<Record<string, unknown>>;
@@ -175,19 +179,6 @@ export function roleResultPayloads(outcome: TerminalRoleOutcome): readonly unkno
175
179
  return [];
176
180
  }
177
181
 
178
- /** Last object payload the role actually wrote. No field remapping. */
179
- export function lastRolePayloadRecord(
180
- payloads: readonly unknown[],
181
- ): Record<string, unknown> | undefined {
182
- for (let index = payloads.length - 1; index >= 0; index -= 1) {
183
- const payload = payloads[index];
184
- if (typeof payload === "object" && payload !== null && !Array.isArray(payload)) {
185
- return payload as Record<string, unknown>;
186
- }
187
- }
188
- return undefined;
189
- }
190
-
191
182
  export type TerminalResult = {
192
183
  roleOutcome: TerminalRoleOutcome;
193
184
  navigator: TerminalNavigatorFact;
@@ -253,7 +244,7 @@ export function formatTerminalResult(result: TerminalResult): string {
253
244
  lines.push("role\toutcome\tstatus");
254
245
  const outcomeStatus =
255
246
  result.roleOutcome.kind === "failure"
256
- ? result.roleOutcome.cause
247
+ ? result.roleOutcome.cause ?? ""
257
248
  : result.roleOutcome.kind === "accepted"
258
249
  ? "accepted"
259
250
  : result.roleOutcome.status;