@akagilnc/pi-workflow-roles 0.1.3932 → 0.1.3975
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/CLAUDE.md +1 -1
- package/dist/acp-host/production-host.js +2389 -6018
- package/dist/analyst-gate-cycles-read.js +15 -19
- package/dist/audit-escalation.js +16 -46
- package/dist/auditor-dossier-tool.js +7 -62
- package/dist/collector-identity.js +0 -157
- package/dist/collector-ledger.js +2 -42
- package/dist/compliance-transport.js +40 -14
- package/dist/diarist-contracts.js +2 -40
- package/dist/doctor-contracts.js +39 -108
- package/dist/doctor-evidence.js +1 -5
- package/dist/engine-detour-tool.js +1 -1
- package/dist/gatekeeper-role.js +49 -38
- package/dist/headless-host/production-host.js +4814 -8450
- package/dist/host-contracts.js +0 -5
- package/dist/merger-contracts.js +4 -6
- package/dist/navigator-attendance.js +30 -52
- package/dist/navigator-invocation-identity.js +0 -1
- package/dist/navigator-public-session.js +2 -1
- package/dist/notary-contracts.js +4 -10
- package/dist/package-contracts/auditor-output.js +5 -23
- package/dist/package-contracts/fixer-output.js +25 -49
- package/dist/package-contracts/gatekeeper-output.js +3 -13
- package/dist/package-contracts/navigator-output.js +4 -7
- package/dist/package-contracts/reviewer-output.js +1 -95
- package/dist/package-contracts/terminating-tools.js +33 -144
- package/dist/package-contracts/worker-output.js +1 -3
- package/dist/public-cli/auto-resume.js +30 -68
- package/dist/public-cli/case-dossier-delivery.js +5 -17
- package/dist/public-cli/diarist-run.js +9 -4
- package/dist/public-cli/inspector-run.js +2 -8
- package/dist/public-cli/instruction-seat-run.js +3 -7
- package/dist/public-cli/invocation.js +5 -2
- package/dist/public-cli/main.js +6068 -6964
- package/dist/public-cli/notary-run.js +1 -8
- package/dist/public-cli/post-admission.js +314 -113
- package/dist/public-cli/run-lifecycle.js +14 -38
- package/dist/public-cli/settlement.js +209 -390
- package/dist/public-cli/terminal.js +51 -45
- package/dist/public-role-summons.js +1 -12
- package/dist/reviewer-dispatch.js +12 -258
- package/dist/submission-correctable-error.js +0 -12
- package/dist/submission-errors.js +6 -1
- package/dist/submission-ledger.js +125 -168
- package/dist/ticket-provenance-contracts.js +2 -49
- package/dist/ticket-provenance.js +82 -31
- package/extensions/role-runtime.ts +1 -6
- package/package.json +1 -1
- package/resources/836-deleted-machine-instruction-inventory.md +18 -0
- package/src/acp-host/role-turn-host.ts +8 -3
- package/src/analyst-gate-cycles-read.ts +17 -29
- package/src/audit-escalation.ts +20 -50
- package/src/auditor-dossier-tool.ts +5 -103
- package/src/canonical-skill-binding.ts +3 -2
- package/src/collector-identity.ts +0 -179
- package/src/collector-ledger.ts +3 -46
- package/src/collector-role.ts +32 -61
- package/src/collector-tool-schemas.ts +20 -14
- package/src/compliance-transport.ts +55 -17
- package/src/countersign-role.ts +17 -8
- package/src/diarist-contracts.ts +3 -36
- package/src/diarist-role.ts +13 -7
- package/src/diarist.ts +4 -16
- package/src/doctor-contracts.ts +73 -94
- package/src/doctor-evidence.ts +1 -1
- package/src/doctor-role.ts +3 -3
- package/src/engine-detour-tool.ts +4 -1
- package/src/external-host-turn-loop.ts +9 -3
- package/src/gatekeeper-pass-envelope.ts +7 -12
- package/src/gatekeeper-role.ts +56 -50
- package/src/gleaner-left-role.ts +4 -2
- package/src/headless-host/role-turn-host.ts +4 -5
- package/src/host-contracts.ts +3 -8
- package/src/judge-role.ts +19 -13
- package/src/merger-contracts.ts +10 -6
- package/src/merger-role.ts +1 -5
- package/src/navigator-attendance.ts +37 -74
- package/src/navigator-invocation-identity.ts +0 -6
- package/src/navigator-public-session.ts +2 -1
- package/src/notary-contracts.ts +7 -10
- package/src/package-contracts/auditor-output.ts +4 -21
- package/src/package-contracts/fixer-output.ts +34 -52
- package/src/package-contracts/gatekeeper-output.ts +5 -22
- package/src/package-contracts/navigator-output.ts +7 -7
- package/src/package-contracts/reviewer-output.ts +2 -150
- package/src/package-contracts/terminating-tools.ts +32 -147
- package/src/package-contracts/worker-output.ts +0 -1
- package/src/pi/adapter.ts +3 -8
- package/src/public-cli/auto-resume.ts +41 -94
- package/src/public-cli/case-dossier-delivery.ts +5 -15
- package/src/public-cli/countersign-run.ts +14 -6
- package/src/public-cli/diarist-run.ts +11 -9
- package/src/public-cli/inspector-run.ts +2 -18
- package/src/public-cli/instruction-seat-run.ts +3 -17
- package/src/public-cli/invocation.ts +5 -2
- package/src/public-cli/merger-run.ts +1 -1
- package/src/public-cli/notary-run.ts +1 -18
- package/src/public-cli/post-admission.ts +385 -115
- package/src/public-cli/run-lifecycle.ts +13 -44
- package/src/public-cli/settlement.ts +314 -562
- package/src/public-cli/terminal.ts +66 -72
- package/src/public-role-summons.ts +5 -30
- package/src/reviewer-dispatch.ts +29 -331
- package/src/reviewer-role.ts +16 -83
- package/src/role-envelope.ts +16 -24
- package/src/role-runtime-dependencies.ts +1 -6
- package/src/role-runtime.ts +65 -201
- package/src/submission-correctable-error.ts +0 -14
- package/src/submission-errors.ts +6 -1
- package/src/submission-ledger.ts +187 -187
- package/src/ticket-provenance-contracts.ts +4 -60
- package/src/ticket-provenance.ts +98 -32
- package/src/worker-role.ts +35 -36
- package/dist/activation-ledger-session.js +0 -105
- package/dist/activation-ledger.js +0 -139
- package/dist/activation-trace.js +0 -33
- package/dist/atomic-write.js +0 -23
- package/dist/auditor-role.js +0 -12
- package/dist/canonical-skill-binding.js +0 -61
- package/dist/collector-handbook.js +0 -142
- package/dist/collector-receipt.js +0 -107
- package/dist/collector-role.js +0 -566
- package/dist/collector-tool-schemas.js +0 -107
- package/dist/countersign-role.js +0 -28
- package/dist/diarist-role.js +0 -44
- package/dist/diarist.js +0 -66
- package/dist/doctor-role.js +0 -75
- package/dist/fixer-bash-seatbelt.js +0 -13
- package/dist/gatekeeper-pass-envelope.js +0 -77
- package/dist/gleaner-left-role.js +0 -26
- package/dist/inspector-role.js +0 -29
- package/dist/judge-role.js +0 -104
- package/dist/merger-role.js +0 -55
- package/dist/navigator-role.js +0 -12
- package/dist/notary-role.js +0 -134
- package/dist/oauth-keepalive.js +0 -158
- package/dist/pi/adapter.js +0 -223
- package/dist/reviewer-agent.js +0 -122
- package/dist/reviewer-child-executor.js +0 -194
- package/dist/reviewer-construction.js +0 -103
- package/dist/reviewer-execution-ledger.js +0 -166
- package/dist/reviewer-failure-diagnostic.js +0 -17
- package/dist/reviewer-role.js +0 -159
- package/dist/reviewer-scope-prompt.js +0 -21
- package/dist/reviewer-settlement.js +0 -66
- package/dist/reviewer-workspace.js +0 -132
- package/dist/role-runtime.js +0 -1604
- package/dist/stderr-jsonl.js +0 -26
- package/dist/tool-execution-observation.js +0 -141
- package/dist/worker-role.js +0 -345
- package/dist/worker-submission-gates.js +0 -305
- package/src/collector-receipt.ts +0 -140
- package/src/diagnostic-tail.ts +0 -18
- package/src/reviewer-agent.ts +0 -135
- package/src/reviewer-child-executor.ts +0 -252
- package/src/reviewer-construction.ts +0 -195
- package/src/reviewer-execution-ledger.ts +0 -212
- package/src/reviewer-failure-diagnostic.ts +0 -18
- package/src/reviewer-scope-prompt.ts +0 -24
- package/src/reviewer-settlement.ts +0 -74
- package/src/reviewer-workspace.ts +0 -105
- package/src/shape-unreadable-failure.ts +0 -49
|
@@ -55,7 +55,7 @@ export async function runPublicNotary(argv, env, io, parseNotaryArgv) {
|
|
|
55
55
|
// #753/#786: gate re-ask and verbatim submission body share summons.instruction
|
|
56
56
|
// (reask wins when both present; no parallel stack).
|
|
57
57
|
{
|
|
58
|
-
const resumeInstruction = env.reviewReask
|
|
58
|
+
const resumeInstruction = env.reviewReask;
|
|
59
59
|
const summons = {
|
|
60
60
|
sourceRunPath: source.runDirectory,
|
|
61
61
|
sourceRun: source,
|
|
@@ -74,13 +74,6 @@ export async function runPublicNotary(argv, env, io, parseNotaryArgv) {
|
|
|
74
74
|
});
|
|
75
75
|
if (resumed !== undefined)
|
|
76
76
|
return resumed;
|
|
77
|
-
// Reask without a prior same-parent run cannot deliver the plain-language ask
|
|
78
|
-
// on a fresh mint without inventing a second prompt path — fail loud (#753).
|
|
79
|
-
// gateReviewInstruction (verbatim body) alone is resume-only; fresh mint ignores it.
|
|
80
|
-
if (env.reviewReask !== undefined) {
|
|
81
|
-
presentStructuralRejection(new CliUsageError("notary review reask requires a prior same-parent run to resume"), io);
|
|
82
|
-
return { exitCode: 2 };
|
|
83
|
-
}
|
|
84
77
|
}
|
|
85
78
|
let admitted;
|
|
86
79
|
try {
|
|
@@ -8,12 +8,20 @@
|
|
|
8
8
|
import { randomUUID } from "node:crypto";
|
|
9
9
|
import { readFile, writeFile } from "node:fs/promises";
|
|
10
10
|
import { isAbsolute, join, resolve } from "node:path";
|
|
11
|
-
import { buildResumeContinuationPrompt, RESUME_TRANSPORT_ENVELOPE, } from "./run-lifecycle.js";
|
|
11
|
+
import { buildResumeContinuationPrompt, GATE_DOSSIER_POINTER_PREFIX, RESUME_TRANSPORT_ENVELOPE, } from "./run-lifecycle.js";
|
|
12
12
|
import { CliUsageError } from "./cli-errors.js";
|
|
13
13
|
import { buildInstructionTransportPrompt, freezeAttachmentsIntoRun, } from "./invocation.js";
|
|
14
14
|
import { pathContainedIn } from "../activation-ledger-topology.js";
|
|
15
15
|
import { resolveHostAwareSessionAvailability } from "../session-identity.js";
|
|
16
16
|
import { projectCaseDossierPointerSection } from "./case-dossier-delivery.js";
|
|
17
|
+
/** Original error bytes, never relabeled — a secondary fact riding beside a classified cause. */
|
|
18
|
+
function describeCaughtError(error) {
|
|
19
|
+
if (error instanceof Error) {
|
|
20
|
+
const code = error.code;
|
|
21
|
+
return { name: error.name, message: error.message, ...(code === undefined ? {} : { code }) };
|
|
22
|
+
}
|
|
23
|
+
return { message: String(error) };
|
|
24
|
+
}
|
|
17
25
|
/** Append one system section to a continuation prompt, keeping its kind. */
|
|
18
26
|
function appendContinuationSection(continuation, section) {
|
|
19
27
|
const prompt = `${continuation.prompt}\n\n${section}`;
|
|
@@ -25,9 +33,8 @@ import { projectHostTransitionPriorNative } from "../host-transition-prior-nativ
|
|
|
25
33
|
import { missingCredentialPreDispatchFailure, postRunMissingCredentialFailure, } from "./public-run-credentials.js";
|
|
26
34
|
import { acquireRunWriterLease, clearCurrentCourt, clearTypedProviderHttpObservation, describeErrorIdentity, markRunRunning, readCurrentCourt, recordCurrentCourt, renderResumeCommand, RunWriterLeaseHeldError, } from "./run-lifecycle.js";
|
|
27
35
|
import { homeFromRunDirectory } from "../activation-ledger-topology.js";
|
|
28
|
-
import { readSealedSubmission } from "../submission-ledger.js";
|
|
29
36
|
import { clearReviewerDispatchRejection } from "./reviewer-dispatch-rejection.js";
|
|
30
|
-
import { classifyPostAdmissionFailure, controlledFailureInputFromResolution, exitCodeForTerminalOutcome, explicitInternalKnownFailureClassificationInput, formatCliDiagnostic, formatTerminalResult, inspectJudgeSession, isLawfulTypedTerminalOutcome, presentFailureTerminal, presentStructuralRejection, resolveAuditedRunnerFailureResolution, resolveControlledFailureResumeObservation, settleFailureTerminalResult,
|
|
37
|
+
import { attemptProducedFreshSubmission, classifyPostAdmissionFailure, controlledFailureInputFromResolution, exitCodeForTerminalOutcome, explicitInternalKnownFailureClassificationInput, formatCliDiagnostic, formatTerminalResult, inspectJudgeSession, isLawfulTypedTerminalOutcome, presentFailureTerminal, presentStructuralRejection, resolveAuditedRunnerFailureResolution, resolveControlledFailureResumeObservation, settleFailureTerminalResult, settleHostEndedNoReceipt, attachRecordedSubmissions, } from "./settlement.js";
|
|
31
38
|
import {} from "./terminal.js";
|
|
32
39
|
import { ensureRealArtifactsDirectory, persistReturnedRunState, runWithAutoResumeLoop, TurnDispatchedFailure, } from "./auto-resume.js";
|
|
33
40
|
/**
|
|
@@ -176,12 +183,12 @@ export async function presentControlledFailure(admitted, failureInput, adapters,
|
|
|
176
183
|
const sessionPrincipalAvailable = await authority.isAvailable(admitted.principal);
|
|
177
184
|
resumable = sessionPrincipalAvailable && typedHttp429 !== undefined;
|
|
178
185
|
}
|
|
179
|
-
if (persistRunState) {
|
|
186
|
+
if (persistRunState && !failureInput.skipRunStateWrite) {
|
|
180
187
|
await persistReturnedRunState(admitted, authority);
|
|
181
188
|
}
|
|
182
|
-
const terminal = await settleFailureTerminalResult(admitted, failure, authority, resumable
|
|
189
|
+
const terminal = await attachRecordedSubmissions(admitted, await settleFailureTerminalResult(admitted, failure, authority, resumable
|
|
183
190
|
? { resume: { command: renderResumeCommand(admitted.runId) } }
|
|
184
|
-
: {});
|
|
191
|
+
: {}));
|
|
185
192
|
presentFailureTerminal(terminal, io);
|
|
186
193
|
return {
|
|
187
194
|
exitCode: exitCodeForTerminalOutcome(terminal.roleOutcome),
|
|
@@ -208,6 +215,35 @@ async function settleAfterTurnStarted(admitted, failureInput, adapters, authorit
|
|
|
208
215
|
throw new TurnDispatchedFailure(error);
|
|
209
216
|
}
|
|
210
217
|
}
|
|
218
|
+
/**
|
|
219
|
+
* Persist run-state for a result dispatchPostAdmissionTurn deferred
|
|
220
|
+
* (needsPersist — station-child / resumable auto-resume loop, #416/#840):
|
|
221
|
+
* that write must land outside the loop's own retried-dispatch try, but its
|
|
222
|
+
* failure still settles through the single existing controlled-failure
|
|
223
|
+
* authority (settleAfterTurnStarted / presentControlledFailure, ADR 0080
|
|
224
|
+
* single-settlement-disposition) — never a second hand-rolled
|
|
225
|
+
* classify/artifact/Terminal (#836 r12 class 3), and never lawful/non-lawful
|
|
226
|
+
* settling differently (#836 r13 class 2: a caller's io here may be a no-op,
|
|
227
|
+
* so a stderr-only trace is never seen and the failure is otherwise
|
|
228
|
+
* swallowed — 失败诚实宪法 真因必须落痕). Both cases settle through
|
|
229
|
+
* settleAfterTurnStarted, which attaches the run's already-recorded ledger
|
|
230
|
+
* submissions to the new failure terminal and returns skipAutoResume so the
|
|
231
|
+
* caller presents it once and stops — never re-entering auto-resume.
|
|
232
|
+
*/
|
|
233
|
+
async function settleDeferredPersist(admitted, authority, adapters, io, result) {
|
|
234
|
+
if (result.needsPersist !== true || result.terminal === undefined)
|
|
235
|
+
return result;
|
|
236
|
+
const { needsPersist: _needsPersist, ...settledResult } = result;
|
|
237
|
+
const lawful = isLawfulTypedTerminalOutcome(result.terminal.roleOutcome);
|
|
238
|
+
try {
|
|
239
|
+
await persistReturnedRunState(admitted, authority, lawful ? { lawful: true } : undefined);
|
|
240
|
+
return settledResult;
|
|
241
|
+
}
|
|
242
|
+
catch (error) {
|
|
243
|
+
const failed = await settleAfterTurnStarted(admitted, { timedOut: false, code: null, stderr: "", thrown: error, skipRunStateWrite: true }, adapters, authority, io, true);
|
|
244
|
+
return { ...failed, turnDispatched: true, skipAutoResume: true };
|
|
245
|
+
}
|
|
246
|
+
}
|
|
211
247
|
export async function dispatchPostAdmissionTurn(input) {
|
|
212
248
|
const { admitted, env, io, request, lease, adapters, effectiveEngine } = input;
|
|
213
249
|
const persistRunState = input.persistRunState !== false;
|
|
@@ -325,6 +361,18 @@ export async function dispatchPostAdmissionTurn(input) {
|
|
|
325
361
|
}, adapters, env.principalAuthority, io, persistRunState);
|
|
326
362
|
return { ...settled, turnDispatched: true, ...deferredPersist };
|
|
327
363
|
}
|
|
364
|
+
// `result.stderr` stays live in memory for the real classification below
|
|
365
|
+
// regardless of whether this durable mirror write succeeds. A write
|
|
366
|
+
// failure here (unwritable run directory, stderr.log occupied as a
|
|
367
|
+
// directory, ...) is a real infrastructure problem and must never be
|
|
368
|
+
// dropped silently (catch-and-continue with no trace is a defect) — but
|
|
369
|
+
// it also must never become THE controlling failure and wash out a
|
|
370
|
+
// primary child signal that already arrived on `result`, or an
|
|
371
|
+
// already-sealed accepted payload (#836: a secondary failure must not
|
|
372
|
+
// overwrite an already-known cause or an already-recorded leg). It rides
|
|
373
|
+
// beside whatever the real classification below determines, and only
|
|
374
|
+
// becomes the reported failure itself when nothing else is wrong.
|
|
375
|
+
//
|
|
328
376
|
// Everything below runs after the host turn genuinely started (#840 r9
|
|
329
377
|
// 判词 class 1 boundary — 覆盖 executeTurn 已启动后至返回带 turnDispatched
|
|
330
378
|
// 结果前的全部异常). Each fallible step routes any failure through the
|
|
@@ -340,33 +388,108 @@ export async function dispatchPostAdmissionTurn(input) {
|
|
|
340
388
|
// turn genuinely started, so the next retry sends a resume payload — the
|
|
341
389
|
// true cause settles through the loop's own existing dispatch-exception
|
|
342
390
|
// machinery once the retry budget is exhausted.
|
|
391
|
+
let stderrLogWriteFailure;
|
|
343
392
|
try {
|
|
344
393
|
await writeFile(join(admitted.runDirectory, "stderr.log"), result.stderr, "utf8");
|
|
345
394
|
}
|
|
346
395
|
catch (error) {
|
|
396
|
+
stderrLogWriteFailure = error;
|
|
347
397
|
// Best-effort: the turn's own stderr capture is secondary to lawful /
|
|
348
398
|
// controlled-failure settlement below, but the failure itself must
|
|
349
399
|
// still leave a real trace (失败诚实宪法 真因必须落痕) — durably, since
|
|
350
|
-
// every auto-resume attempt's io is dummyIo (#840 r9 判词 class 1).
|
|
400
|
+
// every auto-resume attempt's io is dummyIo (#840 r9 判词 class 1). It
|
|
401
|
+
// still rides beside the classification below and, if nothing else is
|
|
402
|
+
// wrong, becomes the reported failure itself (#836).
|
|
351
403
|
await recordBestEffortPostDispatchDiagnostic(admitted, env, `stderr.log write failed (best-effort continue): ${describeErrorIdentity(error)}`, io);
|
|
352
404
|
}
|
|
353
|
-
let settled;
|
|
354
|
-
// Same-ticket re-summons carry courtAttemptId — settle only that attempt so a
|
|
355
|
-
// prior sealed pass cannot wash this turn's missing/escalated/failed result.
|
|
356
405
|
const courtScope = request.courtAttemptId === undefined || request.courtAttemptId.length === 0
|
|
357
406
|
? undefined
|
|
358
407
|
: { courtAttemptId: request.courtAttemptId };
|
|
359
|
-
// Single complete boundary (#840 r9 判词 class 1):
|
|
360
|
-
// shouldPresent gate, and the
|
|
361
|
-
// through this one catch
|
|
362
|
-
//
|
|
363
|
-
//
|
|
364
|
-
//
|
|
365
|
-
//
|
|
408
|
+
// Single complete boundary (#840 r9 判词 class 1): resolving the
|
|
409
|
+
// host/runner failure facts, trySettle, its shouldPresent gate, and the
|
|
410
|
+
// accepted-settlement cleanup all settle through this one catch — a
|
|
411
|
+
// throw from any of them (including the session-file decode itself)
|
|
412
|
+
// still routes through settleAfterTurnStarted's TurnDispatchedFailure
|
|
413
|
+
// instead of losing turnDispatched to an uncaught throw. The facts are
|
|
414
|
+
// resolved before trySettle (#836) so an already-accepted settlement is
|
|
415
|
+
// never presented over a real current host/runner failure signal or a
|
|
416
|
+
// real stderr.log durable-write failure — both stay a real failure with
|
|
417
|
+
// the recorded payload riding beside it, not replacing it.
|
|
418
|
+
let settled;
|
|
366
419
|
let settledOutcome;
|
|
420
|
+
let hostSignalFailed = false;
|
|
421
|
+
let resolution;
|
|
367
422
|
try {
|
|
423
|
+
const sessionFile = admitted.principal !== undefined
|
|
424
|
+
? env.principalAuthority.decode(admitted.principal).sessionFile
|
|
425
|
+
: "";
|
|
426
|
+
const runnerKnownFailure = adapters.resolveRunnerKnownFailure !== undefined && sessionFile !== ""
|
|
427
|
+
? await adapters.resolveRunnerKnownFailure({ result, sessionFile })
|
|
428
|
+
: result.knownFailure;
|
|
429
|
+
const credentialFailure = postRunMissingCredentialFailure(result, env.model, env.credentials);
|
|
430
|
+
resolution = await resolveAuditedRunnerFailureResolution({
|
|
431
|
+
runner: runnerKnownFailure,
|
|
432
|
+
sessionFile,
|
|
433
|
+
credential: credentialFailure,
|
|
434
|
+
runDirectory: admitted.runDirectory,
|
|
435
|
+
});
|
|
436
|
+
// A direct, current signal from the host/runner itself (timeout / host
|
|
437
|
+
// knownFailure / runner knownFailure / missing credential) is a real
|
|
438
|
+
// problem regardless of what else already settled — a settled accepted
|
|
439
|
+
// outcome must not paper over it (it rides beside the recorded payload
|
|
440
|
+
// via `submissions`, never replacing the payload). The audited
|
|
441
|
+
// resolution's own typed session read (malformed JSONL, provider-stop,
|
|
442
|
+
// an illegal/unsealed accepted status, a stale/superseded typed-HTTP
|
|
443
|
+
// observation, ...) makes a run with no sealed acceptance a true
|
|
444
|
+
// failure too — it must not be discarded into a lawful no_receipt just
|
|
445
|
+
// because the raw runner signal alone looked clean. But it must not
|
|
446
|
+
// retroactively invalidate an acceptance that already sealed this turn
|
|
447
|
+
// — a resolved 429 observed earlier in the same session is exactly
|
|
448
|
+
// that.
|
|
449
|
+
const directHostFailureSignal = result.timedOut
|
|
450
|
+
|| result.knownFailure !== undefined
|
|
451
|
+
|| runnerKnownFailure !== undefined
|
|
452
|
+
|| credentialFailure !== undefined;
|
|
453
|
+
hostSignalFailed =
|
|
454
|
+
directHostFailureSignal
|
|
455
|
+
|| (result.code !== null && result.code !== 0)
|
|
456
|
+
|| resolution.knownFailure !== undefined;
|
|
368
457
|
settled = await adapters.trySettle(admitted, env.principalAuthority, courtScope);
|
|
369
|
-
if (settled !== undefined
|
|
458
|
+
if (settled !== undefined) {
|
|
459
|
+
settled = await attachRecordedSubmissions(admitted, settled, courtScope);
|
|
460
|
+
}
|
|
461
|
+
// #836 r12 class 2: an accepted/audit_escalation settlement can be
|
|
462
|
+
// entirely a prior attempt's stale payload (courtAttempt is a
|
|
463
|
+
// recording tag, not a visibility gate — attachRecordedSubmissions
|
|
464
|
+
// above still surfaces that historical payload honestly either way).
|
|
465
|
+
// Consume the ledger's own subject.attemptId (submission-ledger.ts)
|
|
466
|
+
// only to learn whether *this* attempt itself produced a fresh seal —
|
|
467
|
+
// never to filter what presents.
|
|
468
|
+
const settledIsFreshThisAttempt = settled === undefined
|
|
469
|
+
|| (settled.roleOutcome.kind !== "accepted" && settled.roleOutcome.kind !== "audit_escalation")
|
|
470
|
+
? true
|
|
471
|
+
: await attemptProducedFreshSubmission(admitted, courtScope);
|
|
472
|
+
// A lawful settled outcome already reached this turn takes precedence
|
|
473
|
+
// over a later bare exit-code / session-inspection signal (trailing
|
|
474
|
+
// nonzero exit, late stderr noise, a stale already-superseded
|
|
475
|
+
// typed-HTTP observation, ...) — but never over a direct current
|
|
476
|
+
// host/runner failure signal, nor over a real stderr.log durable-write
|
|
477
|
+
// failure (confirmed infrastructure trouble, not weak/bare evidence),
|
|
478
|
+
// both of which stay a real failure with the recorded payload riding
|
|
479
|
+
// beside it, not replacing it (#836: never kill an already-recorded
|
|
480
|
+
// leg, but never wash a real failure away either). Note: the narrower
|
|
481
|
+
// directHostFailureSignal gates acceptance here; the broader
|
|
482
|
+
// hostSignalFailed (adds bare exit code / resolution.knownFailure)
|
|
483
|
+
// only gates the no-settlement fallback below — except when the
|
|
484
|
+
// settlement itself is entirely stale (no fresh seal this attempt),
|
|
485
|
+
// where a bare nonzero exit / resolution failure must not be outranked
|
|
486
|
+
// by someone else's earlier success (#836 r12 class 2).
|
|
487
|
+
const staleAcceptanceOutranksRealFailure = !settledIsFreshThisAttempt && hostSignalFailed;
|
|
488
|
+
if (settled !== undefined
|
|
489
|
+
&& shouldPresent(settled)
|
|
490
|
+
&& !directHostFailureSignal
|
|
491
|
+
&& !staleAcceptanceOutranksRealFailure
|
|
492
|
+
&& stderrLogWriteFailure === undefined) {
|
|
370
493
|
// This court sealed — drop open-court pointer (bare resume no longer continues it).
|
|
371
494
|
if (settled.roleOutcome.kind === "accepted" &&
|
|
372
495
|
request.courtAttemptId !== undefined &&
|
|
@@ -395,8 +518,8 @@ export async function dispatchPostAdmissionTurn(input) {
|
|
|
395
518
|
}
|
|
396
519
|
}
|
|
397
520
|
catch (error) {
|
|
398
|
-
// Settle (or its shouldPresent gate
|
|
399
|
-
// never swallow into undefined.
|
|
521
|
+
// Settle (or its shouldPresent gate, or the failure-fact resolution
|
|
522
|
+
// above) throw is a real failure fact — never swallow into undefined.
|
|
400
523
|
const settledFailure = await settleAfterTurnStarted(admitted, {
|
|
401
524
|
timedOut: false,
|
|
402
525
|
code: result.code,
|
|
@@ -406,47 +529,102 @@ export async function dispatchPostAdmissionTurn(input) {
|
|
|
406
529
|
return { ...settledFailure, turnDispatched: true, ...deferredPersist };
|
|
407
530
|
}
|
|
408
531
|
if (settledOutcome !== undefined) {
|
|
532
|
+
if (persistRunState) {
|
|
533
|
+
try {
|
|
534
|
+
await persistReturnedRunState(admitted, env.principalAuthority, { lawful: true });
|
|
535
|
+
}
|
|
536
|
+
catch (error) {
|
|
537
|
+
// #836: `settledOutcome.terminal` already carries recorded
|
|
538
|
+
// submissions (attachRecordedSubmissions above). A real run-state
|
|
539
|
+
// persistence failure here must surface loudly through the same
|
|
540
|
+
// controlled-failure seam every other dispatch-time failure in
|
|
541
|
+
// this function uses (ADR 0080: one settlement disposition owner)
|
|
542
|
+
// — not escape uncaught to auto-resume's dispatch-retry path,
|
|
543
|
+
// whose exhausted-budget terminal carries no recorded submissions
|
|
544
|
+
// at all. skipRunStateWrite: the write that just threw is the same
|
|
545
|
+
// write presentControlledFailure would otherwise retry — don't
|
|
546
|
+
// call a known-failing operation twice.
|
|
547
|
+
const failed = await settleAfterTurnStarted(admitted, {
|
|
548
|
+
timedOut: false,
|
|
549
|
+
code: null,
|
|
550
|
+
stderr: "",
|
|
551
|
+
thrown: error,
|
|
552
|
+
skipRunStateWrite: true,
|
|
553
|
+
}, adapters, env.principalAuthority, io, persistRunState);
|
|
554
|
+
return { ...failed, turnDispatched: true, ...deferredPersist };
|
|
555
|
+
}
|
|
556
|
+
}
|
|
409
557
|
// Lawful persist + present is the caller's stop seam (auto-resume loop /
|
|
410
558
|
// manual resume), not this retried host-turn function.
|
|
411
559
|
return { ...settledOutcome, ...deferredPersist };
|
|
412
560
|
}
|
|
413
|
-
//
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
const sessionFile = admitted.principal !== undefined
|
|
421
|
-
? env.principalAuthority.decode(admitted.principal).sessionFile
|
|
422
|
-
: "";
|
|
423
|
-
const runnerKnownFailure = adapters.resolveRunnerKnownFailure !== undefined && sessionFile !== ""
|
|
424
|
-
? await adapters.resolveRunnerKnownFailure({ result, sessionFile })
|
|
425
|
-
: result.knownFailure;
|
|
426
|
-
const credentialFailure = postRunMissingCredentialFailure(result, env.model, env.credentials);
|
|
427
|
-
const resolution = await resolveAuditedRunnerFailureResolution({
|
|
428
|
-
runner: runnerKnownFailure,
|
|
429
|
-
sessionFile,
|
|
430
|
-
credential: credentialFailure,
|
|
431
|
-
runDirectory: admitted.runDirectory,
|
|
432
|
-
});
|
|
433
|
-
failureInput = {
|
|
561
|
+
// Host/runner true failure coexists with already-recorded payloads — never wash as accepted.
|
|
562
|
+
if (hostSignalFailed) {
|
|
563
|
+
const resolutionInput = controlledFailureInputFromResolution(resolution);
|
|
564
|
+
const stderrLogWriteDetails = stderrLogWriteFailure === undefined
|
|
565
|
+
? undefined
|
|
566
|
+
: { stderrLogWriteFailure: describeCaughtError(stderrLogWriteFailure) };
|
|
567
|
+
const failed = await settleAfterTurnStarted(admitted, {
|
|
434
568
|
timedOut: result.timedOut,
|
|
435
569
|
code: result.code,
|
|
436
570
|
stderr: result.stderr,
|
|
437
|
-
...
|
|
438
|
-
|
|
571
|
+
...resolutionInput,
|
|
572
|
+
// Secondary fact only — never the cause. Rides on whichever channel
|
|
573
|
+
// classification actually reads (knownFailure.details owns it when
|
|
574
|
+
// a knownFailure exists; the top-level knownDetails otherwise).
|
|
575
|
+
...(stderrLogWriteDetails === undefined
|
|
576
|
+
? {}
|
|
577
|
+
: resolutionInput.knownFailure !== undefined
|
|
578
|
+
? {
|
|
579
|
+
knownFailure: {
|
|
580
|
+
...resolutionInput.knownFailure,
|
|
581
|
+
details: { ...(resolutionInput.knownFailure.details ?? {}), ...stderrLogWriteDetails },
|
|
582
|
+
},
|
|
583
|
+
}
|
|
584
|
+
: { knownDetails: stderrLogWriteDetails }),
|
|
585
|
+
}, adapters, env.principalAuthority, io, persistRunState);
|
|
586
|
+
return { ...failed, turnDispatched: true, ...deferredPersist };
|
|
439
587
|
}
|
|
440
|
-
|
|
441
|
-
|
|
588
|
+
// Nothing else was wrong, but the durable stderr mirror itself failed to
|
|
589
|
+
// write — that is the real (infrastructure) problem in this case, not a
|
|
590
|
+
// lawful absence of a receipt. Honest and loud, not silently no_receipt.
|
|
591
|
+
if (stderrLogWriteFailure !== undefined) {
|
|
592
|
+
const failed = await settleAfterTurnStarted(admitted, {
|
|
442
593
|
timedOut: false,
|
|
443
594
|
code: result.code,
|
|
444
595
|
stderr: result.stderr,
|
|
445
|
-
thrown:
|
|
446
|
-
};
|
|
596
|
+
thrown: stderrLogWriteFailure,
|
|
597
|
+
}, adapters, env.principalAuthority, io, persistRunState);
|
|
598
|
+
return { ...failed, turnDispatched: true, ...deferredPersist };
|
|
447
599
|
}
|
|
448
|
-
const
|
|
449
|
-
|
|
600
|
+
const noReceipt = await attachRecordedSubmissions(admitted, await settleHostEndedNoReceipt(admitted, env.principalAuthority), courtScope);
|
|
601
|
+
if (persistRunState) {
|
|
602
|
+
try {
|
|
603
|
+
await persistReturnedRunState(admitted, env.principalAuthority, { lawful: true });
|
|
604
|
+
}
|
|
605
|
+
catch (error) {
|
|
606
|
+
// #836: same run-state persistence hazard as the settled/accepted
|
|
607
|
+
// branch above — route through the shared controlled-failure seam so
|
|
608
|
+
// the real failure surfaces loudly instead of escaping uncaught to
|
|
609
|
+
// auto-resume's dispatch-retry path with no recorded submissions.
|
|
610
|
+
// skipRunStateWrite: don't retry the write that just threw.
|
|
611
|
+
const failed = await settleAfterTurnStarted(admitted, {
|
|
612
|
+
timedOut: false,
|
|
613
|
+
code: null,
|
|
614
|
+
stderr: "",
|
|
615
|
+
thrown: error,
|
|
616
|
+
skipRunStateWrite: true,
|
|
617
|
+
}, adapters, env.principalAuthority, io, persistRunState);
|
|
618
|
+
return { ...failed, turnDispatched: true, ...deferredPersist };
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
return {
|
|
622
|
+
exitCode: exitCodeForTerminalOutcome(noReceipt.roleOutcome),
|
|
623
|
+
admitted,
|
|
624
|
+
terminal: noReceipt,
|
|
625
|
+
turnDispatched: true,
|
|
626
|
+
...deferredPersist,
|
|
627
|
+
};
|
|
450
628
|
}
|
|
451
629
|
finally {
|
|
452
630
|
try {
|
|
@@ -478,20 +656,32 @@ export async function dispatchPostAdmissionTurn(input) {
|
|
|
478
656
|
* first when request.summons carries instruction or attachment paths.
|
|
479
657
|
*/
|
|
480
658
|
export function resumeTurnRequestProjectionOptions(admitted, request, env, summonsPrepared) {
|
|
659
|
+
const officerSourcePath = request.summons?.sourceRunPath;
|
|
660
|
+
const withReread = (body) => {
|
|
661
|
+
if (officerSourcePath === undefined
|
|
662
|
+
|| (admitted.role !== "notary"
|
|
663
|
+
&& admitted.role !== "inspector"
|
|
664
|
+
&& admitted.role !== "auditor")) {
|
|
665
|
+
return body;
|
|
666
|
+
}
|
|
667
|
+
if (body.startsWith("请重读"))
|
|
668
|
+
return body;
|
|
669
|
+
return `请重读\n${body}`;
|
|
670
|
+
};
|
|
481
671
|
let prompt;
|
|
482
672
|
if (request.message !== undefined) {
|
|
483
673
|
if (summonsPrepared !== undefined) {
|
|
484
674
|
// #755: same-ticket review / open-court — caller words + optional paths.
|
|
485
675
|
// Attachments are not a gate: message-only summons must stay plain too.
|
|
486
|
-
prompt = buildInstructionTransportPrompt({
|
|
676
|
+
prompt = withReread(buildInstructionTransportPrompt({
|
|
487
677
|
instruction: request.message,
|
|
488
678
|
instructionEmpty: false,
|
|
489
679
|
attachments: summonsPrepared.attachments,
|
|
490
|
-
});
|
|
680
|
+
}));
|
|
491
681
|
}
|
|
492
682
|
else if (request.summons !== undefined) {
|
|
493
683
|
// #755: same-ticket summons without prepared materials — caller words only.
|
|
494
|
-
prompt = request.message;
|
|
684
|
+
prompt = withReread(request.message);
|
|
495
685
|
}
|
|
496
686
|
else {
|
|
497
687
|
// Bare manual resume — outsourcing engine axis keeps handbook (#600/#736).
|
|
@@ -504,12 +694,26 @@ export function resumeTurnRequestProjectionOptions(admitted, request, env, summo
|
|
|
504
694
|
}
|
|
505
695
|
else if (summonsPrepared !== undefined) {
|
|
506
696
|
// #755: same-ticket review summons — instruction/attachments only.
|
|
507
|
-
prompt = buildInstructionTransportPrompt(summonsPrepared);
|
|
697
|
+
prompt = withReread(buildInstructionTransportPrompt(summonsPrepared));
|
|
508
698
|
}
|
|
509
699
|
else if (request.summons !== undefined) {
|
|
510
700
|
// #755: same-ticket summons with no instruction/attachments (e.g. notary
|
|
511
|
-
// source-run pointer)
|
|
512
|
-
|
|
701
|
+
// source-run pointer). #836: officer resume opening adds「请重读」+ path pointer.
|
|
702
|
+
const path = request.summons.sourceRunPath;
|
|
703
|
+
if (path !== undefined &&
|
|
704
|
+
(admitted.role === "notary" ||
|
|
705
|
+
admitted.role === "inspector" ||
|
|
706
|
+
admitted.role === "auditor")) {
|
|
707
|
+
prompt = `请重读\n${GATE_DOSSIER_POINTER_PREFIX}${path}`;
|
|
708
|
+
}
|
|
709
|
+
else if (admitted.role === "notary" ||
|
|
710
|
+
admitted.role === "inspector" ||
|
|
711
|
+
admitted.role === "auditor") {
|
|
712
|
+
prompt = "请重读";
|
|
713
|
+
}
|
|
714
|
+
else {
|
|
715
|
+
prompt = "";
|
|
716
|
+
}
|
|
513
717
|
}
|
|
514
718
|
else {
|
|
515
719
|
// Bare manual resume — outsourcing engine axis keeps handbook (#600/#736).
|
|
@@ -628,35 +832,23 @@ export async function runPostAdmissionSeatResume(input) {
|
|
|
628
832
|
// Build uses the admitted judged under this lease (rehydrated when open
|
|
629
833
|
// court materials ride). Settlement identity stays on the outer admitted.
|
|
630
834
|
let admittedForBuild = loaded.admitted;
|
|
631
|
-
// Bare resume:
|
|
835
|
+
// Bare resume: open-court pointer is the continue signal (not ledger seal).
|
|
632
836
|
if (request.summons === undefined) {
|
|
633
837
|
const openCourt = await readCurrentCourt(admittedForBuild.runDirectory);
|
|
634
838
|
if (openCourt !== undefined) {
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
...(openCourt.summons === undefined
|
|
649
|
-
? {}
|
|
650
|
-
: { summons: openCourt.summons }),
|
|
651
|
-
};
|
|
652
|
-
if (openCourt.summons !== undefined) {
|
|
653
|
-
const reloaded = await input.load(request);
|
|
654
|
-
admittedForBuild = reloaded.admitted;
|
|
655
|
-
}
|
|
656
|
-
}
|
|
657
|
-
else {
|
|
658
|
-
// Open court already sealed — clear only the court id just judged.
|
|
659
|
-
await clearCurrentCourt(admittedForBuild.runDirectory, openCourt.courtAttemptId);
|
|
839
|
+
openCourtAttemptId = openCourt.courtAttemptId;
|
|
840
|
+
request = {
|
|
841
|
+
runId: request.runId,
|
|
842
|
+
...(request.message === undefined
|
|
843
|
+
? {}
|
|
844
|
+
: { message: request.message }),
|
|
845
|
+
...(openCourt.summons === undefined
|
|
846
|
+
? {}
|
|
847
|
+
: { summons: openCourt.summons }),
|
|
848
|
+
};
|
|
849
|
+
if (openCourt.summons !== undefined) {
|
|
850
|
+
const reloaded = await input.load(request);
|
|
851
|
+
admittedForBuild = reloaded.admitted;
|
|
660
852
|
}
|
|
661
853
|
}
|
|
662
854
|
}
|
|
@@ -743,23 +935,26 @@ export async function runPostAdmissionSeatResume(input) {
|
|
|
743
935
|
firstTurn = turnRequest;
|
|
744
936
|
return turnRequest;
|
|
745
937
|
},
|
|
746
|
-
dispatch: (turnRequest) =>
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
938
|
+
dispatch: async (turnRequest) => {
|
|
939
|
+
const result = await dispatchPostAdmissionTurn({
|
|
940
|
+
admitted: loaded.admitted,
|
|
941
|
+
env: {
|
|
942
|
+
...input.env,
|
|
943
|
+
...(loaded.admitted.correlationId === undefined
|
|
944
|
+
? {}
|
|
945
|
+
: { correlationId: loaded.admitted.correlationId }),
|
|
946
|
+
},
|
|
947
|
+
io: attemptIo,
|
|
948
|
+
request: turnRequest,
|
|
949
|
+
lease,
|
|
950
|
+
adapters: stationAdapters,
|
|
951
|
+
persistRunState: false,
|
|
952
|
+
...(input.effectiveEngine === undefined
|
|
751
953
|
? {}
|
|
752
|
-
: {
|
|
753
|
-
}
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
lease,
|
|
757
|
-
adapters: stationAdapters,
|
|
758
|
-
persistRunState: false,
|
|
759
|
-
...(input.effectiveEngine === undefined
|
|
760
|
-
? {}
|
|
761
|
-
: { effectiveEngine: input.effectiveEngine }),
|
|
762
|
-
}),
|
|
954
|
+
: { effectiveEngine: input.effectiveEngine }),
|
|
955
|
+
});
|
|
956
|
+
return settleDeferredPersist(loaded.admitted, input.env.principalAuthority, stationAdapters, attemptIo, result);
|
|
957
|
+
},
|
|
763
958
|
}),
|
|
764
959
|
});
|
|
765
960
|
}
|
|
@@ -827,21 +1022,23 @@ export async function runPostAdmissionResumable(input) {
|
|
|
827
1022
|
autoResumeLimit: env.autoResumeLimit,
|
|
828
1023
|
buildInitialPayload: buildInitialRequest,
|
|
829
1024
|
buildResumePayload: buildResumeRequest,
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
1025
|
+
dispatch: async (request, lease, _isFirst, attemptIo) => {
|
|
1026
|
+
const result = await dispatchPostAdmissionTurn({
|
|
1027
|
+
admitted,
|
|
1028
|
+
env: {
|
|
1029
|
+
...env,
|
|
1030
|
+
...(admitted.correlationId === undefined ? {} : { correlationId: admitted.correlationId }),
|
|
1031
|
+
},
|
|
1032
|
+
io: attemptIo,
|
|
1033
|
+
request,
|
|
1034
|
+
lease,
|
|
1035
|
+
adapters,
|
|
1036
|
+
persistRunState: false,
|
|
1037
|
+
// #600: every attempt (initial + auto-resume) writes seat engine when present.
|
|
1038
|
+
...(effectiveEngine === undefined ? {} : { effectiveEngine }),
|
|
1039
|
+
});
|
|
1040
|
+
return settleDeferredPersist(admitted, env.principalAuthority, adapters, attemptIo, result);
|
|
1041
|
+
},
|
|
845
1042
|
});
|
|
846
1043
|
}
|
|
847
1044
|
/**
|
|
@@ -911,7 +1108,11 @@ export async function runPostAdmissionManualResume(input) {
|
|
|
911
1108
|
});
|
|
912
1109
|
if (result.terminal !== undefined &&
|
|
913
1110
|
isLawfulTypedTerminalOutcome(result.terminal.roleOutcome)) {
|
|
914
|
-
|
|
1111
|
+
// dispatchPostAdmissionTurn already persisted this lawful outcome inline
|
|
1112
|
+
// (persistRunState defaults true here — no station-child/loop deferral)
|
|
1113
|
+
// through its own settleAfterTurnStarted-backed branches; a lawful result
|
|
1114
|
+
// only ever reaches this point once that persist has already succeeded
|
|
1115
|
+
// (#836 r12 class 3 dedup — one persist owner, not a second here).
|
|
915
1116
|
io.stdout(formatTerminalResult(result.terminal));
|
|
916
1117
|
}
|
|
917
1118
|
if (result.terminal !== undefined) {
|