@akagilnc/pi-workflow-roles 0.1.3391 → 0.1.3403
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.
|
@@ -8584,16 +8584,8 @@ function runIdentity(context) {
|
|
|
8584
8584
|
if (typeof headerId === "string" && headerId.length > 0) return headerId;
|
|
8585
8585
|
throw new Error("\u63D0\u4EA4\u8D26\u9700\u8981\u5DF2\u53D7\u7406\u7684 run \u8EAB\u4EFD");
|
|
8586
8586
|
}
|
|
8587
|
-
function latestUserAttemptId(entries) {
|
|
8588
|
-
const ordered = [...entries];
|
|
8589
|
-
for (let index = ordered.length - 1; index >= 0; index -= 1) {
|
|
8590
|
-
const entry = ordered[index];
|
|
8591
|
-
if (entry?.message?.role === "user" && typeof entry.id === "string") return entry.id;
|
|
8592
|
-
}
|
|
8593
|
-
return void 0;
|
|
8594
|
-
}
|
|
8595
8587
|
function attemptIdentity(context, runId) {
|
|
8596
|
-
return
|
|
8588
|
+
return context.sessionManager.getHeader?.()?.id ?? context.sessionManager.getLeafId?.() ?? `${runId}:initial`;
|
|
8597
8589
|
}
|
|
8598
8590
|
function submissionRecordFile(cwd, runId, home) {
|
|
8599
8591
|
const ledgerHome = resolveActivationLedgerHome(home);
|
package/dist/public-cli/main.js
CHANGED
|
@@ -24326,14 +24326,6 @@ var init_run_terminal_artifacts = __esm({
|
|
|
24326
24326
|
});
|
|
24327
24327
|
|
|
24328
24328
|
// src/submission-ledger.ts
|
|
24329
|
-
function latestUserAttemptId(entries) {
|
|
24330
|
-
const ordered = [...entries];
|
|
24331
|
-
for (let index = ordered.length - 1; index >= 0; index -= 1) {
|
|
24332
|
-
const entry = ordered[index];
|
|
24333
|
-
if (entry?.message?.role === "user" && typeof entry.id === "string") return entry.id;
|
|
24334
|
-
}
|
|
24335
|
-
return void 0;
|
|
24336
|
-
}
|
|
24337
24329
|
function isAcceptedProjection(value) {
|
|
24338
24330
|
if (typeof value !== "object" || value === null) return false;
|
|
24339
24331
|
const candidate = value;
|
|
@@ -24372,17 +24364,13 @@ async function readSealedSubmission(cwd, runId, home) {
|
|
|
24372
24364
|
}
|
|
24373
24365
|
return void 0;
|
|
24374
24366
|
}
|
|
24375
|
-
async function readAuditEscalationSubmission(cwd, runId, home
|
|
24367
|
+
async function readAuditEscalationSubmission(cwd, runId, home) {
|
|
24376
24368
|
const { owned } = await readOwnedSubmissionRecords(cwd, runId, home);
|
|
24377
|
-
const latestAttemptId = currentAttemptId ?? owned.at(-1)?.subject?.attemptId;
|
|
24378
|
-
if (typeof latestAttemptId !== "string") return void 0;
|
|
24379
24369
|
for (let index = owned.length - 1; index >= 0; index -= 1) {
|
|
24380
24370
|
const record4 = owned[index];
|
|
24381
|
-
if (record4?.subject?.attemptId !== latestAttemptId) continue;
|
|
24382
24371
|
if (record4?.kind !== "outcome") continue;
|
|
24383
24372
|
const payload = record4.payload;
|
|
24384
|
-
if (payload?.type !== "outcome") continue;
|
|
24385
|
-
if (payload.outcome !== "audit-escalation") return void 0;
|
|
24373
|
+
if (payload?.type !== "outcome" || payload.outcome !== "audit-escalation") continue;
|
|
24386
24374
|
if (isAuditEscalationTerminalProjection(payload.projection)) return payload.projection;
|
|
24387
24375
|
}
|
|
24388
24376
|
return void 0;
|
|
@@ -24956,27 +24944,28 @@ function sealedLedgerHome(admitted) {
|
|
|
24956
24944
|
async function sealedLedgerOutcome(admitted) {
|
|
24957
24945
|
return readSealedSubmission(admitted.projectRoot, admitted.runId, sealedLedgerHome(admitted));
|
|
24958
24946
|
}
|
|
24959
|
-
async function
|
|
24960
|
-
|
|
24961
|
-
|
|
24962
|
-
|
|
24963
|
-
|
|
24964
|
-
|
|
24965
|
-
|
|
24966
|
-
|
|
24947
|
+
async function sealedAcceptanceRedispatchDisposition(admitted) {
|
|
24948
|
+
try {
|
|
24949
|
+
if (await sealedLedgerOutcome(admitted) !== void 0) {
|
|
24950
|
+
return { kind: "block", reason: "sealed-accepted" };
|
|
24951
|
+
}
|
|
24952
|
+
return { kind: "allow" };
|
|
24953
|
+
} catch (cause) {
|
|
24954
|
+
return { kind: "block", reason: "authority-failed", cause };
|
|
24967
24955
|
}
|
|
24956
|
+
}
|
|
24957
|
+
async function auditEscalationLedgerOutcome(admitted, role) {
|
|
24968
24958
|
const projection = await readAuditEscalationSubmission(
|
|
24969
24959
|
admitted.projectRoot,
|
|
24970
24960
|
admitted.runId,
|
|
24971
|
-
sealedLedgerHome(admitted)
|
|
24972
|
-
currentAttemptId
|
|
24961
|
+
sealedLedgerHome(admitted)
|
|
24973
24962
|
);
|
|
24974
24963
|
if (projection?.role !== role) return void 0;
|
|
24975
24964
|
return projection;
|
|
24976
24965
|
}
|
|
24977
|
-
async function closedLedgerOutcome(admitted, role
|
|
24966
|
+
async function closedLedgerOutcome(admitted, role) {
|
|
24978
24967
|
const sealed = await sealedLedgerOutcome(admitted);
|
|
24979
|
-
return sealed?.role === role ? sealed : auditEscalationLedgerOutcome(admitted, role
|
|
24968
|
+
return sealed?.role === role ? sealed : auditEscalationLedgerOutcome(admitted, role);
|
|
24980
24969
|
}
|
|
24981
24970
|
function coordinatesFromAdmitted(authority, admitted) {
|
|
24982
24971
|
return authority.decode(admitted.principal);
|
|
@@ -26301,7 +26290,7 @@ async function readLawfulJudgeRoleOutcome(admitted, authority) {
|
|
|
26301
26290
|
decisiveFacts: judgeDecisiveFacts(details, sealed.status)
|
|
26302
26291
|
};
|
|
26303
26292
|
}
|
|
26304
|
-
return auditEscalationLedgerOutcome(admitted, "judge"
|
|
26293
|
+
return auditEscalationLedgerOutcome(admitted, "judge");
|
|
26305
26294
|
}
|
|
26306
26295
|
async function settleLawfulJudgeTerminalResult(admitted, authority) {
|
|
26307
26296
|
const roleOutcome = await readLawfulJudgeRoleOutcome(admitted, authority);
|
|
@@ -26328,7 +26317,7 @@ async function trySettleJudgeTerminalResult(admitted, authority) {
|
|
|
26328
26317
|
return settleLawfulJudgeTerminalResult(admitted, authority);
|
|
26329
26318
|
}
|
|
26330
26319
|
async function settleLawfulCoderTerminalResult(admitted, authority, options = {}) {
|
|
26331
|
-
const ledgerOutcome = await closedLedgerOutcome(admitted, "coder"
|
|
26320
|
+
const ledgerOutcome = await closedLedgerOutcome(admitted, "coder");
|
|
26332
26321
|
if (ledgerOutcome === void 0) return void 0;
|
|
26333
26322
|
let roleOutcome = ledgerOutcome;
|
|
26334
26323
|
let output;
|
|
@@ -26448,7 +26437,7 @@ async function publishFixerArtifacts(admitted, roleOutcome, coordinates, options
|
|
|
26448
26437
|
];
|
|
26449
26438
|
}
|
|
26450
26439
|
async function settleLawfulFixerTerminalResult(admitted, authority, options) {
|
|
26451
|
-
const ledgerOutcome = await closedLedgerOutcome(admitted, "fixer"
|
|
26440
|
+
const ledgerOutcome = await closedLedgerOutcome(admitted, "fixer");
|
|
26452
26441
|
if (ledgerOutcome === void 0) return void 0;
|
|
26453
26442
|
let roleOutcome = ledgerOutcome;
|
|
26454
26443
|
let output;
|
|
@@ -26655,7 +26644,7 @@ async function settleLawfulDoctorTerminalResult(admitted, authority) {
|
|
|
26655
26644
|
const { sessionDirectory, sessionFile } = coordinates;
|
|
26656
26645
|
const entries = await readLawfulSettlementEntries(sessionFile) ?? [];
|
|
26657
26646
|
if (sealed?.role !== "doctor") {
|
|
26658
|
-
const escalation = await auditEscalationLedgerOutcome(admitted, "doctor"
|
|
26647
|
+
const escalation = await auditEscalationLedgerOutcome(admitted, "doctor");
|
|
26659
26648
|
if (escalation === void 0) return void 0;
|
|
26660
26649
|
const artifacts2 = await publishDoctorArtifacts(admitted, escalation, coordinates);
|
|
26661
26650
|
return withOptionalGateProjection(
|
|
@@ -26719,7 +26708,7 @@ async function settleLawfulSeatAcceptedTerminalResult(admitted, authority, spec)
|
|
|
26719
26708
|
const coordinates = coordinatesFromAdmitted(authority, admitted);
|
|
26720
26709
|
const { sessionDirectory, sessionFile } = coordinates;
|
|
26721
26710
|
const entries = await readLawfulSettlementEntries(sessionFile) ?? [];
|
|
26722
|
-
const roleOutcome = await closedLedgerOutcome(admitted, spec.role
|
|
26711
|
+
const roleOutcome = await closedLedgerOutcome(admitted, spec.role);
|
|
26723
26712
|
if (roleOutcome?.kind === "audit_escalation") {
|
|
26724
26713
|
const navigator2 = extractNavigatorFact(entries);
|
|
26725
26714
|
return withOptionalGateProjection(
|
|
@@ -27955,36 +27944,21 @@ async function runWithAutoResumeLoop(options) {
|
|
|
27955
27944
|
return result2;
|
|
27956
27945
|
}
|
|
27957
27946
|
}
|
|
27958
|
-
if (options.
|
|
27959
|
-
|
|
27960
|
-
|
|
27961
|
-
|
|
27962
|
-
|
|
27963
|
-
|
|
27964
|
-
failClosed = {
|
|
27965
|
-
cause: authorityError,
|
|
27966
|
-
endReason: "sealed-acceptance authority failed closed"
|
|
27967
|
-
};
|
|
27968
|
-
}
|
|
27969
|
-
if (failClosed === void 0 && sealedStop) {
|
|
27970
|
-
if (result2 !== void 0) {
|
|
27971
|
-
const terminal = result2.terminal;
|
|
27972
|
-
if (terminal !== void 0) presentTerminal(terminal, options.io);
|
|
27947
|
+
if (options.sealedAcceptanceDisposition !== void 0) {
|
|
27948
|
+
const disposition = await options.sealedAcceptanceDisposition();
|
|
27949
|
+
if (disposition.kind === "block") {
|
|
27950
|
+
if (disposition.reason === "sealed-accepted" && result2 !== void 0) {
|
|
27951
|
+
const terminal2 = result2.terminal;
|
|
27952
|
+
if (terminal2 !== void 0) presentTerminal(terminal2, options.io);
|
|
27973
27953
|
return result2;
|
|
27974
27954
|
}
|
|
27975
|
-
failClosed = {
|
|
27976
|
-
cause: lastThrownError,
|
|
27977
|
-
endReason: "sealed accepted projection already present"
|
|
27978
|
-
};
|
|
27979
|
-
}
|
|
27980
|
-
if (failClosed !== void 0) {
|
|
27981
27955
|
const terminal = dispatchExceptionFailureTerminal({
|
|
27982
27956
|
role: options.admitted.role,
|
|
27983
27957
|
runId: options.admitted.runId,
|
|
27984
|
-
causeError:
|
|
27958
|
+
causeError: disposition.reason === "authority-failed" ? disposition.cause : lastThrownError,
|
|
27985
27959
|
errorFiles: retainedErrorFiles,
|
|
27986
27960
|
autoResumeAttempts,
|
|
27987
|
-
endReason:
|
|
27961
|
+
endReason: disposition.reason === "authority-failed" ? "sealed-acceptance authority failed closed" : "sealed accepted projection already present",
|
|
27988
27962
|
everyAttemptThrew
|
|
27989
27963
|
});
|
|
27990
27964
|
await finalizeExceptionRunBestEffort(options.admitted.runDirectory, options.io);
|
|
@@ -28338,7 +28312,7 @@ async function runPostAdmissionResumable(input) {
|
|
|
28338
28312
|
autoResumeLimit: env.autoResumeLimit,
|
|
28339
28313
|
buildInitialPayload: buildInitialRequest,
|
|
28340
28314
|
buildResumePayload: buildResumeRequest,
|
|
28341
|
-
|
|
28315
|
+
sealedAcceptanceDisposition: () => sealedAcceptanceRedispatchDisposition(admitted),
|
|
28342
28316
|
dispatch: (request, lease, _isFirst, attemptIo) => dispatchPostAdmissionTurn({
|
|
28343
28317
|
admitted,
|
|
28344
28318
|
env: {
|
|
@@ -28370,22 +28344,15 @@ async function runPostAdmissionManualResume(input) {
|
|
|
28370
28344
|
};
|
|
28371
28345
|
}
|
|
28372
28346
|
} catch (error) {
|
|
28373
|
-
|
|
28374
|
-
|
|
28375
|
-
if (await hasSealedAcceptedProjection(admitted)) {
|
|
28376
|
-
failClosed = { cause: error };
|
|
28377
|
-
}
|
|
28378
|
-
} catch (authorityError) {
|
|
28379
|
-
failClosed = { cause: authorityError };
|
|
28380
|
-
}
|
|
28381
|
-
if (failClosed !== void 0) {
|
|
28347
|
+
const disposition = await sealedAcceptanceRedispatchDisposition(admitted);
|
|
28348
|
+
if (disposition.kind === "block") {
|
|
28382
28349
|
return await presentControlledFailure2(
|
|
28383
28350
|
admitted,
|
|
28384
28351
|
{
|
|
28385
28352
|
timedOut: false,
|
|
28386
28353
|
code: null,
|
|
28387
28354
|
stderr: "",
|
|
28388
|
-
thrown:
|
|
28355
|
+
thrown: disposition.reason === "authority-failed" ? disposition.cause : error
|
|
28389
28356
|
},
|
|
28390
28357
|
adapters,
|
|
28391
28358
|
env.principalAuthority,
|
package/package.json
CHANGED
|
@@ -31,7 +31,11 @@ import {
|
|
|
31
31
|
} from "./run-lifecycle.ts";
|
|
32
32
|
import { parseAutoResumeLimit } from "./config.ts";
|
|
33
33
|
import { isLawfulTypedTerminalOutcome, formatTerminalResult, type TerminalArtifactRef, type TerminalResult, type TerminalRoleName } from "./terminal.ts";
|
|
34
|
-
import {
|
|
34
|
+
import {
|
|
35
|
+
presentFailureTerminal,
|
|
36
|
+
presentStructuralRejection,
|
|
37
|
+
type SealedAcceptanceRedispatchDisposition,
|
|
38
|
+
} from "./settlement.ts";
|
|
35
39
|
import type { CliIo } from "./cli-io.ts";
|
|
36
40
|
|
|
37
41
|
const dummyIo: CliIo = { stdout: () => {}, stderr: () => {} };
|
|
@@ -343,11 +347,12 @@ export async function runWithAutoResumeLoop<
|
|
|
343
347
|
buildResumePayload: () => TPayload;
|
|
344
348
|
dispatch: (payload: TPayload, lease: RunWriterLease, isFirst: boolean, attemptIo: CliIo) => Promise<T>;
|
|
345
349
|
/**
|
|
346
|
-
* After a non-lawful terminal or dispatch throw,
|
|
347
|
-
*
|
|
348
|
-
* and destroy the sealed read
|
|
350
|
+
* After a non-lawful terminal or dispatch throw, consult settlement-owned
|
|
351
|
+
* sealed-acceptance redispatch disposition (#672 / ADR 0080). Publication
|
|
352
|
+
* miss must not redispatch and destroy the sealed read (#648 / #599).
|
|
353
|
+
* Loop presents entry-specific terminals; it must not rebuild the gate.
|
|
349
354
|
*/
|
|
350
|
-
|
|
355
|
+
sealedAcceptanceDisposition?: () => Promise<SealedAcceptanceRedispatchDisposition>;
|
|
351
356
|
}): Promise<T> {
|
|
352
357
|
// #422 single-point resolution + domain validation. NaN would bypass every
|
|
353
358
|
// `attempts >= limit` comparison (always false) — reject here, before any dispatch.
|
|
@@ -431,42 +436,30 @@ export async function runWithAutoResumeLoop<
|
|
|
431
436
|
}
|
|
432
437
|
}
|
|
433
438
|
|
|
434
|
-
//
|
|
435
|
-
// non-lawful return and direct throw.
|
|
436
|
-
//
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
let failClosed: { cause: unknown; endReason: string } | undefined;
|
|
442
|
-
let sealedStop = false;
|
|
443
|
-
try {
|
|
444
|
-
sealedStop = await options.shouldStopAutoResume();
|
|
445
|
-
} catch (authorityError) {
|
|
446
|
-
failClosed = {
|
|
447
|
-
cause: authorityError,
|
|
448
|
-
endReason: "sealed-acceptance authority failed closed",
|
|
449
|
-
};
|
|
450
|
-
}
|
|
451
|
-
if (failClosed === undefined && sealedStop) {
|
|
452
|
-
if (result !== undefined) {
|
|
439
|
+
// Settlement-owned sealed disposition before any redispatch (#648 / #672):
|
|
440
|
+
// shared for non-lawful return and direct throw. Only entry presentation
|
|
441
|
+
// differs (present returned terminal vs throw-path synthetic).
|
|
442
|
+
if (options.sealedAcceptanceDisposition !== undefined) {
|
|
443
|
+
const disposition = await options.sealedAcceptanceDisposition();
|
|
444
|
+
if (disposition.kind === "block") {
|
|
445
|
+
if (disposition.reason === "sealed-accepted" && result !== undefined) {
|
|
453
446
|
const terminal = (result as { terminal?: TerminalResult }).terminal;
|
|
454
447
|
if (terminal !== undefined) presentTerminal(terminal, options.io);
|
|
455
448
|
return result;
|
|
456
449
|
}
|
|
457
|
-
failClosed = {
|
|
458
|
-
cause: lastThrownError,
|
|
459
|
-
endReason: "sealed accepted projection already present",
|
|
460
|
-
};
|
|
461
|
-
}
|
|
462
|
-
if (failClosed !== undefined) {
|
|
463
450
|
const terminal = dispatchExceptionFailureTerminal({
|
|
464
451
|
role: options.admitted.role,
|
|
465
452
|
runId: options.admitted.runId,
|
|
466
|
-
causeError:
|
|
453
|
+
causeError:
|
|
454
|
+
disposition.reason === "authority-failed"
|
|
455
|
+
? disposition.cause
|
|
456
|
+
: lastThrownError,
|
|
467
457
|
errorFiles: retainedErrorFiles,
|
|
468
458
|
autoResumeAttempts,
|
|
469
|
-
endReason:
|
|
459
|
+
endReason:
|
|
460
|
+
disposition.reason === "authority-failed"
|
|
461
|
+
? "sealed-acceptance authority failed closed"
|
|
462
|
+
: "sealed accepted projection already present",
|
|
470
463
|
everyAttemptThrew,
|
|
471
464
|
});
|
|
472
465
|
await finalizeExceptionRunBestEffort(options.admitted.runDirectory, options.io);
|
|
@@ -57,7 +57,7 @@ import {
|
|
|
57
57
|
resolveAuditedRunnerFailureResolution,
|
|
58
58
|
resolveControlledFailureResumeObservation,
|
|
59
59
|
settleFailureTerminalResult,
|
|
60
|
-
|
|
60
|
+
sealedAcceptanceRedispatchDisposition,
|
|
61
61
|
} from "./settlement.ts";
|
|
62
62
|
import type { CliIo } from "./cli-io.ts";
|
|
63
63
|
import type { AdmittedRoleInvocation } from "./invocation.ts";
|
|
@@ -547,8 +547,8 @@ export async function runPostAdmissionResumable<
|
|
|
547
547
|
autoResumeLimit: env.autoResumeLimit,
|
|
548
548
|
buildInitialPayload: buildInitialRequest,
|
|
549
549
|
buildResumePayload: buildResumeRequest,
|
|
550
|
-
|
|
551
|
-
|
|
550
|
+
sealedAcceptanceDisposition: () =>
|
|
551
|
+
sealedAcceptanceRedispatchDisposition(admitted),
|
|
552
552
|
dispatch: (request, lease, _isFirst, attemptIo) =>
|
|
553
553
|
dispatchPostAdmissionTurn({
|
|
554
554
|
admitted,
|
|
@@ -614,27 +614,21 @@ export async function runPostAdmissionManualResume<
|
|
|
614
614
|
};
|
|
615
615
|
}
|
|
616
616
|
} catch (error) {
|
|
617
|
-
//
|
|
618
|
-
//
|
|
619
|
-
//
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
let failClosed: { cause: unknown } | undefined;
|
|
623
|
-
try {
|
|
624
|
-
if (await hasSealedAcceptedProjection(admitted)) {
|
|
625
|
-
failClosed = { cause: error };
|
|
626
|
-
}
|
|
627
|
-
} catch (authorityError) {
|
|
628
|
-
failClosed = { cause: authorityError };
|
|
629
|
-
}
|
|
630
|
-
if (failClosed !== undefined) {
|
|
617
|
+
// Settlement-owned sealed disposition (#648 / #599 / #672): sealed accepted +
|
|
618
|
+
// publication/settle throw fail closed without redispatch; authority failure
|
|
619
|
+
// preserves true cause. Manual resume only presents — does not rebuild the gate.
|
|
620
|
+
const disposition = await sealedAcceptanceRedispatchDisposition(admitted);
|
|
621
|
+
if (disposition.kind === "block") {
|
|
631
622
|
return (await presentControlledFailure(
|
|
632
623
|
admitted,
|
|
633
624
|
{
|
|
634
625
|
timedOut: false,
|
|
635
626
|
code: null,
|
|
636
627
|
stderr: "",
|
|
637
|
-
thrown:
|
|
628
|
+
thrown:
|
|
629
|
+
disposition.reason === "authority-failed"
|
|
630
|
+
? disposition.cause
|
|
631
|
+
: error,
|
|
638
632
|
},
|
|
639
633
|
adapters,
|
|
640
634
|
env.principalAuthority,
|
|
@@ -13,7 +13,6 @@ import {
|
|
|
13
13
|
} from "../analyst-gate-cycles-read.ts";
|
|
14
14
|
import { readSitianRecords, resolveSitianRecordPath, sitianReport } from "../sitian-facade.ts";
|
|
15
15
|
import {
|
|
16
|
-
latestUserAttemptId,
|
|
17
16
|
readAuditEscalationSubmission,
|
|
18
17
|
readLatestSubmissionOutcome,
|
|
19
18
|
readSealedSubmission,
|
|
@@ -164,32 +163,41 @@ async function sealedLedgerOutcome(admitted: AdmittedRoleInvocation): Promise<Ex
|
|
|
164
163
|
}
|
|
165
164
|
|
|
166
165
|
/**
|
|
167
|
-
* Shared sealed-
|
|
168
|
-
*
|
|
166
|
+
* Shared sealed-acceptance redispatch disposition for resume entrypoints
|
|
167
|
+
* (#648 sealed authority; #672 / ADR 0080 single-settlement-disposition).
|
|
168
|
+
* Owns the fail-closed gate auto and manual resume previously rebuilt beside
|
|
169
|
+
* the shared sealed query: sealed → block; authority throw → block with
|
|
170
|
+
* preserved cause; otherwise allow. Callers present entry-specific terminals;
|
|
171
|
+
* they must not re-derive this judgment. Ledger projection remains the sole
|
|
172
|
+
* seal truth — this is disposition over that read, not a second state.
|
|
169
173
|
*/
|
|
170
|
-
export
|
|
174
|
+
export type SealedAcceptanceRedispatchDisposition =
|
|
175
|
+
| { readonly kind: "allow" }
|
|
176
|
+
| { readonly kind: "block"; readonly reason: "sealed-accepted" }
|
|
177
|
+
| { readonly kind: "block"; readonly reason: "authority-failed"; readonly cause: unknown };
|
|
178
|
+
|
|
179
|
+
export async function sealedAcceptanceRedispatchDisposition(
|
|
171
180
|
admitted: AdmittedRoleInvocation,
|
|
172
|
-
): Promise<
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
181
|
+
): Promise<SealedAcceptanceRedispatchDisposition> {
|
|
182
|
+
try {
|
|
183
|
+
if ((await sealedLedgerOutcome(admitted)) !== undefined) {
|
|
184
|
+
return { kind: "block", reason: "sealed-accepted" };
|
|
185
|
+
}
|
|
186
|
+
return { kind: "allow" };
|
|
187
|
+
} catch (cause) {
|
|
188
|
+
// Ledger authority must not wash read failure into "unsealed" (#648).
|
|
189
|
+
return { kind: "block", reason: "authority-failed", cause };
|
|
190
|
+
}
|
|
176
191
|
}
|
|
177
192
|
|
|
178
193
|
async function auditEscalationLedgerOutcome(
|
|
179
194
|
admitted: AdmittedRoleInvocation,
|
|
180
195
|
role: TerminalRoleName,
|
|
181
|
-
authority: DurablePrincipalAuthority,
|
|
182
196
|
): Promise<Extract<TerminalRoleOutcome, { kind: "audit_escalation" }> | undefined> {
|
|
183
|
-
let currentAttemptId: string | undefined;
|
|
184
|
-
if (role === "coder" || role === "fixer") {
|
|
185
|
-
const entries = await readBoundSessionEntries(coordinatesFromAdmitted(authority, admitted).sessionFile);
|
|
186
|
-
currentAttemptId = latestUserAttemptId(entries);
|
|
187
|
-
}
|
|
188
197
|
const projection = await readAuditEscalationSubmission(
|
|
189
198
|
admitted.projectRoot,
|
|
190
199
|
admitted.runId,
|
|
191
200
|
sealedLedgerHome(admitted),
|
|
192
|
-
currentAttemptId,
|
|
193
201
|
);
|
|
194
202
|
if (projection?.role !== role) return undefined;
|
|
195
203
|
return projection;
|
|
@@ -198,12 +206,11 @@ async function auditEscalationLedgerOutcome(
|
|
|
198
206
|
async function closedLedgerOutcome(
|
|
199
207
|
admitted: AdmittedRoleInvocation,
|
|
200
208
|
role: TerminalRoleName,
|
|
201
|
-
authority: DurablePrincipalAuthority,
|
|
202
209
|
): Promise<Extract<TerminalRoleOutcome, { kind: "accepted" | "audit_escalation" }> | undefined> {
|
|
203
210
|
const sealed = await sealedLedgerOutcome(admitted);
|
|
204
211
|
return sealed?.role === role
|
|
205
212
|
? sealed
|
|
206
|
-
: auditEscalationLedgerOutcome(admitted, role
|
|
213
|
+
: auditEscalationLedgerOutcome(admitted, role);
|
|
207
214
|
}
|
|
208
215
|
|
|
209
216
|
/** Transitional host-session reads remain only for non-sealed failure and audit evidence. */
|
|
@@ -2513,7 +2520,7 @@ export async function readLawfulJudgeRoleOutcome(
|
|
|
2513
2520
|
};
|
|
2514
2521
|
}
|
|
2515
2522
|
// Non-final: consume ledger audit-escalation projection (no JSONL accepted rebuild).
|
|
2516
|
-
return auditEscalationLedgerOutcome(admitted, "judge"
|
|
2523
|
+
return auditEscalationLedgerOutcome(admitted, "judge");
|
|
2517
2524
|
}
|
|
2518
2525
|
|
|
2519
2526
|
/**
|
|
@@ -2590,7 +2597,7 @@ async function settleLawfulCoderTerminalResult(
|
|
|
2590
2597
|
readonly methodProvenance?: PackagedMethodSkillProvenance;
|
|
2591
2598
|
} = {},
|
|
2592
2599
|
): Promise<TerminalResult | undefined> {
|
|
2593
|
-
const ledgerOutcome = await closedLedgerOutcome(admitted, "coder"
|
|
2600
|
+
const ledgerOutcome = await closedLedgerOutcome(admitted, "coder");
|
|
2594
2601
|
if (ledgerOutcome === undefined) return undefined;
|
|
2595
2602
|
let roleOutcome: TerminalRoleOutcome = ledgerOutcome;
|
|
2596
2603
|
let output: CoderOutput | undefined;
|
|
@@ -2778,7 +2785,7 @@ async function settleLawfulFixerTerminalResult(
|
|
|
2778
2785
|
readonly methodSkillConfiguredPath: string;
|
|
2779
2786
|
},
|
|
2780
2787
|
): Promise<TerminalResult | undefined> {
|
|
2781
|
-
const ledgerOutcome = await closedLedgerOutcome(admitted, "fixer"
|
|
2788
|
+
const ledgerOutcome = await closedLedgerOutcome(admitted, "fixer");
|
|
2782
2789
|
if (ledgerOutcome === undefined) return undefined;
|
|
2783
2790
|
let roleOutcome: TerminalRoleOutcome = ledgerOutcome;
|
|
2784
2791
|
let output: FixerOutput | undefined;
|
|
@@ -3071,7 +3078,7 @@ async function settleLawfulDoctorTerminalResult(
|
|
|
3071
3078
|
const { sessionDirectory, sessionFile } = coordinates;
|
|
3072
3079
|
const entries = await readLawfulSettlementEntries(sessionFile) ?? [];
|
|
3073
3080
|
if (sealed?.role !== "doctor") {
|
|
3074
|
-
const escalation = await auditEscalationLedgerOutcome(admitted, "doctor"
|
|
3081
|
+
const escalation = await auditEscalationLedgerOutcome(admitted, "doctor");
|
|
3075
3082
|
if (escalation === undefined) return undefined;
|
|
3076
3083
|
const artifacts = await publishDoctorArtifacts(admitted, escalation, coordinates);
|
|
3077
3084
|
return withOptionalGateProjection(
|
|
@@ -3196,7 +3203,7 @@ async function settleLawfulSeatAcceptedTerminalResult(
|
|
|
3196
3203
|
const coordinates = coordinatesFromAdmitted(authority, admitted);
|
|
3197
3204
|
const { sessionDirectory, sessionFile } = coordinates;
|
|
3198
3205
|
const entries = await readLawfulSettlementEntries(sessionFile) ?? [];
|
|
3199
|
-
const roleOutcome = await closedLedgerOutcome(admitted, spec.role as TerminalRoleName
|
|
3206
|
+
const roleOutcome = await closedLedgerOutcome(admitted, spec.role as TerminalRoleName);
|
|
3200
3207
|
if (roleOutcome?.kind === "audit_escalation") {
|
|
3201
3208
|
const navigator = extractNavigatorFact(entries);
|
|
3202
3209
|
return withOptionalGateProjection(
|
package/src/submission-ledger.ts
CHANGED
|
@@ -56,22 +56,8 @@ function runIdentity(context: HostContext): string {
|
|
|
56
56
|
throw new Error("提交账需要已受理的 run 身份");
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
-
export function latestUserAttemptId(
|
|
60
|
-
entries: Iterable<{ readonly id?: unknown; readonly message?: { readonly role?: unknown } }>,
|
|
61
|
-
): string | undefined {
|
|
62
|
-
const ordered = [...entries];
|
|
63
|
-
for (let index = ordered.length - 1; index >= 0; index -= 1) {
|
|
64
|
-
const entry = ordered[index];
|
|
65
|
-
if (entry?.message?.role === "user" && typeof entry.id === "string") return entry.id;
|
|
66
|
-
}
|
|
67
|
-
return undefined;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
59
|
function attemptIdentity(context: HostContext, runId: string): string {
|
|
71
|
-
return
|
|
72
|
-
?? context.sessionManager.getHeader?.()?.id
|
|
73
|
-
?? context.sessionManager.getLeafId?.()
|
|
74
|
-
?? `${runId}:initial`;
|
|
60
|
+
return context.sessionManager.getHeader?.()?.id ?? context.sessionManager.getLeafId?.() ?? `${runId}:initial`;
|
|
75
61
|
}
|
|
76
62
|
|
|
77
63
|
function isAcceptedProjection(value: unknown): value is Extract<TerminalRoleOutcome, { kind: "accepted" }> {
|
|
@@ -139,18 +125,13 @@ export async function readAuditEscalationSubmission(
|
|
|
139
125
|
cwd: string,
|
|
140
126
|
runId: string,
|
|
141
127
|
home?: string,
|
|
142
|
-
currentAttemptId?: string,
|
|
143
128
|
): Promise<AuditEscalationSubmissionProjection | undefined> {
|
|
144
129
|
const { owned } = await readOwnedSubmissionRecords(cwd, runId, home);
|
|
145
|
-
const latestAttemptId = currentAttemptId ?? (owned.at(-1)?.subject as { attemptId?: unknown } | undefined)?.attemptId;
|
|
146
|
-
if (typeof latestAttemptId !== "string") return undefined;
|
|
147
130
|
for (let index = owned.length - 1; index >= 0; index -= 1) {
|
|
148
131
|
const record = owned[index];
|
|
149
|
-
if ((record?.subject as { attemptId?: unknown } | undefined)?.attemptId !== latestAttemptId) continue;
|
|
150
132
|
if (record?.kind !== "outcome") continue;
|
|
151
133
|
const payload = record.payload as Partial<Extract<SubmissionLedgerEvent, { type: "outcome" }>> | undefined;
|
|
152
|
-
if (payload?.type !== "outcome") continue;
|
|
153
|
-
if (payload.outcome !== "audit-escalation") return undefined;
|
|
134
|
+
if (payload?.type !== "outcome" || payload.outcome !== "audit-escalation") continue;
|
|
154
135
|
if (isAuditEscalationTerminalProjection(payload.projection)) return payload.projection;
|
|
155
136
|
}
|
|
156
137
|
return undefined;
|