@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.
- package/dist/acp-host/production-host.js +208 -107
- package/dist/headless-host/production-host.js +208 -107
- package/dist/navigator-attendance.js +2 -0
- package/dist/navigator-public-session.js +18 -34
- package/dist/navigator-session-contracts.js +19 -0
- package/dist/pi/known-failure.js +3 -4
- package/dist/public-cli/auto-resume.js +20 -7
- package/dist/public-cli/diarist-run.js +9 -23
- package/dist/public-cli/instruction-seat-run.js +3 -1
- package/dist/public-cli/judge-run.js +3 -1
- package/dist/public-cli/main.js +203 -112
- package/dist/public-cli/settlement.js +64 -61
- package/dist/public-cli/terminal.js +1 -11
- package/dist/submission-ledger.js +109 -11
- package/package.json +1 -1
- package/src/host-contracts.ts +8 -4
- package/src/navigator-attendance.ts +2 -0
- package/src/navigator-public-session.ts +19 -55
- package/src/navigator-session-contracts.ts +39 -0
- package/src/pi/known-failure.ts +3 -4
- package/src/public-cli/auto-resume.ts +57 -20
- package/src/public-cli/cli.ts +2 -2
- package/src/public-cli/collector-run.ts +3 -1
- package/src/public-cli/countersign-run.ts +34 -27
- package/src/public-cli/diarist-run.ts +10 -27
- package/src/public-cli/instruction-seat-run.ts +3 -1
- package/src/public-cli/judge-run.ts +3 -1
- package/src/public-cli/reviewer-run.ts +3 -1
- package/src/public-cli/settlement.ts +83 -84
- package/src/public-cli/terminal.ts +7 -16
- package/src/submission-ledger.ts +147 -13
|
@@ -8,9 +8,8 @@
|
|
|
8
8
|
import { sitianReport } from "./sitian-facade.ts";
|
|
9
9
|
import {
|
|
10
10
|
NavigatorUnavailableError,
|
|
11
|
-
|
|
11
|
+
navigatorProviderFailureFromPublicTerminal,
|
|
12
12
|
navigatorProviderFailureFromError,
|
|
13
|
-
navigatorProviderFailureFromStatus,
|
|
14
13
|
navigatorUnavailableError,
|
|
15
14
|
parseNavigatorModelSetting,
|
|
16
15
|
resolveNavigatorSeatSelection,
|
|
@@ -18,43 +17,6 @@ import {
|
|
|
18
17
|
type NavigatorSessionFactory,
|
|
19
18
|
} from "./navigator-session-contracts.ts";
|
|
20
19
|
import type { NoReceiptLifecycleFacts } from "./receipt-delivery-policy.ts";
|
|
21
|
-
import { lastRolePayloadRecord } from "./public-cli/terminal.ts";
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* Classify public-navigator failure terminal from structured decisiveFacts only
|
|
25
|
-
* (httpStatus / diagnostics / secondaryEvidence on the terminal) — same fields
|
|
26
|
-
* settlement already stamps from typed HTTP observation / provider stop.
|
|
27
|
-
*/
|
|
28
|
-
function providerFailureFromPublicTerminal(outcome: {
|
|
29
|
-
readonly cause: string;
|
|
30
|
-
readonly diagnostic: string;
|
|
31
|
-
readonly decisiveFacts: Readonly<Record<string, unknown>>;
|
|
32
|
-
}): NavigatorProviderFailureFact {
|
|
33
|
-
const facts = outcome.decisiveFacts;
|
|
34
|
-
const secondary =
|
|
35
|
-
typeof facts.secondaryEvidence === "object" && facts.secondaryEvidence !== null
|
|
36
|
-
? (facts.secondaryEvidence as Record<string, unknown>)
|
|
37
|
-
: undefined;
|
|
38
|
-
const httpStatus =
|
|
39
|
-
typeof secondary?.httpStatus === "number"
|
|
40
|
-
? secondary.httpStatus
|
|
41
|
-
: typeof facts.httpStatus === "number"
|
|
42
|
-
? facts.httpStatus
|
|
43
|
-
: typeof facts.errorCode === "number"
|
|
44
|
-
? facts.errorCode
|
|
45
|
-
: undefined;
|
|
46
|
-
const fromStatus = navigatorProviderFailureFromStatus(httpStatus);
|
|
47
|
-
if (fromStatus !== undefined) return fromStatus;
|
|
48
|
-
const diagnostics = secondary?.diagnostics ?? facts.diagnostics;
|
|
49
|
-
const fromDiagnostics = navigatorProviderFailureFromDiagnostics(diagnostics);
|
|
50
|
-
if (fromDiagnostics !== undefined) return fromDiagnostics;
|
|
51
|
-
const fromCode = navigatorProviderFailureFromError({
|
|
52
|
-
code: secondary?.code ?? facts.errorCode,
|
|
53
|
-
});
|
|
54
|
-
if (fromCode !== undefined) return fromCode;
|
|
55
|
-
if (outcome.cause === "provider") return { source: "transport", cause: "transport" };
|
|
56
|
-
return { source: "session", cause: "session" };
|
|
57
|
-
}
|
|
58
20
|
|
|
59
21
|
export function createNativeNavigatorSessionFactory(): NavigatorSessionFactory {
|
|
60
22
|
return async ({ context, subject, tool }) => {
|
|
@@ -122,14 +84,16 @@ export function createNativeNavigatorSessionFactory(): NavigatorSessionFactory {
|
|
|
122
84
|
const outcome = summoned.terminal?.roleOutcome;
|
|
123
85
|
if (outcome === undefined) {
|
|
124
86
|
const detail = summoned.stderr?.trim() || `exit ${summoned.exitCode}`;
|
|
125
|
-
|
|
87
|
+
// Known source is the public-summon transport path; unconfirmed cause stays unknown.
|
|
88
|
+
providerFailure = { source: "transport", cause: "unknown" };
|
|
126
89
|
throw navigatorUnavailableError(
|
|
127
|
-
|
|
90
|
+
providerFailure.source,
|
|
128
91
|
new Error(`Navigator public summon produced no terminal (${detail})`),
|
|
92
|
+
providerFailure.cause,
|
|
129
93
|
);
|
|
130
94
|
}
|
|
131
95
|
if (outcome.kind === "failure") {
|
|
132
|
-
providerFailure =
|
|
96
|
+
providerFailure = navigatorProviderFailureFromPublicTerminal(outcome);
|
|
133
97
|
throw navigatorUnavailableError(
|
|
134
98
|
providerFailure.source,
|
|
135
99
|
new Error(outcome.diagnostic),
|
|
@@ -147,23 +111,23 @@ export function createNativeNavigatorSessionFactory(): NavigatorSessionFactory {
|
|
|
147
111
|
// Not a shape-unusable judgment on the navigator reply (#757).
|
|
148
112
|
return;
|
|
149
113
|
}
|
|
150
|
-
const
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
114
|
+
for (const payload of outcome.payloads ?? []) {
|
|
115
|
+
if (typeof payload !== "object" || payload === null || Array.isArray(payload)) continue;
|
|
116
|
+
const candidates = (payload as { candidates?: unknown }).candidates;
|
|
117
|
+
if (!Array.isArray(candidates)) continue;
|
|
118
|
+
await tool.execute(
|
|
119
|
+
"navigator-public-prepare",
|
|
120
|
+
{ candidates },
|
|
121
|
+
undefined,
|
|
122
|
+
undefined,
|
|
123
|
+
context as never,
|
|
124
|
+
);
|
|
154
125
|
}
|
|
155
|
-
// Rejoin attendance prepare tool sink (same candidate shape as public advice).
|
|
156
|
-
await tool.execute(
|
|
157
|
-
"navigator-public-prepare",
|
|
158
|
-
{ candidates },
|
|
159
|
-
undefined,
|
|
160
|
-
undefined,
|
|
161
|
-
context as never,
|
|
162
|
-
);
|
|
163
126
|
} catch (error) {
|
|
164
127
|
if (error instanceof NavigatorUnavailableError) throw error;
|
|
165
128
|
const fact = navigatorProviderFailureFromError(error);
|
|
166
|
-
|
|
129
|
+
// Catch path is the public-summon seam (source transport); untyped cause stays unknown.
|
|
130
|
+
providerFailure = fact ?? { source: "transport", cause: "unknown" };
|
|
167
131
|
throw navigatorUnavailableError(providerFailure.source, error, providerFailure.cause);
|
|
168
132
|
}
|
|
169
133
|
})();
|
|
@@ -133,6 +133,45 @@ export function navigatorProviderFailureFromDiagnostics(diagnostics: unknown): N
|
|
|
133
133
|
return undefined;
|
|
134
134
|
}
|
|
135
135
|
|
|
136
|
+
/**
|
|
137
|
+
* Classify a public-navigator failure terminal from structured facts only.
|
|
138
|
+
* Untyped cause stays unknown — never relabeled session.
|
|
139
|
+
*/
|
|
140
|
+
export function navigatorProviderFailureFromPublicTerminal(outcome: {
|
|
141
|
+
readonly cause?: string;
|
|
142
|
+
readonly diagnostic: string;
|
|
143
|
+
readonly decisiveFacts: Readonly<Record<string, unknown>>;
|
|
144
|
+
}): NavigatorProviderFailureFact {
|
|
145
|
+
const facts = outcome.decisiveFacts;
|
|
146
|
+
const secondary =
|
|
147
|
+
typeof facts.secondaryEvidence === "object" && facts.secondaryEvidence !== null
|
|
148
|
+
? (facts.secondaryEvidence as Record<string, unknown>)
|
|
149
|
+
: undefined;
|
|
150
|
+
const httpStatus =
|
|
151
|
+
typeof secondary?.httpStatus === "number"
|
|
152
|
+
? secondary.httpStatus
|
|
153
|
+
: typeof facts.httpStatus === "number"
|
|
154
|
+
? facts.httpStatus
|
|
155
|
+
: typeof facts.errorCode === "number"
|
|
156
|
+
? facts.errorCode
|
|
157
|
+
: undefined;
|
|
158
|
+
const fromStatus = navigatorProviderFailureFromStatus(httpStatus);
|
|
159
|
+
if (fromStatus !== undefined) return fromStatus;
|
|
160
|
+
const diagnostics = secondary?.diagnostics ?? facts.diagnostics;
|
|
161
|
+
const fromDiagnostics = navigatorProviderFailureFromDiagnostics(diagnostics);
|
|
162
|
+
if (fromDiagnostics !== undefined) return fromDiagnostics;
|
|
163
|
+
const fromCode = navigatorProviderFailureFromError({
|
|
164
|
+
code: secondary?.code ?? facts.errorCode,
|
|
165
|
+
});
|
|
166
|
+
if (fromCode !== undefined) return fromCode;
|
|
167
|
+
// cause=provider names the known source region only; without status/diagnostics/code
|
|
168
|
+
// the specific cause stays unknown (#881 — never invent transport/session labels).
|
|
169
|
+
if (outcome.cause === "provider") return { source: "transport", cause: "unknown" };
|
|
170
|
+
const typed = navigatorUnavailableKey(outcome.cause);
|
|
171
|
+
if (typed !== undefined) return { source: typed, cause: typed };
|
|
172
|
+
return { source: "unknown", cause: "unknown" };
|
|
173
|
+
}
|
|
174
|
+
|
|
136
175
|
const navigatorProviderFailureSchema = Type.Object({
|
|
137
176
|
source: Type.Union([
|
|
138
177
|
Type.Literal("context"), Type.Literal("session"), Type.Literal("model"), Type.Literal("thinking"),
|
package/src/pi/known-failure.ts
CHANGED
|
@@ -49,9 +49,8 @@ function sessionStopDetails(input: {
|
|
|
49
49
|
/**
|
|
50
50
|
* Project a native session assistant stop onto the existing knownFailure chain.
|
|
51
51
|
* Classification follows two-way testimony: typed HTTP status or SDK structure
|
|
52
|
-
* keeps provider; stopReason
|
|
53
|
-
*
|
|
54
|
-
* in details without rewriting; missing fields are omitted.
|
|
52
|
+
* keeps provider; stopReason / errorMessage prose alone never invents a class (#881).
|
|
53
|
+
* Present upstream payload is preserved in details without rewriting; missing fields are omitted.
|
|
55
54
|
*/
|
|
56
55
|
export function knownFailureFromProviderStop(input: {
|
|
57
56
|
readonly stopReason?: string;
|
|
@@ -70,7 +69,7 @@ export function knownFailureFromProviderStop(input: {
|
|
|
70
69
|
const diagnostic = nonEmptyString(input.errorMessage);
|
|
71
70
|
const details = sessionStopDetails(input);
|
|
72
71
|
return {
|
|
73
|
-
|
|
72
|
+
...(hasUpstreamErrorTestimony(input) ? { cause: "provider" as const } : {}),
|
|
74
73
|
...(diagnostic === undefined ? {} : { diagnostic }),
|
|
75
74
|
...(Object.keys(details).length === 0 ? {} : { details }),
|
|
76
75
|
};
|
|
@@ -33,6 +33,7 @@ import {
|
|
|
33
33
|
import { parseAutoResumeLimit } from "./config.ts";
|
|
34
34
|
import { isLawfulTypedTerminalOutcome, formatTerminalResult, type TerminalArtifactRef, type TerminalResult, type TerminalRoleName } from "./terminal.ts";
|
|
35
35
|
import {
|
|
36
|
+
attachRecordedSubmissions,
|
|
36
37
|
presentFailureTerminal,
|
|
37
38
|
presentStructuralRejection,
|
|
38
39
|
resolveControlledFailureResumeObservation,
|
|
@@ -362,6 +363,33 @@ function unwrapTurnDispatchedFailure(error: unknown): unknown {
|
|
|
362
363
|
return current;
|
|
363
364
|
}
|
|
364
365
|
|
|
366
|
+
async function attachDispatchExceptionTerminal(
|
|
367
|
+
admitted: {
|
|
368
|
+
readonly runDirectory: string;
|
|
369
|
+
readonly runId: string;
|
|
370
|
+
readonly projectRoot: string;
|
|
371
|
+
},
|
|
372
|
+
terminal: TerminalResult,
|
|
373
|
+
io: CliIo,
|
|
374
|
+
): Promise<TerminalResult> {
|
|
375
|
+
try {
|
|
376
|
+
return await attachRecordedSubmissions(
|
|
377
|
+
{
|
|
378
|
+
projectRoot: admitted.projectRoot,
|
|
379
|
+
runId: admitted.runId,
|
|
380
|
+
runDirectory: admitted.runDirectory,
|
|
381
|
+
},
|
|
382
|
+
terminal,
|
|
383
|
+
);
|
|
384
|
+
} catch (error) {
|
|
385
|
+
// Existing diagnostic seam: attach true cause on stderr, original Terminal stays.
|
|
386
|
+
io.stderr(
|
|
387
|
+
`dispatch exception ledger attach failed (best-effort continue): ${describeErrorIdentity(error)}\n`,
|
|
388
|
+
);
|
|
389
|
+
return terminal;
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
|
|
365
393
|
/**
|
|
366
394
|
* Typed failure terminal for a retry path that ended with only exceptions:
|
|
367
395
|
* loud, non-lawful, carrying the last true cause and the pointers to the
|
|
@@ -384,8 +412,8 @@ function dispatchExceptionFailureTerminal(input: {
|
|
|
384
412
|
? "dispatch threw an exception on every attempt"
|
|
385
413
|
: "the final dispatch threw an exception";
|
|
386
414
|
const diagnostic = `${history} (${input.endReason}; resumes used ${input.autoResumeAttempts}); last cause: ${describeErrorIdentity(causeError)}`;
|
|
415
|
+
// #881: no fabricated cause class — original error identity + error-file pointers carry the fact.
|
|
387
416
|
const decisiveFacts: Record<string, unknown> = {
|
|
388
|
-
cause: "unrecognized",
|
|
389
417
|
diagnostic,
|
|
390
418
|
resumesUsed: input.autoResumeAttempts,
|
|
391
419
|
dispatchErrorFiles: [...input.errorFiles],
|
|
@@ -406,7 +434,6 @@ function dispatchExceptionFailureTerminal(input: {
|
|
|
406
434
|
roleOutcome: {
|
|
407
435
|
kind: "failure",
|
|
408
436
|
role: input.role,
|
|
409
|
-
cause: "unrecognized",
|
|
410
437
|
diagnostic,
|
|
411
438
|
decisiveFacts,
|
|
412
439
|
},
|
|
@@ -427,6 +454,8 @@ export async function runWithAutoResumeLoop<
|
|
|
427
454
|
role: TerminalRoleName;
|
|
428
455
|
runId: string;
|
|
429
456
|
principal: DurablePrincipal;
|
|
457
|
+
/** Required: exception terminals attach the ledger via this existing admitted fact. */
|
|
458
|
+
projectRoot: string;
|
|
430
459
|
};
|
|
431
460
|
principalAuthority: DurablePrincipalAuthority;
|
|
432
461
|
/**
|
|
@@ -571,15 +600,19 @@ export async function runWithAutoResumeLoop<
|
|
|
571
600
|
} else {
|
|
572
601
|
// Exception path: continue through the identical budget/session gates.
|
|
573
602
|
if (autoResumeAttempts >= limit) {
|
|
574
|
-
const terminal =
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
603
|
+
const terminal = await attachDispatchExceptionTerminal(
|
|
604
|
+
options.admitted,
|
|
605
|
+
dispatchExceptionFailureTerminal({
|
|
606
|
+
role: options.admitted.role,
|
|
607
|
+
runId: options.admitted.runId,
|
|
608
|
+
causeError: lastThrownError,
|
|
609
|
+
errorFiles: retainedErrorFiles,
|
|
610
|
+
autoResumeAttempts,
|
|
611
|
+
endReason: "auto-resume budget exhausted",
|
|
612
|
+
everyAttemptThrew,
|
|
613
|
+
}),
|
|
614
|
+
options.io,
|
|
615
|
+
);
|
|
583
616
|
await finalizeExceptionRunBestEffort(options.admitted.runDirectory, options.io);
|
|
584
617
|
presentTerminal(terminal, options.io);
|
|
585
618
|
return {
|
|
@@ -588,15 +621,19 @@ export async function runWithAutoResumeLoop<
|
|
|
588
621
|
} as T;
|
|
589
622
|
}
|
|
590
623
|
if (!(await isPrincipalAvailable(options.admitted.principal))) {
|
|
591
|
-
const terminal =
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
624
|
+
const terminal = await attachDispatchExceptionTerminal(
|
|
625
|
+
options.admitted,
|
|
626
|
+
dispatchExceptionFailureTerminal({
|
|
627
|
+
role: options.admitted.role,
|
|
628
|
+
runId: options.admitted.runId,
|
|
629
|
+
causeError: lastThrownError,
|
|
630
|
+
errorFiles: retainedErrorFiles,
|
|
631
|
+
autoResumeAttempts,
|
|
632
|
+
endReason: "session principal unavailable before further resume",
|
|
633
|
+
everyAttemptThrew,
|
|
634
|
+
}),
|
|
635
|
+
options.io,
|
|
636
|
+
);
|
|
600
637
|
await finalizeExceptionRunBestEffort(options.admitted.runDirectory, options.io);
|
|
601
638
|
presentTerminal(terminal, options.io);
|
|
602
639
|
return {
|
package/src/public-cli/cli.ts
CHANGED
|
@@ -1637,10 +1637,10 @@ export async function runAkRole(
|
|
|
1637
1637
|
if (error.cause !== undefined) {
|
|
1638
1638
|
const detail = formatErrorCauseDetail(error.cause);
|
|
1639
1639
|
if (detail.trim().length > 0) {
|
|
1640
|
-
label = `${label || error.name || "
|
|
1640
|
+
label = `${label || error.name || "exception"}; cause: ${detail}`;
|
|
1641
1641
|
}
|
|
1642
1642
|
}
|
|
1643
|
-
io.stderr(formatCliDiagnostic(label || error.name || "
|
|
1643
|
+
io.stderr(formatCliDiagnostic(label || error.name || "exception"));
|
|
1644
1644
|
return { exitCode: 1 };
|
|
1645
1645
|
}
|
|
1646
1646
|
io.stderr(formatCliDiagnostic(String(error)));
|
|
@@ -142,7 +142,9 @@ function collectorAdapters(): PostAdmissionAdapters<AdmittedCollectorInvocation>
|
|
|
142
142
|
(infrastructureFailure === undefined
|
|
143
143
|
? undefined
|
|
144
144
|
: {
|
|
145
|
-
|
|
145
|
+
...(infrastructureFailure.cause === undefined
|
|
146
|
+
? {}
|
|
147
|
+
: { cause: infrastructureFailure.cause }),
|
|
146
148
|
diagnostic: infrastructureFailure.diagnostic,
|
|
147
149
|
...(infrastructureFailure.identity === undefined
|
|
148
150
|
? {}
|
|
@@ -54,7 +54,7 @@ import {
|
|
|
54
54
|
trySettleCountersignTerminalResult,
|
|
55
55
|
} from "./settlement.ts";
|
|
56
56
|
import type { CliIo } from "./cli-io.ts";
|
|
57
|
-
import {
|
|
57
|
+
import type { TerminalResult, TerminalRoleOutcome } from "./terminal.ts";
|
|
58
58
|
import {
|
|
59
59
|
projectRoleTurnRequest,
|
|
60
60
|
type RoleTurnRequestProjectionOptions,
|
|
@@ -96,7 +96,24 @@ export function buildCountersignTurnRequest(
|
|
|
96
96
|
type CourtDiaristIdentity =
|
|
97
97
|
| { readonly kind: "ticket"; readonly ticketNumber: number }
|
|
98
98
|
| { readonly kind: "unbound" }
|
|
99
|
-
| { readonly kind: "escalate"
|
|
99
|
+
| { readonly kind: "escalate" };
|
|
100
|
+
|
|
101
|
+
type CourtDiaristInvocationResult = {
|
|
102
|
+
readonly identity: CourtDiaristIdentity;
|
|
103
|
+
readonly failedWithoutEscalate?: { readonly diagnostic: string };
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
/** Routing boolean over the child's own typed sequence — does not pick or rewrite a sole row. */
|
|
107
|
+
function courtDiaristEscalated(roleOutcome: TerminalRoleOutcome | undefined): boolean {
|
|
108
|
+
if (roleOutcome === undefined) return false;
|
|
109
|
+
if (roleOutcome.kind === "audit_escalation") return true;
|
|
110
|
+
if (roleOutcome.kind !== "accepted") return false;
|
|
111
|
+
return (roleOutcome.payloads ?? []).some((payload) => {
|
|
112
|
+
if (typeof payload !== "object" || payload === null || Array.isArray(payload)) return false;
|
|
113
|
+
const record = payload as Record<string, unknown>;
|
|
114
|
+
return record.status === "escalate" || record.countersignStatus === "escalate";
|
|
115
|
+
});
|
|
116
|
+
}
|
|
100
117
|
|
|
101
118
|
/**
|
|
102
119
|
* Invoke public 起居郎 under the court-pipeline quiet face.
|
|
@@ -112,10 +129,7 @@ async function invokeCourtDiarist(input: {
|
|
|
112
129
|
readonly failureLabel: string;
|
|
113
130
|
/** Already-verified typed key from countersign (refresh / post-assert handoff). */
|
|
114
131
|
readonly boundTicketNumber?: number;
|
|
115
|
-
}, env: CountersignRunEnv, io: CliIo): Promise<{
|
|
116
|
-
readonly identity: CourtDiaristIdentity;
|
|
117
|
-
readonly failedWithoutEscalate?: { readonly diagnostic: string };
|
|
118
|
-
}> {
|
|
132
|
+
}, env: CountersignRunEnv, io: CliIo): Promise<CourtDiaristInvocationResult> {
|
|
119
133
|
// Quiet face: the countersign caller must not see diarist CLI chatter.
|
|
120
134
|
const quietIo: CliIo = {
|
|
121
135
|
stdout() {},
|
|
@@ -145,23 +159,12 @@ async function invokeCourtDiarist(input: {
|
|
|
145
159
|
});
|
|
146
160
|
|
|
147
161
|
const roleOutcome = result.terminal?.roleOutcome;
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
? facts.countersignStatus
|
|
155
|
-
: roleOutcome.kind === "audit_escalation"
|
|
156
|
-
? "escalate"
|
|
157
|
-
: undefined;
|
|
158
|
-
if (status === "escalate") {
|
|
159
|
-
const reason =
|
|
160
|
-
typeof facts?.reason === "string"
|
|
161
|
-
? facts.reason
|
|
162
|
-
: "diarist escalated without reason";
|
|
163
|
-
return { identity: { kind: "escalate", reason } };
|
|
164
|
-
}
|
|
162
|
+
// Escalate routing is a boolean over the preserved sequence (#881). Reasons and
|
|
163
|
+
// payload bodies stay on roleOutcome — never rewritten into a sole identity reason.
|
|
164
|
+
if (courtDiaristEscalated(roleOutcome)) {
|
|
165
|
+
return {
|
|
166
|
+
identity: { kind: "escalate" },
|
|
167
|
+
};
|
|
165
168
|
}
|
|
166
169
|
|
|
167
170
|
if (result.exitCode !== 0) {
|
|
@@ -183,9 +186,13 @@ async function invokeCourtDiarist(input: {
|
|
|
183
186
|
Number.isSafeInteger(asserted) &&
|
|
184
187
|
asserted >= 1
|
|
185
188
|
) {
|
|
186
|
-
return {
|
|
189
|
+
return {
|
|
190
|
+
identity: { kind: "ticket", ticketNumber: asserted },
|
|
191
|
+
};
|
|
187
192
|
}
|
|
188
|
-
return {
|
|
193
|
+
return {
|
|
194
|
+
identity: { kind: "unbound" },
|
|
195
|
+
};
|
|
189
196
|
}
|
|
190
197
|
|
|
191
198
|
/**
|
|
@@ -226,7 +233,7 @@ export async function runCountersignCourtDiaristStation(
|
|
|
226
233
|
|
|
227
234
|
if (outcome.identity.kind === "escalate") {
|
|
228
235
|
throw new StationChildExhaustedError(
|
|
229
|
-
|
|
236
|
+
"court diarist station escalated (cannot identify court target)",
|
|
230
237
|
);
|
|
231
238
|
}
|
|
232
239
|
if (outcome.failedWithoutEscalate !== undefined) {
|
|
@@ -309,7 +316,7 @@ export async function runPublicCountersign(
|
|
|
309
316
|
code: null,
|
|
310
317
|
stderr: "",
|
|
311
318
|
thrown: new Error(
|
|
312
|
-
|
|
319
|
+
"court diarist station escalated (cannot identify court target)",
|
|
313
320
|
),
|
|
314
321
|
},
|
|
315
322
|
countersignAdapters(),
|
|
@@ -35,11 +35,12 @@ import {
|
|
|
35
35
|
trySettleDiaristTerminalResult,
|
|
36
36
|
} from "./settlement.ts";
|
|
37
37
|
import type { CliIo } from "./cli-io.ts";
|
|
38
|
-
import {
|
|
38
|
+
import type { TerminalResult } from "./terminal.ts";
|
|
39
39
|
import {
|
|
40
40
|
projectRoleTurnRequest,
|
|
41
41
|
type RoleTurnRequestProjectionOptions,
|
|
42
42
|
} from "./turn-request.ts";
|
|
43
|
+
import { readRunTicketNumber } from "../run-ticket-number.ts";
|
|
43
44
|
|
|
44
45
|
export type DiaristRunEnv = PostAdmissionEnv & {
|
|
45
46
|
principalAuthority: DurablePrincipalAuthority;
|
|
@@ -191,33 +192,15 @@ export async function runPublicDiarist(
|
|
|
191
192
|
adapters: diaristAdapters(),
|
|
192
193
|
...(env.engine === undefined ? {} : { effectiveEngine: env.engine }),
|
|
193
194
|
}).then(async (result) => {
|
|
194
|
-
// Accept
|
|
195
|
-
//
|
|
196
|
-
//
|
|
195
|
+
// Accept hook binds ticket onto durable pages (#771). Mirror that page fact
|
|
196
|
+
// onto the caller-visible admitted object — never pick a ticketNumber out of
|
|
197
|
+
// the payload sequence (#881 sole-collapse ban on ticket/escalate).
|
|
197
198
|
if (admitted.ticketNumber === undefined && result.admitted !== undefined) {
|
|
198
|
-
const
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
if (
|
|
204
|
-
roleOutcome !== undefined &&
|
|
205
|
-
roleOutcome.kind === "accepted" &&
|
|
206
|
-
facts?.status !== "escalate"
|
|
207
|
-
) {
|
|
208
|
-
const raw =
|
|
209
|
-
typeof facts?.ticketNumber === "number"
|
|
210
|
-
? facts.ticketNumber
|
|
211
|
-
: typeof facts?.sitian === "object"
|
|
212
|
-
&& facts.sitian !== null
|
|
213
|
-
&& typeof (facts.sitian as { ticketNumber?: unknown }).ticketNumber === "number"
|
|
214
|
-
? (facts.sitian as { ticketNumber: number }).ticketNumber
|
|
215
|
-
: undefined;
|
|
216
|
-
if (typeof raw === "number" && Number.isSafeInteger(raw) && raw >= 1) {
|
|
217
|
-
(admitted as { ticketNumber?: number }).ticketNumber = raw;
|
|
218
|
-
if (result.admitted.ticketNumber === undefined) {
|
|
219
|
-
(result.admitted as { ticketNumber?: number }).ticketNumber = raw;
|
|
220
|
-
}
|
|
199
|
+
const fromPages = await readRunTicketNumber(admitted.runDirectory);
|
|
200
|
+
if (fromPages !== undefined) {
|
|
201
|
+
await bindAdmittedTicketNumber(admitted, fromPages);
|
|
202
|
+
if (result.admitted.ticketNumber === undefined) {
|
|
203
|
+
(result.admitted as { ticketNumber?: number }).ticketNumber = fromPages;
|
|
221
204
|
}
|
|
222
205
|
}
|
|
223
206
|
}
|
|
@@ -122,7 +122,9 @@ function instructionSeatAdapters(options?: {
|
|
|
122
122
|
return infrastructureFailure === undefined
|
|
123
123
|
? result.knownFailure
|
|
124
124
|
: {
|
|
125
|
-
|
|
125
|
+
...(infrastructureFailure.cause === undefined
|
|
126
|
+
? {}
|
|
127
|
+
: { cause: infrastructureFailure.cause }),
|
|
126
128
|
diagnostic: infrastructureFailure.diagnostic,
|
|
127
129
|
...(infrastructureFailure.identity === undefined
|
|
128
130
|
? {}
|
|
@@ -63,7 +63,9 @@ function judgeAdapters(): PostAdmissionAdapters<AdmittedJudgeInvocation> {
|
|
|
63
63
|
(infrastructureFailure === undefined
|
|
64
64
|
? undefined
|
|
65
65
|
: {
|
|
66
|
-
|
|
66
|
+
...(infrastructureFailure.cause === undefined
|
|
67
|
+
? {}
|
|
68
|
+
: { cause: infrastructureFailure.cause }),
|
|
67
69
|
diagnostic: infrastructureFailure.diagnostic,
|
|
68
70
|
...(infrastructureFailure.identity === undefined
|
|
69
71
|
? {}
|
|
@@ -104,7 +104,9 @@ function reviewerAdapters(
|
|
|
104
104
|
return infrastructureFailure === undefined
|
|
105
105
|
? result.knownFailure
|
|
106
106
|
: {
|
|
107
|
-
|
|
107
|
+
...(infrastructureFailure.cause === undefined
|
|
108
|
+
? {}
|
|
109
|
+
: { cause: infrastructureFailure.cause }),
|
|
108
110
|
diagnostic: infrastructureFailure.diagnostic,
|
|
109
111
|
...(infrastructureFailure.identity === undefined
|
|
110
112
|
? {}
|