@akagilnc/pi-workflow-roles 0.1.5382 → 0.1.5462
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/README.md +4 -2
- package/README.zh-CN.md +4 -2
- package/dist/acp-host/production-host.js +8843 -9012
- package/dist/archivist-record-pointer.js +38 -0
- package/dist/compliance-transport.js +7 -5
- package/dist/doctor-auditor.js +1 -0
- package/dist/engine-detour-usage.js +9 -36
- package/dist/gatekeeper-role.js +4 -18
- package/dist/headless-host/description.js +0 -209
- package/dist/headless-host/production-host.js +7828 -8247
- package/dist/host-contracts.js +8 -0
- package/dist/judge-role.js +14 -1
- package/dist/migrate-book-topology.js +215 -96
- package/dist/navigator-attendance.js +10 -9
- package/dist/navigator-invocation-identity.js +18 -0
- package/dist/packaged-role-registry.js +1 -9
- package/dist/pi/role-turn-host.js +46 -19
- package/dist/public-cli/auto-resume.js +29 -66
- package/dist/public-cli/cli.js +1 -0
- package/dist/public-cli/countersign-run.js +4 -18
- package/dist/public-cli/instruction-seat-run.js +258 -69
- package/dist/public-cli/main.js +7488 -7758
- package/dist/public-cli/post-admission.js +451 -349
- package/dist/public-cli/process-cancel.js +8 -0
- package/dist/public-cli/run-lifecycle.js +24 -94
- package/dist/public-cli/settlement.js +624 -1471
- package/dist/public-cli/terminal.js +34 -53
- package/dist/public-cli/turn-request.js +3 -0
- package/dist/public-role-summons.js +3 -8
- package/dist/receipt-delivery-policy.js +162 -28
- package/dist/run-terminal-artifacts.js +19 -14
- package/dist/serialize-thrown-value.js +7 -1
- package/dist/submission-errors.js +11 -1
- package/dist/submission-gate.js +27 -4
- package/dist/submission-ledger.js +21 -89
- package/package.json +1 -1
- package/scripts/build-package.mjs +0 -2
- package/src/acp-host/role-turn-host.ts +168 -75
- package/src/archivist-record-pointer.ts +48 -0
- package/src/compliance-transport.ts +13 -8
- package/src/doctor-auditor.ts +3 -0
- package/src/engine-detour-usage.ts +10 -39
- package/src/external-host-turn-loop.ts +100 -43
- package/src/gatekeeper-role.ts +7 -22
- package/src/headless-host/description.ts +4 -214
- package/src/headless-host/production-host.ts +2 -1
- package/src/headless-host/role-turn-host.ts +153 -186
- package/src/host-contracts.ts +20 -10
- package/src/judge-role.ts +24 -5
- package/src/navigator-attendance.ts +17 -12
- package/src/navigator-invocation-identity.ts +31 -0
- package/src/navigator-public-session.ts +1 -1
- package/src/navigator-session-contracts.ts +1 -1
- package/src/packaged-role-registry.ts +2 -10
- package/src/pi/adapter.ts +33 -11
- package/src/pi/role-turn-host.ts +49 -28
- package/src/prepared-role-turn.ts +2 -0
- package/src/public-cli/auto-resume.ts +27 -66
- package/src/public-cli/cli.ts +1 -0
- package/src/public-cli/countersign-run.ts +4 -22
- package/src/public-cli/instruction-seat-run.ts +307 -74
- package/src/public-cli/post-admission.ts +615 -459
- package/src/public-cli/process-cancel.ts +9 -0
- package/src/public-cli/run-lifecycle.ts +25 -126
- package/src/public-cli/settlement.ts +801 -1859
- package/src/public-cli/terminal.ts +42 -70
- package/src/public-cli/turn-request.ts +10 -1
- package/src/public-role-summons.ts +3 -8
- package/src/receipt-delivery-policy.ts +219 -28
- package/src/role-envelope.ts +21 -10
- package/src/role-runtime-dependencies.ts +1 -0
- package/src/role-runtime.ts +79 -102
- package/src/run-terminal-artifacts.ts +21 -17
- package/src/serialize-thrown-value.ts +7 -1
- package/src/submission-correctable-error.ts +5 -2
- package/src/submission-errors.ts +12 -1
- package/src/submission-gate.ts +34 -4
- package/src/submission-ledger.ts +30 -116
- package/src/worker-role.ts +19 -7
- package/src/worker-submission-gates.ts +29 -7
- package/dist/audit-escalation.js +0 -7
- package/dist/pi/known-failure.js +0 -51
- package/dist/typed-provider-http.js +0 -57
- package/dist/upstream-error-testimony.js +0 -19
- package/src/pi/known-failure.ts +0 -76
- package/src/typed-provider-http.ts +0 -89
- package/src/upstream-error-testimony.ts +0 -45
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
import { dirname, resolve } from "node:path";
|
|
7
7
|
import { isUnboundRunDirectory } from "../role-run-placement.js";
|
|
8
8
|
import { AUDITOR_DOSSIER_PROMPT } from "../compliance-transport.js";
|
|
9
|
-
import { bookDirectOfficerRunPointer } from "../archivist-record-pointer.js";
|
|
9
|
+
import { bookDirectOfficerRunPointer, readDirectOfficerRunPointer } from "../archivist-record-pointer.js";
|
|
10
10
|
import { createPiDoctorAuditor } from "../doctor-auditor.js";
|
|
11
11
|
import { officerConclusionReask, gateOfficerForSubject } from "../gatekeeper-role.js";
|
|
12
12
|
import { receivedDiscriminator } from "../submission-errors.js";
|
|
@@ -15,6 +15,7 @@ import { runJudgeGates } from "../judge-role.js";
|
|
|
15
15
|
import { WORKER_DONE_STATUSES } from "../worker-submission-contracts.js";
|
|
16
16
|
import { SECRETARIAT_GATE_OFFICER_ENTRY_TYPE } from "../secretariat-contracts.js";
|
|
17
17
|
import { readableGateItem } from "../readable-gate-item.js";
|
|
18
|
+
import { deliveryLimitFromConfig } from "../receipt-delivery-policy.js";
|
|
18
19
|
import { runIdFromRunDirectory } from "../run-terminal-artifacts.js";
|
|
19
20
|
import { createDefaultGateOfficerSummon, requireSubmissionGate } from "../submission-gate.js";
|
|
20
21
|
import { readRecordedSubmissionRows } from "../submission-ledger.js";
|
|
@@ -28,13 +29,14 @@ import { packagedAdmitsCountersign, packagedBindsBoardTicket, packagedRebindSour
|
|
|
28
29
|
import { readAuditorResumeBinding } from "../auditor-soul.js";
|
|
29
30
|
import { CliUsageError } from "./cli-errors.js";
|
|
30
31
|
import { admitPublicRole, bindAdmittedTicketNumber, buildInstructionTransportPrompt, materializeCountersignInvocation, persistAdmittedSourceRunPath, recordAdmittedCorrelation, recordChildDiaristRun, relocateAdmittedRunToTicket, withPreparedAttachments, } from "./invocation.js";
|
|
31
|
-
import { presentControlledFailure, prepareSummonsResumeMaterials, roleTurnOptions, runPostAdmissionOneShot, runPostAdmissionResumable, runPostAdmissionSeatResume, showResumeErrorPointer, resumeTurnRequestProjectionOptions, } from "./post-admission.js";
|
|
32
|
-
import {
|
|
32
|
+
import { presentControlledFailure, packageFaultNoteFor, prepareSummonsResumeMaterials, roleTurnOptions, runPostAdmissionOneShot, runPostAdmissionResumable, runPostAdmissionSeatResume, showResumeErrorPointer, resumeTurnRequestProjectionOptions, } from "./post-admission.js";
|
|
33
|
+
import { presentTerminal } from "./auto-resume.js";
|
|
34
|
+
import { buildAutoResumeContinuationPrompt, loadResumablePublicRole, markRunAdmitted, parentRunPathFromGatePointerInstruction, readCurrentCourt, } from "./run-lifecycle.js";
|
|
33
35
|
import { tryResumeSameTicketSeatRun } from "./seat-ticket-binding.js";
|
|
34
|
-
import { presentStructuralRejection, readBoundSessionEntries,
|
|
36
|
+
import { presentStructuralRejection, readBoundSessionEntries, attachPostAuditProjection, trySettlePublicSeat, } from "./settlement.js";
|
|
35
37
|
import { warnMissingMethodSkills } from "./machine-method-skills.js";
|
|
36
38
|
import { formatTerminalResult, isLawfulTypedTerminalOutcome, } from "./terminal.js";
|
|
37
|
-
import { admittedSeatTurnDetails,
|
|
39
|
+
import { admittedSeatTurnDetails, projectRoleTurnRequest, requiredMethodSkills, } from "./turn-request.js";
|
|
38
40
|
import { invokeCourtDiarist, latestPayloadEscalated, } from "./countersign-run.js";
|
|
39
41
|
import { isRecord, errorText } from "../unknown-value.js";
|
|
40
42
|
const AUDITED_ROLES = new Set(["judge", "fixer", "coder", "secretariat", "countersign", "doctor"]);
|
|
@@ -80,11 +82,81 @@ function unreadablePostSubmissionStatus(admitted, terminal) {
|
|
|
80
82
|
? undefined
|
|
81
83
|
: route.reask ?? officerConclusionReask(status);
|
|
82
84
|
}
|
|
83
|
-
|
|
84
|
-
|
|
85
|
+
/**
|
|
86
|
+
* One more unreadable-status reask. This loop has its own counter and reads
|
|
87
|
+
* the same autoResumeLimit as the other loops. Exhaustion is not a readable
|
|
88
|
+
* status: the caller presents the volumes already in hand and does not advance
|
|
89
|
+
* review. ADR 0007 audit continues are not this shape.
|
|
90
|
+
*/
|
|
91
|
+
function withUnreadableReask(env) {
|
|
92
|
+
const spent = env.unreadableReasksSpent ?? 0;
|
|
93
|
+
if (spent >= deliveryLimitFromConfig(env.autoResumeLimit))
|
|
94
|
+
return undefined;
|
|
95
|
+
return { ...env, unreadableReasksSpent: spent + 1 };
|
|
96
|
+
}
|
|
97
|
+
/** Budget spent on an unreadable status. Distinct from "status is readable". */
|
|
98
|
+
const UNREADABLE_REASK_EXHAUSTED = { unreadableReaskExhausted: true };
|
|
99
|
+
function isUnreadableReaskExhausted(value) {
|
|
100
|
+
return value === UNREADABLE_REASK_EXHAUSTED;
|
|
101
|
+
}
|
|
102
|
+
async function presentOriginalVolume(held, terminal, io, runDirectory) {
|
|
103
|
+
if (terminal !== undefined && runDirectory !== undefined) {
|
|
104
|
+
// Direction facts were attached after the held volume was formatted.
|
|
105
|
+
await presentTerminal(terminal, { ...io, omitFailureStderrDiagnostic: true }, runDirectory, terminal.roleOutcome.decisiveFacts?.directionUnsettled === true ? undefined : held);
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
// No settled host report exists to preserve at this pre-result boundary.
|
|
109
|
+
for (const value of held)
|
|
110
|
+
io.stdout(value);
|
|
111
|
+
}
|
|
112
|
+
/** Runtime fact beside the original volume. Payloads stay as submitted. */
|
|
113
|
+
function withUnsettledDirection(parent, officer) {
|
|
114
|
+
const outcome = parent.roleOutcome;
|
|
115
|
+
if (outcome.kind !== "accepted" && outcome.kind !== "audit_escalation")
|
|
116
|
+
return parent;
|
|
117
|
+
const officerOutcome = officer?.roleOutcome;
|
|
118
|
+
const officerPayloads = officer?.submissions !== undefined && officer.submissions.length > 0
|
|
119
|
+
? officer.submissions
|
|
120
|
+
: officerOutcome !== undefined && officerOutcome.kind !== "no_receipt"
|
|
121
|
+
? officerOutcome.payloads ?? []
|
|
122
|
+
: [];
|
|
123
|
+
return {
|
|
124
|
+
...parent,
|
|
125
|
+
roleOutcome: {
|
|
126
|
+
...outcome,
|
|
127
|
+
decisiveFacts: {
|
|
128
|
+
...(outcome.decisiveFacts ?? {}),
|
|
129
|
+
directionUnsettled: true,
|
|
130
|
+
subsequentAudit: "incomplete",
|
|
131
|
+
...(officerOutcome === undefined ? {} : { officerRole: officerOutcome.role }),
|
|
132
|
+
...(officer?.runId === undefined ? {} : { officerRunId: officer.runId }),
|
|
133
|
+
...(officerPayloads.length === 0 ? {} : { officerPayloads }),
|
|
134
|
+
},
|
|
135
|
+
},
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
function heldUnreadableTerminal(terminal) {
|
|
139
|
+
if (terminal?.roleOutcome.kind !== "accepted")
|
|
140
|
+
return false;
|
|
141
|
+
if (latestPayloadEscalated(terminal.roleOutcome))
|
|
142
|
+
return false;
|
|
143
|
+
const status = latestQueueStatus(terminal);
|
|
144
|
+
return typeof status !== "string" || !REVIEW_QUEUE_STATUSES.has(status);
|
|
145
|
+
}
|
|
146
|
+
async function presentUnsettledAudit(parent, officer, io, runDirectory) {
|
|
147
|
+
const terminal = withUnsettledDirection(parent, officer);
|
|
148
|
+
await presentTerminal(terminal, { ...io, omitFailureStderrDiagnostic: true }, runDirectory);
|
|
149
|
+
if (officer !== undefined)
|
|
150
|
+
await presentTerminal(officer, { ...io, omitFailureStderrDiagnostic: true }, runDirectory);
|
|
151
|
+
return terminal;
|
|
152
|
+
}
|
|
153
|
+
async function reaskUnreadablePostSubmissionStatus(admitted, terminal, env, io, message = unreadablePostSubmissionStatus(admitted, terminal)) {
|
|
85
154
|
if (message === undefined)
|
|
86
155
|
return undefined;
|
|
87
|
-
|
|
156
|
+
const next = withUnreadableReask(env);
|
|
157
|
+
if (next === undefined)
|
|
158
|
+
return UNREADABLE_REASK_EXHAUSTED;
|
|
159
|
+
return runPublicInstructionSeatResume({ runId: admitted.runId, summons: { instruction: message } }, next, io);
|
|
88
160
|
}
|
|
89
161
|
function roleRecord(role) {
|
|
90
162
|
const record = packagedRoleMetadata(role);
|
|
@@ -108,10 +180,6 @@ function initialPrompt(admitted, env) {
|
|
|
108
180
|
packageRoot: env.packageRoot,
|
|
109
181
|
}));
|
|
110
182
|
}
|
|
111
|
-
function infraFailure(role) {
|
|
112
|
-
const resolveRunnerKnownFailure = seatKnownFailureResolver(role);
|
|
113
|
-
return resolveRunnerKnownFailure === undefined ? {} : { resolveRunnerKnownFailure };
|
|
114
|
-
}
|
|
115
183
|
function isBoardTicketSeat(seat) {
|
|
116
184
|
return packagedBindsBoardTicket(seat.role);
|
|
117
185
|
}
|
|
@@ -124,6 +192,9 @@ async function bindAndRelocateDiarist(admitted, authority, lease) {
|
|
|
124
192
|
}
|
|
125
193
|
return await relocateAdmittedRunToTicket(admitted, authority, lease);
|
|
126
194
|
}
|
|
195
|
+
function packageFaultScope(admitted, env, io) {
|
|
196
|
+
return { notePackageFault: packageFaultNoteFor(admitted, env, io) };
|
|
197
|
+
}
|
|
127
198
|
function seatAdapters(admitted, env) {
|
|
128
199
|
const record = roleRecord(admitted.role);
|
|
129
200
|
const present = "presentSettled" in record ? record.presentSettled : "default";
|
|
@@ -133,7 +204,6 @@ function seatAdapters(admitted, env) {
|
|
|
133
204
|
...(present === "typed"
|
|
134
205
|
? { shouldPresentSettled: (terminal) => isLawfulTypedTerminalOutcome(terminal.roleOutcome) }
|
|
135
206
|
: {}),
|
|
136
|
-
...infraFailure(admitted.role),
|
|
137
207
|
...(packagedBindsBoardTicket(admitted.role)
|
|
138
208
|
? {
|
|
139
209
|
beforeDispatch: async (seat, lease) => {
|
|
@@ -232,13 +302,19 @@ async function dispatchAdmitted(admitted, env, io) {
|
|
|
232
302
|
};
|
|
233
303
|
const result = await execute(env);
|
|
234
304
|
const unreadableReask = await reaskUnreadablePostSubmissionStatus(admitted, result.terminal, env, io);
|
|
305
|
+
if (isUnreadableReaskExhausted(unreadableReask)) {
|
|
306
|
+
const terminal = result.terminal === undefined
|
|
307
|
+
? undefined
|
|
308
|
+
: withUnsettledDirection(result.terminal);
|
|
309
|
+
await presentOriginalVolume(held, terminal, io, admitted.runDirectory);
|
|
310
|
+
return terminal === undefined ? result : { ...result, terminal };
|
|
311
|
+
}
|
|
235
312
|
if (unreadableReask !== undefined)
|
|
236
313
|
return unreadableReask;
|
|
237
314
|
if (AUDITED_ROLES.has(admitted.role) && result.terminal?.roleOutcome.kind === "accepted") {
|
|
238
315
|
return auditSubmittedRole(result, env, io);
|
|
239
316
|
}
|
|
240
|
-
|
|
241
|
-
io.stdout(value);
|
|
317
|
+
await presentOriginalVolume(held, result.terminal, io, admitted.runDirectory);
|
|
242
318
|
return result;
|
|
243
319
|
}
|
|
244
320
|
/**
|
|
@@ -306,7 +382,11 @@ async function runOmittedLensBatch(argv, parsed, env, io) {
|
|
|
306
382
|
},
|
|
307
383
|
artifacts: terminals.flatMap((item) => item.artifacts),
|
|
308
384
|
};
|
|
309
|
-
|
|
385
|
+
const childRunDirectory = children.completeness.admitted?.runDirectory ?? children.correctness.admitted?.runDirectory;
|
|
386
|
+
if (childRunDirectory !== undefined)
|
|
387
|
+
await presentTerminal(terminal, { ...io, omitFailureStderrDiagnostic: true }, childRunDirectory);
|
|
388
|
+
else
|
|
389
|
+
io.stdout(formatTerminalResult(terminal));
|
|
310
390
|
return { exitCode: failed ? 1 : 0, terminal };
|
|
311
391
|
}
|
|
312
392
|
/**
|
|
@@ -387,20 +467,14 @@ async function runCountersignBody(parsed, env, io) {
|
|
|
387
467
|
await persistAdmittedSourceRunPath(admitted, gateParentRunPath);
|
|
388
468
|
admitted = { ...admitted, sourceRunPath: gateParentRunPath };
|
|
389
469
|
}
|
|
390
|
-
const turnProjection = {
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
?? buildInstructionTransportPrompt(admitted, engineSessionMaterialFromOptions({
|
|
399
|
-
...pickEngineAxis(env),
|
|
400
|
-
packageRoot: env.packageRoot,
|
|
401
|
-
})),
|
|
402
|
-
},
|
|
403
|
-
};
|
|
470
|
+
const turnProjection = roleTurnOptions(env, admitted, {
|
|
471
|
+
kind: "initial",
|
|
472
|
+
prompt: (env.reviewReask ?? env.gateReviewInstruction)
|
|
473
|
+
?? buildInstructionTransportPrompt(admitted, engineSessionMaterialFromOptions({
|
|
474
|
+
...pickEngineAxis(env),
|
|
475
|
+
packageRoot: env.packageRoot,
|
|
476
|
+
})),
|
|
477
|
+
});
|
|
404
478
|
const turnRequest = buildInstructionSeatTurnRequest(admitted, turnProjection);
|
|
405
479
|
const result = await runPostAdmissionOneShot({
|
|
406
480
|
admitted,
|
|
@@ -448,8 +522,7 @@ export async function runPublicInstructionSeat(argv, env, io, role, parseArgv) {
|
|
|
448
522
|
});
|
|
449
523
|
if (result.terminal?.roleOutcome.kind === "accepted")
|
|
450
524
|
return auditSubmittedRole(result, env, io);
|
|
451
|
-
|
|
452
|
-
io.stdout(value);
|
|
525
|
+
await presentOriginalVolume(held, result.terminal, io, result.admitted?.runDirectory);
|
|
453
526
|
return result;
|
|
454
527
|
}
|
|
455
528
|
if ("parallelLenses" in record && record.parallelLenses === true) {
|
|
@@ -611,7 +684,7 @@ export async function runPublicInstructionSeat(argv, env, io, role, parseArgv) {
|
|
|
611
684
|
catch (error) {
|
|
612
685
|
return await presentControlledFailure(admitted, {
|
|
613
686
|
timedOut: false, code: null, stderr: "", thrown: error,
|
|
614
|
-
}, seatAdapters(admitted, env), env.principalAuthority, io);
|
|
687
|
+
}, seatAdapters(admitted, env), env.principalAuthority, io, true, packageFaultNoteFor(admitted, env, io));
|
|
615
688
|
}
|
|
616
689
|
if (outcome.admitted !== undefined && isUnboundRunDirectory(outcome.admitted.runDirectory)) {
|
|
617
690
|
await recordChildDiaristRun(admitted, outcome.admitted.runId);
|
|
@@ -620,12 +693,12 @@ export async function runPublicInstructionSeat(argv, env, io, role, parseArgv) {
|
|
|
620
693
|
return await presentControlledFailure(admitted, {
|
|
621
694
|
timedOut: false, code: null, stderr: "",
|
|
622
695
|
thrown: new Error(outcome.failedWithoutEscalate.diagnostic),
|
|
623
|
-
}, seatAdapters(admitted, env), env.principalAuthority, io);
|
|
696
|
+
}, seatAdapters(admitted, env), env.principalAuthority, io, true, packageFaultNoteFor(admitted, env, io));
|
|
624
697
|
}
|
|
625
698
|
// The diarist's escalation pauses only the diarist's own run; call order
|
|
626
699
|
// belongs to the caller, so the Secretariat still takes its own turn.
|
|
627
700
|
if (outcome.identity.kind === "escalate" && outcome.terminal !== undefined) {
|
|
628
|
-
|
|
701
|
+
await presentTerminal(outcome.terminal, { ...io, omitFailureStderrDiagnostic: true }, outcome.admitted?.runDirectory ?? admitted.runDirectory);
|
|
629
702
|
}
|
|
630
703
|
}
|
|
631
704
|
return dispatchAdmitted(admitted, env, io);
|
|
@@ -684,14 +757,20 @@ export async function runPublicInstructionSeatResume(request, env, io) {
|
|
|
684
757
|
const unreadableReask = result.admitted === undefined
|
|
685
758
|
? undefined
|
|
686
759
|
: await reaskUnreadablePostSubmissionStatus(result.admitted, result.terminal, env, io);
|
|
760
|
+
if (isUnreadableReaskExhausted(unreadableReask)) {
|
|
761
|
+
const terminal = result.terminal === undefined
|
|
762
|
+
? undefined
|
|
763
|
+
: withUnsettledDirection(result.terminal);
|
|
764
|
+
await presentOriginalVolume(held, terminal, io, result.admitted?.runDirectory);
|
|
765
|
+
return terminal === undefined ? result : { ...result, terminal };
|
|
766
|
+
}
|
|
687
767
|
if (unreadableReask !== undefined)
|
|
688
768
|
return unreadableReask;
|
|
689
769
|
if (result.admitted !== undefined && AUDITED_ROLES.has(result.admitted.role)
|
|
690
770
|
&& result.terminal?.roleOutcome.kind === "accepted") {
|
|
691
771
|
return auditSubmittedRole(result, env, io);
|
|
692
772
|
}
|
|
693
|
-
|
|
694
|
-
io.stdout(value);
|
|
773
|
+
await presentOriginalVolume(held, result.terminal, io, result.admitted?.runDirectory);
|
|
695
774
|
return result;
|
|
696
775
|
};
|
|
697
776
|
let binding;
|
|
@@ -717,23 +796,42 @@ export async function runPublicInstructionSeatResume(request, env, io) {
|
|
|
717
796
|
const GATE_CHILD_ROLES = new Set(["notary", "auditor", "inspector", "countersign"]);
|
|
718
797
|
/**
|
|
719
798
|
* A gate child's conclusion outside the three states goes back to that child.
|
|
720
|
-
* The words are the existing officer re-ask.
|
|
799
|
+
* The words are the existing officer re-ask. Each reask spends this loop's own
|
|
800
|
+
* copy of the configured ceiling; exhaustion keeps the terminal already in hand.
|
|
801
|
+
* A host failure stops here.
|
|
802
|
+
* Countersign already spends that ceiling inside its own seat, or the summoning
|
|
803
|
+
* gate does. This loop does not open a second one for the same conclusion.
|
|
721
804
|
*/
|
|
722
805
|
async function queueConclusionFromChild(child, env, io) {
|
|
723
806
|
if (!GATE_CHILD_ROLES.has(child.role))
|
|
724
807
|
return undefined;
|
|
808
|
+
if (child.role === "countersign") {
|
|
809
|
+
const terminal = await trySettlePublicSeat(child, env.principalAuthority, { ...await readCurrentCourt(child.runDirectory), ...packageFaultScope(child, env, io) });
|
|
810
|
+
const status = latestQueueStatus(terminal);
|
|
811
|
+
if (terminal !== undefined && typeof status === "string" && REVIEW_QUEUE_STATUSES.has(status)) {
|
|
812
|
+
return { admitted: child, terminal, status };
|
|
813
|
+
}
|
|
814
|
+
return { stop: { exitCode: 0, ...(terminal === undefined ? {} : { terminal }) } };
|
|
815
|
+
}
|
|
725
816
|
let current = child;
|
|
817
|
+
// Notary, auditor, and inspector have no seat-local status reask. This loop
|
|
818
|
+
// is their one budget. The child resume keeps the caller's env so delivery,
|
|
819
|
+
// failure recovery, and other reask loops stay separate.
|
|
820
|
+
let budgetEnv = { ...env, unreadableReasksSpent: 0 };
|
|
726
821
|
for (;;) {
|
|
727
|
-
const terminal = await trySettlePublicSeat(current, env.principalAuthority,
|
|
822
|
+
const terminal = await trySettlePublicSeat(current, env.principalAuthority, { ...await readCurrentCourt(current.runDirectory), ...packageFaultScope(current, env, io) });
|
|
728
823
|
const status = latestQueueStatus(terminal);
|
|
729
824
|
if (terminal !== undefined && typeof status === "string" && REVIEW_QUEUE_STATUSES.has(status)) {
|
|
730
825
|
return { admitted: current, terminal, status };
|
|
731
826
|
}
|
|
732
|
-
const reasked = await
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
}
|
|
736
|
-
|
|
827
|
+
const reasked = await reaskUnreadablePostSubmissionStatus(current, terminal, budgetEnv, io, officerConclusionReask(status));
|
|
828
|
+
if (reasked === undefined || isUnreadableReaskExhausted(reasked)) {
|
|
829
|
+
return { stop: { exitCode: 0, ...(terminal === undefined ? {} : { terminal }) } };
|
|
830
|
+
}
|
|
831
|
+
budgetEnv = withUnreadableReask(budgetEnv);
|
|
832
|
+
if (reasked.exitCode !== 0 || reasked.admitted === undefined || reasked.terminal === undefined
|
|
833
|
+
|| reasked.terminal.roleOutcome.kind === "no_receipt"
|
|
834
|
+
|| reasked.terminal.roleOutcome.decisiveFacts?.directionUnsettled === true) {
|
|
737
835
|
return { stop: reasked };
|
|
738
836
|
}
|
|
739
837
|
const reaskedStatus = latestQueueStatus(reasked.terminal);
|
|
@@ -753,29 +851,72 @@ export async function continueParentAfterChild(parentRunId, child, env, io) {
|
|
|
753
851
|
}
|
|
754
852
|
const admitted = loaded.admitted;
|
|
755
853
|
const resolved = await queueConclusionFromChild(child, env, io);
|
|
756
|
-
if (resolved !== undefined && "stop" in resolved)
|
|
757
|
-
|
|
854
|
+
if (resolved !== undefined && "stop" in resolved) {
|
|
855
|
+
const stopped = resolved.stop;
|
|
856
|
+
if (stopped.exitCode === 0
|
|
857
|
+
&& heldUnreadableTerminal(stopped.terminal)
|
|
858
|
+
&& stopped.terminal !== undefined) {
|
|
859
|
+
const parentTerminal = await trySettlePublicSeat(admitted, env.principalAuthority, undefined);
|
|
860
|
+
if (parentTerminal?.roleOutcome.kind === "accepted"
|
|
861
|
+
|| parentTerminal?.roleOutcome.kind === "audit_escalation") {
|
|
862
|
+
const terminal = await presentUnsettledAudit(parentTerminal, stopped.terminal, io, admitted.runDirectory);
|
|
863
|
+
return { exitCode: 0, admitted, terminal };
|
|
864
|
+
}
|
|
865
|
+
}
|
|
866
|
+
return stopped;
|
|
867
|
+
}
|
|
758
868
|
if (resolved !== undefined && resolved.status === "escalate") {
|
|
759
869
|
return { exitCode: 0, admitted: resolved.admitted, terminal: resolved.terminal };
|
|
760
870
|
}
|
|
761
871
|
if (resolved !== undefined && (resolved.status === "continue" || resolved.status === "converged")) {
|
|
762
872
|
if (AUDITED_ROLES.has(admitted.role) && resolved.status === "converged") {
|
|
763
|
-
const terminal = await trySettlePublicSeat(admitted, env.principalAuthority,
|
|
873
|
+
const terminal = await trySettlePublicSeat(admitted, env.principalAuthority, packageFaultScope(admitted, env, io));
|
|
764
874
|
if (terminal?.roleOutcome.kind !== "accepted")
|
|
765
875
|
throw new Error("pending submission is not recorded");
|
|
766
|
-
return auditSubmittedRole({ exitCode: 0, admitted, terminal }, env, io, resolved.admitted
|
|
876
|
+
return auditSubmittedRole({ exitCode: 0, admitted, terminal }, env, io, resolved.admitted, latestQueuePayload(resolved.terminal));
|
|
767
877
|
}
|
|
768
878
|
return runPublicInstructionSeatResume({
|
|
769
879
|
runId: parentRunId,
|
|
770
|
-
|
|
771
|
-
}, { ...env,
|
|
880
|
+
summons: { instruction: readableGateItem(latestQueuePayload(resolved.terminal)) },
|
|
881
|
+
}, { ...env, unreadableReasksSpent: 0 }, io);
|
|
772
882
|
}
|
|
773
883
|
const result = await dispatchAdmitted(admitted, env, { ...io, omitFailureStderrDiagnostic: true });
|
|
774
884
|
showResumeErrorPointer(io, result.exitCode, result.terminal);
|
|
775
885
|
return result;
|
|
776
886
|
}
|
|
887
|
+
/**
|
|
888
|
+
* A gate is already passed only when an officer run reviewed this submission
|
|
889
|
+
* and its latest queue word is converged. The resumed seat's role is not itself
|
|
890
|
+
* a pass. Unknown or unreadable evidence does not skip the gate.
|
|
891
|
+
*/
|
|
892
|
+
async function officerPassedCurrentSubmission(input) {
|
|
893
|
+
const { env, officer } = input;
|
|
894
|
+
const pointer = await readDirectOfficerRunPointer(input.parentSessionFile, officer);
|
|
895
|
+
if (pointer?.runDirectory === undefined)
|
|
896
|
+
return false;
|
|
897
|
+
if (pointer.submissionToolCallId !== input.toolCallId)
|
|
898
|
+
return false;
|
|
899
|
+
const officerRunId = runIdFromRunDirectory(pointer.runDirectory);
|
|
900
|
+
if (officerRunId === undefined)
|
|
901
|
+
return false;
|
|
902
|
+
let admitted;
|
|
903
|
+
try {
|
|
904
|
+
const loaded = await loadResumablePublicRole(env.home, officerRunId, env.principalAuthority);
|
|
905
|
+
admitted = loaded.admitted;
|
|
906
|
+
}
|
|
907
|
+
catch {
|
|
908
|
+
return false;
|
|
909
|
+
}
|
|
910
|
+
if (admitted.role !== officer)
|
|
911
|
+
return false;
|
|
912
|
+
// A summon binding identifies the requested review, not its outcome. An open
|
|
913
|
+
// court (including a failed host turn) must not borrow a previous court's seal.
|
|
914
|
+
const court = await readCurrentCourt(admitted.runDirectory);
|
|
915
|
+
const terminal = await trySettlePublicSeat(admitted, env.principalAuthority, court);
|
|
916
|
+
return latestQueueStatus(terminal) === "converged";
|
|
917
|
+
}
|
|
777
918
|
/** Finished submissions enter the existing audit gate after their tool call has returned. */
|
|
778
|
-
async function auditSubmittedRole(turn, env, io,
|
|
919
|
+
async function auditSubmittedRole(turn, env, io, resumedOfficer, passedReceipt) {
|
|
779
920
|
const admitted = turn.admitted;
|
|
780
921
|
if (admitted === undefined || !AUDITED_ROLES.has(admitted.role)
|
|
781
922
|
|| turn.terminal?.roleOutcome.kind !== "accepted")
|
|
@@ -786,11 +927,30 @@ async function auditSubmittedRole(turn, env, io, passedOfficer, passedReceipt, p
|
|
|
786
927
|
const record = isRecord(accepted)
|
|
787
928
|
? accepted : undefined;
|
|
788
929
|
const status = admitted.role === "secretariat" ? record?.secretariatStatus : record?.status;
|
|
930
|
+
// A gate summon already owns this conclusion's reasks. The seat must not
|
|
931
|
+
// start another budget on the same run (parentRunPath is that summon).
|
|
932
|
+
const gateOwnsStatusReask = typeof env.parentRunPath === "string" && env.parentRunPath.trim() !== "";
|
|
789
933
|
if (admitted.role === "secretariat" && status !== "converged" && status !== "escalate") {
|
|
790
|
-
|
|
934
|
+
if (gateOwnsStatusReask)
|
|
935
|
+
return turn;
|
|
936
|
+
const next = withUnreadableReask(env);
|
|
937
|
+
if (next === undefined) {
|
|
938
|
+
const terminal = withUnsettledDirection(turn.terminal);
|
|
939
|
+
await presentTerminal(terminal, { ...io, omitFailureStderrDiagnostic: true }, admitted.runDirectory);
|
|
940
|
+
return { ...turn, terminal };
|
|
941
|
+
}
|
|
942
|
+
return runPublicInstructionSeatResume({ runId: admitted.runId, summons: { instruction: SECRETARIAT_STATUS_REASK } }, next, io);
|
|
791
943
|
}
|
|
792
944
|
if (admitted.role === "countersign" && (typeof status !== "string" || !REVIEW_QUEUE_STATUSES.has(status))) {
|
|
793
|
-
|
|
945
|
+
if (gateOwnsStatusReask)
|
|
946
|
+
return turn;
|
|
947
|
+
const next = withUnreadableReask(env);
|
|
948
|
+
if (next === undefined) {
|
|
949
|
+
const terminal = withUnsettledDirection(turn.terminal);
|
|
950
|
+
await presentTerminal(terminal, { ...io, omitFailureStderrDiagnostic: true }, admitted.runDirectory);
|
|
951
|
+
return { ...turn, terminal };
|
|
952
|
+
}
|
|
953
|
+
return runPublicInstructionSeatResume({ runId: admitted.runId, summons: { instruction: officerConclusionReask(status) } }, next, io);
|
|
794
954
|
}
|
|
795
955
|
// Self-escalation is a valid open routing state for these seats only.
|
|
796
956
|
// Doctor's declared domain is completed|refused — an open "escalate" must
|
|
@@ -802,7 +962,7 @@ async function auditSubmittedRole(turn, env, io, passedOfficer, passedReceipt, p
|
|
|
802
962
|
|| ((admitted.role === "fixer" || admitted.role === "coder")
|
|
803
963
|
&& (typeof status !== "string" || !WORKER_DONE_STATUSES.has(status)));
|
|
804
964
|
if (skipAudit) {
|
|
805
|
-
|
|
965
|
+
await presentTerminal(turn.terminal, { ...io, omitFailureStderrDiagnostic: true }, admitted.runDirectory);
|
|
806
966
|
return turn;
|
|
807
967
|
}
|
|
808
968
|
const rows = await readRecordedSubmissionRows(admitted.projectRoot, admitted.runId, env.home);
|
|
@@ -811,7 +971,9 @@ async function auditSubmittedRole(turn, env, io, passedOfficer, passedReceipt, p
|
|
|
811
971
|
if (toolCallId === undefined)
|
|
812
972
|
throw new Error("accepted submission has no tool call identity");
|
|
813
973
|
const sessionFile = env.principalAuthority.decode(admitted.principal).sessionFile;
|
|
814
|
-
const entries = admitted.role === "doctor"
|
|
974
|
+
const entries = admitted.role === "doctor"
|
|
975
|
+
? await readBoundSessionEntries(sessionFile)
|
|
976
|
+
: [];
|
|
815
977
|
const context = {
|
|
816
978
|
cwd: admitted.projectRoot,
|
|
817
979
|
mode: "print",
|
|
@@ -827,11 +989,18 @@ async function auditSubmittedRole(turn, env, io, passedOfficer, passedReceipt, p
|
|
|
827
989
|
},
|
|
828
990
|
abort() { },
|
|
829
991
|
};
|
|
992
|
+
const passedThisSubmission = (officer) => officerPassedCurrentSubmission({
|
|
993
|
+
env,
|
|
994
|
+
parentSessionFile: sessionFile,
|
|
995
|
+
officer,
|
|
996
|
+
toolCallId,
|
|
997
|
+
});
|
|
830
998
|
if (admitted.role === "doctor") {
|
|
831
|
-
if (
|
|
999
|
+
if (!await passedThisSubmission("auditor")) {
|
|
832
1000
|
let lastSummon;
|
|
833
1001
|
const decision = await createPiDoctorAuditor()({
|
|
834
1002
|
context, submission: accepted,
|
|
1003
|
+
...(env.autoResumeLimit === undefined ? {} : { autoResumeLimit: env.autoResumeLimit }),
|
|
835
1004
|
...(env.signal === undefined ? {} : { signal: env.signal }),
|
|
836
1005
|
summonAuditor: async (subject, sourceRunDirectory, signal, reask, submission) => {
|
|
837
1006
|
const summoned = await summonPublicRole({
|
|
@@ -851,6 +1020,7 @@ async function auditSubmittedRole(turn, env, io, passedOfficer, passedReceipt, p
|
|
|
851
1020
|
if (officerSession !== undefined) {
|
|
852
1021
|
bookDirectOfficerRunPointer({
|
|
853
1022
|
parentSessionFile: sessionFile, officer: "auditor", sessionFile: officerSession,
|
|
1023
|
+
submissionToolCallId: toolCallId,
|
|
854
1024
|
...(summoned.runDirectory === undefined ? {} : { runDirectory: summoned.runDirectory }),
|
|
855
1025
|
});
|
|
856
1026
|
}
|
|
@@ -860,12 +1030,21 @@ async function auditSubmittedRole(turn, env, io, passedOfficer, passedReceipt, p
|
|
|
860
1030
|
});
|
|
861
1031
|
if (decision.status === "continue") {
|
|
862
1032
|
return runPublicInstructionSeatResume({
|
|
863
|
-
runId: admitted.runId,
|
|
864
|
-
}, { ...env,
|
|
1033
|
+
runId: admitted.runId, summons: { instruction: readableGateItem(decision.receipt ?? decision.violations) },
|
|
1034
|
+
}, { ...env, unreadableReasksSpent: 0 }, io);
|
|
1035
|
+
}
|
|
1036
|
+
if (decision.status === "received") {
|
|
1037
|
+
if (lastSummon?.terminal === undefined) {
|
|
1038
|
+
throw new Error("doctor audit kept an unreadable reply with no terminal");
|
|
1039
|
+
}
|
|
1040
|
+
if (turn.terminal === undefined)
|
|
1041
|
+
throw new Error("doctor submission has no terminal");
|
|
1042
|
+
const terminal = await presentUnsettledAudit(turn.terminal, lastSummon.terminal, io, admitted.runDirectory);
|
|
1043
|
+
return { exitCode: 0, admitted, terminal };
|
|
865
1044
|
}
|
|
866
1045
|
if (decision.status !== "converged") {
|
|
867
1046
|
if (lastSummon?.terminal !== undefined) {
|
|
868
|
-
|
|
1047
|
+
await presentTerminal(lastSummon.terminal, { ...io, omitFailureStderrDiagnostic: true }, lastSummon.admitted?.runDirectory ?? admitted.runDirectory);
|
|
869
1048
|
return { exitCode: lastSummon.exitCode,
|
|
870
1049
|
...(lastSummon.admitted === undefined ? {} : { admitted: lastSummon.admitted }),
|
|
871
1050
|
terminal: lastSummon.terminal };
|
|
@@ -883,13 +1062,14 @@ async function auditSubmittedRole(turn, env, io, passedOfficer, passedReceipt, p
|
|
|
883
1062
|
...(env.hostAdapters === undefined ? {} : { hostAdapters: env.hostAdapters }),
|
|
884
1063
|
});
|
|
885
1064
|
let chain;
|
|
886
|
-
let officerRunId =
|
|
1065
|
+
let officerRunId = resumedOfficer?.runId;
|
|
887
1066
|
const runGate = (subject) => requireSubmissionGate({
|
|
888
1067
|
context,
|
|
889
1068
|
subject,
|
|
890
1069
|
toolCallId,
|
|
891
1070
|
submission: accepted,
|
|
892
1071
|
summonOfficer,
|
|
1072
|
+
...(env.autoResumeLimit === undefined ? {} : { autoResumeLimit: env.autoResumeLimit }),
|
|
893
1073
|
...(env.signal === undefined ? {} : { signal: env.signal }),
|
|
894
1074
|
hostActions: {
|
|
895
1075
|
failInfrastructure(error) { throw error; },
|
|
@@ -898,8 +1078,7 @@ async function auditSubmittedRole(turn, env, io, passedOfficer, passedReceipt, p
|
|
|
898
1078
|
});
|
|
899
1079
|
if (admitted.role === "judge") {
|
|
900
1080
|
chain = await runJudgeGates({
|
|
901
|
-
gateAlreadyConverged: async (subject) =>
|
|
902
|
-
|| (passedOfficer === "notary" && subject.kind === "judge_draft"),
|
|
1081
|
+
gateAlreadyConverged: async (subject) => passedThisSubmission(gateOfficerForSubject(subject)),
|
|
903
1082
|
runGate,
|
|
904
1083
|
});
|
|
905
1084
|
}
|
|
@@ -910,7 +1089,7 @@ async function auditSubmittedRole(turn, env, io, passedOfficer, passedReceipt, p
|
|
|
910
1089
|
? { kind: "secretariat_verdict" }
|
|
911
1090
|
: { kind: "countersign_verdict" };
|
|
912
1091
|
const officer = gateOfficerForSubject(subject);
|
|
913
|
-
if (
|
|
1092
|
+
if (await passedThisSubmission(officer)) {
|
|
914
1093
|
chain = { status: "converged", passes: [] };
|
|
915
1094
|
}
|
|
916
1095
|
else {
|
|
@@ -926,10 +1105,20 @@ async function auditSubmittedRole(turn, env, io, passedOfficer, passedReceipt, p
|
|
|
926
1105
|
receipt: pass.receipt,
|
|
927
1106
|
...(pass.runId === undefined ? {} : { runId: pass.runId }),
|
|
928
1107
|
...(pass.runDirectory === undefined ? {} : { runDirectory: pass.runDirectory }),
|
|
1108
|
+
...(pass.terminal === undefined ? {} : { terminal: pass.terminal }),
|
|
929
1109
|
}],
|
|
930
1110
|
};
|
|
931
1111
|
}
|
|
932
1112
|
}
|
|
1113
|
+
if (chain.status === "needs_reask") {
|
|
1114
|
+
const officerTerminal = chain.passes.at(-1)?.terminal;
|
|
1115
|
+
if (officerTerminal === undefined)
|
|
1116
|
+
throw new Error("unreadable audit has no terminal result");
|
|
1117
|
+
if (turn.terminal === undefined)
|
|
1118
|
+
throw new Error("audited submission has no terminal");
|
|
1119
|
+
const terminal = await presentUnsettledAudit(turn.terminal, officerTerminal, io, admitted.runDirectory);
|
|
1120
|
+
return { exitCode: 0, admitted, terminal };
|
|
1121
|
+
}
|
|
933
1122
|
if (chain.status === "escalate") {
|
|
934
1123
|
const escalation = chain.passes.at(-1);
|
|
935
1124
|
const escalatedRunId = escalation?.runId
|
|
@@ -938,17 +1127,17 @@ async function auditSubmittedRole(turn, env, io, passedOfficer, passedReceipt, p
|
|
|
938
1127
|
if (escalatedRunId === undefined)
|
|
939
1128
|
throw new Error("escalated audit has no resumable run identity");
|
|
940
1129
|
const officer = await loadResumablePublicRole(env.home, escalatedRunId, env.principalAuthority);
|
|
941
|
-
const terminal = await trySettlePublicSeat(officer.admitted, env.principalAuthority,
|
|
1130
|
+
const terminal = await trySettlePublicSeat(officer.admitted, env.principalAuthority, { ...await readCurrentCourt(officer.admitted.runDirectory), ...packageFaultScope(officer.admitted, env, io) });
|
|
942
1131
|
if (terminal === undefined)
|
|
943
1132
|
throw new Error("escalated audit has no terminal result");
|
|
944
|
-
io.
|
|
1133
|
+
await presentTerminal(terminal, { ...io, omitFailureStderrDiagnostic: true }, officer.admitted.runDirectory);
|
|
945
1134
|
return { exitCode: 0, admitted: officer.admitted, terminal };
|
|
946
1135
|
}
|
|
947
1136
|
if (chain.status === "continue") {
|
|
948
1137
|
return runPublicInstructionSeatResume({
|
|
949
1138
|
runId: admitted.runId,
|
|
950
|
-
|
|
951
|
-
}, { ...env,
|
|
1139
|
+
summons: { instruction: readableGateItem(chain.passes.at(-1)?.receipt) },
|
|
1140
|
+
}, { ...env, unreadableReasksSpent: 0 }, io);
|
|
952
1141
|
}
|
|
953
1142
|
if (admitted.role === "secretariat") {
|
|
954
1143
|
const pass = chain.passes.at(-1);
|
|
@@ -966,8 +1155,8 @@ async function auditSubmittedRole(turn, env, io, passedOfficer, passedReceipt, p
|
|
|
966
1155
|
// settle would republish the same attempt.
|
|
967
1156
|
if (turn.terminal === undefined)
|
|
968
1157
|
throw new Error(`audited ${admitted.role} submission did not settle`);
|
|
969
|
-
const terminal = await attachPostAuditProjection(admitted, env.principalAuthority, turn.terminal);
|
|
1158
|
+
const terminal = await attachPostAuditProjection(admitted, env.principalAuthority, turn.terminal, packageFaultScope(admitted, env, io));
|
|
970
1159
|
turn = { ...turn, terminal };
|
|
971
|
-
io.
|
|
1160
|
+
await presentTerminal(terminal, { ...io, omitFailureStderrDiagnostic: true }, admitted.runDirectory);
|
|
972
1161
|
return turn;
|
|
973
1162
|
}
|