@akagilnc/pi-workflow-roles 0.1.3886 → 0.1.3898
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 +1 -1
- package/README.zh-CN.md +1 -1
- package/dist/acp-host/production-host.js +37 -82
- package/dist/headless-host/production-host.js +37 -82
- package/dist/public-cli/doctor-run.js +1 -1
- package/dist/public-cli/judge-run.js +1 -1
- package/dist/public-cli/main.js +204 -287
- package/dist/public-cli/option-definitions.js +4 -3
- package/dist/public-cli/post-admission.js +57 -98
- package/dist/public-cli/run-lifecycle.js +3 -3
- package/dist/public-cli/settlement.js +47 -47
- package/dist/public-cli/turn-request.js +3 -0
- package/dist/submission-ledger.js +7 -8
- package/package.json +1 -1
- package/src/host-contracts.ts +2 -3
- package/src/public-cli/cli.ts +6 -2
- package/src/public-cli/coder-run.ts +34 -52
- package/src/public-cli/collector-run.ts +2 -1
- package/src/public-cli/doctor-run.ts +2 -1
- package/src/public-cli/fixer-run.ts +35 -50
- package/src/public-cli/judge-run.ts +2 -1
- package/src/public-cli/merger-run.ts +36 -51
- package/src/public-cli/option-definitions.ts +4 -3
- package/src/public-cli/post-admission.ts +104 -132
- package/src/public-cli/reviewer-run.ts +35 -50
- package/src/public-cli/run-lifecycle.ts +3 -3
- package/src/public-cli/settlement.ts +49 -28
- package/src/public-cli/turn-request.ts +5 -0
- package/src/submission-ledger.ts +7 -7
|
@@ -179,8 +179,8 @@ const GLOBAL_OPTIONS = [
|
|
|
179
179
|
repeatable: false,
|
|
180
180
|
form: "option",
|
|
181
181
|
description: {
|
|
182
|
-
en: "Override the effective seat model for this invocation (before or after the command).",
|
|
183
|
-
zh: "
|
|
182
|
+
en: "Override the effective seat model for this invocation (before or after the command name).",
|
|
183
|
+
zh: "覆盖本调用有效席位模型(可置于子命令名前或后)。",
|
|
184
184
|
},
|
|
185
185
|
},
|
|
186
186
|
{
|
|
@@ -1110,13 +1110,14 @@ const SUPPORT_COMMAND_HELP = {
|
|
|
1110
1110
|
},
|
|
1111
1111
|
resume: {
|
|
1112
1112
|
command: "resume",
|
|
1113
|
-
summary: "Resume a role run under the live seat table (model/host/engine); session principal must still exist. [message] applies only to seats that accept caller instruction; Notary/符宝郎 must omit message and derives evidence from the existing source-run/dossier binding.",
|
|
1113
|
+
summary: "Resume a role run under the live seat table (model/host/engine); session principal must still exist. [message] applies only to seats that accept caller instruction; Notary/符宝郎 must omit message and derives evidence from the existing source-run/dossier binding. Global --model/--thinking/--host/--engine must be placed before <runId> (either before `resume` or between `resume` and <runId>); the one argv after <runId> is the opaque message, not a flag position (#471).",
|
|
1114
1114
|
usage: ["ak-role resume <runId> [message]"],
|
|
1115
1115
|
examples: [
|
|
1116
1116
|
"ak-role resume 01abc…",
|
|
1117
1117
|
"ak-role resume 01abc… \"owner ruling\"",
|
|
1118
1118
|
"ak-role --host grok-build resume 01abc…",
|
|
1119
1119
|
"ak-role --engine agy resume 01abc…",
|
|
1120
|
+
"ak-role resume --model xai/grok-4.5 01abc… \"owner ruling\"",
|
|
1120
1121
|
],
|
|
1121
1122
|
},
|
|
1122
1123
|
new: {
|
|
@@ -40,6 +40,30 @@ async function readInvocationHost(runDirectory) {
|
|
|
40
40
|
throw error;
|
|
41
41
|
}
|
|
42
42
|
}
|
|
43
|
+
/**
|
|
44
|
+
* Factory-seat resume method-material face (#833): one authority for
|
|
45
|
+
* load → adapters / controlled-failure short-circuit. Seats only declare
|
|
46
|
+
* irreducible differences (loader, adapter factories, optional gate, knownCause).
|
|
47
|
+
*/
|
|
48
|
+
export async function resolveResumeMethodMaterialAdapters(input) {
|
|
49
|
+
if (input.shouldLoad === false) {
|
|
50
|
+
return { kind: "continue", adapters: input.emptyAdapters };
|
|
51
|
+
}
|
|
52
|
+
try {
|
|
53
|
+
const material = await input.loadMaterial();
|
|
54
|
+
return { kind: "continue", adapters: input.adaptersWith(material) };
|
|
55
|
+
}
|
|
56
|
+
catch (error) {
|
|
57
|
+
const terminal = await presentControlledFailure(input.admitted, {
|
|
58
|
+
timedOut: false,
|
|
59
|
+
code: null,
|
|
60
|
+
stderr: "",
|
|
61
|
+
thrown: error,
|
|
62
|
+
...(input.knownCause === undefined ? {} : { knownCause: input.knownCause }),
|
|
63
|
+
}, input.emptyAdapters, input.authority, input.io);
|
|
64
|
+
return { kind: "terminal", ...terminal };
|
|
65
|
+
}
|
|
66
|
+
}
|
|
43
67
|
export async function presentControlledFailure(admitted, failureInput, adapters, authority, io) {
|
|
44
68
|
const hasThrown = Object.hasOwn(failureInput, "thrown");
|
|
45
69
|
const resumeObservation = await resolveControlledFailureResumeObservation({
|
|
@@ -219,7 +243,7 @@ export async function dispatchPostAdmissionTurn(input) {
|
|
|
219
243
|
}, adapters, env.principalAuthority, io));
|
|
220
244
|
}
|
|
221
245
|
if (settled !== undefined && shouldPresent(settled)) {
|
|
222
|
-
// This court sealed — drop open-court pointer
|
|
246
|
+
// This court sealed — drop open-court pointer (bare resume no longer continues it).
|
|
223
247
|
if (settled.roleOutcome.kind === "accepted" &&
|
|
224
248
|
request.courtAttemptId !== undefined &&
|
|
225
249
|
request.courtAttemptId.length > 0) {
|
|
@@ -326,6 +350,7 @@ export function resumeTurnRequestProjectionOptions(admitted, request, env, summo
|
|
|
326
350
|
kind: "resume",
|
|
327
351
|
prompt,
|
|
328
352
|
},
|
|
353
|
+
...(request.message === undefined ? {} : { courtAttemptId: randomUUID() }),
|
|
329
354
|
};
|
|
330
355
|
}
|
|
331
356
|
function isAlreadyFrozenSummonsAttachment(runDirectory, attachmentPath) {
|
|
@@ -360,9 +385,10 @@ export async function prepareSummonsResumeMaterials(runDirectory, summons) {
|
|
|
360
385
|
}
|
|
361
386
|
/**
|
|
362
387
|
* Shared manual-resume orchestration for seats whose continuation is the
|
|
363
|
-
* package resume envelope (#599 / #633): load → structural rejection →
|
|
364
|
-
*
|
|
365
|
-
* turn
|
|
388
|
+
* package resume envelope (#599 / #633): load once → structural rejection →
|
|
389
|
+
* optional seat afterAdmittedLoad (method material / controlled failure) →
|
|
390
|
+
* seat turn projection → runPostAdmissionManualResume. Seat-owned loader
|
|
391
|
+
* validation, turn builder, and adapters stay on the seat.
|
|
366
392
|
*
|
|
367
393
|
* Court open/recovery transaction (#637): under the existing writer lease,
|
|
368
394
|
* read currentCourt, judge seal, clear (bound to the judged court id), freeze,
|
|
@@ -370,8 +396,8 @@ export async function prepareSummonsResumeMaterials(runDirectory, summons) {
|
|
|
370
396
|
*/
|
|
371
397
|
export async function runPostAdmissionSeatResume(input) {
|
|
372
398
|
let request = input.request;
|
|
373
|
-
// Load once for runDirectory / structural rejection
|
|
374
|
-
// only after the writer lease is held (below).
|
|
399
|
+
// Load once for runDirectory / structural rejection / afterAdmittedLoad;
|
|
400
|
+
// court identity is judged only after the writer lease is held (below).
|
|
375
401
|
let loaded;
|
|
376
402
|
try {
|
|
377
403
|
loaded = await input.load(request);
|
|
@@ -383,20 +409,28 @@ export async function runPostAdmissionSeatResume(input) {
|
|
|
383
409
|
}
|
|
384
410
|
throw error;
|
|
385
411
|
}
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
412
|
+
let adapters = input.adapters;
|
|
413
|
+
if (input.afterAdmittedLoad !== undefined) {
|
|
414
|
+
const prepared = await input.afterAdmittedLoad(loaded.admitted);
|
|
415
|
+
if (prepared.kind === "terminal") {
|
|
416
|
+
return {
|
|
417
|
+
exitCode: prepared.exitCode,
|
|
418
|
+
admitted: prepared.admitted,
|
|
419
|
+
terminal: prepared.terminal,
|
|
420
|
+
};
|
|
421
|
+
}
|
|
422
|
+
adapters = prepared.adapters;
|
|
423
|
+
}
|
|
424
|
+
// Court recovery / open under lease, then always dispatch (resume is pass-through).
|
|
390
425
|
try {
|
|
391
426
|
return await runPostAdmissionManualResume({
|
|
392
427
|
admitted: loaded.admitted,
|
|
393
428
|
env: input.env,
|
|
394
429
|
io: input.io,
|
|
395
|
-
adapters
|
|
430
|
+
adapters,
|
|
396
431
|
...(input.effectiveEngine === undefined
|
|
397
432
|
? {}
|
|
398
433
|
: { effectiveEngine: input.effectiveEngine }),
|
|
399
|
-
forceContinuation: true,
|
|
400
434
|
buildRequestAfterLease: async () => {
|
|
401
435
|
let openCourtAttemptId;
|
|
402
436
|
// Build uses the admitted judged under this lease (rehydrated when open
|
|
@@ -450,10 +484,11 @@ export async function runPostAdmissionSeatResume(input) {
|
|
|
450
484
|
}
|
|
451
485
|
}
|
|
452
486
|
let turnRequest = await input.buildTurnRequest(admittedForBuild, request);
|
|
453
|
-
//
|
|
454
|
-
// Bare resume
|
|
455
|
-
|
|
456
|
-
|
|
487
|
+
// Open court continue, or new court for summons / message re-review
|
|
488
|
+
// (clause 0 新庭可再交卷; #833). Bare resume without open court omits id.
|
|
489
|
+
if (openCourtAttemptId !== undefined ||
|
|
490
|
+
request.summons !== undefined ||
|
|
491
|
+
request.message !== undefined) {
|
|
457
492
|
const courtAttemptId = openCourtAttemptId ??
|
|
458
493
|
(turnRequest.courtAttemptId !== undefined &&
|
|
459
494
|
turnRequest.courtAttemptId.length > 0
|
|
@@ -543,79 +578,15 @@ export async function runPostAdmissionResumable(input) {
|
|
|
543
578
|
});
|
|
544
579
|
}
|
|
545
580
|
/**
|
|
546
|
-
*
|
|
547
|
-
* (#
|
|
548
|
-
*
|
|
549
|
-
* Returns undefined to fall through to dispatch; never rebuilds the gate.
|
|
550
|
-
*/
|
|
551
|
-
async function presentSealedAcceptedManualResumeIfAny(input) {
|
|
552
|
-
const { admitted, env, io, adapters, shouldPresent } = input;
|
|
553
|
-
try {
|
|
554
|
-
const existing = await adapters.trySettle(admitted, env.principalAuthority);
|
|
555
|
-
if (existing !== undefined &&
|
|
556
|
-
existing.roleOutcome.kind === "accepted" &&
|
|
557
|
-
shouldPresent(existing)) {
|
|
558
|
-
existing.autoResumeCount = 0;
|
|
559
|
-
io.stdout(formatTerminalResult(existing));
|
|
560
|
-
return {
|
|
561
|
-
exitCode: exitCodeForTerminalOutcome(existing.roleOutcome),
|
|
562
|
-
admitted,
|
|
563
|
-
terminal: existing,
|
|
564
|
-
};
|
|
565
|
-
}
|
|
566
|
-
}
|
|
567
|
-
catch (error) {
|
|
568
|
-
// Settlement-owned sealed disposition: sealed accepted + publication/settle
|
|
569
|
-
// throw fail closed without redispatch; authority failure preserves cause.
|
|
570
|
-
const disposition = await sealedAcceptanceRedispatchDisposition(admitted);
|
|
571
|
-
if (disposition.kind === "block") {
|
|
572
|
-
return (await presentControlledFailure(admitted, {
|
|
573
|
-
timedOut: false,
|
|
574
|
-
code: null,
|
|
575
|
-
stderr: "",
|
|
576
|
-
thrown: disposition.reason === "authority-failed"
|
|
577
|
-
? disposition.cause
|
|
578
|
-
: error,
|
|
579
|
-
}, adapters, env.principalAuthority, io));
|
|
580
|
-
}
|
|
581
|
-
// Pre-dispatch settle failure without a sealed accepted projection is not
|
|
582
|
-
// proof of seal; fall through to dispatch so the attempt path can settle
|
|
583
|
-
// or fail honestly.
|
|
584
|
-
}
|
|
585
|
-
return undefined;
|
|
586
|
-
}
|
|
587
|
-
/**
|
|
588
|
-
* Shared post-admission manual resume path: acquire writer lease and dispatch turn.
|
|
589
|
-
* When the submission ledger is already sealed, project that accepted terminal
|
|
590
|
-
* idempotently — do not dispatch a doomed turn that would append
|
|
591
|
-
* post-seal-anomaly and erase the sealed read (#599; keep #416 open load).
|
|
592
|
-
* Same-ticket re-summons (#637) pass forceContinuation + courtAttemptId so a new
|
|
593
|
-
* court turn still runs with this summons' materials despite a prior sealed
|
|
594
|
-
* acceptance, while submission-ledger sole-final stays per-attempt.
|
|
581
|
+
* Manual resume: lease + dispatch. Pass-through to the host — no sealed-accepted
|
|
582
|
+
* short-circuit (#833 / #416). Court open (summons / message / open court) is
|
|
583
|
+
* built under lease when using buildRequestAfterLease; sole-final stays per-attempt.
|
|
595
584
|
*/
|
|
596
585
|
export async function runPostAdmissionManualResume(input) {
|
|
597
|
-
const { admitted, env, io, adapters, effectiveEngine,
|
|
586
|
+
const { admitted, env, io, adapters, effectiveEngine, buildRequestAfterLease, } = input;
|
|
598
587
|
let request = input.request;
|
|
599
588
|
// #617 DK-3: manual resume writes the live seat/env model (same as new legs).
|
|
600
589
|
const effectiveModel = env.model;
|
|
601
|
-
const shouldPresent = adapters.shouldPresentSettled ??
|
|
602
|
-
((terminal) => isLawfulTypedTerminalOutcome(terminal.roleOutcome));
|
|
603
|
-
const sealedIdempotenceInput = {
|
|
604
|
-
admitted,
|
|
605
|
-
env,
|
|
606
|
-
io,
|
|
607
|
-
adapters,
|
|
608
|
-
shouldPresent,
|
|
609
|
-
};
|
|
610
|
-
// Sealed accepted receipt only — audit_escalation / residual failure must not
|
|
611
|
-
// short-circuit; those still need a real continuation turn.
|
|
612
|
-
// Same-ticket re-summons / court recovery forceContinuation skips the pre-lease
|
|
613
|
-
// face; post-builder reuses the same presenter when no courtAttemptId remains.
|
|
614
|
-
if (forceContinuation !== true && request !== undefined) {
|
|
615
|
-
const presented = await presentSealedAcceptedManualResumeIfAny(sealedIdempotenceInput);
|
|
616
|
-
if (presented !== undefined)
|
|
617
|
-
return presented;
|
|
618
|
-
}
|
|
619
590
|
let lease;
|
|
620
591
|
let staleWriterLeaseReclaimed;
|
|
621
592
|
try {
|
|
@@ -644,8 +615,8 @@ export async function runPostAdmissionManualResume(input) {
|
|
|
644
615
|
throw error;
|
|
645
616
|
}
|
|
646
617
|
// Court open/recovery under held lease until dispatch owns release (finally
|
|
647
|
-
// below). Builder
|
|
648
|
-
//
|
|
618
|
+
// below). Builder and any throw on this seam must release here — dispatch's
|
|
619
|
+
// finally only runs after handoff.
|
|
649
620
|
let handedOffToDispatch = false;
|
|
650
621
|
try {
|
|
651
622
|
if (request === undefined) {
|
|
@@ -653,18 +624,6 @@ export async function runPostAdmissionManualResume(input) {
|
|
|
653
624
|
throw new Error("runPostAdmissionManualResume requires request or buildRequestAfterLease");
|
|
654
625
|
}
|
|
655
626
|
request = await buildRequestAfterLease();
|
|
656
|
-
if (request.courtAttemptId === undefined ||
|
|
657
|
-
request.courtAttemptId.length === 0) {
|
|
658
|
-
const presented = await presentSealedAcceptedManualResumeIfAny(sealedIdempotenceInput);
|
|
659
|
-
if (presented !== undefined) {
|
|
660
|
-
return {
|
|
661
|
-
...presented,
|
|
662
|
-
...(staleWriterLeaseReclaimed === true
|
|
663
|
-
? { staleWriterLeaseReclaimed: true }
|
|
664
|
-
: {}),
|
|
665
|
-
};
|
|
666
|
-
}
|
|
667
|
-
}
|
|
668
627
|
}
|
|
669
628
|
handedOffToDispatch = true;
|
|
670
629
|
const result = await dispatchPostAdmissionTurn({
|
|
@@ -417,9 +417,9 @@ export async function recordCurrentCourt(runDirectory, court) {
|
|
|
417
417
|
}
|
|
418
418
|
/**
|
|
419
419
|
* Clear open court after this courtAttemptId seals, or when the open court is
|
|
420
|
-
* already sealed
|
|
421
|
-
*
|
|
422
|
-
*
|
|
420
|
+
* already sealed (#637). When expectedCourtAttemptId is set, clear only if it
|
|
421
|
+
* still matches — never drop a different court recorded under the writer lease
|
|
422
|
+
* after our judgment.
|
|
423
423
|
*/
|
|
424
424
|
export async function clearCurrentCourt(runDirectory, expectedCourtAttemptId) {
|
|
425
425
|
const current = await readRoleRunStateDisk(runDirectory);
|
|
@@ -1810,8 +1810,8 @@ async function readLawfulSettlementEntries(sessionFile) {
|
|
|
1810
1810
|
* Returns undefined for genuine absence (missing path / no lawful verdict).
|
|
1811
1811
|
* Session-read failures propagate with typed identity.
|
|
1812
1812
|
*/
|
|
1813
|
-
export async function readLawfulJudgeRoleOutcome(admitted, authority) {
|
|
1814
|
-
const sealed = await sealedLedgerOutcome(admitted);
|
|
1813
|
+
export async function readLawfulJudgeRoleOutcome(admitted, authority, scope) {
|
|
1814
|
+
const sealed = await sealedLedgerOutcome(admitted, scope);
|
|
1815
1815
|
if (sealed?.role === "judge") {
|
|
1816
1816
|
const details = sealed.decisiveFacts;
|
|
1817
1817
|
// sealed.status is the sole authority (written by acceptedFacts at seal).
|
|
@@ -1824,7 +1824,7 @@ export async function readLawfulJudgeRoleOutcome(admitted, authority) {
|
|
|
1824
1824
|
};
|
|
1825
1825
|
}
|
|
1826
1826
|
// Non-final: consume ledger audit-escalation projection (no JSONL accepted rebuild).
|
|
1827
|
-
return auditEscalationLedgerOutcome(admitted, "judge");
|
|
1827
|
+
return auditEscalationLedgerOutcome(admitted, "judge", scope);
|
|
1828
1828
|
}
|
|
1829
1829
|
/**
|
|
1830
1830
|
* Single lawful-settlement implementation (session → outcome/Navigator/artifacts).
|
|
@@ -1837,8 +1837,8 @@ export async function readLawfulJudgeRoleOutcome(admitted, authority) {
|
|
|
1837
1837
|
* - Lawful outcome presence is decided before publication so a later write error
|
|
1838
1838
|
* cannot erase the fact that a lawful result already exists.
|
|
1839
1839
|
*/
|
|
1840
|
-
async function settleLawfulJudgeTerminalResult(admitted, authority) {
|
|
1841
|
-
const roleOutcome = await readLawfulJudgeRoleOutcome(admitted, authority);
|
|
1840
|
+
async function settleLawfulJudgeTerminalResult(admitted, authority, scope) {
|
|
1841
|
+
const roleOutcome = await readLawfulJudgeRoleOutcome(admitted, authority, scope);
|
|
1842
1842
|
if (roleOutcome === undefined)
|
|
1843
1843
|
return undefined;
|
|
1844
1844
|
const coordinates = coordinatesFromAdmitted(authority, admitted);
|
|
@@ -1858,8 +1858,8 @@ async function settleLawfulJudgeTerminalResult(admitted, authority) {
|
|
|
1858
1858
|
* Throws when no lawful outcome is present (tests/callers that require success).
|
|
1859
1859
|
* Session-read and publication failures retain their typed identity.
|
|
1860
1860
|
*/
|
|
1861
|
-
export async function settleJudgeTerminalResult(admitted, authority) {
|
|
1862
|
-
const settled = await settleLawfulJudgeTerminalResult(admitted, authority);
|
|
1861
|
+
export async function settleJudgeTerminalResult(admitted, authority, scope) {
|
|
1862
|
+
const settled = await settleLawfulJudgeTerminalResult(admitted, authority, scope);
|
|
1863
1863
|
if (settled === undefined) {
|
|
1864
1864
|
throw new Error("Judge Role run completed without a lawful typed terminal result");
|
|
1865
1865
|
}
|
|
@@ -1870,11 +1870,11 @@ export async function settleJudgeTerminalResult(admitted, authority) {
|
|
|
1870
1870
|
* Returns undefined only for genuine absence (no lawful verdict / missing path).
|
|
1871
1871
|
* Session malformation and publication exceptions propagate with typed identity.
|
|
1872
1872
|
*/
|
|
1873
|
-
export async function trySettleJudgeTerminalResult(admitted, authority) {
|
|
1874
|
-
return settleLawfulJudgeTerminalResult(admitted, authority);
|
|
1873
|
+
export async function trySettleJudgeTerminalResult(admitted, authority, scope) {
|
|
1874
|
+
return settleLawfulJudgeTerminalResult(admitted, authority, scope);
|
|
1875
1875
|
}
|
|
1876
|
-
async function settleLawfulCoderTerminalResult(admitted, authority, options = {}) {
|
|
1877
|
-
const ledgerOutcome = await closedLedgerOutcome(admitted, "coder");
|
|
1876
|
+
async function settleLawfulCoderTerminalResult(admitted, authority, options = {}, scope) {
|
|
1877
|
+
const ledgerOutcome = await closedLedgerOutcome(admitted, "coder", scope);
|
|
1878
1878
|
if (ledgerOutcome === undefined)
|
|
1879
1879
|
return undefined;
|
|
1880
1880
|
// #757: sealed facts pass through — no shape re-project / field drop.
|
|
@@ -1899,8 +1899,8 @@ async function settleLawfulCoderTerminalResult(admitted, authority, options = {}
|
|
|
1899
1899
|
}, coordinates.sessionDirectory);
|
|
1900
1900
|
}
|
|
1901
1901
|
/** Settle a lawful Coder Terminal from the admitted session (shared #106 success interface). */
|
|
1902
|
-
export async function settleCoderTerminalResult(admitted, authority, options = {}) {
|
|
1903
|
-
const settled = await settleLawfulCoderTerminalResult(admitted, authority, options);
|
|
1902
|
+
export async function settleCoderTerminalResult(admitted, authority, options = {}, scope) {
|
|
1903
|
+
const settled = await settleLawfulCoderTerminalResult(admitted, authority, options, scope);
|
|
1904
1904
|
if (settled === undefined) {
|
|
1905
1905
|
throw new Error("Coder Role run completed without a lawful typed terminal result");
|
|
1906
1906
|
}
|
|
@@ -1995,8 +1995,8 @@ export async function publishFixerArtifacts(admitted, roleOutcome, coordinates,
|
|
|
1995
1995
|
{ kind: "evidence", path: evidencePath },
|
|
1996
1996
|
];
|
|
1997
1997
|
}
|
|
1998
|
-
async function settleLawfulFixerTerminalResult(admitted, authority, options) {
|
|
1999
|
-
const ledgerOutcome = await closedLedgerOutcome(admitted, "fixer");
|
|
1998
|
+
async function settleLawfulFixerTerminalResult(admitted, authority, options, scope) {
|
|
1999
|
+
const ledgerOutcome = await closedLedgerOutcome(admitted, "fixer", scope);
|
|
2000
2000
|
if (ledgerOutcome === undefined)
|
|
2001
2001
|
return undefined;
|
|
2002
2002
|
// #757: sealed facts pass through — no shape re-project / field drop.
|
|
@@ -2027,8 +2027,8 @@ async function settleLawfulFixerTerminalResult(admitted, authority, options) {
|
|
|
2027
2027
|
}, sessionDirectory);
|
|
2028
2028
|
}
|
|
2029
2029
|
/** Settle a lawful Fixer Terminal from the admitted session (shared #106 success interface). */
|
|
2030
|
-
export async function settleFixerTerminalResult(admitted, authority, options) {
|
|
2031
|
-
const settled = await settleLawfulFixerTerminalResult(admitted, authority, options);
|
|
2030
|
+
export async function settleFixerTerminalResult(admitted, authority, options, scope) {
|
|
2031
|
+
const settled = await settleLawfulFixerTerminalResult(admitted, authority, options, scope);
|
|
2032
2032
|
if (settled === undefined) {
|
|
2033
2033
|
throw new Error("Fixer Role run completed without a lawful typed terminal result");
|
|
2034
2034
|
}
|
|
@@ -2068,11 +2068,11 @@ export async function publishCollectorArtifacts(admitted, roleOutcome, coordinat
|
|
|
2068
2068
|
{ kind: "evidence", path: evidencePath },
|
|
2069
2069
|
];
|
|
2070
2070
|
}
|
|
2071
|
-
async function settleLawfulCollectorTerminalResult(admitted, authority) {
|
|
2071
|
+
async function settleLawfulCollectorTerminalResult(admitted, authority, scope) {
|
|
2072
2072
|
const coordinates = coordinatesFromAdmitted(authority, admitted);
|
|
2073
2073
|
const { sessionDirectory, sessionFile } = coordinates;
|
|
2074
2074
|
const entries = await readLawfulSettlementEntries(sessionFile) ?? [];
|
|
2075
|
-
const roleOutcome = await sealedLedgerOutcome(admitted);
|
|
2075
|
+
const roleOutcome = await sealedLedgerOutcome(admitted, scope);
|
|
2076
2076
|
if (roleOutcome?.role !== "collector") {
|
|
2077
2077
|
// Bounded to the current attempt so multi-attempt resume timeout/no-output
|
|
2078
2078
|
// is not masked by a prior wait-tool residual (#633).
|
|
@@ -2122,16 +2122,16 @@ async function settleLawfulCollectorTerminalResult(admitted, authority) {
|
|
|
2122
2122
|
}, sessionDirectory);
|
|
2123
2123
|
}
|
|
2124
2124
|
/** Settle a lawful Collector Terminal from the admitted session. */
|
|
2125
|
-
export async function settleCollectorTerminalResult(admitted, authority) {
|
|
2126
|
-
const settled = await settleLawfulCollectorTerminalResult(admitted, authority);
|
|
2125
|
+
export async function settleCollectorTerminalResult(admitted, authority, scope) {
|
|
2126
|
+
const settled = await settleLawfulCollectorTerminalResult(admitted, authority, scope);
|
|
2127
2127
|
if (settled === undefined) {
|
|
2128
2128
|
throw new Error("Collector Role run completed without a lawful typed terminal result");
|
|
2129
2129
|
}
|
|
2130
2130
|
return settled;
|
|
2131
2131
|
}
|
|
2132
2132
|
/** Try to settle a lawful Collector Terminal; undefined only for genuine absence. */
|
|
2133
|
-
export async function trySettleCollectorTerminalResult(admitted, authority) {
|
|
2134
|
-
return settleLawfulCollectorTerminalResult(admitted, authority);
|
|
2133
|
+
export async function trySettleCollectorTerminalResult(admitted, authority, scope) {
|
|
2134
|
+
return settleLawfulCollectorTerminalResult(admitted, authority, scope);
|
|
2135
2135
|
}
|
|
2136
2136
|
export async function publishDoctorArtifacts(admitted, roleOutcome, coordinates, options = {}) {
|
|
2137
2137
|
await appendRunAttemptHistory({ role: admitted.role, runId: admitted.runId, sessionFile: coordinates.sessionFile }, roleOutcome);
|
|
@@ -2167,13 +2167,13 @@ export async function publishDoctorArtifacts(admitted, roleOutcome, coordinates,
|
|
|
2167
2167
|
{ kind: "evidence", path: evidencePath },
|
|
2168
2168
|
];
|
|
2169
2169
|
}
|
|
2170
|
-
async function settleLawfulDoctorTerminalResult(admitted, authority) {
|
|
2171
|
-
const sealed = await sealedLedgerOutcome(admitted);
|
|
2170
|
+
async function settleLawfulDoctorTerminalResult(admitted, authority, scope) {
|
|
2171
|
+
const sealed = await sealedLedgerOutcome(admitted, scope);
|
|
2172
2172
|
const coordinates = coordinatesFromAdmitted(authority, admitted);
|
|
2173
2173
|
const { sessionDirectory, sessionFile } = coordinates;
|
|
2174
2174
|
const entries = await readLawfulSettlementEntries(sessionFile) ?? [];
|
|
2175
2175
|
if (sealed?.role !== "doctor") {
|
|
2176
|
-
const escalation = await auditEscalationLedgerOutcome(admitted, "doctor");
|
|
2176
|
+
const escalation = await auditEscalationLedgerOutcome(admitted, "doctor", scope);
|
|
2177
2177
|
if (escalation === undefined)
|
|
2178
2178
|
return undefined;
|
|
2179
2179
|
const artifacts = await publishDoctorArtifacts(admitted, escalation, coordinates);
|
|
@@ -2213,16 +2213,16 @@ async function settleLawfulDoctorTerminalResult(admitted, authority) {
|
|
|
2213
2213
|
}, sessionDirectory);
|
|
2214
2214
|
}
|
|
2215
2215
|
/** Settle a lawful Doctor Terminal from the admitted session. */
|
|
2216
|
-
export async function settleDoctorTerminalResult(admitted, authority) {
|
|
2217
|
-
const settled = await settleLawfulDoctorTerminalResult(admitted, authority);
|
|
2216
|
+
export async function settleDoctorTerminalResult(admitted, authority, scope) {
|
|
2217
|
+
const settled = await settleLawfulDoctorTerminalResult(admitted, authority, scope);
|
|
2218
2218
|
if (settled === undefined) {
|
|
2219
2219
|
throw new Error("Doctor Role run completed without a lawful typed terminal result");
|
|
2220
2220
|
}
|
|
2221
2221
|
return settled;
|
|
2222
2222
|
}
|
|
2223
2223
|
/** Try to settle a lawful Doctor Terminal; undefined only for genuine absence. */
|
|
2224
|
-
export async function trySettleDoctorTerminalResult(admitted, authority) {
|
|
2225
|
-
return settleLawfulDoctorTerminalResult(admitted, authority);
|
|
2224
|
+
export async function trySettleDoctorTerminalResult(admitted, authority, scope) {
|
|
2225
|
+
return settleLawfulDoctorTerminalResult(admitted, authority, scope);
|
|
2226
2226
|
}
|
|
2227
2227
|
/** Latest top-level user message index; 0 when the session has none (initial attempt). */
|
|
2228
2228
|
function currentAttemptStartIndex(entries) {
|
|
@@ -2388,12 +2388,12 @@ export async function trySettleAuditorTerminalResult(admitted, authority, scope)
|
|
|
2388
2388
|
return settleLawfulAuditorTerminalResult(admitted, authority, scope);
|
|
2389
2389
|
}
|
|
2390
2390
|
/** Try to settle a lawful Coder Terminal; undefined only for genuine absence. */
|
|
2391
|
-
export async function trySettleCoderTerminalResult(admitted, authority, options = {}) {
|
|
2392
|
-
return settleLawfulCoderTerminalResult(admitted, authority, options);
|
|
2391
|
+
export async function trySettleCoderTerminalResult(admitted, authority, options = {}, scope) {
|
|
2392
|
+
return settleLawfulCoderTerminalResult(admitted, authority, options, scope);
|
|
2393
2393
|
}
|
|
2394
2394
|
/** Try to settle a lawful Fixer Terminal; undefined only for genuine absence. */
|
|
2395
|
-
export async function trySettleFixerTerminalResult(admitted, authority, options) {
|
|
2396
|
-
return settleLawfulFixerTerminalResult(admitted, authority, options);
|
|
2395
|
+
export async function trySettleFixerTerminalResult(admitted, authority, options, scope) {
|
|
2396
|
+
return settleLawfulFixerTerminalResult(admitted, authority, options, scope);
|
|
2397
2397
|
}
|
|
2398
2398
|
/**
|
|
2399
2399
|
* Observe forced Reviewer code-review Skill expansions from the session.
|
|
@@ -2468,8 +2468,8 @@ export async function publishReviewerArtifacts(admitted, roleOutcome, coordinate
|
|
|
2468
2468
|
{ kind: "evidence", path: evidencePath },
|
|
2469
2469
|
];
|
|
2470
2470
|
}
|
|
2471
|
-
async function settleLawfulReviewerTerminalResult(admitted, authority, options) {
|
|
2472
|
-
const sealed = await sealedLedgerOutcome(admitted);
|
|
2471
|
+
async function settleLawfulReviewerTerminalResult(admitted, authority, options, scope) {
|
|
2472
|
+
const sealed = await sealedLedgerOutcome(admitted, scope);
|
|
2473
2473
|
if (sealed?.role !== "reviewer")
|
|
2474
2474
|
return undefined;
|
|
2475
2475
|
const coordinates = coordinatesFromAdmitted(authority, admitted);
|
|
@@ -2503,16 +2503,16 @@ async function settleLawfulReviewerTerminalResult(admitted, authority, options)
|
|
|
2503
2503
|
}, sessionDirectory);
|
|
2504
2504
|
}
|
|
2505
2505
|
/** Settle a lawful Reviewer Terminal from the admitted session (shared #106 success interface). */
|
|
2506
|
-
export async function settleReviewerTerminalResult(admitted, authority, options) {
|
|
2507
|
-
const settled = await settleLawfulReviewerTerminalResult(admitted, authority, options);
|
|
2506
|
+
export async function settleReviewerTerminalResult(admitted, authority, options, scope) {
|
|
2507
|
+
const settled = await settleLawfulReviewerTerminalResult(admitted, authority, options, scope);
|
|
2508
2508
|
if (settled === undefined) {
|
|
2509
2509
|
throw new Error("Reviewer Role run completed without a lawful typed terminal result");
|
|
2510
2510
|
}
|
|
2511
2511
|
return settled;
|
|
2512
2512
|
}
|
|
2513
2513
|
/** Try to settle a lawful Reviewer Terminal; undefined only for genuine absence. */
|
|
2514
|
-
export async function trySettleReviewerTerminalResult(admitted, authority, options) {
|
|
2515
|
-
return settleLawfulReviewerTerminalResult(admitted, authority, options);
|
|
2514
|
+
export async function trySettleReviewerTerminalResult(admitted, authority, options, scope) {
|
|
2515
|
+
return settleLawfulReviewerTerminalResult(admitted, authority, options, scope);
|
|
2516
2516
|
}
|
|
2517
2517
|
/**
|
|
2518
2518
|
* Observe forced Merger resolving-merge-conflicts Skill expansions from the session.
|
|
@@ -2579,14 +2579,14 @@ export async function publishMergerArtifacts(admitted, roleOutcome, coordinates,
|
|
|
2579
2579
|
{ kind: "evidence", path: evidencePath },
|
|
2580
2580
|
];
|
|
2581
2581
|
}
|
|
2582
|
-
async function settleLawfulMergerTerminalResult(admitted, authority, options) {
|
|
2582
|
+
async function settleLawfulMergerTerminalResult(admitted, authority, options, scope) {
|
|
2583
2583
|
const coordinates = coordinatesFromAdmitted(authority, admitted);
|
|
2584
2584
|
const { sessionDirectory, sessionFile } = coordinates;
|
|
2585
2585
|
const entries = await readLawfulSettlementEntries(sessionFile) ?? [];
|
|
2586
|
-
const roleOutcome = await sealedLedgerOutcome(admitted);
|
|
2586
|
+
const roleOutcome = await sealedLedgerOutcome(admitted, scope);
|
|
2587
2587
|
if (roleOutcome?.role !== "merger") {
|
|
2588
2588
|
// Ledger owns 0041: a non-sole closed round is not residual-incomplete material.
|
|
2589
|
-
const latestOutcome = await readLatestSubmissionOutcome(admitted.projectRoot, admitted.runId,
|
|
2589
|
+
const latestOutcome = await readLatestSubmissionOutcome(admitted.projectRoot, admitted.runId, ledgerReadScope(admitted, scope));
|
|
2590
2590
|
if (latestOutcome?.outcome === "correctable-rejection" && latestOutcome.code === "non-sole-round") {
|
|
2591
2591
|
return undefined;
|
|
2592
2592
|
}
|
|
@@ -2650,16 +2650,16 @@ async function settleLawfulMergerTerminalResult(admitted, authority, options) {
|
|
|
2650
2650
|
}, sessionDirectory);
|
|
2651
2651
|
}
|
|
2652
2652
|
/** Settle a lawful Merger Terminal from the admitted session (shared #106 success interface). */
|
|
2653
|
-
export async function settleMergerTerminalResult(admitted, authority, options) {
|
|
2654
|
-
const settled = await settleLawfulMergerTerminalResult(admitted, authority, options);
|
|
2653
|
+
export async function settleMergerTerminalResult(admitted, authority, options, scope) {
|
|
2654
|
+
const settled = await settleLawfulMergerTerminalResult(admitted, authority, options, scope);
|
|
2655
2655
|
if (settled === undefined) {
|
|
2656
2656
|
throw new Error("Merger Role run completed without a lawful typed terminal result");
|
|
2657
2657
|
}
|
|
2658
2658
|
return settled;
|
|
2659
2659
|
}
|
|
2660
2660
|
/** Try to settle a lawful Merger Terminal; undefined only for genuine absence. */
|
|
2661
|
-
export async function trySettleMergerTerminalResult(admitted, authority, options) {
|
|
2662
|
-
return settleLawfulMergerTerminalResult(admitted, authority, options);
|
|
2661
|
+
export async function trySettleMergerTerminalResult(admitted, authority, options, scope) {
|
|
2662
|
+
return settleLawfulMergerTerminalResult(admitted, authority, options, scope);
|
|
2663
2663
|
}
|
|
2664
2664
|
function publicationAttemptFromError(path, error) {
|
|
2665
2665
|
if (error instanceof Error) {
|
|
@@ -21,5 +21,8 @@ export function projectRoleTurnRequest(admitted, roleDetails, options) {
|
|
|
21
21
|
? {}
|
|
22
22
|
: { correlationId: options.correlationId }),
|
|
23
23
|
...(options.timeoutMs === undefined ? {} : { timeoutMs: options.timeoutMs }),
|
|
24
|
+
...(options.courtAttemptId === undefined || options.courtAttemptId.length === 0
|
|
25
|
+
? {}
|
|
26
|
+
: { courtAttemptId: options.courtAttemptId }),
|
|
24
27
|
};
|
|
25
28
|
}
|
|
@@ -25,10 +25,10 @@ function runIdentity(context) {
|
|
|
25
25
|
throw new Error("提交账需要已受理的 run 身份");
|
|
26
26
|
}
|
|
27
27
|
/**
|
|
28
|
-
* Court-turn attempt identity (#637 same-ticket re-summons).
|
|
29
|
-
* AK_ROLE_COURT_ATTEMPT is injected
|
|
30
|
-
*
|
|
31
|
-
* session-stable id keeps sole-final
|
|
28
|
+
* Court-turn attempt identity (#637 same-ticket re-summons / #833 message re-review).
|
|
29
|
+
* AK_ROLE_COURT_ATTEMPT is injected for a new court turn on an already-retained run
|
|
30
|
+
* (summons / message / open-court continue). Bare resume and first mint omit it so
|
|
31
|
+
* the session-stable id keeps sole-final per attempt.
|
|
32
32
|
*/
|
|
33
33
|
export const COURT_ATTEMPT_ENV = "AK_ROLE_COURT_ATTEMPT";
|
|
34
34
|
function attemptIdentity(context, runId) {
|
|
@@ -96,16 +96,15 @@ function recordsForAttempt(owned, attemptId) {
|
|
|
96
96
|
return owned.filter((record) => recordAttemptId(record) === attemptId);
|
|
97
97
|
}
|
|
98
98
|
/** Settlement read seam: typed sealed projection only, never host session JSONL.
|
|
99
|
-
* Omit attemptId for run-scoped latest sealed
|
|
100
|
-
* Pass attemptId for the current court turn so a prior seal cannot wash this turn.
|
|
99
|
+
* Omit attemptId for run-scoped latest sealed.
|
|
100
|
+
* Pass attemptId for the current court turn so a prior seal cannot wash this turn.
|
|
101
|
+
* post-seal-anomaly is forensic only — later turns must not erase an earlier seal (#833). */
|
|
101
102
|
export async function readSealedSubmission(cwd, runId, homeOrScope) {
|
|
102
103
|
const scope = resolveReadScope(homeOrScope);
|
|
103
104
|
const { owned } = await readOwnedSubmissionRecords(cwd, runId, scope.home);
|
|
104
105
|
const scoped = recordsForAttempt(owned, scope.attemptId);
|
|
105
106
|
for (let index = scoped.length - 1; index >= 0; index -= 1) {
|
|
106
107
|
const record = scoped[index];
|
|
107
|
-
if (record?.kind === "post-seal-anomaly")
|
|
108
|
-
return undefined;
|
|
109
108
|
if (record?.kind !== "sealed")
|
|
110
109
|
continue;
|
|
111
110
|
const payload = record.payload;
|
package/package.json
CHANGED
package/src/host-contracts.ts
CHANGED
|
@@ -179,9 +179,8 @@ export type RoleTurnRequest = {
|
|
|
179
179
|
/** Set by post-admission only on a real host switch; never on same-host resume. */
|
|
180
180
|
readonly hostTransition?: RoleTurnHostTransition;
|
|
181
181
|
/**
|
|
182
|
-
*
|
|
183
|
-
*
|
|
184
|
-
* Manual resume never sets this — sealed idempotent short-circuit stays intact.
|
|
182
|
+
* Court-turn attempt (#637 / #833): sole-final per attempt. Open court, summons,
|
|
183
|
+
* and resume-with-message set this; bare resume without an open court omits it.
|
|
185
184
|
*/
|
|
186
185
|
readonly courtAttemptId?: string;
|
|
187
186
|
};
|
package/src/public-cli/cli.ts
CHANGED
|
@@ -605,13 +605,16 @@ function parseArgv(argv: readonly string[]): ParsedGlobal {
|
|
|
605
605
|
* Unique public resume request parser (#471).
|
|
606
606
|
* One optional argv after runId is the opaque message; no further positionals.
|
|
607
607
|
*/
|
|
608
|
+
const RESUME_USAGE_ERROR =
|
|
609
|
+
"usage: ak-role resume <runId> [message] (put --model/--thinking/--host/--engine before <runId>; the one argv after <runId> is the opaque message, #471)";
|
|
610
|
+
|
|
608
611
|
function parseResumeRequest(args: readonly string[]): PublicResumeRequest {
|
|
609
612
|
const runId = args[0];
|
|
610
613
|
if (runId === undefined || runId.trim() === "" || runId.startsWith("-")) {
|
|
611
|
-
throw new CliUsageError(
|
|
614
|
+
throw new CliUsageError(RESUME_USAGE_ERROR);
|
|
612
615
|
}
|
|
613
616
|
if (args.length > 2) {
|
|
614
|
-
throw new CliUsageError(
|
|
617
|
+
throw new CliUsageError(RESUME_USAGE_ERROR);
|
|
615
618
|
}
|
|
616
619
|
if (args.length === 2) {
|
|
617
620
|
return { runId, message: args[1]! };
|
|
@@ -781,6 +784,7 @@ function renderHelp(): string {
|
|
|
781
784
|
"Persistent host (callable roles): ak-role config set-host <seat> <name> | unset-host <seat>",
|
|
782
785
|
"Host providers: ~/.ak-roles/host-providers.json (owner-edited; table > unique host directory > fail)",
|
|
783
786
|
"Host resolution: --host → persistent seat host → pi (resume uses the same order; #617)",
|
|
787
|
+
"Resume flag position: --model/--thinking/--host/--engine go before <runId> (before `resume` or between `resume` and <runId>); the one argv after <runId> is always the opaque message, never a flag (#471)",
|
|
784
788
|
"Effective seats: ak-role roles",
|
|
785
789
|
);
|
|
786
790
|
return `${lines.join("\n")}\n`;
|