@akagilnc/pi-workflow-roles 0.1.3661 → 0.1.3669
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 +52 -28
- package/dist/public-cli/case-dossier-delivery.js +5 -2
- package/dist/public-cli/main.js +378 -291
- package/dist/public-cli/notary-run.js +20 -5
- package/dist/public-cli/post-admission.js +28 -35
- package/dist/public-cli/run-lifecycle.js +14 -6
- package/package.json +1 -1
- package/src/public-cli/case-dossier-delivery.ts +5 -2
- package/src/public-cli/countersign-run.ts +105 -12
- package/src/public-cli/notary-run.ts +18 -6
- package/src/public-cli/post-admission.ts +42 -36
- package/src/public-cli/run-lifecycle.ts +17 -6
|
@@ -1,10 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public Notary Role run: admit source-run locator → shared post-admission coordinator
|
|
3
|
+
* → settle Terminal result (#448 / #517). Zero caller prompt/attachment. Lifecycle is
|
|
4
|
+
* the shared post-admission seam; this module keeps only Notary adapters.
|
|
5
|
+
* #637 / #747: same-parent (--source-run) re-summons resume the seat's previous run.
|
|
6
|
+
*/
|
|
7
|
+
import { existsSync } from "node:fs";
|
|
8
|
+
import { gateSubmissionCandidatePath } from "../auditor-dossier-tool.js";
|
|
1
9
|
import { NotarySourceRunError, resolveNotarySourceRunLocator, } from "../notary-source-run.js";
|
|
2
10
|
import { engineSessionMaterialFromOptions } from "../package-resources/engine-material.js";
|
|
3
11
|
import { CliUsageError } from "./cli-errors.js";
|
|
4
12
|
import { admitNotaryInvocation, buildNotaryTransportPrompt, } from "./invocation.js";
|
|
5
13
|
import { tryResumeSameTicketSeatRun } from "./seat-ticket-binding.js";
|
|
6
14
|
import { runPostAdmissionOneShot, runPostAdmissionSeatResume, resumeTurnRequestProjectionOptions, } from "./post-admission.js";
|
|
7
|
-
import { loadResumableNotaryRun, markRunAdmitted, } from "./run-lifecycle.js";
|
|
15
|
+
import { appendResumeMaterialReread, loadResumableNotaryRun, markRunAdmitted, } from "./run-lifecycle.js";
|
|
8
16
|
import { presentStructuralRejection, trySettleNotaryTerminalResult, } from "./settlement.js";
|
|
9
17
|
import { projectRoleTurnRequest, } from "./turn-request.js";
|
|
10
18
|
/** Project admitted invocation onto the host-neutral turn request. */
|
|
@@ -153,10 +161,17 @@ export async function runPublicNotaryResume(request, env, io) {
|
|
|
153
161
|
}
|
|
154
162
|
return loaded;
|
|
155
163
|
},
|
|
156
|
-
buildTurnRequest: (admitted, effective) =>
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
164
|
+
buildTurnRequest: (admitted, effective) => {
|
|
165
|
+
const projection = resumeTurnRequestProjectionOptions(admitted, effective, env);
|
|
166
|
+
const candidatePath = gateSubmissionCandidatePath(admitted.sourceRunPath);
|
|
167
|
+
const prompt = existsSync(candidatePath)
|
|
168
|
+
? appendResumeMaterialReread(projection.continuation.prompt, candidatePath)
|
|
169
|
+
: projection.continuation.prompt;
|
|
170
|
+
return buildNotaryTurnRequest(admitted, {
|
|
171
|
+
...projection,
|
|
172
|
+
continuation: { kind: "resume", prompt },
|
|
173
|
+
});
|
|
174
|
+
},
|
|
160
175
|
adapters: notaryAdapters(),
|
|
161
176
|
...(env.engine === undefined ? {} : { effectiveEngine: env.engine }),
|
|
162
177
|
});
|
|
@@ -8,10 +8,11 @@
|
|
|
8
8
|
import { randomUUID } from "node:crypto";
|
|
9
9
|
import { readFile, writeFile } from "node:fs/promises";
|
|
10
10
|
import { isAbsolute, join, resolve } from "node:path";
|
|
11
|
-
import { buildResumeContinuationPrompt,
|
|
11
|
+
import { buildResumeContinuationPrompt, instructResumeHandbookRead, } from "./run-lifecycle.js";
|
|
12
12
|
import { CliUsageError } from "./cli-errors.js";
|
|
13
13
|
import { buildInstructionTransportPrompt, freezeAttachmentsIntoRun, } from "./invocation.js";
|
|
14
14
|
import { pathContainedIn } from "../activation-ledger-topology.js";
|
|
15
|
+
import { engineSessionMaterialFromOptions } from "../package-resources/engine-material.js";
|
|
15
16
|
import { projectCaseDossierPointerSection } from "./case-dossier-delivery.js";
|
|
16
17
|
/** Append one system section to a continuation prompt, keeping its kind. */
|
|
17
18
|
function appendContinuationSection(continuation, section) {
|
|
@@ -162,11 +163,11 @@ export async function dispatchPostAdmissionTurn(input) {
|
|
|
162
163
|
}
|
|
163
164
|
}
|
|
164
165
|
// Turn request is assembled after beforeDispatch so this turn sees whatever it
|
|
165
|
-
// settled — the seat's ticket bind re-projection
|
|
166
|
-
// (ADR 0081) rides here for
|
|
167
|
-
// re-summons and manual resume
|
|
168
|
-
//
|
|
169
|
-
// never rewritten.
|
|
166
|
+
// settled — the seat's ticket bind re-projection and any court diarist station
|
|
167
|
+
// writes (#742). Case dossier delivery (ADR 0081 / #709) rides here once for
|
|
168
|
+
// every public entry: first call, same-ticket re-summons and manual resume
|
|
169
|
+
// alike. System refs append their own neutral section; caller frozen
|
|
170
|
+
// attachments and the seat's own prompt bytes are never rewritten.
|
|
170
171
|
let turnRequest = env.signal === undefined ? request : { ...request, signal: env.signal };
|
|
171
172
|
if (hostTransition !== undefined) {
|
|
172
173
|
turnRequest = { ...turnRequest, hostTransition };
|
|
@@ -258,37 +259,36 @@ export async function dispatchPostAdmissionTurn(input) {
|
|
|
258
259
|
}
|
|
259
260
|
}
|
|
260
261
|
/**
|
|
261
|
-
* Shared resume continuation projection (#471 / #600 / #633 / #637
|
|
262
|
-
*
|
|
263
|
-
* - manual resume
|
|
264
|
-
*
|
|
265
|
-
*
|
|
266
|
-
*
|
|
267
|
-
*
|
|
268
|
-
* Caller message wins as prompt base when supplied (bytes unchanged, including
|
|
269
|
-
* blank/whitespace); else summons instruction. Attachment projection must not
|
|
270
|
-
* re-interpret the caller message as instructionEmpty.
|
|
262
|
+
* Shared resume continuation projection (#471 / #600 / #633 / #637): seat-table
|
|
263
|
+
* model/engine/timeout axes, restored correlation, and either
|
|
264
|
+
* - manual resume: package envelope / optional caller message (unchanged), or
|
|
265
|
+
* - same-ticket summons: this turn's instruction + frozen attachment paths.
|
|
266
|
+
* Caller message and summons materials each keep their place: a resume message
|
|
267
|
+
* keeps manual-resume prompt semantics while open-court frozen attachments still
|
|
268
|
+
* ride; summons instruction is only the prompt base when no caller message.
|
|
271
269
|
* Seats add only their activation projection. Call prepareSummonsResumeMaterials
|
|
272
|
-
* first when request.summons carries
|
|
270
|
+
* first when request.summons carries attachment paths.
|
|
273
271
|
*/
|
|
274
272
|
export function resumeTurnRequestProjectionOptions(admitted, request, env, summonsPrepared) {
|
|
273
|
+
const engineMaterial = engineSessionMaterialFromOptions({
|
|
274
|
+
...(env.engine === undefined ? {} : { engine: env.engine }),
|
|
275
|
+
packageRoot: env.packageRoot,
|
|
276
|
+
});
|
|
275
277
|
let prompt;
|
|
276
278
|
if (request.message !== undefined) {
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
279
|
+
// Manual resume caller-message semantics stay authoritative for the prompt:
|
|
280
|
+
// message present → base bytes unchanged (including blank/whitespace).
|
|
281
|
+
// Open-court frozen attachments still continue when present; attachment
|
|
282
|
+
// projection must not re-interpret the caller message as instructionEmpty.
|
|
283
|
+
if (summonsPrepared !== undefined &&
|
|
284
|
+
summonsPrepared.attachments.length > 0) {
|
|
285
|
+
prompt = instructResumeHandbookRead(buildInstructionTransportPrompt({
|
|
281
286
|
instruction: request.message,
|
|
282
287
|
instructionEmpty: false,
|
|
283
288
|
attachments: summonsPrepared.attachments,
|
|
284
|
-
});
|
|
285
|
-
}
|
|
286
|
-
else if (request.summons !== undefined) {
|
|
287
|
-
// #755: same-ticket summons without prepared materials — caller words only.
|
|
288
|
-
prompt = request.message;
|
|
289
|
+
}, engineMaterial), engineMaterial);
|
|
289
290
|
}
|
|
290
291
|
else {
|
|
291
|
-
// Bare manual resume — outsourcing engine axis keeps handbook (#600/#736).
|
|
292
292
|
prompt = buildResumeContinuationPrompt({
|
|
293
293
|
packageRoot: env.packageRoot,
|
|
294
294
|
...(env.engine === undefined ? {} : { engine: env.engine }),
|
|
@@ -297,16 +297,9 @@ export function resumeTurnRequestProjectionOptions(admitted, request, env, summo
|
|
|
297
297
|
}
|
|
298
298
|
}
|
|
299
299
|
else if (summonsPrepared !== undefined) {
|
|
300
|
-
|
|
301
|
-
prompt = buildInstructionTransportPrompt(summonsPrepared);
|
|
302
|
-
}
|
|
303
|
-
else if (request.summons !== undefined) {
|
|
304
|
-
// #755: same-ticket summons with no instruction/attachments (e.g. notary
|
|
305
|
-
// source-run pointer) — plain resume envelope, no handbook / 重新读.
|
|
306
|
-
prompt = RESUME_TRANSPORT_ENVELOPE;
|
|
300
|
+
prompt = instructResumeHandbookRead(buildInstructionTransportPrompt(summonsPrepared, engineMaterial), engineMaterial);
|
|
307
301
|
}
|
|
308
302
|
else {
|
|
309
|
-
// Bare manual resume — outsourcing engine axis keeps handbook (#600/#736).
|
|
310
303
|
prompt = buildResumeContinuationPrompt({
|
|
311
304
|
packageRoot: env.packageRoot,
|
|
312
305
|
...(env.engine === undefined ? {} : { engine: env.engine }),
|
|
@@ -32,10 +32,11 @@ function resumeRereadInstruction(materialPath, handbook) {
|
|
|
32
32
|
: `重新读 ${materialPath}`;
|
|
33
33
|
}
|
|
34
34
|
/**
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
35
|
+
* Resume-only material lines (#736 ticket exemption to ADR 0073 §3).
|
|
36
|
+
* Neutral `- <absolute path>` pointers already on the continuation
|
|
37
|
+
* (handbook from appendEngineSessionMaterial; frozen attachments from
|
|
38
|
+
* instruction-seat transport) become reread instructions.
|
|
39
|
+
* Handbook keeps the argv suffix; other materials are path-only.
|
|
39
40
|
* First-round delivery is unchanged; never pastes material body.
|
|
40
41
|
*/
|
|
41
42
|
export function instructResumeHandbookRead(prompt, engineMaterial) {
|
|
@@ -55,9 +56,16 @@ export function instructResumeHandbookRead(prompt, engineMaterial) {
|
|
|
55
56
|
})
|
|
56
57
|
.join("\n");
|
|
57
58
|
}
|
|
59
|
+
/** Append a live-path reread instruction when the pointer is not already on the continuation. */
|
|
60
|
+
export function appendResumeMaterialReread(prompt, materialPath) {
|
|
61
|
+
const instruction = resumeRereadInstruction(materialPath, false);
|
|
62
|
+
const lines = prompt.split("\n");
|
|
63
|
+
if (lines.includes(instruction))
|
|
64
|
+
return prompt;
|
|
65
|
+
return prompt.length === 0 ? instruction : `${prompt}\n${instruction}`;
|
|
66
|
+
}
|
|
58
67
|
/**
|
|
59
|
-
* Unique continuation-prompt selector for manual/auto
|
|
60
|
-
* (#471 / #600 / #736). Not used for 审核循环 same-ticket summons (#755).
|
|
68
|
+
* Unique continuation-prompt selector for manual/auto resume (#471 / #600 / #736).
|
|
61
69
|
* Message present → base bytes unchanged; absent → package transport envelope.
|
|
62
70
|
* When engine material is present, append structured engine coordinates then
|
|
63
71
|
* rewrite absolute material pointer lines into 重新读 instructions. Zero parse,
|
package/package.json
CHANGED
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* 系统随案递送本票起居录的中立指针段(ADR 0081 `automatic-case-material`;
|
|
3
|
+
* #709 公共入口通用递送与 #742 给事中受理链路同源;
|
|
3
4
|
* 指针输入沿 ADR 0079 `summons-pointer-input`,不把卷宗正文塞进提示词)。
|
|
4
5
|
* 只读已有案卷:不刷新、不生成、不校验内容、不新增拒收或停工条件。
|
|
5
6
|
* 机器文本仅中立标识材料(ADR 0073),用途说明归角色材料所有。
|
|
7
|
+
*
|
|
8
|
+
* 递送挂载点唯一:`post-admission` 在 beforeDispatch 之后为每个公共入口追加本段。
|
|
6
9
|
*/
|
|
7
10
|
import { stat } from "node:fs/promises";
|
|
8
11
|
|
|
9
12
|
import { resolveTicketProvenanceVolume } from "../ticket-provenance.ts";
|
|
10
13
|
|
|
11
|
-
/** Section heading of the system-delivered dossier pointer. */
|
|
12
|
-
|
|
14
|
+
/** Section heading of the system-delivered dossier pointer (presentation only). */
|
|
15
|
+
const CASE_DOSSIER_SECTION_HEADING = "## 本票起居录(系统随案提供)" as const;
|
|
13
16
|
|
|
14
17
|
/** Honest one-line state of one dossier file: present, absent, or unreadable. */
|
|
15
18
|
async function describeDossierFile(path: string): Promise<string> {
|
|
@@ -1,9 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Public Countersign Role run: admit ticket materials →
|
|
3
|
-
* coordinator → settle Terminal result
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
2
|
+
* Public Countersign Role run: admit ticket materials → court-pipeline prior
|
|
3
|
+
* station (起居郎) → shared post-admission coordinator → settle Terminal result
|
|
4
|
+
* (#572 / ADR 0074 / ADR 0075 / #742). #599: manual resume continues the exact
|
|
5
|
+
* session. Unbound admission reuses a known ticket identity (#709) before the
|
|
6
|
+
* diary station.
|
|
7
|
+
*
|
|
8
|
+
* Court admission auto-runs 起居郎 first, then the countersign body — caller
|
|
9
|
+
* adds no diarist argv (L66672). This is the admission pipeline's prior station,
|
|
10
|
+
* not the countersign role calling 起居郎 (L66958 / L66966). Who may call 起居郎
|
|
11
|
+
* and in what order is not written into law (ADR 0075 `no-call-rule`); the
|
|
12
|
+
* present admission effect is what this seat currently does (L108315 目前是这样用的).
|
|
13
|
+
* 起居录 path delivery is owned once by post-admission (#709 / ADR 0081).
|
|
7
14
|
*/
|
|
8
15
|
import type { DurablePrincipalAuthority, RoleTurnRequest } from "../host-contracts.ts";
|
|
9
16
|
import { engineSessionMaterialFromOptions } from "../package-resources/engine-material.ts";
|
|
@@ -11,6 +18,7 @@ import { CliUsageError } from "./cli-errors.ts";
|
|
|
11
18
|
import {
|
|
12
19
|
admitCountersignInvocation,
|
|
13
20
|
buildCountersignTransportPrompt,
|
|
21
|
+
parseDiaristArgv,
|
|
14
22
|
type AdmittedCountersignInvocation,
|
|
15
23
|
type ParseCountersignArgvResult,
|
|
16
24
|
} from "./invocation.ts";
|
|
@@ -46,6 +54,13 @@ import {
|
|
|
46
54
|
export type CountersignRunEnv = PostAdmissionEnv & {
|
|
47
55
|
principalAuthority: DurablePrincipalAuthority;
|
|
48
56
|
createRunId?: () => string;
|
|
57
|
+
/**
|
|
58
|
+
* Test seam: replace the court-pipeline 起居郎 station.
|
|
59
|
+
* Production leaves this unset and runs the public diarist seat.
|
|
60
|
+
*/
|
|
61
|
+
runCourtDiaristStation?: (
|
|
62
|
+
admitted: AdmittedCountersignInvocation,
|
|
63
|
+
) => Promise<void>;
|
|
49
64
|
};
|
|
50
65
|
|
|
51
66
|
/** Project admitted invocation onto the host-neutral turn request. */
|
|
@@ -68,6 +83,75 @@ export function buildCountersignTurnRequest(
|
|
|
68
83
|
);
|
|
69
84
|
}
|
|
70
85
|
|
|
86
|
+
/**
|
|
87
|
+
* Court-pipeline prior station: refresh this ticket's 起居录 before the
|
|
88
|
+
* countersign body turn (ADR 0075 `refresh-every-court`; #742 restore).
|
|
89
|
+
* Caller-invisible — no diarist argv on the countersign command line.
|
|
90
|
+
* Missing ticketNumber (true-unbound) skips the station — no diary is minted
|
|
91
|
+
* for a true-unbound run.
|
|
92
|
+
*
|
|
93
|
+
* Invokes the public 起居郎 seat so the book carries an `@diarist` run ahead of
|
|
94
|
+
* the countersign body. Station failure propagates (失败诚实 — no wash).
|
|
95
|
+
* Path delivery onto materials is not this station's job — post-admission owns it.
|
|
96
|
+
*/
|
|
97
|
+
export async function runCountersignCourtDiaristStation(
|
|
98
|
+
admitted: AdmittedCountersignInvocation,
|
|
99
|
+
env: CountersignRunEnv,
|
|
100
|
+
io: CliIo,
|
|
101
|
+
): Promise<void> {
|
|
102
|
+
if (admitted.ticketNumber === undefined) return;
|
|
103
|
+
if (env.runCourtDiaristStation !== undefined) {
|
|
104
|
+
await env.runCourtDiaristStation(admitted);
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Quiet face: the countersign caller must not see diarist CLI chatter.
|
|
109
|
+
const quietIo: CliIo = {
|
|
110
|
+
stdout() {},
|
|
111
|
+
stderr(text: string) {
|
|
112
|
+
// Surface nested failures onto the parent stderr only; no success noise.
|
|
113
|
+
if (text.trim() !== "") io.stderr(text);
|
|
114
|
+
},
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
const { runPublicDiarist } = await import("./diarist-run.ts");
|
|
118
|
+
const result = await runPublicDiarist(
|
|
119
|
+
[
|
|
120
|
+
"--project",
|
|
121
|
+
admitted.projectRoot,
|
|
122
|
+
`整理 #${admitted.ticketNumber} 的本案依据。`,
|
|
123
|
+
],
|
|
124
|
+
{
|
|
125
|
+
home: env.home,
|
|
126
|
+
agentDir: env.agentDir,
|
|
127
|
+
packageRoot: env.packageRoot,
|
|
128
|
+
cwd: env.cwd,
|
|
129
|
+
principalAuthority: env.principalAuthority,
|
|
130
|
+
roleTurnHost: env.roleTurnHost,
|
|
131
|
+
sessionAppender: env.sessionAppender,
|
|
132
|
+
...(env.model === undefined ? {} : { model: env.model }),
|
|
133
|
+
...(env.engine === undefined ? {} : { engine: env.engine }),
|
|
134
|
+
...(env.host === undefined ? {} : { host: env.host }),
|
|
135
|
+
...(env.timeoutMs === undefined ? {} : { timeoutMs: env.timeoutMs }),
|
|
136
|
+
...(env.credentials === undefined ? {} : { credentials: env.credentials }),
|
|
137
|
+
...(env.correlationId === undefined ? {} : { correlationId: env.correlationId }),
|
|
138
|
+
...(env.signal === undefined ? {} : { signal: env.signal }),
|
|
139
|
+
},
|
|
140
|
+
quietIo,
|
|
141
|
+
parseDiaristArgv,
|
|
142
|
+
);
|
|
143
|
+
|
|
144
|
+
if (result.exitCode !== 0) {
|
|
145
|
+
const detail =
|
|
146
|
+
result.terminal?.roleOutcome.kind === "failure"
|
|
147
|
+
? ` (roleOutcome=failure)`
|
|
148
|
+
: "";
|
|
149
|
+
throw new Error(
|
|
150
|
+
`court diarist station failed for ticket #${admitted.ticketNumber}: exit ${result.exitCode}${detail}`,
|
|
151
|
+
);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
71
155
|
export async function runPublicCountersign(
|
|
72
156
|
argv: readonly string[],
|
|
73
157
|
env: CountersignRunEnv,
|
|
@@ -174,13 +258,16 @@ export async function runPublicCountersign(
|
|
|
174
258
|
io,
|
|
175
259
|
request: turnRequest,
|
|
176
260
|
adapters: countersignAdapters({
|
|
177
|
-
beforeDispatch: async (
|
|
261
|
+
beforeDispatch: async (admittedSeat) => {
|
|
178
262
|
// #635/#709: bind the reused identity inside the controlled-failure boundary.
|
|
179
|
-
await bindReusedTicketNumber(
|
|
263
|
+
await bindReusedTicketNumber(admittedSeat, reusedTicketNumber);
|
|
180
264
|
Object.assign(
|
|
181
265
|
turnRequest,
|
|
182
|
-
buildCountersignTurnRequest(
|
|
266
|
+
buildCountersignTurnRequest(admittedSeat, turnProjection),
|
|
183
267
|
);
|
|
268
|
+
// Court station after bind so the diarist round sees the ticket.
|
|
269
|
+
// Dossier pointer delivery rides post-admission after this hook (#709).
|
|
270
|
+
await runCountersignCourtDiaristStation(admittedSeat, env, io);
|
|
184
271
|
},
|
|
185
272
|
}),
|
|
186
273
|
...(env.engine === undefined ? {} : { effectiveEngine: env.engine }),
|
|
@@ -208,9 +295,11 @@ function countersignAdapters(options?: {
|
|
|
208
295
|
|
|
209
296
|
/**
|
|
210
297
|
* Resume a previously admitted Countersign run (#599 / DK-3 / #637).
|
|
211
|
-
* Restores role/ticket/session identity.
|
|
212
|
-
*
|
|
213
|
-
*
|
|
298
|
+
* Restores role/ticket/session identity. Every court re-entry runs the diarist
|
|
299
|
+
* station first (ADR 0075 `refresh-every-court`). Same-ticket summons deliver this
|
|
300
|
+
* turn's instruction + frozen attachments on the resume prompt; manual resume
|
|
301
|
+
* keeps package-envelope / caller-message semantics and birth attachments.
|
|
302
|
+
* 起居录 path delivery remains post-admission's single mount (#709).
|
|
214
303
|
*/
|
|
215
304
|
export async function runPublicCountersignResume(
|
|
216
305
|
request: PublicResumeRequest,
|
|
@@ -246,7 +335,11 @@ export async function runPublicCountersignResume(
|
|
|
246
335
|
),
|
|
247
336
|
);
|
|
248
337
|
},
|
|
249
|
-
adapters: countersignAdapters(
|
|
338
|
+
adapters: countersignAdapters({
|
|
339
|
+
beforeDispatch: async (admitted) => {
|
|
340
|
+
await runCountersignCourtDiaristStation(admitted, env, io);
|
|
341
|
+
},
|
|
342
|
+
}),
|
|
250
343
|
...(env.engine === undefined ? {} : { effectiveEngine: env.engine }),
|
|
251
344
|
});
|
|
252
345
|
}
|
|
@@ -4,6 +4,9 @@
|
|
|
4
4
|
* the shared post-admission seam; this module keeps only Notary adapters.
|
|
5
5
|
* #637 / #747: same-parent (--source-run) re-summons resume the seat's previous run.
|
|
6
6
|
*/
|
|
7
|
+
import { existsSync } from "node:fs";
|
|
8
|
+
|
|
9
|
+
import { gateSubmissionCandidatePath } from "../auditor-dossier-tool.ts";
|
|
7
10
|
import type { DurablePrincipalAuthority, RoleTurnRequest } from "../host-contracts.ts";
|
|
8
11
|
import {
|
|
9
12
|
NotarySourceRunError,
|
|
@@ -26,6 +29,7 @@ import {
|
|
|
26
29
|
resumeTurnRequestProjectionOptions,
|
|
27
30
|
} from "./post-admission.ts";
|
|
28
31
|
import {
|
|
32
|
+
appendResumeMaterialReread,
|
|
29
33
|
loadResumableNotaryRun,
|
|
30
34
|
markRunAdmitted,
|
|
31
35
|
type PublicResumeRequest,
|
|
@@ -234,13 +238,21 @@ export async function runPublicNotaryResume(
|
|
|
234
238
|
}
|
|
235
239
|
return loaded;
|
|
236
240
|
},
|
|
237
|
-
buildTurnRequest: (admitted, effective) =>
|
|
238
|
-
|
|
239
|
-
//「重新读」candidate line, no engine handbook packaging.
|
|
240
|
-
buildNotaryTurnRequest(
|
|
241
|
+
buildTurnRequest: (admitted, effective) => {
|
|
242
|
+
const projection = resumeTurnRequestProjectionOptions(
|
|
241
243
|
admitted,
|
|
242
|
-
|
|
243
|
-
|
|
244
|
+
effective,
|
|
245
|
+
env,
|
|
246
|
+
);
|
|
247
|
+
const candidatePath = gateSubmissionCandidatePath(admitted.sourceRunPath);
|
|
248
|
+
const prompt = existsSync(candidatePath)
|
|
249
|
+
? appendResumeMaterialReread(projection.continuation.prompt, candidatePath)
|
|
250
|
+
: projection.continuation.prompt;
|
|
251
|
+
return buildNotaryTurnRequest(admitted, {
|
|
252
|
+
...projection,
|
|
253
|
+
continuation: { kind: "resume", prompt },
|
|
254
|
+
});
|
|
255
|
+
},
|
|
244
256
|
adapters: notaryAdapters(),
|
|
245
257
|
...(env.engine === undefined ? {} : { effectiveEngine: env.engine }),
|
|
246
258
|
});
|
|
@@ -11,7 +11,7 @@ import { isAbsolute, join, resolve } from "node:path";
|
|
|
11
11
|
|
|
12
12
|
import {
|
|
13
13
|
buildResumeContinuationPrompt,
|
|
14
|
-
|
|
14
|
+
instructResumeHandbookRead,
|
|
15
15
|
type PublicResumeRequest,
|
|
16
16
|
type SameTicketSummonsMaterials,
|
|
17
17
|
} from "./run-lifecycle.ts";
|
|
@@ -22,6 +22,7 @@ import {
|
|
|
22
22
|
freezeAttachmentsIntoRun,
|
|
23
23
|
} from "./invocation.ts";
|
|
24
24
|
import { pathContainedIn } from "../activation-ledger-topology.ts";
|
|
25
|
+
import { engineSessionMaterialFromOptions } from "../package-resources/engine-material.ts";
|
|
25
26
|
|
|
26
27
|
import type {
|
|
27
28
|
ControlledFailureCause,
|
|
@@ -361,11 +362,11 @@ export async function dispatchPostAdmissionTurn<
|
|
|
361
362
|
}
|
|
362
363
|
|
|
363
364
|
// Turn request is assembled after beforeDispatch so this turn sees whatever it
|
|
364
|
-
// settled — the seat's ticket bind re-projection
|
|
365
|
-
// (ADR 0081) rides here for
|
|
366
|
-
// re-summons and manual resume
|
|
367
|
-
//
|
|
368
|
-
// never rewritten.
|
|
365
|
+
// settled — the seat's ticket bind re-projection and any court diarist station
|
|
366
|
+
// writes (#742). Case dossier delivery (ADR 0081 / #709) rides here once for
|
|
367
|
+
// every public entry: first call, same-ticket re-summons and manual resume
|
|
368
|
+
// alike. System refs append their own neutral section; caller frozen
|
|
369
|
+
// attachments and the seat's own prompt bytes are never rewritten.
|
|
369
370
|
let turnRequest: RoleTurnRequest =
|
|
370
371
|
env.signal === undefined ? request : { ...request, signal: env.signal };
|
|
371
372
|
if (hostTransition !== undefined) {
|
|
@@ -493,18 +494,15 @@ export async function dispatchPostAdmissionTurn<
|
|
|
493
494
|
}
|
|
494
495
|
|
|
495
496
|
/**
|
|
496
|
-
* Shared resume continuation projection (#471 / #600 / #633 / #637
|
|
497
|
-
*
|
|
498
|
-
* - manual resume
|
|
499
|
-
*
|
|
500
|
-
*
|
|
501
|
-
*
|
|
502
|
-
*
|
|
503
|
-
* Caller message wins as prompt base when supplied (bytes unchanged, including
|
|
504
|
-
* blank/whitespace); else summons instruction. Attachment projection must not
|
|
505
|
-
* re-interpret the caller message as instructionEmpty.
|
|
497
|
+
* Shared resume continuation projection (#471 / #600 / #633 / #637): seat-table
|
|
498
|
+
* model/engine/timeout axes, restored correlation, and either
|
|
499
|
+
* - manual resume: package envelope / optional caller message (unchanged), or
|
|
500
|
+
* - same-ticket summons: this turn's instruction + frozen attachment paths.
|
|
501
|
+
* Caller message and summons materials each keep their place: a resume message
|
|
502
|
+
* keeps manual-resume prompt semantics while open-court frozen attachments still
|
|
503
|
+
* ride; summons instruction is only the prompt base when no caller message.
|
|
506
504
|
* Seats add only their activation projection. Call prepareSummonsResumeMaterials
|
|
507
|
-
* first when request.summons carries
|
|
505
|
+
* first when request.summons carries attachment paths.
|
|
508
506
|
*/
|
|
509
507
|
export function resumeTurnRequestProjectionOptions(
|
|
510
508
|
admitted: AdmittedRoleInvocation,
|
|
@@ -516,21 +514,32 @@ export function resumeTurnRequestProjectionOptions(
|
|
|
516
514
|
readonly attachments: readonly { frozenPath: string }[];
|
|
517
515
|
},
|
|
518
516
|
): RoleTurnRequestProjectionOptions {
|
|
517
|
+
const engineMaterial = engineSessionMaterialFromOptions({
|
|
518
|
+
...(env.engine === undefined ? {} : { engine: env.engine }),
|
|
519
|
+
packageRoot: env.packageRoot,
|
|
520
|
+
});
|
|
519
521
|
let prompt: string;
|
|
520
522
|
if (request.message !== undefined) {
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
523
|
+
// Manual resume caller-message semantics stay authoritative for the prompt:
|
|
524
|
+
// message present → base bytes unchanged (including blank/whitespace).
|
|
525
|
+
// Open-court frozen attachments still continue when present; attachment
|
|
526
|
+
// projection must not re-interpret the caller message as instructionEmpty.
|
|
527
|
+
if (
|
|
528
|
+
summonsPrepared !== undefined &&
|
|
529
|
+
summonsPrepared.attachments.length > 0
|
|
530
|
+
) {
|
|
531
|
+
prompt = instructResumeHandbookRead(
|
|
532
|
+
buildInstructionTransportPrompt(
|
|
533
|
+
{
|
|
534
|
+
instruction: request.message,
|
|
535
|
+
instructionEmpty: false,
|
|
536
|
+
attachments: summonsPrepared.attachments,
|
|
537
|
+
},
|
|
538
|
+
engineMaterial,
|
|
539
|
+
),
|
|
540
|
+
engineMaterial,
|
|
541
|
+
);
|
|
532
542
|
} else {
|
|
533
|
-
// Bare manual resume — outsourcing engine axis keeps handbook (#600/#736).
|
|
534
543
|
prompt = buildResumeContinuationPrompt({
|
|
535
544
|
packageRoot: env.packageRoot,
|
|
536
545
|
...(env.engine === undefined ? {} : { engine: env.engine }),
|
|
@@ -538,14 +547,11 @@ export function resumeTurnRequestProjectionOptions(
|
|
|
538
547
|
});
|
|
539
548
|
}
|
|
540
549
|
} else if (summonsPrepared !== undefined) {
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
// source-run pointer) — plain resume envelope, no handbook / 重新读.
|
|
546
|
-
prompt = RESUME_TRANSPORT_ENVELOPE;
|
|
550
|
+
prompt = instructResumeHandbookRead(
|
|
551
|
+
buildInstructionTransportPrompt(summonsPrepared, engineMaterial),
|
|
552
|
+
engineMaterial,
|
|
553
|
+
);
|
|
547
554
|
} else {
|
|
548
|
-
// Bare manual resume — outsourcing engine axis keeps handbook (#600/#736).
|
|
549
555
|
prompt = buildResumeContinuationPrompt({
|
|
550
556
|
packageRoot: env.packageRoot,
|
|
551
557
|
...(env.engine === undefined ? {} : { engine: env.engine }),
|
|
@@ -163,10 +163,11 @@ function resumeRereadInstruction(materialPath: string, handbook: boolean): strin
|
|
|
163
163
|
}
|
|
164
164
|
|
|
165
165
|
/**
|
|
166
|
-
*
|
|
167
|
-
*
|
|
168
|
-
*
|
|
169
|
-
*
|
|
166
|
+
* Resume-only material lines (#736 ticket exemption to ADR 0073 §3).
|
|
167
|
+
* Neutral `- <absolute path>` pointers already on the continuation
|
|
168
|
+
* (handbook from appendEngineSessionMaterial; frozen attachments from
|
|
169
|
+
* instruction-seat transport) become reread instructions.
|
|
170
|
+
* Handbook keeps the argv suffix; other materials are path-only.
|
|
170
171
|
* First-round delivery is unchanged; never pastes material body.
|
|
171
172
|
*/
|
|
172
173
|
export function instructResumeHandbookRead(
|
|
@@ -188,9 +189,19 @@ export function instructResumeHandbookRead(
|
|
|
188
189
|
.join("\n");
|
|
189
190
|
}
|
|
190
191
|
|
|
192
|
+
/** Append a live-path reread instruction when the pointer is not already on the continuation. */
|
|
193
|
+
export function appendResumeMaterialReread(
|
|
194
|
+
prompt: string,
|
|
195
|
+
materialPath: string,
|
|
196
|
+
): string {
|
|
197
|
+
const instruction = resumeRereadInstruction(materialPath, false);
|
|
198
|
+
const lines = prompt.split("\n");
|
|
199
|
+
if (lines.includes(instruction)) return prompt;
|
|
200
|
+
return prompt.length === 0 ? instruction : `${prompt}\n${instruction}`;
|
|
201
|
+
}
|
|
202
|
+
|
|
191
203
|
/**
|
|
192
|
-
* Unique continuation-prompt selector for manual/auto
|
|
193
|
-
* (#471 / #600 / #736). Not used for 审核循环 same-ticket summons (#755).
|
|
204
|
+
* Unique continuation-prompt selector for manual/auto resume (#471 / #600 / #736).
|
|
194
205
|
* Message present → base bytes unchanged; absent → package transport envelope.
|
|
195
206
|
* When engine material is present, append structured engine coordinates then
|
|
196
207
|
* rewrite absolute material pointer lines into 重新读 instructions. Zero parse,
|