@akagilnc/pi-workflow-roles 0.1.3631 → 0.1.3637
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/acp-host/production-host.js +100 -22
- package/dist/public-cli/inspector-run.js +6 -6
- package/dist/public-cli/instruction-seat-run.js +31 -17
- package/dist/public-cli/invocation.js +17 -0
- package/dist/public-cli/main.js +97 -20
- package/dist/public-cli/notary-run.js +4 -5
- package/dist/public-cli/run-lifecycle.js +52 -4
- package/dist/public-cli/seat-ticket-binding.js +14 -5
- package/dist/submission-ledger.js +5 -2
- package/package.json +1 -1
- package/src/public-cli/inspector-run.ts +6 -6
- package/src/public-cli/instruction-seat-run.ts +39 -21
- package/src/public-cli/invocation.ts +29 -0
- package/src/public-cli/notary-run.ts +4 -5
- package/src/public-cli/run-lifecycle.ts +57 -5
- package/src/public-cli/seat-ticket-binding.ts +16 -6
- package/src/submission-ledger.ts +5 -2
|
@@ -4707,6 +4707,33 @@ async function findRunDirectoryById(home, runId) {
|
|
|
4707
4707
|
}
|
|
4708
4708
|
return void 0;
|
|
4709
4709
|
}
|
|
4710
|
+
function parentRunPathFromGatePointerInstruction(instruction) {
|
|
4711
|
+
if (!instruction.startsWith(GATE_DOSSIER_POINTER_PREFIX)) return void 0;
|
|
4712
|
+
const path = instruction.slice(GATE_DOSSIER_POINTER_PREFIX.length).trim();
|
|
4713
|
+
return path === "" ? void 0 : path;
|
|
4714
|
+
}
|
|
4715
|
+
async function readRunParentPath(runDirectory) {
|
|
4716
|
+
let raw;
|
|
4717
|
+
try {
|
|
4718
|
+
raw = JSON.parse(
|
|
4719
|
+
await readFile8(join11(runDirectory, "admitted-request.json"), "utf8")
|
|
4720
|
+
);
|
|
4721
|
+
} catch (error) {
|
|
4722
|
+
if (errorCodeOf2(error) === "ENOENT") return void 0;
|
|
4723
|
+
throw error;
|
|
4724
|
+
}
|
|
4725
|
+
if (raw === null || typeof raw !== "object" || Array.isArray(raw)) {
|
|
4726
|
+
return void 0;
|
|
4727
|
+
}
|
|
4728
|
+
const record4 = raw;
|
|
4729
|
+
if (typeof record4.sourceRunPath === "string" && record4.sourceRunPath.trim() !== "") {
|
|
4730
|
+
return record4.sourceRunPath;
|
|
4731
|
+
}
|
|
4732
|
+
if (typeof record4.instruction === "string") {
|
|
4733
|
+
return parentRunPathFromGatePointerInstruction(record4.instruction);
|
|
4734
|
+
}
|
|
4735
|
+
return void 0;
|
|
4736
|
+
}
|
|
4710
4737
|
async function findLatestRunIdForSeatTicket(input) {
|
|
4711
4738
|
const ledgerHome = resolveActivationLedgerHome(input.home);
|
|
4712
4739
|
const runsDir = join11(
|
|
@@ -4726,8 +4753,16 @@ async function findLatestRunIdForSeatTicket(input) {
|
|
|
4726
4753
|
if (!entry.endsWith(suffix)) continue;
|
|
4727
4754
|
const runId = entry.slice(0, entry.length - suffix.length);
|
|
4728
4755
|
if (runId.length === 0) continue;
|
|
4729
|
-
const
|
|
4730
|
-
if (
|
|
4756
|
+
const runDirectory = join11(runsDir, entry);
|
|
4757
|
+
if (input.parentRunPath !== void 0) {
|
|
4758
|
+
const parentPath = await readRunParentPath(runDirectory);
|
|
4759
|
+
if (parentPath !== input.parentRunPath) continue;
|
|
4760
|
+
} else if (input.ticketNumber !== void 0) {
|
|
4761
|
+
const ticketNumber = await readRunTicketNumber(runDirectory);
|
|
4762
|
+
if (ticketNumber !== input.ticketNumber) continue;
|
|
4763
|
+
} else {
|
|
4764
|
+
continue;
|
|
4765
|
+
}
|
|
4731
4766
|
if (best === void 0 || runId > best) best = runId;
|
|
4732
4767
|
}
|
|
4733
4768
|
return best;
|
|
@@ -5074,7 +5109,7 @@ async function loadResumableInspectorRun(home, runId, authority) {
|
|
|
5074
5109
|
};
|
|
5075
5110
|
return seatLoadedResult(loaded, admitted);
|
|
5076
5111
|
}
|
|
5077
|
-
var V1_RESUMABLE_PROVIDERS, AUTO_RESUME_LIMIT, RESUME_TRANSPORT_ENVELOPE, RUN_STATE_FILE, WRITER_LOCK_FILE, RunWriterLeaseHeldError, WRITER_LEASE_RECLAIM_ROUNDS;
|
|
5112
|
+
var V1_RESUMABLE_PROVIDERS, AUTO_RESUME_LIMIT, RESUME_TRANSPORT_ENVELOPE, RUN_STATE_FILE, WRITER_LOCK_FILE, RunWriterLeaseHeldError, WRITER_LEASE_RECLAIM_ROUNDS, GATE_DOSSIER_POINTER_PREFIX;
|
|
5078
5113
|
var init_run_lifecycle = __esm({
|
|
5079
5114
|
"src/public-cli/run-lifecycle.ts"() {
|
|
5080
5115
|
"use strict";
|
|
@@ -5099,6 +5134,7 @@ var init_run_lifecycle = __esm({
|
|
|
5099
5134
|
}
|
|
5100
5135
|
};
|
|
5101
5136
|
WRITER_LEASE_RECLAIM_ROUNDS = 3;
|
|
5137
|
+
GATE_DOSSIER_POINTER_PREFIX = "\u5377\u5B97\u6307\u9488\uFF1A";
|
|
5102
5138
|
}
|
|
5103
5139
|
});
|
|
5104
5140
|
|
|
@@ -6288,6 +6324,7 @@ __export(invocation_exports, {
|
|
|
6288
6324
|
parseNotaryArgv: () => parseNotaryArgv,
|
|
6289
6325
|
parsePositiveTicketNumber: () => parsePositiveTicketNumber,
|
|
6290
6326
|
parseReviewerArgv: () => parseReviewerArgv,
|
|
6327
|
+
persistAdmittedSourceRunPath: () => persistAdmittedSourceRunPath,
|
|
6291
6328
|
recordEffectiveInvocationModel: () => recordEffectiveInvocationModel,
|
|
6292
6329
|
recordLaunchedPiIdentity: () => recordLaunchedPiIdentity,
|
|
6293
6330
|
recordLaunchedRolePackageIdentity: () => recordLaunchedRolePackageIdentity,
|
|
@@ -6403,6 +6440,25 @@ async function mergeInvocationIdentityPage(runDirectory, fields) {
|
|
|
6403
6440
|
"utf8"
|
|
6404
6441
|
);
|
|
6405
6442
|
}
|
|
6443
|
+
async function persistAdmittedSourceRunPath(admitted, sourceRunPath) {
|
|
6444
|
+
if (sourceRunPath.trim() === "") {
|
|
6445
|
+
throw new Error("persistAdmittedSourceRunPath requires a non-empty sourceRunPath");
|
|
6446
|
+
}
|
|
6447
|
+
const admittedPath = admitted.admittedRequestPath;
|
|
6448
|
+
const current = JSON.parse(await readFile9(admittedPath, "utf8"));
|
|
6449
|
+
if (typeof current.sourceRunPath === "string") {
|
|
6450
|
+
if (current.sourceRunPath === sourceRunPath) return;
|
|
6451
|
+
throw new Error(
|
|
6452
|
+
`persistAdmittedSourceRunPath refuses to replace ${current.sourceRunPath} with ${sourceRunPath}`
|
|
6453
|
+
);
|
|
6454
|
+
}
|
|
6455
|
+
await writeFile4(
|
|
6456
|
+
admittedPath,
|
|
6457
|
+
`${JSON.stringify({ ...current, sourceRunPath }, null, 2)}
|
|
6458
|
+
`,
|
|
6459
|
+
"utf8"
|
|
6460
|
+
);
|
|
6461
|
+
}
|
|
6406
6462
|
async function bindAdmittedTicketNumber(admitted, ticketNumber) {
|
|
6407
6463
|
if (!Number.isSafeInteger(ticketNumber) || ticketNumber < 1) {
|
|
6408
6464
|
throw new Error(`bindAdmittedTicketNumber requires a safe positive integer, got ${String(ticketNumber)}`);
|
|
@@ -10537,11 +10593,15 @@ async function resolveSeatTicketBinding(admitted, env = {}) {
|
|
|
10537
10593
|
}
|
|
10538
10594
|
async function tryResumeSameTicketSeatRun(input) {
|
|
10539
10595
|
if (input.freshSummons === true) return void 0;
|
|
10596
|
+
if (input.parentRunPath === void 0 && input.ticketNumber === void 0) {
|
|
10597
|
+
return void 0;
|
|
10598
|
+
}
|
|
10540
10599
|
const previousRunId = await findLatestRunIdForSeatTicket({
|
|
10541
10600
|
home: input.home,
|
|
10542
10601
|
bookKey: resolveBookKeyFromGit(input.projectRoot),
|
|
10543
10602
|
role: input.role,
|
|
10544
|
-
|
|
10603
|
+
...input.parentRunPath === void 0 ? {} : { parentRunPath: input.parentRunPath },
|
|
10604
|
+
...input.ticketNumber === void 0 ? {} : { ticketNumber: input.ticketNumber }
|
|
10545
10605
|
});
|
|
10546
10606
|
if (previousRunId === void 0) return void 0;
|
|
10547
10607
|
return await input.resume(previousRunId, input.summons);
|
|
@@ -11117,7 +11177,7 @@ function createSubmissionLedgerHost(host, outputTools, failInfrastructure2 = (er
|
|
|
11117
11177
|
});
|
|
11118
11178
|
rounds.set(attemptId, candidates2);
|
|
11119
11179
|
return {
|
|
11120
|
-
content:
|
|
11180
|
+
content: result.content,
|
|
11121
11181
|
details: { submissionDisposition: "pending-round-closure" }
|
|
11122
11182
|
};
|
|
11123
11183
|
}
|
|
@@ -11133,7 +11193,7 @@ function createSubmissionLedgerHost(host, outputTools, failInfrastructure2 = (er
|
|
|
11133
11193
|
candidates.push({ toolCallId, toolName: tool.name, role, result, context });
|
|
11134
11194
|
rounds.set(attemptId, candidates);
|
|
11135
11195
|
return {
|
|
11136
|
-
content:
|
|
11196
|
+
content: result.content,
|
|
11137
11197
|
details: { submissionDisposition: "pending-round-closure" }
|
|
11138
11198
|
};
|
|
11139
11199
|
}
|
|
@@ -16962,8 +17022,7 @@ async function runPublicNotary(argv, env, io, parseNotaryArgv2) {
|
|
|
16962
17022
|
}
|
|
16963
17023
|
throw error;
|
|
16964
17024
|
}
|
|
16965
|
-
|
|
16966
|
-
if (ticketNumber !== void 0) {
|
|
17025
|
+
{
|
|
16967
17026
|
const summons = {
|
|
16968
17027
|
sourceRunPath: source.runDirectory,
|
|
16969
17028
|
sourceRun: source
|
|
@@ -16972,7 +17031,7 @@ async function runPublicNotary(argv, env, io, parseNotaryArgv2) {
|
|
|
16972
17031
|
home: env.home,
|
|
16973
17032
|
projectRoot,
|
|
16974
17033
|
role: "notary",
|
|
16975
|
-
|
|
17034
|
+
parentRunPath: source.runDirectory,
|
|
16976
17035
|
freshSummons: env.freshSummons,
|
|
16977
17036
|
summons,
|
|
16978
17037
|
resume: (runId, materials) => runPublicNotaryResume(
|
|
@@ -17087,7 +17146,6 @@ var init_notary_run = __esm({
|
|
|
17087
17146
|
init_auditor_dossier_tool();
|
|
17088
17147
|
init_notary_source_run();
|
|
17089
17148
|
init_engine_material();
|
|
17090
|
-
init_run_ticket_number();
|
|
17091
17149
|
init_cli_errors();
|
|
17092
17150
|
init_invocation();
|
|
17093
17151
|
init_seat_ticket_binding();
|
|
@@ -17133,8 +17191,8 @@ async function runPublicInspector(argv, env, io, parseInspectorArgv2) {
|
|
|
17133
17191
|
projectRoot,
|
|
17134
17192
|
env
|
|
17135
17193
|
);
|
|
17136
|
-
const
|
|
17137
|
-
if (
|
|
17194
|
+
const parentRunPath = parentRunPathFromGatePointerInstruction(parsed.instruction);
|
|
17195
|
+
if (parentRunPath !== void 0) {
|
|
17138
17196
|
const summons = {
|
|
17139
17197
|
instruction: parsed.instruction,
|
|
17140
17198
|
instructionEmpty: parsed.instruction.trim() === "",
|
|
@@ -17144,7 +17202,7 @@ async function runPublicInspector(argv, env, io, parseInspectorArgv2) {
|
|
|
17144
17202
|
home: env.home,
|
|
17145
17203
|
projectRoot,
|
|
17146
17204
|
role: "inspector",
|
|
17147
|
-
|
|
17205
|
+
parentRunPath,
|
|
17148
17206
|
freshSummons: env.freshSummons,
|
|
17149
17207
|
summons,
|
|
17150
17208
|
resume: (runId, materials) => runPublicInspectorResume(
|
|
@@ -17429,21 +17487,20 @@ async function runPublicInstructionSeat(argv, env, io, role, parseArgv) {
|
|
|
17429
17487
|
env
|
|
17430
17488
|
);
|
|
17431
17489
|
}
|
|
17432
|
-
const
|
|
17433
|
-
|
|
17434
|
-
|
|
17435
|
-
|
|
17436
|
-
|
|
17437
|
-
|
|
17438
|
-
};
|
|
17490
|
+
const summons = {
|
|
17491
|
+
instruction: parsed.instruction,
|
|
17492
|
+
instructionEmpty: parsed.instruction.trim() === "",
|
|
17493
|
+
attachmentPaths: parsed.attachmentPaths
|
|
17494
|
+
};
|
|
17495
|
+
if (role === "auditor" && auditorSourceRun !== void 0) {
|
|
17439
17496
|
const resumed = await withAuditorSoulEnv({
|
|
17440
17497
|
...auditorSubject === void 0 ? {} : { subject: auditorSubject },
|
|
17441
|
-
|
|
17498
|
+
sourceRunDirectory: auditorSourceRun,
|
|
17442
17499
|
run: () => tryResumeSameTicketSeatRun({
|
|
17443
17500
|
home: env.home,
|
|
17444
17501
|
projectRoot,
|
|
17445
17502
|
role,
|
|
17446
|
-
|
|
17503
|
+
parentRunPath: auditorSourceRun,
|
|
17447
17504
|
freshSummons: env.freshSummons,
|
|
17448
17505
|
summons,
|
|
17449
17506
|
resume: (runId, materials) => runPublicInstructionSeatResume(
|
|
@@ -17454,6 +17511,24 @@ async function runPublicInstructionSeat(argv, env, io, role, parseArgv) {
|
|
|
17454
17511
|
})
|
|
17455
17512
|
});
|
|
17456
17513
|
if (resumed !== void 0) return resumed;
|
|
17514
|
+
} else {
|
|
17515
|
+
const probedTicketNumber = ticketProbe === void 0 ? void 0 : ticketNumberFromProbe(ticketProbe);
|
|
17516
|
+
if (probedTicketNumber !== void 0) {
|
|
17517
|
+
const resumed = await tryResumeSameTicketSeatRun({
|
|
17518
|
+
home: env.home,
|
|
17519
|
+
projectRoot,
|
|
17520
|
+
role,
|
|
17521
|
+
ticketNumber: probedTicketNumber,
|
|
17522
|
+
freshSummons: env.freshSummons,
|
|
17523
|
+
summons,
|
|
17524
|
+
resume: (runId, materials) => runPublicInstructionSeatResume(
|
|
17525
|
+
{ runId, ...materials === void 0 ? {} : { summons: materials } },
|
|
17526
|
+
env,
|
|
17527
|
+
io
|
|
17528
|
+
)
|
|
17529
|
+
});
|
|
17530
|
+
if (resumed !== void 0) return resumed;
|
|
17531
|
+
}
|
|
17457
17532
|
}
|
|
17458
17533
|
let admitted;
|
|
17459
17534
|
try {
|
|
@@ -17475,6 +17550,9 @@ async function runPublicInstructionSeat(argv, env, io, role, parseArgv) {
|
|
|
17475
17550
|
}
|
|
17476
17551
|
throw error;
|
|
17477
17552
|
}
|
|
17553
|
+
if (role === "auditor" && auditorSourceRun !== void 0) {
|
|
17554
|
+
await persistAdmittedSourceRunPath(admitted, auditorSourceRun);
|
|
17555
|
+
}
|
|
17478
17556
|
return await withAuditorSoulEnv({
|
|
17479
17557
|
...auditorSubject === void 0 ? {} : { subject: auditorSubject },
|
|
17480
17558
|
...auditorSourceRun === void 0 ? {} : { sourceRunDirectory: auditorSourceRun },
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { engineSessionMaterialFromOptions } from "../package-resources/engine-material.js";
|
|
2
2
|
import { CliUsageError } from "./cli-errors.js";
|
|
3
|
-
import { applyInstructionTicketProbe, probeInstructionTicket,
|
|
3
|
+
import { applyInstructionTicketProbe, probeInstructionTicket, tryResumeSameTicketSeatRun, } from "./seat-ticket-binding.js";
|
|
4
4
|
import { admitInspectorInvocation, buildInspectorTransportPrompt, } from "./invocation.js";
|
|
5
5
|
import { prepareSummonsResumeMaterials, runPostAdmissionOneShot, runPostAdmissionSeatResume, resumeTurnRequestProjectionOptions, } from "./post-admission.js";
|
|
6
|
-
import { loadResumableInspectorRun, markRunAdmitted, } from "./run-lifecycle.js";
|
|
6
|
+
import { loadResumableInspectorRun, markRunAdmitted, parentRunPathFromGatePointerInstruction, } from "./run-lifecycle.js";
|
|
7
7
|
import { presentStructuralRejection, trySettleInspectorTerminalResult, } from "./settlement.js";
|
|
8
8
|
import { projectRoleTurnRequest, } from "./turn-request.js";
|
|
9
9
|
/** Project admitted invocation onto the host-neutral turn request. */
|
|
@@ -26,14 +26,14 @@ export async function runPublicInspector(argv, env, io, parseInspectorArgv) {
|
|
|
26
26
|
}
|
|
27
27
|
throw error;
|
|
28
28
|
}
|
|
29
|
-
// #
|
|
29
|
+
// #747: same parent (卷宗指针) → resume prior inspector run with this summons' materials.
|
|
30
30
|
// Probe captures DiaristTicketResolutionError so admit+beforeDispatch can settle
|
|
31
31
|
// controlled failure (bare pre-admit throw skips terminal settlement).
|
|
32
32
|
// No bare catch→fresh: lookup/resume failures surface; only true absence mints new.
|
|
33
33
|
const projectRoot = parsed.project ?? env.cwd;
|
|
34
34
|
const ticketProbe = await probeInstructionTicket(parsed.instruction, projectRoot, env);
|
|
35
|
-
const
|
|
36
|
-
if (
|
|
35
|
+
const parentRunPath = parentRunPathFromGatePointerInstruction(parsed.instruction);
|
|
36
|
+
if (parentRunPath !== undefined) {
|
|
37
37
|
const summons = {
|
|
38
38
|
instruction: parsed.instruction,
|
|
39
39
|
instructionEmpty: parsed.instruction.trim() === "",
|
|
@@ -43,7 +43,7 @@ export async function runPublicInspector(argv, env, io, parseInspectorArgv) {
|
|
|
43
43
|
home: env.home,
|
|
44
44
|
projectRoot,
|
|
45
45
|
role: "inspector",
|
|
46
|
-
|
|
46
|
+
parentRunPath,
|
|
47
47
|
freshSummons: env.freshSummons,
|
|
48
48
|
summons,
|
|
49
49
|
resume: (runId, materials) => runPublicInspectorResume({ runId, ...(materials === undefined ? {} : { summons: materials }) }, env, io),
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { engineSessionMaterialFromOptions } from "../package-resources/engine-material.js";
|
|
2
2
|
import { readRunTicketNumber } from "../run-ticket-number.js";
|
|
3
3
|
import { CliUsageError } from "./cli-errors.js";
|
|
4
|
-
import { admitAuditorInvocation, admitEvidenceChildInvocation, admitGatekeeperInvocation, admitNavigatorInvocation, bindAdmittedTicketNumber, buildInstructionTransportPrompt, } from "./invocation.js";
|
|
4
|
+
import { admitAuditorInvocation, admitEvidenceChildInvocation, admitGatekeeperInvocation, admitNavigatorInvocation, bindAdmittedTicketNumber, buildInstructionTransportPrompt, persistAdmittedSourceRunPath, } from "./invocation.js";
|
|
5
5
|
import { prepareSummonsResumeMaterials, runPostAdmissionOneShot, runPostAdmissionSeatResume, resumeTurnRequestProjectionOptions, } from "./post-admission.js";
|
|
6
6
|
import { loadResumableInstructionSeatRun, markRunAdmitted, } from "./run-lifecycle.js";
|
|
7
7
|
import { applyInstructionTicketProbe, probeInstructionTicket, ticketNumberFromProbe, tryResumeSameTicketSeatRun, } from "./seat-ticket-binding.js";
|
|
@@ -124,10 +124,9 @@ export async function runPublicInstructionSeat(argv, env, io, role, parseArgv) {
|
|
|
124
124
|
let auditorSourceRun;
|
|
125
125
|
let auditorSourceTicket;
|
|
126
126
|
let ticketProbe;
|
|
127
|
-
// #637
|
|
128
|
-
// Auditor
|
|
129
|
-
//
|
|
130
|
-
// surface; only true absence of a prior run mints new.
|
|
127
|
+
// #637 / #747: resume prior seat run with this summons' materials.
|
|
128
|
+
// Auditor (#747): parent --source-run path is the lookup key.
|
|
129
|
+
// Other instruction seats: ticket probe (inspector face). No bare catch→fresh.
|
|
131
130
|
const projectRoot = parsed.project ?? env.cwd;
|
|
132
131
|
if (role === "auditor") {
|
|
133
132
|
if (parsed.subject !== "judge" && parsed.subject !== "doctor") {
|
|
@@ -159,24 +158,20 @@ export async function runPublicInstructionSeat(argv, env, io, role, parseArgv) {
|
|
|
159
158
|
// Inspector face: unconditional probe (same seam as inspector-run.ts).
|
|
160
159
|
ticketProbe = await probeInstructionTicket(parsed.instruction, projectRoot, env);
|
|
161
160
|
}
|
|
162
|
-
const
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
attachmentPaths: parsed.attachmentPaths,
|
|
169
|
-
};
|
|
161
|
+
const summons = {
|
|
162
|
+
instruction: parsed.instruction,
|
|
163
|
+
instructionEmpty: parsed.instruction.trim() === "",
|
|
164
|
+
attachmentPaths: parsed.attachmentPaths,
|
|
165
|
+
};
|
|
166
|
+
if (role === "auditor" && auditorSourceRun !== undefined) {
|
|
170
167
|
const resumed = await withAuditorSoulEnv({
|
|
171
168
|
...(auditorSubject === undefined ? {} : { subject: auditorSubject }),
|
|
172
|
-
|
|
173
|
-
? {}
|
|
174
|
-
: { sourceRunDirectory: auditorSourceRun }),
|
|
169
|
+
sourceRunDirectory: auditorSourceRun,
|
|
175
170
|
run: () => tryResumeSameTicketSeatRun({
|
|
176
171
|
home: env.home,
|
|
177
172
|
projectRoot,
|
|
178
173
|
role,
|
|
179
|
-
|
|
174
|
+
parentRunPath: auditorSourceRun,
|
|
180
175
|
freshSummons: env.freshSummons,
|
|
181
176
|
summons,
|
|
182
177
|
resume: (runId, materials) => runPublicInstructionSeatResume({ runId, ...(materials === undefined ? {} : { summons: materials }) }, env, io),
|
|
@@ -185,6 +180,22 @@ export async function runPublicInstructionSeat(argv, env, io, role, parseArgv) {
|
|
|
185
180
|
if (resumed !== undefined)
|
|
186
181
|
return resumed;
|
|
187
182
|
}
|
|
183
|
+
else {
|
|
184
|
+
const probedTicketNumber = ticketProbe === undefined ? undefined : ticketNumberFromProbe(ticketProbe);
|
|
185
|
+
if (probedTicketNumber !== undefined) {
|
|
186
|
+
const resumed = await tryResumeSameTicketSeatRun({
|
|
187
|
+
home: env.home,
|
|
188
|
+
projectRoot,
|
|
189
|
+
role,
|
|
190
|
+
ticketNumber: probedTicketNumber,
|
|
191
|
+
freshSummons: env.freshSummons,
|
|
192
|
+
summons,
|
|
193
|
+
resume: (runId, materials) => runPublicInstructionSeatResume({ runId, ...(materials === undefined ? {} : { summons: materials }) }, env, io),
|
|
194
|
+
});
|
|
195
|
+
if (resumed !== undefined)
|
|
196
|
+
return resumed;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
188
199
|
let admitted;
|
|
189
200
|
try {
|
|
190
201
|
admitted = await admitInstructionSeat(role, {
|
|
@@ -206,6 +217,9 @@ export async function runPublicInstructionSeat(argv, env, io, role, parseArgv) {
|
|
|
206
217
|
}
|
|
207
218
|
throw error;
|
|
208
219
|
}
|
|
220
|
+
if (role === "auditor" && auditorSourceRun !== undefined) {
|
|
221
|
+
await persistAdmittedSourceRunPath(admitted, auditorSourceRun);
|
|
222
|
+
}
|
|
209
223
|
return await withAuditorSoulEnv({
|
|
210
224
|
...(auditorSubject === undefined ? {} : { subject: auditorSubject }),
|
|
211
225
|
...(auditorSourceRun === undefined
|
|
@@ -126,6 +126,23 @@ async function mergeInvocationIdentityPage(runDirectory, fields) {
|
|
|
126
126
|
...fields,
|
|
127
127
|
}, null, 2)}\n`, "utf8");
|
|
128
128
|
}
|
|
129
|
+
/**
|
|
130
|
+
* Persist parent --source-run path onto admitted-request for officer resume lookup (#747).
|
|
131
|
+
* Reuses the existing notary sourceRunPath key; does not invent a new field name.
|
|
132
|
+
*/
|
|
133
|
+
export async function persistAdmittedSourceRunPath(admitted, sourceRunPath) {
|
|
134
|
+
if (sourceRunPath.trim() === "") {
|
|
135
|
+
throw new Error("persistAdmittedSourceRunPath requires a non-empty sourceRunPath");
|
|
136
|
+
}
|
|
137
|
+
const admittedPath = admitted.admittedRequestPath;
|
|
138
|
+
const current = JSON.parse(await readFile(admittedPath, "utf8"));
|
|
139
|
+
if (typeof current.sourceRunPath === "string") {
|
|
140
|
+
if (current.sourceRunPath === sourceRunPath)
|
|
141
|
+
return;
|
|
142
|
+
throw new Error(`persistAdmittedSourceRunPath refuses to replace ${current.sourceRunPath} with ${sourceRunPath}`);
|
|
143
|
+
}
|
|
144
|
+
await writeFile(admittedPath, `${JSON.stringify({ ...current, sourceRunPath }, null, 2)}\n`, "utf8");
|
|
145
|
+
}
|
|
129
146
|
/**
|
|
130
147
|
* Bind a post-admission resolved ticketNumber onto the in-memory admitted
|
|
131
148
|
* object and both durable pages (invocation.json + admitted-request.json).
|
package/dist/public-cli/main.js
CHANGED
|
@@ -18001,6 +18001,33 @@ async function findRunDirectoryById(home, runId) {
|
|
|
18001
18001
|
}
|
|
18002
18002
|
return void 0;
|
|
18003
18003
|
}
|
|
18004
|
+
function parentRunPathFromGatePointerInstruction(instruction) {
|
|
18005
|
+
if (!instruction.startsWith(GATE_DOSSIER_POINTER_PREFIX)) return void 0;
|
|
18006
|
+
const path = instruction.slice(GATE_DOSSIER_POINTER_PREFIX.length).trim();
|
|
18007
|
+
return path === "" ? void 0 : path;
|
|
18008
|
+
}
|
|
18009
|
+
async function readRunParentPath(runDirectory) {
|
|
18010
|
+
let raw;
|
|
18011
|
+
try {
|
|
18012
|
+
raw = JSON.parse(
|
|
18013
|
+
await readFile8(join12(runDirectory, "admitted-request.json"), "utf8")
|
|
18014
|
+
);
|
|
18015
|
+
} catch (error) {
|
|
18016
|
+
if (errorCodeOf2(error) === "ENOENT") return void 0;
|
|
18017
|
+
throw error;
|
|
18018
|
+
}
|
|
18019
|
+
if (raw === null || typeof raw !== "object" || Array.isArray(raw)) {
|
|
18020
|
+
return void 0;
|
|
18021
|
+
}
|
|
18022
|
+
const record4 = raw;
|
|
18023
|
+
if (typeof record4.sourceRunPath === "string" && record4.sourceRunPath.trim() !== "") {
|
|
18024
|
+
return record4.sourceRunPath;
|
|
18025
|
+
}
|
|
18026
|
+
if (typeof record4.instruction === "string") {
|
|
18027
|
+
return parentRunPathFromGatePointerInstruction(record4.instruction);
|
|
18028
|
+
}
|
|
18029
|
+
return void 0;
|
|
18030
|
+
}
|
|
18004
18031
|
async function findLatestRunIdForSeatTicket(input) {
|
|
18005
18032
|
const ledgerHome = resolveActivationLedgerHome(input.home);
|
|
18006
18033
|
const runsDir = join12(
|
|
@@ -18020,8 +18047,16 @@ async function findLatestRunIdForSeatTicket(input) {
|
|
|
18020
18047
|
if (!entry.endsWith(suffix)) continue;
|
|
18021
18048
|
const runId = entry.slice(0, entry.length - suffix.length);
|
|
18022
18049
|
if (runId.length === 0) continue;
|
|
18023
|
-
const
|
|
18024
|
-
if (
|
|
18050
|
+
const runDirectory = join12(runsDir, entry);
|
|
18051
|
+
if (input.parentRunPath !== void 0) {
|
|
18052
|
+
const parentPath = await readRunParentPath(runDirectory);
|
|
18053
|
+
if (parentPath !== input.parentRunPath) continue;
|
|
18054
|
+
} else if (input.ticketNumber !== void 0) {
|
|
18055
|
+
const ticketNumber = await readRunTicketNumber(runDirectory);
|
|
18056
|
+
if (ticketNumber !== input.ticketNumber) continue;
|
|
18057
|
+
} else {
|
|
18058
|
+
continue;
|
|
18059
|
+
}
|
|
18025
18060
|
if (best === void 0 || runId > best) best = runId;
|
|
18026
18061
|
}
|
|
18027
18062
|
return best;
|
|
@@ -18578,7 +18613,7 @@ async function peekRoleRunRole(home, runId) {
|
|
|
18578
18613
|
const run = await readRoleRunIdentity(runDirectory);
|
|
18579
18614
|
return run?.role;
|
|
18580
18615
|
}
|
|
18581
|
-
var V1_RESUMABLE_PROVIDERS, AUTO_RESUME_LIMIT, RESUME_TRANSPORT_ENVELOPE, RUN_STATE_FILE, WRITER_LOCK_FILE, RunWriterLeaseHeldError, WRITER_LEASE_RECLAIM_ROUNDS;
|
|
18616
|
+
var V1_RESUMABLE_PROVIDERS, AUTO_RESUME_LIMIT, RESUME_TRANSPORT_ENVELOPE, RUN_STATE_FILE, WRITER_LOCK_FILE, RunWriterLeaseHeldError, WRITER_LEASE_RECLAIM_ROUNDS, GATE_DOSSIER_POINTER_PREFIX;
|
|
18582
18617
|
var init_run_lifecycle = __esm({
|
|
18583
18618
|
"src/public-cli/run-lifecycle.ts"() {
|
|
18584
18619
|
"use strict";
|
|
@@ -18603,6 +18638,7 @@ var init_run_lifecycle = __esm({
|
|
|
18603
18638
|
}
|
|
18604
18639
|
};
|
|
18605
18640
|
WRITER_LEASE_RECLAIM_ROUNDS = 3;
|
|
18641
|
+
GATE_DOSSIER_POINTER_PREFIX = "\u5377\u5B97\u6307\u9488\uFF1A";
|
|
18606
18642
|
}
|
|
18607
18643
|
});
|
|
18608
18644
|
|
|
@@ -19899,6 +19935,25 @@ async function mergeInvocationIdentityPage(runDirectory, fields) {
|
|
|
19899
19935
|
"utf8"
|
|
19900
19936
|
);
|
|
19901
19937
|
}
|
|
19938
|
+
async function persistAdmittedSourceRunPath(admitted, sourceRunPath) {
|
|
19939
|
+
if (sourceRunPath.trim() === "") {
|
|
19940
|
+
throw new Error("persistAdmittedSourceRunPath requires a non-empty sourceRunPath");
|
|
19941
|
+
}
|
|
19942
|
+
const admittedPath = admitted.admittedRequestPath;
|
|
19943
|
+
const current = JSON.parse(await readFile9(admittedPath, "utf8"));
|
|
19944
|
+
if (typeof current.sourceRunPath === "string") {
|
|
19945
|
+
if (current.sourceRunPath === sourceRunPath) return;
|
|
19946
|
+
throw new Error(
|
|
19947
|
+
`persistAdmittedSourceRunPath refuses to replace ${current.sourceRunPath} with ${sourceRunPath}`
|
|
19948
|
+
);
|
|
19949
|
+
}
|
|
19950
|
+
await writeFile5(
|
|
19951
|
+
admittedPath,
|
|
19952
|
+
`${JSON.stringify({ ...current, sourceRunPath }, null, 2)}
|
|
19953
|
+
`,
|
|
19954
|
+
"utf8"
|
|
19955
|
+
);
|
|
19956
|
+
}
|
|
19902
19957
|
async function bindAdmittedTicketNumber(admitted, ticketNumber) {
|
|
19903
19958
|
if (!Number.isSafeInteger(ticketNumber) || ticketNumber < 1) {
|
|
19904
19959
|
throw new Error(`bindAdmittedTicketNumber requires a safe positive integer, got ${String(ticketNumber)}`);
|
|
@@ -23783,11 +23838,15 @@ async function resolveSeatTicketBinding(admitted, env = {}) {
|
|
|
23783
23838
|
}
|
|
23784
23839
|
async function tryResumeSameTicketSeatRun(input) {
|
|
23785
23840
|
if (input.freshSummons === true) return void 0;
|
|
23841
|
+
if (input.parentRunPath === void 0 && input.ticketNumber === void 0) {
|
|
23842
|
+
return void 0;
|
|
23843
|
+
}
|
|
23786
23844
|
const previousRunId = await findLatestRunIdForSeatTicket({
|
|
23787
23845
|
home: input.home,
|
|
23788
23846
|
bookKey: resolveBookKeyFromGit(input.projectRoot),
|
|
23789
23847
|
role: input.role,
|
|
23790
|
-
|
|
23848
|
+
...input.parentRunPath === void 0 ? {} : { parentRunPath: input.parentRunPath },
|
|
23849
|
+
...input.ticketNumber === void 0 ? {} : { ticketNumber: input.ticketNumber }
|
|
23791
23850
|
});
|
|
23792
23851
|
if (previousRunId === void 0) return void 0;
|
|
23793
23852
|
return await input.resume(previousRunId, input.summons);
|
|
@@ -29437,21 +29496,20 @@ async function runPublicInstructionSeat(argv, env, io, role, parseArgv2) {
|
|
|
29437
29496
|
env
|
|
29438
29497
|
);
|
|
29439
29498
|
}
|
|
29440
|
-
const
|
|
29441
|
-
|
|
29442
|
-
|
|
29443
|
-
|
|
29444
|
-
|
|
29445
|
-
|
|
29446
|
-
};
|
|
29499
|
+
const summons = {
|
|
29500
|
+
instruction: parsed.instruction,
|
|
29501
|
+
instructionEmpty: parsed.instruction.trim() === "",
|
|
29502
|
+
attachmentPaths: parsed.attachmentPaths
|
|
29503
|
+
};
|
|
29504
|
+
if (role === "auditor" && auditorSourceRun !== void 0) {
|
|
29447
29505
|
const resumed = await withAuditorSoulEnv({
|
|
29448
29506
|
...auditorSubject === void 0 ? {} : { subject: auditorSubject },
|
|
29449
|
-
|
|
29507
|
+
sourceRunDirectory: auditorSourceRun,
|
|
29450
29508
|
run: () => tryResumeSameTicketSeatRun({
|
|
29451
29509
|
home: env.home,
|
|
29452
29510
|
projectRoot,
|
|
29453
29511
|
role,
|
|
29454
|
-
|
|
29512
|
+
parentRunPath: auditorSourceRun,
|
|
29455
29513
|
freshSummons: env.freshSummons,
|
|
29456
29514
|
summons,
|
|
29457
29515
|
resume: (runId, materials) => runPublicInstructionSeatResume(
|
|
@@ -29462,6 +29520,24 @@ async function runPublicInstructionSeat(argv, env, io, role, parseArgv2) {
|
|
|
29462
29520
|
})
|
|
29463
29521
|
});
|
|
29464
29522
|
if (resumed !== void 0) return resumed;
|
|
29523
|
+
} else {
|
|
29524
|
+
const probedTicketNumber = ticketProbe === void 0 ? void 0 : ticketNumberFromProbe(ticketProbe);
|
|
29525
|
+
if (probedTicketNumber !== void 0) {
|
|
29526
|
+
const resumed = await tryResumeSameTicketSeatRun({
|
|
29527
|
+
home: env.home,
|
|
29528
|
+
projectRoot,
|
|
29529
|
+
role,
|
|
29530
|
+
ticketNumber: probedTicketNumber,
|
|
29531
|
+
freshSummons: env.freshSummons,
|
|
29532
|
+
summons,
|
|
29533
|
+
resume: (runId, materials) => runPublicInstructionSeatResume(
|
|
29534
|
+
{ runId, ...materials === void 0 ? {} : { summons: materials } },
|
|
29535
|
+
env,
|
|
29536
|
+
io
|
|
29537
|
+
)
|
|
29538
|
+
});
|
|
29539
|
+
if (resumed !== void 0) return resumed;
|
|
29540
|
+
}
|
|
29465
29541
|
}
|
|
29466
29542
|
let admitted;
|
|
29467
29543
|
try {
|
|
@@ -29483,6 +29559,9 @@ async function runPublicInstructionSeat(argv, env, io, role, parseArgv2) {
|
|
|
29483
29559
|
}
|
|
29484
29560
|
throw error;
|
|
29485
29561
|
}
|
|
29562
|
+
if (role === "auditor" && auditorSourceRun !== void 0) {
|
|
29563
|
+
await persistAdmittedSourceRunPath(admitted, auditorSourceRun);
|
|
29564
|
+
}
|
|
29486
29565
|
return await withAuditorSoulEnv({
|
|
29487
29566
|
...auditorSubject === void 0 ? {} : { subject: auditorSubject },
|
|
29488
29567
|
...auditorSourceRun === void 0 ? {} : { sourceRunDirectory: auditorSourceRun },
|
|
@@ -30428,8 +30507,7 @@ async function runPublicNotary(argv, env, io, parseNotaryArgv2) {
|
|
|
30428
30507
|
}
|
|
30429
30508
|
throw error;
|
|
30430
30509
|
}
|
|
30431
|
-
|
|
30432
|
-
if (ticketNumber !== void 0) {
|
|
30510
|
+
{
|
|
30433
30511
|
const summons = {
|
|
30434
30512
|
sourceRunPath: source.runDirectory,
|
|
30435
30513
|
sourceRun: source
|
|
@@ -30438,7 +30516,7 @@ async function runPublicNotary(argv, env, io, parseNotaryArgv2) {
|
|
|
30438
30516
|
home: env.home,
|
|
30439
30517
|
projectRoot,
|
|
30440
30518
|
role: "notary",
|
|
30441
|
-
|
|
30519
|
+
parentRunPath: source.runDirectory,
|
|
30442
30520
|
freshSummons: env.freshSummons,
|
|
30443
30521
|
summons,
|
|
30444
30522
|
resume: (runId, materials) => runPublicNotaryResume(
|
|
@@ -30553,7 +30631,6 @@ var init_notary_run = __esm({
|
|
|
30553
30631
|
init_auditor_dossier_tool();
|
|
30554
30632
|
init_notary_source_run();
|
|
30555
30633
|
init_engine_material();
|
|
30556
|
-
init_run_ticket_number();
|
|
30557
30634
|
init_cli_errors();
|
|
30558
30635
|
init_invocation();
|
|
30559
30636
|
init_seat_ticket_binding();
|
|
@@ -30593,8 +30670,8 @@ async function runPublicInspector(argv, env, io, parseInspectorArgv2) {
|
|
|
30593
30670
|
projectRoot,
|
|
30594
30671
|
env
|
|
30595
30672
|
);
|
|
30596
|
-
const
|
|
30597
|
-
if (
|
|
30673
|
+
const parentRunPath = parentRunPathFromGatePointerInstruction(parsed.instruction);
|
|
30674
|
+
if (parentRunPath !== void 0) {
|
|
30598
30675
|
const summons = {
|
|
30599
30676
|
instruction: parsed.instruction,
|
|
30600
30677
|
instructionEmpty: parsed.instruction.trim() === "",
|
|
@@ -30604,7 +30681,7 @@ async function runPublicInspector(argv, env, io, parseInspectorArgv2) {
|
|
|
30604
30681
|
home: env.home,
|
|
30605
30682
|
projectRoot,
|
|
30606
30683
|
role: "inspector",
|
|
30607
|
-
|
|
30684
|
+
parentRunPath,
|
|
30608
30685
|
freshSummons: env.freshSummons,
|
|
30609
30686
|
summons,
|
|
30610
30687
|
resume: (runId, materials) => runPublicInspectorResume(
|
|
@@ -2,13 +2,12 @@
|
|
|
2
2
|
* Public Notary Role run: admit source-run locator → shared post-admission coordinator
|
|
3
3
|
* → settle Terminal result (#448 / #517). Zero caller prompt/attachment. Lifecycle is
|
|
4
4
|
* the shared post-admission seam; this module keeps only Notary adapters.
|
|
5
|
-
* #637: same-
|
|
5
|
+
* #637 / #747: same-parent (--source-run) re-summons resume the seat's previous run.
|
|
6
6
|
*/
|
|
7
7
|
import { existsSync } from "node:fs";
|
|
8
8
|
import { gateSubmissionCandidatePath } from "../auditor-dossier-tool.js";
|
|
9
9
|
import { NotarySourceRunError, resolveNotarySourceRunLocator, } from "../notary-source-run.js";
|
|
10
10
|
import { engineSessionMaterialFromOptions } from "../package-resources/engine-material.js";
|
|
11
|
-
import { readRunTicketNumber } from "../run-ticket-number.js";
|
|
12
11
|
import { CliUsageError } from "./cli-errors.js";
|
|
13
12
|
import { admitNotaryInvocation, buildNotaryTransportPrompt, } from "./invocation.js";
|
|
14
13
|
import { tryResumeSameTicketSeatRun } from "./seat-ticket-binding.js";
|
|
@@ -60,8 +59,8 @@ export async function runPublicNotary(argv, env, io, parseNotaryArgv) {
|
|
|
60
59
|
}
|
|
61
60
|
throw error;
|
|
62
61
|
}
|
|
63
|
-
|
|
64
|
-
|
|
62
|
+
// #747: officer resume key is this parent source-run path (not ticket number).
|
|
63
|
+
{
|
|
65
64
|
const summons = {
|
|
66
65
|
sourceRunPath: source.runDirectory,
|
|
67
66
|
sourceRun: source,
|
|
@@ -70,7 +69,7 @@ export async function runPublicNotary(argv, env, io, parseNotaryArgv) {
|
|
|
70
69
|
home: env.home,
|
|
71
70
|
projectRoot,
|
|
72
71
|
role: "notary",
|
|
73
|
-
|
|
72
|
+
parentRunPath: source.runDirectory,
|
|
74
73
|
freshSummons: env.freshSummons,
|
|
75
74
|
summons,
|
|
76
75
|
resume: (runId, materials) => runPublicNotaryResume({ runId, ...(materials === undefined ? {} : { summons: materials }) }, env, io),
|
|
@@ -746,9 +746,46 @@ export async function findRunDirectoryById(home, runId) {
|
|
|
746
746
|
}
|
|
747
747
|
return undefined;
|
|
748
748
|
}
|
|
749
|
+
/** Code-owned gate inspector summons prefix (public-role-summons / #747). */
|
|
750
|
+
export const GATE_DOSSIER_POINTER_PREFIX = "卷宗指针:";
|
|
751
|
+
/** Parent path from a code-owned inspector 卷宗指针 instruction; else undefined. */
|
|
752
|
+
export function parentRunPathFromGatePointerInstruction(instruction) {
|
|
753
|
+
if (!instruction.startsWith(GATE_DOSSIER_POINTER_PREFIX))
|
|
754
|
+
return undefined;
|
|
755
|
+
const path = instruction.slice(GATE_DOSSIER_POINTER_PREFIX.length).trim();
|
|
756
|
+
return path === "" ? undefined : path;
|
|
757
|
+
}
|
|
749
758
|
/**
|
|
750
|
-
*
|
|
751
|
-
*
|
|
759
|
+
* Parent-run binding on a retained officer run (#747).
|
|
760
|
+
* Notary/auditor: typed sourceRunPath. Inspector: exact code-owned 卷宗指针 instruction.
|
|
761
|
+
* Missing page → undefined; damage / non-ENOENT IO propagates.
|
|
762
|
+
*/
|
|
763
|
+
export async function readRunParentPath(runDirectory) {
|
|
764
|
+
let raw;
|
|
765
|
+
try {
|
|
766
|
+
raw = JSON.parse(await readFile(join(runDirectory, "admitted-request.json"), "utf8"));
|
|
767
|
+
}
|
|
768
|
+
catch (error) {
|
|
769
|
+
if (errorCodeOf(error) === "ENOENT")
|
|
770
|
+
return undefined;
|
|
771
|
+
throw error;
|
|
772
|
+
}
|
|
773
|
+
if (raw === null || typeof raw !== "object" || Array.isArray(raw)) {
|
|
774
|
+
return undefined;
|
|
775
|
+
}
|
|
776
|
+
const record = raw;
|
|
777
|
+
if (typeof record.sourceRunPath === "string" && record.sourceRunPath.trim() !== "") {
|
|
778
|
+
return record.sourceRunPath;
|
|
779
|
+
}
|
|
780
|
+
if (typeof record.instruction === "string") {
|
|
781
|
+
return parentRunPathFromGatePointerInstruction(record.instruction);
|
|
782
|
+
}
|
|
783
|
+
return undefined;
|
|
784
|
+
}
|
|
785
|
+
/**
|
|
786
|
+
* Locate the latest retained run for one seat under a book (#637 / #747).
|
|
787
|
+
* Same walk surface as findRunDirectoryById. Match by parent run path (officer
|
|
788
|
+
* seats, #747) or by ticket number (countersign / diarist principal).
|
|
752
789
|
* runId is UUIDv7 — lexicographic max is latest. No parallel index.
|
|
753
790
|
* Only a truly missing runs directory means no history; damage/permission errors propagate.
|
|
754
791
|
*/
|
|
@@ -772,9 +809,20 @@ export async function findLatestRunIdForSeatTicket(input) {
|
|
|
772
809
|
const runId = entry.slice(0, entry.length - suffix.length);
|
|
773
810
|
if (runId.length === 0)
|
|
774
811
|
continue;
|
|
775
|
-
const
|
|
776
|
-
if (
|
|
812
|
+
const runDirectory = join(runsDir, entry);
|
|
813
|
+
if (input.parentRunPath !== undefined) {
|
|
814
|
+
const parentPath = await readRunParentPath(runDirectory);
|
|
815
|
+
if (parentPath !== input.parentRunPath)
|
|
816
|
+
continue;
|
|
817
|
+
}
|
|
818
|
+
else if (input.ticketNumber !== undefined) {
|
|
819
|
+
const ticketNumber = await readRunTicketNumber(runDirectory);
|
|
820
|
+
if (ticketNumber !== input.ticketNumber)
|
|
821
|
+
continue;
|
|
822
|
+
}
|
|
823
|
+
else {
|
|
777
824
|
continue;
|
|
825
|
+
}
|
|
778
826
|
if (best === undefined || runId > best)
|
|
779
827
|
best = runId;
|
|
780
828
|
}
|
|
@@ -91,21 +91,30 @@ export async function resolveSeatTicketBinding(admitted, env = {}) {
|
|
|
91
91
|
return resolution;
|
|
92
92
|
}
|
|
93
93
|
/**
|
|
94
|
-
* Sole same-
|
|
95
|
-
*
|
|
96
|
-
*
|
|
97
|
-
*
|
|
94
|
+
* Sole same-seat → resume decision (#637 / #724 / #747).
|
|
95
|
+
* Officer seats (notary/inspector/auditor) look up by parent run path; countersign
|
|
96
|
+
* / diarist keep ticket-number principal. When found, runs resume with this
|
|
97
|
+
* summons' materials. Lookup/resume failures propagate (失败诚实) — never wash
|
|
98
|
+
* into a fresh mint. Returns undefined when the caller declared an explicit
|
|
98
99
|
* fresh summons (`ak-role new`) or when no prior run exists; both mint new.
|
|
99
100
|
* freshSummons is required so no seat can drift back into its own skip branch.
|
|
100
101
|
*/
|
|
101
102
|
export async function tryResumeSameTicketSeatRun(input) {
|
|
102
103
|
if (input.freshSummons === true)
|
|
103
104
|
return undefined;
|
|
105
|
+
if (input.parentRunPath === undefined && input.ticketNumber === undefined) {
|
|
106
|
+
return undefined;
|
|
107
|
+
}
|
|
104
108
|
const previousRunId = await findLatestRunIdForSeatTicket({
|
|
105
109
|
home: input.home,
|
|
106
110
|
bookKey: resolveBookKeyFromGit(input.projectRoot),
|
|
107
111
|
role: input.role,
|
|
108
|
-
|
|
112
|
+
...(input.parentRunPath === undefined
|
|
113
|
+
? {}
|
|
114
|
+
: { parentRunPath: input.parentRunPath }),
|
|
115
|
+
...(input.ticketNumber === undefined
|
|
116
|
+
? {}
|
|
117
|
+
: { ticketNumber: input.ticketNumber }),
|
|
109
118
|
});
|
|
110
119
|
if (previousRunId === undefined)
|
|
111
120
|
return undefined;
|
|
@@ -361,8 +361,11 @@ export function createSubmissionLedgerHost(host, outputTools, failInfrastructure
|
|
|
361
361
|
},
|
|
362
362
|
});
|
|
363
363
|
rounds.set(attemptId, candidates);
|
|
364
|
+
// The role's own acceptance text must reach the model: an empty
|
|
365
|
+
// result reads as "nothing happened" on hosts without terminate
|
|
366
|
+
// semantics (grok build kept resubmitting, #750 evidence).
|
|
364
367
|
return {
|
|
365
|
-
content:
|
|
368
|
+
content: result.content,
|
|
366
369
|
details: { submissionDisposition: "pending-round-closure" },
|
|
367
370
|
};
|
|
368
371
|
}
|
|
@@ -378,7 +381,7 @@ export function createSubmissionLedgerHost(host, outputTools, failInfrastructure
|
|
|
378
381
|
candidates.push({ toolCallId, toolName: tool.name, role, result, context });
|
|
379
382
|
rounds.set(attemptId, candidates);
|
|
380
383
|
return {
|
|
381
|
-
content:
|
|
384
|
+
content: result.content,
|
|
382
385
|
details: { submissionDisposition: "pending-round-closure" },
|
|
383
386
|
};
|
|
384
387
|
},
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* coordinator → settle Terminal result (#568 / ADR 0074). Lawful releases:
|
|
4
4
|
* pass/bounce/escalate. #633: manual resume continues the exact session. Dual path
|
|
5
5
|
* with gate-province dispatch; this module is the direct command face.
|
|
6
|
-
* #637: same-
|
|
6
|
+
* #637 / #747: same-parent (卷宗指针) re-summons resume the seat's previous run.
|
|
7
7
|
*/
|
|
8
8
|
import type { DurablePrincipalAuthority, RoleTurnRequest } from "../host-contracts.ts";
|
|
9
9
|
import { engineSessionMaterialFromOptions } from "../package-resources/engine-material.ts";
|
|
@@ -11,7 +11,6 @@ import { CliUsageError } from "./cli-errors.ts";
|
|
|
11
11
|
import {
|
|
12
12
|
applyInstructionTicketProbe,
|
|
13
13
|
probeInstructionTicket,
|
|
14
|
-
ticketNumberFromProbe,
|
|
15
14
|
tryResumeSameTicketSeatRun,
|
|
16
15
|
} from "./seat-ticket-binding.ts";
|
|
17
16
|
import {
|
|
@@ -31,6 +30,7 @@ import {
|
|
|
31
30
|
import {
|
|
32
31
|
loadResumableInspectorRun,
|
|
33
32
|
markRunAdmitted,
|
|
33
|
+
parentRunPathFromGatePointerInstruction,
|
|
34
34
|
type PublicResumeRequest,
|
|
35
35
|
type SameTicketSummonsMaterials,
|
|
36
36
|
} from "./run-lifecycle.ts";
|
|
@@ -87,7 +87,7 @@ export async function runPublicInspector(
|
|
|
87
87
|
throw error;
|
|
88
88
|
}
|
|
89
89
|
|
|
90
|
-
// #
|
|
90
|
+
// #747: same parent (卷宗指针) → resume prior inspector run with this summons' materials.
|
|
91
91
|
// Probe captures DiaristTicketResolutionError so admit+beforeDispatch can settle
|
|
92
92
|
// controlled failure (bare pre-admit throw skips terminal settlement).
|
|
93
93
|
// No bare catch→fresh: lookup/resume failures surface; only true absence mints new.
|
|
@@ -97,8 +97,8 @@ export async function runPublicInspector(
|
|
|
97
97
|
projectRoot,
|
|
98
98
|
env,
|
|
99
99
|
);
|
|
100
|
-
const
|
|
101
|
-
if (
|
|
100
|
+
const parentRunPath = parentRunPathFromGatePointerInstruction(parsed.instruction);
|
|
101
|
+
if (parentRunPath !== undefined) {
|
|
102
102
|
const summons: SameTicketSummonsMaterials = {
|
|
103
103
|
instruction: parsed.instruction,
|
|
104
104
|
instructionEmpty: parsed.instruction.trim() === "",
|
|
@@ -108,7 +108,7 @@ export async function runPublicInspector(
|
|
|
108
108
|
home: env.home,
|
|
109
109
|
projectRoot,
|
|
110
110
|
role: "inspector",
|
|
111
|
-
|
|
111
|
+
parentRunPath,
|
|
112
112
|
freshSummons: env.freshSummons,
|
|
113
113
|
summons,
|
|
114
114
|
resume: (runId, materials) =>
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Shared instruction-seat run (#639 / #675 / #637): gatekeeper, navigator, auditor,
|
|
3
3
|
* and evidence-child share admit → turn-request → post-admission → settle.
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* Auditor same-parent (--source-run) re-summons resume via tryResumeSameTicketSeatRun
|
|
5
|
+
* (#747); other instruction seats keep ticket-number principal — no independent
|
|
6
|
+
* run/rebind/nest path.
|
|
7
7
|
*/
|
|
8
8
|
import type { DurablePrincipalAuthority, RoleTurnRequest } from "../host-contracts.ts";
|
|
9
9
|
import { engineSessionMaterialFromOptions } from "../package-resources/engine-material.ts";
|
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
admitNavigatorInvocation,
|
|
17
17
|
bindAdmittedTicketNumber,
|
|
18
18
|
buildInstructionTransportPrompt,
|
|
19
|
+
persistAdmittedSourceRunPath,
|
|
19
20
|
type AdmittedAuditorInvocation,
|
|
20
21
|
type AdmittedEvidenceChildInvocation,
|
|
21
22
|
type AdmittedGatekeeperInvocation,
|
|
@@ -258,10 +259,9 @@ export async function runPublicInstructionSeat(
|
|
|
258
259
|
let auditorSourceTicket: number | undefined;
|
|
259
260
|
let ticketProbe: InstructionTicketProbe | undefined;
|
|
260
261
|
|
|
261
|
-
// #637
|
|
262
|
-
// Auditor
|
|
263
|
-
//
|
|
264
|
-
// surface; only true absence of a prior run mints new.
|
|
262
|
+
// #637 / #747: resume prior seat run with this summons' materials.
|
|
263
|
+
// Auditor (#747): parent --source-run path is the lookup key.
|
|
264
|
+
// Other instruction seats: ticket probe (inspector face). No bare catch→fresh.
|
|
265
265
|
const projectRoot = parsed.project ?? env.cwd;
|
|
266
266
|
if (role === "auditor") {
|
|
267
267
|
if (parsed.subject !== "judge" && parsed.subject !== "doctor") {
|
|
@@ -305,27 +305,21 @@ export async function runPublicInstructionSeat(
|
|
|
305
305
|
);
|
|
306
306
|
}
|
|
307
307
|
|
|
308
|
-
const
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
instruction: parsed.instruction,
|
|
315
|
-
instructionEmpty: parsed.instruction.trim() === "",
|
|
316
|
-
attachmentPaths: parsed.attachmentPaths,
|
|
317
|
-
};
|
|
308
|
+
const summons: SameTicketSummonsMaterials = {
|
|
309
|
+
instruction: parsed.instruction,
|
|
310
|
+
instructionEmpty: parsed.instruction.trim() === "",
|
|
311
|
+
attachmentPaths: parsed.attachmentPaths,
|
|
312
|
+
};
|
|
313
|
+
if (role === "auditor" && auditorSourceRun !== undefined) {
|
|
318
314
|
const resumed = await withAuditorSoulEnv({
|
|
319
315
|
...(auditorSubject === undefined ? {} : { subject: auditorSubject }),
|
|
320
|
-
|
|
321
|
-
? {}
|
|
322
|
-
: { sourceRunDirectory: auditorSourceRun }),
|
|
316
|
+
sourceRunDirectory: auditorSourceRun,
|
|
323
317
|
run: () =>
|
|
324
318
|
tryResumeSameTicketSeatRun({
|
|
325
319
|
home: env.home,
|
|
326
320
|
projectRoot,
|
|
327
321
|
role,
|
|
328
|
-
|
|
322
|
+
parentRunPath: auditorSourceRun,
|
|
329
323
|
freshSummons: env.freshSummons,
|
|
330
324
|
summons,
|
|
331
325
|
resume: (runId, materials) =>
|
|
@@ -337,6 +331,26 @@ export async function runPublicInstructionSeat(
|
|
|
337
331
|
}),
|
|
338
332
|
});
|
|
339
333
|
if (resumed !== undefined) return resumed;
|
|
334
|
+
} else {
|
|
335
|
+
const probedTicketNumber =
|
|
336
|
+
ticketProbe === undefined ? undefined : ticketNumberFromProbe(ticketProbe);
|
|
337
|
+
if (probedTicketNumber !== undefined) {
|
|
338
|
+
const resumed = await tryResumeSameTicketSeatRun({
|
|
339
|
+
home: env.home,
|
|
340
|
+
projectRoot,
|
|
341
|
+
role,
|
|
342
|
+
ticketNumber: probedTicketNumber,
|
|
343
|
+
freshSummons: env.freshSummons,
|
|
344
|
+
summons,
|
|
345
|
+
resume: (runId, materials) =>
|
|
346
|
+
runPublicInstructionSeatResume(
|
|
347
|
+
{ runId, ...(materials === undefined ? {} : { summons: materials }) },
|
|
348
|
+
env,
|
|
349
|
+
io,
|
|
350
|
+
),
|
|
351
|
+
});
|
|
352
|
+
if (resumed !== undefined) return resumed;
|
|
353
|
+
}
|
|
340
354
|
}
|
|
341
355
|
|
|
342
356
|
let admitted: AdmittedInstructionSeatInvocation;
|
|
@@ -360,6 +374,10 @@ export async function runPublicInstructionSeat(
|
|
|
360
374
|
throw error;
|
|
361
375
|
}
|
|
362
376
|
|
|
377
|
+
if (role === "auditor" && auditorSourceRun !== undefined) {
|
|
378
|
+
await persistAdmittedSourceRunPath(admitted, auditorSourceRun);
|
|
379
|
+
}
|
|
380
|
+
|
|
363
381
|
return await withAuditorSoulEnv({
|
|
364
382
|
...(auditorSubject === undefined ? {} : { subject: auditorSubject }),
|
|
365
383
|
...(auditorSourceRun === undefined
|
|
@@ -437,6 +437,35 @@ async function mergeInvocationIdentityPage(
|
|
|
437
437
|
);
|
|
438
438
|
}
|
|
439
439
|
|
|
440
|
+
/**
|
|
441
|
+
* Persist parent --source-run path onto admitted-request for officer resume lookup (#747).
|
|
442
|
+
* Reuses the existing notary sourceRunPath key; does not invent a new field name.
|
|
443
|
+
*/
|
|
444
|
+
export async function persistAdmittedSourceRunPath(
|
|
445
|
+
admitted: AdmittedRoleInvocation,
|
|
446
|
+
sourceRunPath: string,
|
|
447
|
+
): Promise<void> {
|
|
448
|
+
if (sourceRunPath.trim() === "") {
|
|
449
|
+
throw new Error("persistAdmittedSourceRunPath requires a non-empty sourceRunPath");
|
|
450
|
+
}
|
|
451
|
+
const admittedPath = admitted.admittedRequestPath;
|
|
452
|
+
const current = JSON.parse(await readFile(admittedPath, "utf8")) as Record<
|
|
453
|
+
string,
|
|
454
|
+
unknown
|
|
455
|
+
>;
|
|
456
|
+
if (typeof current.sourceRunPath === "string") {
|
|
457
|
+
if (current.sourceRunPath === sourceRunPath) return;
|
|
458
|
+
throw new Error(
|
|
459
|
+
`persistAdmittedSourceRunPath refuses to replace ${current.sourceRunPath} with ${sourceRunPath}`,
|
|
460
|
+
);
|
|
461
|
+
}
|
|
462
|
+
await writeFile(
|
|
463
|
+
admittedPath,
|
|
464
|
+
`${JSON.stringify({ ...current, sourceRunPath }, null, 2)}\n`,
|
|
465
|
+
"utf8",
|
|
466
|
+
);
|
|
467
|
+
}
|
|
468
|
+
|
|
440
469
|
/**
|
|
441
470
|
* Bind a post-admission resolved ticketNumber onto the in-memory admitted
|
|
442
471
|
* object and both durable pages (invocation.json + admitted-request.json).
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Public Notary Role run: admit source-run locator → shared post-admission coordinator
|
|
3
3
|
* → settle Terminal result (#448 / #517). Zero caller prompt/attachment. Lifecycle is
|
|
4
4
|
* the shared post-admission seam; this module keeps only Notary adapters.
|
|
5
|
-
* #637: same-
|
|
5
|
+
* #637 / #747: same-parent (--source-run) re-summons resume the seat's previous run.
|
|
6
6
|
*/
|
|
7
7
|
import { existsSync } from "node:fs";
|
|
8
8
|
|
|
@@ -13,7 +13,6 @@ import {
|
|
|
13
13
|
resolveNotarySourceRunLocator,
|
|
14
14
|
} from "../notary-source-run.ts";
|
|
15
15
|
import { engineSessionMaterialFromOptions } from "../package-resources/engine-material.ts";
|
|
16
|
-
import { readRunTicketNumber } from "../run-ticket-number.ts";
|
|
17
16
|
import { CliUsageError } from "./cli-errors.ts";
|
|
18
17
|
import {
|
|
19
18
|
admitNotaryInvocation,
|
|
@@ -112,8 +111,8 @@ export async function runPublicNotary(
|
|
|
112
111
|
}
|
|
113
112
|
throw error;
|
|
114
113
|
}
|
|
115
|
-
|
|
116
|
-
|
|
114
|
+
// #747: officer resume key is this parent source-run path (not ticket number).
|
|
115
|
+
{
|
|
117
116
|
const summons: SameTicketSummonsMaterials = {
|
|
118
117
|
sourceRunPath: source.runDirectory,
|
|
119
118
|
sourceRun: source,
|
|
@@ -122,7 +121,7 @@ export async function runPublicNotary(
|
|
|
122
121
|
home: env.home,
|
|
123
122
|
projectRoot,
|
|
124
123
|
role: "notary",
|
|
125
|
-
|
|
124
|
+
parentRunPath: source.runDirectory,
|
|
126
125
|
freshSummons: env.freshSummons,
|
|
127
126
|
summons,
|
|
128
127
|
resume: (runId, materials) =>
|
|
@@ -1052,9 +1052,52 @@ export async function findRunDirectoryById(
|
|
|
1052
1052
|
return undefined;
|
|
1053
1053
|
}
|
|
1054
1054
|
|
|
1055
|
+
/** Code-owned gate inspector summons prefix (public-role-summons / #747). */
|
|
1056
|
+
export const GATE_DOSSIER_POINTER_PREFIX = "卷宗指针:" as const;
|
|
1057
|
+
|
|
1058
|
+
/** Parent path from a code-owned inspector 卷宗指针 instruction; else undefined. */
|
|
1059
|
+
export function parentRunPathFromGatePointerInstruction(
|
|
1060
|
+
instruction: string,
|
|
1061
|
+
): string | undefined {
|
|
1062
|
+
if (!instruction.startsWith(GATE_DOSSIER_POINTER_PREFIX)) return undefined;
|
|
1063
|
+
const path = instruction.slice(GATE_DOSSIER_POINTER_PREFIX.length).trim();
|
|
1064
|
+
return path === "" ? undefined : path;
|
|
1065
|
+
}
|
|
1066
|
+
|
|
1055
1067
|
/**
|
|
1056
|
-
*
|
|
1057
|
-
*
|
|
1068
|
+
* Parent-run binding on a retained officer run (#747).
|
|
1069
|
+
* Notary/auditor: typed sourceRunPath. Inspector: exact code-owned 卷宗指针 instruction.
|
|
1070
|
+
* Missing page → undefined; damage / non-ENOENT IO propagates.
|
|
1071
|
+
*/
|
|
1072
|
+
export async function readRunParentPath(
|
|
1073
|
+
runDirectory: string,
|
|
1074
|
+
): Promise<string | undefined> {
|
|
1075
|
+
let raw: unknown;
|
|
1076
|
+
try {
|
|
1077
|
+
raw = JSON.parse(
|
|
1078
|
+
await readFile(join(runDirectory, "admitted-request.json"), "utf8"),
|
|
1079
|
+
);
|
|
1080
|
+
} catch (error) {
|
|
1081
|
+
if (errorCodeOf(error) === "ENOENT") return undefined;
|
|
1082
|
+
throw error;
|
|
1083
|
+
}
|
|
1084
|
+
if (raw === null || typeof raw !== "object" || Array.isArray(raw)) {
|
|
1085
|
+
return undefined;
|
|
1086
|
+
}
|
|
1087
|
+
const record = raw as Record<string, unknown>;
|
|
1088
|
+
if (typeof record.sourceRunPath === "string" && record.sourceRunPath.trim() !== "") {
|
|
1089
|
+
return record.sourceRunPath;
|
|
1090
|
+
}
|
|
1091
|
+
if (typeof record.instruction === "string") {
|
|
1092
|
+
return parentRunPathFromGatePointerInstruction(record.instruction);
|
|
1093
|
+
}
|
|
1094
|
+
return undefined;
|
|
1095
|
+
}
|
|
1096
|
+
|
|
1097
|
+
/**
|
|
1098
|
+
* Locate the latest retained run for one seat under a book (#637 / #747).
|
|
1099
|
+
* Same walk surface as findRunDirectoryById. Match by parent run path (officer
|
|
1100
|
+
* seats, #747) or by ticket number (countersign / diarist principal).
|
|
1058
1101
|
* runId is UUIDv7 — lexicographic max is latest. No parallel index.
|
|
1059
1102
|
* Only a truly missing runs directory means no history; damage/permission errors propagate.
|
|
1060
1103
|
*/
|
|
@@ -1062,7 +1105,8 @@ export async function findLatestRunIdForSeatTicket(input: {
|
|
|
1062
1105
|
readonly home: string;
|
|
1063
1106
|
readonly bookKey: string;
|
|
1064
1107
|
readonly role: RoleRunRecord["role"];
|
|
1065
|
-
readonly ticketNumber
|
|
1108
|
+
readonly ticketNumber?: number;
|
|
1109
|
+
readonly parentRunPath?: string;
|
|
1066
1110
|
}): Promise<string | undefined> {
|
|
1067
1111
|
const ledgerHome = resolveActivationLedgerHome(input.home);
|
|
1068
1112
|
const runsDir = join(
|
|
@@ -1082,8 +1126,16 @@ export async function findLatestRunIdForSeatTicket(input: {
|
|
|
1082
1126
|
if (!entry.endsWith(suffix)) continue;
|
|
1083
1127
|
const runId = entry.slice(0, entry.length - suffix.length);
|
|
1084
1128
|
if (runId.length === 0) continue;
|
|
1085
|
-
const
|
|
1086
|
-
if (
|
|
1129
|
+
const runDirectory = join(runsDir, entry);
|
|
1130
|
+
if (input.parentRunPath !== undefined) {
|
|
1131
|
+
const parentPath = await readRunParentPath(runDirectory);
|
|
1132
|
+
if (parentPath !== input.parentRunPath) continue;
|
|
1133
|
+
} else if (input.ticketNumber !== undefined) {
|
|
1134
|
+
const ticketNumber = await readRunTicketNumber(runDirectory);
|
|
1135
|
+
if (ticketNumber !== input.ticketNumber) continue;
|
|
1136
|
+
} else {
|
|
1137
|
+
continue;
|
|
1138
|
+
}
|
|
1087
1139
|
if (best === undefined || runId > best) best = runId;
|
|
1088
1140
|
}
|
|
1089
1141
|
return best;
|
|
@@ -149,10 +149,11 @@ export async function resolveSeatTicketBinding(
|
|
|
149
149
|
}
|
|
150
150
|
|
|
151
151
|
/**
|
|
152
|
-
* Sole same-
|
|
153
|
-
*
|
|
154
|
-
*
|
|
155
|
-
*
|
|
152
|
+
* Sole same-seat → resume decision (#637 / #724 / #747).
|
|
153
|
+
* Officer seats (notary/inspector/auditor) look up by parent run path; countersign
|
|
154
|
+
* / diarist keep ticket-number principal. When found, runs resume with this
|
|
155
|
+
* summons' materials. Lookup/resume failures propagate (失败诚实) — never wash
|
|
156
|
+
* into a fresh mint. Returns undefined when the caller declared an explicit
|
|
156
157
|
* fresh summons (`ak-role new`) or when no prior run exists; both mint new.
|
|
157
158
|
* freshSummons is required so no seat can drift back into its own skip branch.
|
|
158
159
|
*/
|
|
@@ -160,7 +161,8 @@ export async function tryResumeSameTicketSeatRun<T>(input: {
|
|
|
160
161
|
readonly home: string;
|
|
161
162
|
readonly projectRoot: string;
|
|
162
163
|
readonly role: RoleRunRecord["role"];
|
|
163
|
-
readonly ticketNumber
|
|
164
|
+
readonly ticketNumber?: number;
|
|
165
|
+
readonly parentRunPath?: string;
|
|
164
166
|
readonly freshSummons: true | undefined;
|
|
165
167
|
readonly summons?: SameTicketSummonsMaterials;
|
|
166
168
|
readonly resume: (
|
|
@@ -169,11 +171,19 @@ export async function tryResumeSameTicketSeatRun<T>(input: {
|
|
|
169
171
|
) => Promise<T>;
|
|
170
172
|
}): Promise<T | undefined> {
|
|
171
173
|
if (input.freshSummons === true) return undefined;
|
|
174
|
+
if (input.parentRunPath === undefined && input.ticketNumber === undefined) {
|
|
175
|
+
return undefined;
|
|
176
|
+
}
|
|
172
177
|
const previousRunId = await findLatestRunIdForSeatTicket({
|
|
173
178
|
home: input.home,
|
|
174
179
|
bookKey: resolveBookKeyFromGit(input.projectRoot),
|
|
175
180
|
role: input.role,
|
|
176
|
-
|
|
181
|
+
...(input.parentRunPath === undefined
|
|
182
|
+
? {}
|
|
183
|
+
: { parentRunPath: input.parentRunPath }),
|
|
184
|
+
...(input.ticketNumber === undefined
|
|
185
|
+
? {}
|
|
186
|
+
: { ticketNumber: input.ticketNumber }),
|
|
177
187
|
});
|
|
178
188
|
if (previousRunId === undefined) return undefined;
|
|
179
189
|
return await input.resume(previousRunId, input.summons);
|
package/src/submission-ledger.ts
CHANGED
|
@@ -439,8 +439,11 @@ export function createSubmissionLedgerHost(
|
|
|
439
439
|
},
|
|
440
440
|
});
|
|
441
441
|
rounds.set(attemptId, candidates);
|
|
442
|
+
// The role's own acceptance text must reach the model: an empty
|
|
443
|
+
// result reads as "nothing happened" on hosts without terminate
|
|
444
|
+
// semantics (grok build kept resubmitting, #750 evidence).
|
|
442
445
|
return {
|
|
443
|
-
content:
|
|
446
|
+
content: result.content,
|
|
444
447
|
details: { submissionDisposition: "pending-round-closure" },
|
|
445
448
|
};
|
|
446
449
|
}
|
|
@@ -456,7 +459,7 @@ export function createSubmissionLedgerHost(
|
|
|
456
459
|
candidates.push({ toolCallId, toolName: tool.name, role, result, context });
|
|
457
460
|
rounds.set(attemptId, candidates);
|
|
458
461
|
return {
|
|
459
|
-
content:
|
|
462
|
+
content: result.content,
|
|
460
463
|
details: { submissionDisposition: "pending-round-closure" },
|
|
461
464
|
};
|
|
462
465
|
},
|