@akagilnc/pi-workflow-roles 0.1.5295 → 0.1.5301
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 +7 -3
- package/README.zh-CN.md +7 -3
- package/dist/acp-host/production-host.js +10 -367
- package/dist/diarist-contracts.js +1 -96
- package/dist/headless-host/production-host.js +10 -367
- package/dist/migrate-book-topology.js +75 -77
- package/dist/public-cli/countersign-run.js +3 -124
- package/dist/public-cli/instruction-seat-run.js +5 -97
- package/dist/public-cli/invocation.js +0 -33
- package/dist/public-cli/main.js +10 -362
- package/dist/public-cli/post-admission.js +2 -14
- package/dist/public-cli/run-lifecycle.js +0 -85
- package/dist/public-role-summons.js +2 -2
- package/package.json +1 -1
- package/src/diarist-contracts.ts +1 -116
- package/src/diarist-role.ts +0 -6
- package/src/public-cli/countersign-run.ts +7 -184
- package/src/public-cli/instruction-seat-run.ts +6 -101
- package/src/public-cli/invocation.ts +2 -64
- package/src/public-cli/post-admission.ts +2 -15
- package/src/public-cli/run-lifecycle.ts +0 -117
- package/src/public-role-summons.ts +3 -3
|
@@ -243,81 +243,6 @@ var init_collector_config = __esm({
|
|
|
243
243
|
}
|
|
244
244
|
});
|
|
245
245
|
|
|
246
|
-
// src/ticket-provenance-contracts.ts
|
|
247
|
-
function isRecord(value2) {
|
|
248
|
-
return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
|
|
249
|
-
}
|
|
250
|
-
function positiveInteger(value2) {
|
|
251
|
-
if (typeof value2 === "number" && Number.isSafeInteger(value2) && value2 >= 1) return value2;
|
|
252
|
-
if (typeof value2 === "string" && /^[1-9][0-9]*$/.test(value2)) {
|
|
253
|
-
const parsed2 = Number(value2);
|
|
254
|
-
if (Number.isSafeInteger(parsed2)) return parsed2;
|
|
255
|
-
}
|
|
256
|
-
return void 0;
|
|
257
|
-
}
|
|
258
|
-
function projectBound(value2) {
|
|
259
|
-
if (!isRecord(value2)) return void 0;
|
|
260
|
-
const id = typeof value2.id === "string" && value2.id !== "" ? value2.id : void 0;
|
|
261
|
-
const line = positiveInteger(value2.line);
|
|
262
|
-
if (id === void 0 && line === void 0) return void 0;
|
|
263
|
-
return { ...id === void 0 ? {} : { id }, ...line === void 0 ? {} : { line } };
|
|
264
|
-
}
|
|
265
|
-
function projectTicketProvenanceSessions(value2) {
|
|
266
|
-
if (!Array.isArray(value2)) return void 0;
|
|
267
|
-
if (value2.length === 0) return [];
|
|
268
|
-
const sessions = [];
|
|
269
|
-
for (const raw of value2) {
|
|
270
|
-
if (!isRecord(raw)) return void 0;
|
|
271
|
-
const path8 = raw.path;
|
|
272
|
-
if (typeof path8 !== "string" || path8.trim() === "") return void 0;
|
|
273
|
-
if (!Array.isArray(raw.ranges) || raw.ranges.length === 0) return void 0;
|
|
274
|
-
const ranges = [];
|
|
275
|
-
for (const rawRange of raw.ranges) {
|
|
276
|
-
if (!isRecord(rawRange)) return void 0;
|
|
277
|
-
const from = projectBound(rawRange.from);
|
|
278
|
-
const to = projectBound(rawRange.to);
|
|
279
|
-
if (from === void 0 || to === void 0) return void 0;
|
|
280
|
-
ranges.push({ from, to });
|
|
281
|
-
}
|
|
282
|
-
sessions.push({ path: path8, ranges });
|
|
283
|
-
}
|
|
284
|
-
return sessions;
|
|
285
|
-
}
|
|
286
|
-
function projectTicketProvenanceHeader(value2) {
|
|
287
|
-
if (!isRecord(value2)) return void 0;
|
|
288
|
-
const ticket = value2.ticket === null ? null : positiveInteger(value2.ticket);
|
|
289
|
-
if (ticket === void 0) return void 0;
|
|
290
|
-
if (typeof value2.repo !== "string") return void 0;
|
|
291
|
-
if (typeof value2.createdAt !== "string" || typeof value2.updatedAt !== "string") {
|
|
292
|
-
return void 0;
|
|
293
|
-
}
|
|
294
|
-
const sessions = projectTicketProvenanceSessions(value2.sessions);
|
|
295
|
-
if (sessions === void 0) return void 0;
|
|
296
|
-
return {
|
|
297
|
-
repo: value2.repo,
|
|
298
|
-
ticket,
|
|
299
|
-
createdAt: value2.createdAt,
|
|
300
|
-
updatedAt: value2.updatedAt,
|
|
301
|
-
sessions
|
|
302
|
-
};
|
|
303
|
-
}
|
|
304
|
-
var init_ticket_provenance_contracts = __esm({
|
|
305
|
-
"src/ticket-provenance-contracts.ts"() {
|
|
306
|
-
"use strict";
|
|
307
|
-
}
|
|
308
|
-
});
|
|
309
|
-
|
|
310
|
-
// src/diarist-contracts.ts
|
|
311
|
-
var DIARIST_OUTPUT_TOOL_NAME;
|
|
312
|
-
var init_diarist_contracts = __esm({
|
|
313
|
-
"src/diarist-contracts.ts"() {
|
|
314
|
-
"use strict";
|
|
315
|
-
init_ticket_provenance_contracts();
|
|
316
|
-
init_run_ticket_number();
|
|
317
|
-
DIARIST_OUTPUT_TOOL_NAME = "ak_diarist_output";
|
|
318
|
-
}
|
|
319
|
-
});
|
|
320
|
-
|
|
321
246
|
// node_modules/.pnpm/typebox@1.3.8/node_modules/typebox/build/system/memory/metrics.mjs
|
|
322
247
|
var Metrics;
|
|
323
248
|
var init_metrics = __esm({
|
|
@@ -13879,6 +13804,81 @@ var init_auditor_output = __esm({
|
|
|
13879
13804
|
}
|
|
13880
13805
|
});
|
|
13881
13806
|
|
|
13807
|
+
// src/ticket-provenance-contracts.ts
|
|
13808
|
+
function isRecord(value2) {
|
|
13809
|
+
return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
|
|
13810
|
+
}
|
|
13811
|
+
function positiveInteger(value2) {
|
|
13812
|
+
if (typeof value2 === "number" && Number.isSafeInteger(value2) && value2 >= 1) return value2;
|
|
13813
|
+
if (typeof value2 === "string" && /^[1-9][0-9]*$/.test(value2)) {
|
|
13814
|
+
const parsed2 = Number(value2);
|
|
13815
|
+
if (Number.isSafeInteger(parsed2)) return parsed2;
|
|
13816
|
+
}
|
|
13817
|
+
return void 0;
|
|
13818
|
+
}
|
|
13819
|
+
function projectBound(value2) {
|
|
13820
|
+
if (!isRecord(value2)) return void 0;
|
|
13821
|
+
const id = typeof value2.id === "string" && value2.id !== "" ? value2.id : void 0;
|
|
13822
|
+
const line = positiveInteger(value2.line);
|
|
13823
|
+
if (id === void 0 && line === void 0) return void 0;
|
|
13824
|
+
return { ...id === void 0 ? {} : { id }, ...line === void 0 ? {} : { line } };
|
|
13825
|
+
}
|
|
13826
|
+
function projectTicketProvenanceSessions(value2) {
|
|
13827
|
+
if (!Array.isArray(value2)) return void 0;
|
|
13828
|
+
if (value2.length === 0) return [];
|
|
13829
|
+
const sessions = [];
|
|
13830
|
+
for (const raw of value2) {
|
|
13831
|
+
if (!isRecord(raw)) return void 0;
|
|
13832
|
+
const path8 = raw.path;
|
|
13833
|
+
if (typeof path8 !== "string" || path8.trim() === "") return void 0;
|
|
13834
|
+
if (!Array.isArray(raw.ranges) || raw.ranges.length === 0) return void 0;
|
|
13835
|
+
const ranges = [];
|
|
13836
|
+
for (const rawRange of raw.ranges) {
|
|
13837
|
+
if (!isRecord(rawRange)) return void 0;
|
|
13838
|
+
const from = projectBound(rawRange.from);
|
|
13839
|
+
const to = projectBound(rawRange.to);
|
|
13840
|
+
if (from === void 0 || to === void 0) return void 0;
|
|
13841
|
+
ranges.push({ from, to });
|
|
13842
|
+
}
|
|
13843
|
+
sessions.push({ path: path8, ranges });
|
|
13844
|
+
}
|
|
13845
|
+
return sessions;
|
|
13846
|
+
}
|
|
13847
|
+
function projectTicketProvenanceHeader(value2) {
|
|
13848
|
+
if (!isRecord(value2)) return void 0;
|
|
13849
|
+
const ticket = value2.ticket === null ? null : positiveInteger(value2.ticket);
|
|
13850
|
+
if (ticket === void 0) return void 0;
|
|
13851
|
+
if (typeof value2.repo !== "string") return void 0;
|
|
13852
|
+
if (typeof value2.createdAt !== "string" || typeof value2.updatedAt !== "string") {
|
|
13853
|
+
return void 0;
|
|
13854
|
+
}
|
|
13855
|
+
const sessions = projectTicketProvenanceSessions(value2.sessions);
|
|
13856
|
+
if (sessions === void 0) return void 0;
|
|
13857
|
+
return {
|
|
13858
|
+
repo: value2.repo,
|
|
13859
|
+
ticket,
|
|
13860
|
+
createdAt: value2.createdAt,
|
|
13861
|
+
updatedAt: value2.updatedAt,
|
|
13862
|
+
sessions
|
|
13863
|
+
};
|
|
13864
|
+
}
|
|
13865
|
+
var init_ticket_provenance_contracts = __esm({
|
|
13866
|
+
"src/ticket-provenance-contracts.ts"() {
|
|
13867
|
+
"use strict";
|
|
13868
|
+
}
|
|
13869
|
+
});
|
|
13870
|
+
|
|
13871
|
+
// src/diarist-contracts.ts
|
|
13872
|
+
var DIARIST_OUTPUT_TOOL_NAME;
|
|
13873
|
+
var init_diarist_contracts = __esm({
|
|
13874
|
+
"src/diarist-contracts.ts"() {
|
|
13875
|
+
"use strict";
|
|
13876
|
+
init_ticket_provenance_contracts();
|
|
13877
|
+
init_run_ticket_number();
|
|
13878
|
+
DIARIST_OUTPUT_TOOL_NAME = "ak_diarist_output";
|
|
13879
|
+
}
|
|
13880
|
+
});
|
|
13881
|
+
|
|
13882
13882
|
// src/secretariat-contracts.ts
|
|
13883
13883
|
var SECRETARIAT_OUTPUT_TOOL_NAME;
|
|
13884
13884
|
var init_secretariat_contracts = __esm({
|
|
@@ -15791,7 +15791,6 @@ var init_invocation = __esm({
|
|
|
15791
15791
|
init_run_ticket_number();
|
|
15792
15792
|
init_role_run_relocation();
|
|
15793
15793
|
init_doctor_evidence();
|
|
15794
|
-
init_diarist_contracts();
|
|
15795
15794
|
init_collector_config();
|
|
15796
15795
|
init_github_remote();
|
|
15797
15796
|
init_fixer_packet();
|
|
@@ -15856,7 +15855,6 @@ var init_run_lifecycle = __esm({
|
|
|
15856
15855
|
init_typed_provider_http();
|
|
15857
15856
|
init_typed_provider_http();
|
|
15858
15857
|
init_collector_config();
|
|
15859
|
-
init_diarist_contracts();
|
|
15860
15858
|
init_role_run_relocation();
|
|
15861
15859
|
init_engine_material();
|
|
15862
15860
|
init_packaged_role_registry();
|
|
@@ -1,7 +1,4 @@
|
|
|
1
|
-
import { projectCourtTicketNumbers } from "../diarist-contracts.js";
|
|
2
1
|
import { readableGateItem } from "../readable-gate-item.js";
|
|
3
|
-
import { isSafePositiveTicketNumber } from "../run-ticket-number.js";
|
|
4
|
-
import { StationChildExhaustedError, } from "./post-admission.js";
|
|
5
2
|
function isRecord(value) {
|
|
6
3
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
7
4
|
}
|
|
@@ -52,50 +49,6 @@ function courtDiaristEscalateDiagnostic(roleOutcome, submissions) {
|
|
|
52
49
|
currentConclusion: escalatePayloads[escalatePayloads.length - 1],
|
|
53
50
|
})}`;
|
|
54
51
|
}
|
|
55
|
-
/**
|
|
56
|
-
* Read #871 set from preserved diarist payloads.
|
|
57
|
-
* - Field absent / null / non-array → undefined (no new set; resume keeps store).
|
|
58
|
-
* - Explicit [] → single-ticket [main] whole-set replace (signed empty-set contract).
|
|
59
|
-
* - Non-empty array with zero lawful typed members after projection → not a new set
|
|
60
|
-
* (do not impersonate explicit empty and wipe a stored multi-ticket fact).
|
|
61
|
-
* - Non-empty array with ≥1 lawful member → sole type/dedupe projection + principal guarantee.
|
|
62
|
-
* - Multiple submissions: last qualifying set wins.
|
|
63
|
-
* Live path never shape-rejects the role turn; durable damage is a separate seam.
|
|
64
|
-
*/
|
|
65
|
-
export function courtTicketNumbersFromOutcome(roleOutcome, principalTicket, submissions) {
|
|
66
|
-
if (roleOutcome === undefined)
|
|
67
|
-
return undefined;
|
|
68
|
-
const payloads = courtDiaristPayloadRows(roleOutcome, submissions);
|
|
69
|
-
let latest;
|
|
70
|
-
for (const payload of payloads) {
|
|
71
|
-
if (typeof payload !== "object" ||
|
|
72
|
-
payload === null ||
|
|
73
|
-
Array.isArray(payload)) {
|
|
74
|
-
continue;
|
|
75
|
-
}
|
|
76
|
-
const record = payload;
|
|
77
|
-
if (!Object.hasOwn(record, "courtTicketNumbers"))
|
|
78
|
-
continue;
|
|
79
|
-
const raw = record.courtTicketNumbers;
|
|
80
|
-
// Only a real array is a candidate set. Non-array is not explicit empty.
|
|
81
|
-
if (!Array.isArray(raw))
|
|
82
|
-
continue;
|
|
83
|
-
// Members only — do not inject principal yet, or all-invalid non-empty becomes [main].
|
|
84
|
-
const members = projectCourtTicketNumbers(raw);
|
|
85
|
-
if (members === null)
|
|
86
|
-
continue;
|
|
87
|
-
if (members.length === 0) {
|
|
88
|
-
// Literal [] is the intentional principal-only replace; non-empty garbage is not.
|
|
89
|
-
if (raw.length === 0) {
|
|
90
|
-
latest =
|
|
91
|
-
projectCourtTicketNumbers([], { principalTicket }) ?? undefined;
|
|
92
|
-
}
|
|
93
|
-
continue;
|
|
94
|
-
}
|
|
95
|
-
latest = projectCourtTicketNumbers(raw, { principalTicket }) ?? undefined;
|
|
96
|
-
}
|
|
97
|
-
return latest;
|
|
98
|
-
}
|
|
99
52
|
/** Latest payload only. An earlier escalate must not block a later non-escalate submission. */
|
|
100
53
|
export function latestPayloadEscalated(roleOutcome) {
|
|
101
54
|
if (roleOutcome === undefined)
|
|
@@ -119,14 +72,11 @@ export function courtDiaristEscalated(roleOutcome) {
|
|
|
119
72
|
}
|
|
120
73
|
/**
|
|
121
74
|
* Invoke public 起居郎 under the court-pipeline quiet face.
|
|
122
|
-
* Returns
|
|
123
|
-
* Non-zero exit without escalate status is not rethrown here — caller
|
|
124
|
-
* whether refresh must fail or first-entry settles controlled failure.
|
|
125
|
-
* When `boundTicketNumber` is set (typed handoff from countersign), diarist
|
|
126
|
-
* binds under that key before the turn — never mechanical recognition from prose.
|
|
75
|
+
* Returns escalate or unbound; the secretariat needs no ticket handoff.
|
|
76
|
+
* Non-zero exit without escalate status is not rethrown here — caller settles controlled failure.
|
|
127
77
|
*/
|
|
128
78
|
export async function invokeCourtDiarist(input, env, io) {
|
|
129
|
-
// Quiet face: the
|
|
79
|
+
// Quiet face: the secretariat caller must not see diarist CLI chatter.
|
|
130
80
|
const quietIo = {
|
|
131
81
|
stdout() { },
|
|
132
82
|
stderr(text) {
|
|
@@ -155,9 +105,6 @@ export async function invokeCourtDiarist(input, env, io) {
|
|
|
155
105
|
...(input.correlationId === undefined
|
|
156
106
|
? {}
|
|
157
107
|
: { correlationId: input.correlationId }),
|
|
158
|
-
...(input.boundTicketNumber === undefined
|
|
159
|
-
? {}
|
|
160
|
-
: { boundTicketNumber: input.boundTicketNumber }),
|
|
161
108
|
// Child seat selects from the composition-root table. Do not pass the
|
|
162
109
|
// already-selected parent adapter (#840 / ADR 0082: --host 旗标>席位配置>缺省 pi).
|
|
163
110
|
...(env.hostAdapters === undefined
|
|
@@ -190,76 +137,8 @@ export async function invokeCourtDiarist(input, env, io) {
|
|
|
190
137
|
},
|
|
191
138
|
};
|
|
192
139
|
}
|
|
193
|
-
const asserted = result.admitted
|
|
194
|
-
?.ticketNumber;
|
|
195
|
-
if (isSafePositiveTicketNumber(asserted)) {
|
|
196
|
-
const courtTicketNumbers = courtTicketNumbersFromOutcome(roleOutcome, asserted, submissions);
|
|
197
|
-
return {
|
|
198
|
-
identity: {
|
|
199
|
-
kind: "ticket",
|
|
200
|
-
ticketNumber: asserted,
|
|
201
|
-
...(courtTicketNumbers === undefined ? {} : { courtTicketNumbers }),
|
|
202
|
-
},
|
|
203
|
-
...(result.admitted === undefined ? {} : { admitted: result.admitted }),
|
|
204
|
-
};
|
|
205
|
-
}
|
|
206
140
|
return {
|
|
207
141
|
identity: { kind: "unbound" },
|
|
208
142
|
...(result.admitted === undefined ? {} : { admitted: result.admitted }),
|
|
209
143
|
};
|
|
210
144
|
}
|
|
211
|
-
/**
|
|
212
|
-
* Court-pipeline prior station: refresh this ticket's 起居录 before the
|
|
213
|
-
* countersign body turn when already bound (ADR 0075 每次过庭都跑)。
|
|
214
|
-
* Caller-invisible — no diarist argv on the countersign command line.
|
|
215
|
-
*
|
|
216
|
-
* Missing ticketNumber (true-unbound / identity deferred) skips the refresh
|
|
217
|
-
* station — no diary is minted for a true-unbound run. First-entry identity
|
|
218
|
-
* lives on the shared countersign entry (typed 起居郎 key for bind). Bound refresh:
|
|
219
|
-
* technical failure propagates; LLM escalation remains a recorded conclusion.
|
|
220
|
-
* Path delivery onto materials is not this station's job — post-admission owns it.
|
|
221
|
-
*/
|
|
222
|
-
export async function runCountersignCourtDiaristStation(admitted, env, io, afterTicketNumber) {
|
|
223
|
-
if (env.runCourtDiaristStation !== undefined) {
|
|
224
|
-
await env.runCourtDiaristStation(admitted);
|
|
225
|
-
return;
|
|
226
|
-
}
|
|
227
|
-
// Production court refresh (ADR 0075: 每次过庭都跑是调用者用法) only under a known ticket identity.
|
|
228
|
-
// First-entry unbound identity is owned by the shared countersign entry.
|
|
229
|
-
if (admitted.ticketNumber === undefined)
|
|
230
|
-
return;
|
|
231
|
-
// #871: refresh every member of the typed co-review set; single-ticket face
|
|
232
|
-
// is just the set [main]. Present-but-empty / missing-principal is damage —
|
|
233
|
-
// never silently fall back to main-only (legacy absent field still may).
|
|
234
|
-
let refreshTickets;
|
|
235
|
-
if (admitted.courtTicketNumbers !== undefined) {
|
|
236
|
-
if (admitted.courtTicketNumbers.length === 0 ||
|
|
237
|
-
!admitted.courtTicketNumbers.includes(admitted.ticketNumber)) {
|
|
238
|
-
throw new StationChildExhaustedError(`court diarist station: courtTicketNumbers is damaged (empty or missing principal #${admitted.ticketNumber})`);
|
|
239
|
-
}
|
|
240
|
-
refreshTickets = admitted.courtTicketNumbers;
|
|
241
|
-
}
|
|
242
|
-
else {
|
|
243
|
-
refreshTickets = [admitted.ticketNumber];
|
|
244
|
-
}
|
|
245
|
-
const completedIndex = afterTicketNumber === undefined ? -1 : refreshTickets.indexOf(afterTicketNumber);
|
|
246
|
-
for (const ticketNumber of refreshTickets.slice(completedIndex + 1)) {
|
|
247
|
-
const outcome = await invokeCourtDiarist({
|
|
248
|
-
instruction: admitted.instruction,
|
|
249
|
-
projectRoot: admitted.projectRoot,
|
|
250
|
-
failureLabel: `ticket #${ticketNumber}`,
|
|
251
|
-
correlationId: admitted.runId,
|
|
252
|
-
// Refresh holds a typed key — hand it off so identity is bound before turn.
|
|
253
|
-
boundTicketNumber: ticketNumber,
|
|
254
|
-
}, env, io);
|
|
255
|
-
if (outcome.failedWithoutEscalate !== undefined) {
|
|
256
|
-
throw new StationChildExhaustedError(outcome.failedWithoutEscalate.diagnostic);
|
|
257
|
-
}
|
|
258
|
-
if (outcome.identity.kind === "escalate" && outcome.terminal !== undefined) {
|
|
259
|
-
return {
|
|
260
|
-
terminal: outcome.terminal,
|
|
261
|
-
...(outcome.admitted === undefined ? {} : { childRunId: outcome.admitted.runId }),
|
|
262
|
-
};
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
|
-
}
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* One public role run: admit → turn request → post-admission → settle.
|
|
3
3
|
* Seat differences are composition-root fields. An omitted reviewer lens
|
|
4
|
-
* starts two ordinary single-axis runs here.
|
|
5
|
-
* identity on this entry; the court diarist station stays in countersign-run.
|
|
4
|
+
* starts two ordinary single-axis runs here.
|
|
6
5
|
*/
|
|
7
6
|
import { dirname, resolve, sep } from "node:path";
|
|
8
7
|
import { AUDITOR_DOSSIER_PROMPT } from "../compliance-transport.js";
|
|
@@ -25,7 +24,7 @@ import { engineSessionMaterialFromOptions, pickEngineAxis } from "../package-res
|
|
|
25
24
|
import { packagedAdmitsCountersign, packagedBindsBoardTicket, packagedRebindSourceOnResume, packagedRoleMetadata, } from "../packaged-role-registry.js";
|
|
26
25
|
import { isAuditorSoulRole, readAuditorResumeBinding } from "../auditor-soul.js";
|
|
27
26
|
import { CliUsageError } from "./cli-errors.js";
|
|
28
|
-
import { admitPublicRole, bindAdmittedTicketNumber,
|
|
27
|
+
import { admitPublicRole, bindAdmittedTicketNumber, buildInstructionTransportPrompt, materializeCountersignInvocation, persistAdmittedSourceRunPath, recordAdmittedCorrelation, recordChildDiaristRun, relocateAdmittedRunToTicket, withPreparedAttachments, } from "./invocation.js";
|
|
29
28
|
import { presentControlledFailure, prepareSummonsResumeMaterials, roleTurnOptions, runPostAdmissionOneShot, runPostAdmissionResumable, runPostAdmissionSeatResume, showResumeErrorPointer, resumeTurnRequestProjectionOptions, } from "./post-admission.js";
|
|
30
29
|
import { buildAutoResumeContinuationPrompt, loadResumablePublicRole, markRunAdmitted, parentRunPathFromGatePointerInstruction, } from "./run-lifecycle.js";
|
|
31
30
|
import { tryResumeSameTicketSeatRun } from "./seat-ticket-binding.js";
|
|
@@ -33,7 +32,7 @@ import { presentStructuralRejection, readBoundSessionEntries, seatKnownFailureRe
|
|
|
33
32
|
import { warnMissingMethodSkills } from "./machine-method-skills.js";
|
|
34
33
|
import { formatTerminalResult, isLawfulTypedTerminalOutcome, } from "./terminal.js";
|
|
35
34
|
import { admittedSeatTurnDetails, projectRoleTurnRequest, requiredMethodSkills, } from "./turn-request.js";
|
|
36
|
-
import { invokeCourtDiarist, latestPayloadEscalated,
|
|
35
|
+
import { invokeCourtDiarist, latestPayloadEscalated, } from "./countersign-run.js";
|
|
37
36
|
const AUDITED_ROLES = new Set(["judge", "fixer", "coder", "secretariat", "countersign", "doctor"]);
|
|
38
37
|
const SECRETARIAT_STATUS_REASK = "secretariatStatus 不是 converged、escalate 之一。请重新交卷,secretariatStatus 写明其一。";
|
|
39
38
|
const COUNTERSIGN_STATUS_REASK = "status 不是 converged、continue、escalate 三态之一。请重新交卷,status 写明其一。";
|
|
@@ -312,8 +311,7 @@ async function runOmittedLensBatch(argv, parsed, env, io) {
|
|
|
312
311
|
}
|
|
313
312
|
/**
|
|
314
313
|
* Countersign on the shared entry: gate parent resume, deferred materialization,
|
|
315
|
-
*
|
|
316
|
-
* Court refresh stays on runCountersignCourtDiaristStation.
|
|
314
|
+
* then the same one-shot settlement as every other seat.
|
|
317
315
|
*/
|
|
318
316
|
async function runCountersignBody(parsed, env, io) {
|
|
319
317
|
const gateParentRunPath = typeof env.parentRunPath === "string" && env.parentRunPath.trim() !== ""
|
|
@@ -359,85 +357,12 @@ async function runCountersignBody(parsed, env, io) {
|
|
|
359
357
|
...(ticketNumber === undefined ? {} : { ticketNumber }),
|
|
360
358
|
});
|
|
361
359
|
};
|
|
362
|
-
|
|
363
|
-
let typedCourtTicketNumbers;
|
|
364
|
-
let identityDiaristRan = false;
|
|
365
|
-
let childDiaristRunId;
|
|
366
|
-
let pausedDiaristTerminal;
|
|
367
|
-
if (gateParentRunPath === undefined && env.runCourtDiaristStation === undefined) {
|
|
368
|
-
let outcome;
|
|
369
|
-
try {
|
|
370
|
-
outcome = await invokeCourtDiarist({
|
|
371
|
-
instruction: parsed.instruction ?? "",
|
|
372
|
-
projectRoot: admitted.projectRoot,
|
|
373
|
-
failureLabel: "unbound summons",
|
|
374
|
-
correlationId: admitted.runId,
|
|
375
|
-
...(env.boundTicketNumber === undefined ? {} : { boundTicketNumber: env.boundTicketNumber }),
|
|
376
|
-
}, env, io);
|
|
377
|
-
}
|
|
378
|
-
catch (error) {
|
|
379
|
-
await materializeAdmission(isSafePositiveTicketNumber(env.boundTicketNumber) ? env.boundTicketNumber : undefined);
|
|
380
|
-
await markRunAdmitted(admitted, env.principalAuthority);
|
|
381
|
-
return await presentControlledFailure(admitted, {
|
|
382
|
-
timedOut: false,
|
|
383
|
-
code: null,
|
|
384
|
-
stderr: "",
|
|
385
|
-
thrown: error,
|
|
386
|
-
}, seatAdapters(admitted, env), env.principalAuthority, io);
|
|
387
|
-
}
|
|
388
|
-
identityDiaristRan = true;
|
|
389
|
-
if (outcome.identity.kind === "escalate")
|
|
390
|
-
pausedDiaristTerminal = outcome.terminal;
|
|
391
|
-
if (outcome.admitted?.runDirectory.includes(`${sep}unbound${sep}runs${sep}`)) {
|
|
392
|
-
childDiaristRunId = outcome.admitted.runId;
|
|
393
|
-
}
|
|
394
|
-
if (outcome.failedWithoutEscalate !== undefined) {
|
|
395
|
-
const diagnostic = outcome.failedWithoutEscalate.diagnostic;
|
|
396
|
-
await materializeAdmission(isSafePositiveTicketNumber(env.boundTicketNumber) ? env.boundTicketNumber : undefined);
|
|
397
|
-
if (childDiaristRunId !== undefined)
|
|
398
|
-
await recordChildDiaristRun(admitted, childDiaristRunId);
|
|
399
|
-
await markRunAdmitted(admitted, env.principalAuthority);
|
|
400
|
-
return await presentControlledFailure(admitted, {
|
|
401
|
-
timedOut: false,
|
|
402
|
-
code: null,
|
|
403
|
-
stderr: "",
|
|
404
|
-
thrown: new Error(diagnostic),
|
|
405
|
-
}, seatAdapters(admitted, env), env.principalAuthority, io);
|
|
406
|
-
}
|
|
407
|
-
if (outcome.identity.kind === "ticket") {
|
|
408
|
-
typedTicket = outcome.identity.ticketNumber;
|
|
409
|
-
typedCourtTicketNumbers = outcome.identity.courtTicketNumbers;
|
|
410
|
-
}
|
|
411
|
-
}
|
|
412
|
-
await materializeAdmission(typedTicket);
|
|
360
|
+
await materializeAdmission(isSafePositiveTicketNumber(env.boundTicketNumber) ? env.boundTicketNumber : undefined);
|
|
413
361
|
await markRunAdmitted(admitted, env.principalAuthority);
|
|
414
|
-
if (childDiaristRunId !== undefined) {
|
|
415
|
-
await recordChildDiaristRun(admitted, childDiaristRunId);
|
|
416
|
-
}
|
|
417
|
-
if (pausedDiaristTerminal !== undefined) {
|
|
418
|
-
// The child already submitted its own pause; no parent turn exists yet.
|
|
419
|
-
io.stdout(formatTerminalResult(pausedDiaristTerminal));
|
|
420
|
-
return { exitCode: 0, admitted, terminal: pausedDiaristTerminal };
|
|
421
|
-
}
|
|
422
362
|
if (gateParentRunPath !== undefined) {
|
|
423
363
|
await persistAdmittedSourceRunPath(admitted, gateParentRunPath);
|
|
424
364
|
admitted = { ...admitted, sourceRunPath: gateParentRunPath };
|
|
425
365
|
}
|
|
426
|
-
if (identityDiaristRan && typedTicket !== undefined) {
|
|
427
|
-
try {
|
|
428
|
-
await bindAdmittedTicketNumber(admitted, typedTicket);
|
|
429
|
-
await relocateAdmittedRunToTicket(admitted, env.principalAuthority);
|
|
430
|
-
await bindCourtTicketNumbersOnAdmitted(admitted, typedCourtTicketNumbers ?? [typedTicket]);
|
|
431
|
-
}
|
|
432
|
-
catch (error) {
|
|
433
|
-
return await presentControlledFailure(admitted, {
|
|
434
|
-
timedOut: false,
|
|
435
|
-
code: null,
|
|
436
|
-
stderr: "",
|
|
437
|
-
thrown: error,
|
|
438
|
-
}, seatAdapters(admitted, env), env.principalAuthority, io);
|
|
439
|
-
}
|
|
440
|
-
}
|
|
441
366
|
const turnProjection = {
|
|
442
367
|
packageRoot: env.packageRoot,
|
|
443
368
|
home: env.home,
|
|
@@ -468,13 +393,6 @@ async function runCountersignBody(parsed, env, io) {
|
|
|
468
393
|
beforeDispatch: async (admittedSeat, lease) => {
|
|
469
394
|
if (!packagedAdmitsCountersign(admittedSeat.role))
|
|
470
395
|
return;
|
|
471
|
-
if (!identityDiaristRan || typedTicket !== undefined) {
|
|
472
|
-
const refresh = await runCountersignCourtDiaristStation(admittedSeat, env, io);
|
|
473
|
-
if (refresh !== undefined) {
|
|
474
|
-
io.stdout(formatTerminalResult(refresh.terminal));
|
|
475
|
-
return refresh.terminal;
|
|
476
|
-
}
|
|
477
|
-
}
|
|
478
396
|
await relocateAdmittedRunToTicket(admittedSeat, env.principalAuthority, lease);
|
|
479
397
|
Object.assign(turnRequest, buildInstructionSeatTurnRequest(admittedSeat, turnProjection));
|
|
480
398
|
},
|
|
@@ -810,16 +728,6 @@ export async function continueParentAfterChild(parentRunId, child, env, io) {
|
|
|
810
728
|
return runPublicInstructionSeatResume({ runId: parentRunId }, env, io);
|
|
811
729
|
}
|
|
812
730
|
const admitted = loaded.admitted;
|
|
813
|
-
// Court diarist refresh advances only after a diarist child; gate officers
|
|
814
|
-
// (notary/auditor/…) resume straight into queueConclusionFromChild (#1057).
|
|
815
|
-
if (admitted.role === "countersign" && admitted.ticketNumber !== undefined
|
|
816
|
-
&& child.role === "diarist") {
|
|
817
|
-
const refresh = await runCountersignCourtDiaristStation(admitted, env, io, child.ticketNumber);
|
|
818
|
-
if (refresh !== undefined) {
|
|
819
|
-
io.stdout(formatTerminalResult(refresh.terminal));
|
|
820
|
-
return { exitCode: 0, admitted, terminal: refresh.terminal };
|
|
821
|
-
}
|
|
822
|
-
}
|
|
823
731
|
const resolved = await queueConclusionFromChild(child, env, io);
|
|
824
732
|
if (resolved !== undefined && "stop" in resolved)
|
|
825
733
|
return resolved.stop;
|
|
@@ -14,7 +14,6 @@ import { packagedAdmittedSubject, packagedArgvResult, packagedBareToken, package
|
|
|
14
14
|
import { isSafePositiveTicketNumber, readBoardTicketNumber, requireSafePositiveTicketNumber, } from "../run-ticket-number.js";
|
|
15
15
|
import { rewriteRunDirectoryPathFields, rewriteRunDirectoryPathValue, } from "../role-run-relocation.js";
|
|
16
16
|
import { loadDoctorCase, } from "../doctor-evidence.js";
|
|
17
|
-
import { projectCourtTicketNumbers } from "../diarist-contracts.js";
|
|
18
17
|
import { emptyCollectorManifest, loadCollectorManifest, parseCollectorPrNumber, parseCollectorRepository, } from "../collector-config.js";
|
|
19
18
|
import { ownerRepoFromGitHubRemoteUrl } from "./github-remote.js";
|
|
20
19
|
import { FixerPacketValidationError, parseFixerPrerequisites, } from "../package-contracts/fixer-packet.js";
|
|
@@ -197,38 +196,6 @@ export async function recordAdmittedCorrelation(admitted, correlationId) {
|
|
|
197
196
|
mutable.correlationId = correlationId;
|
|
198
197
|
mutable.correlationIds = correlationIds;
|
|
199
198
|
}
|
|
200
|
-
/**
|
|
201
|
-
* #871: persist the typed co-review set as a countersign run fact (admitted-request +
|
|
202
|
-
* invocation.json). Whole-set replace — never union with a prior set. Main ticket
|
|
203
|
-
* binding stays on `ticketNumber` alone. Projection reuses the sole contract helper;
|
|
204
|
-
* principal membership is mandatory.
|
|
205
|
-
*/
|
|
206
|
-
export async function bindCourtTicketNumbersOnAdmitted(admitted, courtTicketNumbers) {
|
|
207
|
-
if (admitted.ticketNumber === undefined) {
|
|
208
|
-
throw new Error("bindCourtTicketNumbersOnAdmitted requires a bound principal ticketNumber");
|
|
209
|
-
}
|
|
210
|
-
const principal = requireSafePositiveTicketNumber(admitted.ticketNumber, "bindCourtTicketNumbersOnAdmitted principal ticketNumber");
|
|
211
|
-
// Strict write path: every member must already be a lawful number (no soft filter).
|
|
212
|
-
for (const item of courtTicketNumbers) {
|
|
213
|
-
if (!isSafePositiveTicketNumber(item)) {
|
|
214
|
-
throw new Error(`bindCourtTicketNumbersOnAdmitted requires safe positive integers, got ${String(item)}`);
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
const projected = projectCourtTicketNumbers(courtTicketNumbers, {
|
|
218
|
-
principalTicket: principal,
|
|
219
|
-
});
|
|
220
|
-
if (projected === null || projected.length === 0) {
|
|
221
|
-
throw new Error("bindCourtTicketNumbersOnAdmitted requires a non-empty ticket set");
|
|
222
|
-
}
|
|
223
|
-
const frozen = Object.freeze([...projected]);
|
|
224
|
-
const admittedPath = admitted.admittedRequestPath;
|
|
225
|
-
const current = JSON.parse(await readFile(admittedPath, "utf8"));
|
|
226
|
-
await writeFile(admittedPath, `${JSON.stringify({ ...current, courtTicketNumbers: frozen }, null, 2)}\n`, "utf8");
|
|
227
|
-
await mergeInvocationIdentityPage(admitted.runDirectory, {
|
|
228
|
-
courtTicketNumbers: frozen,
|
|
229
|
-
});
|
|
230
|
-
admitted.courtTicketNumbers = frozen;
|
|
231
|
-
}
|
|
232
199
|
/** File a role run under its latest typed ticket identity. */
|
|
233
200
|
export async function relocateAdmittedRunToTicket(admitted, authority, heldLease) {
|
|
234
201
|
if (admitted.ticketNumber === undefined || !admitted.runDirectory.includes(`${sep}unbound${sep}runs${sep}`))
|