@akagilnc/pi-workflow-roles 0.1.6014 → 0.1.6021
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 +2 -0
- package/README.zh-CN.md +2 -0
- package/dist/acp-host/production-host.js +172 -249
- package/dist/headless-host/production-host.js +181 -258
- package/dist/public-cli/instruction-seat-run.js +9 -146
- package/dist/public-cli/main.js +125 -213
- package/dist/public-cli/post-admission.js +1 -19
- package/dist/report-ticket-tool.js +1 -4
- package/dist/submission-ledger.js +16 -1
- package/package.json +1 -1
- package/resources/ticket-at-receipt.md +1 -0
- package/souls/audit-law.md +2 -0
- package/souls/judge.md +1 -1
- package/souls/quality-law.md +1 -1
- package/src/public-cli/instruction-seat-run.ts +9 -182
- package/src/public-cli/post-admission.ts +1 -37
- package/src/report-ticket-tool.ts +1 -5
- package/src/submission-ledger.ts +16 -1
- package/resources/missing-ticket-reask.md +0 -1
|
@@ -4,10 +4,7 @@
|
|
|
4
4
|
* starts two ordinary single-axis runs here.
|
|
5
5
|
*/
|
|
6
6
|
import { dirname, resolve } from "node:path";
|
|
7
|
-
import { MISSING_TICKET_REASK_MATERIAL } from "../report-ticket-tool.js";
|
|
8
7
|
import { isUnboundRunDirectory, sessionFileOf } from "../role-run-placement.js";
|
|
9
|
-
import { rewriteRunDirectoryPathValue } from "../role-run-relocation.js";
|
|
10
|
-
import { readPackageMaterial } from "../session-opening-materials.js";
|
|
11
8
|
import { createPiDoctorAuditor } from "../doctor-auditor.js";
|
|
12
9
|
import { officerConclusionReask, gateOfficerForSubject } from "../gatekeeper-role.js";
|
|
13
10
|
import { receivedDiscriminator } from "../submission-errors.js";
|
|
@@ -100,21 +97,11 @@ function unreadablePostSubmissionStatus(admitted, terminal) {
|
|
|
100
97
|
* status: the caller presents the volumes already in hand and does not advance
|
|
101
98
|
* review. ADR 0007 audit continues are not this shape.
|
|
102
99
|
*/
|
|
103
|
-
/**
|
|
104
|
-
* Drop turn-scoped soft-reask identity; keep cross-turn budgets and ownership cell.
|
|
105
|
-
* #1171 F2-R5 / F2-R9: ordinary status reask and court continue must not inherit
|
|
106
|
-
* softTicketReaskTurn (that flag only governs the soft-reask turn's own settle).
|
|
107
|
-
*/
|
|
108
|
-
function withoutSoftTicketReaskTurn(env) {
|
|
109
|
-
const { softTicketReaskTurn: _softTicketReaskTurn, ...rest } = env;
|
|
110
|
-
return rest;
|
|
111
|
-
}
|
|
112
100
|
function withUnreadableReask(env) {
|
|
113
101
|
const spent = env.unreadableReasksSpent ?? 0;
|
|
114
102
|
if (spent >= deliveryLimitFromConfig(env.autoResumeLimit))
|
|
115
103
|
return undefined;
|
|
116
|
-
|
|
117
|
-
return { ...withoutSoftTicketReaskTurn(env), unreadableReasksSpent: spent + 1 };
|
|
104
|
+
return { ...env, unreadableReasksSpent: spent + 1 };
|
|
118
105
|
}
|
|
119
106
|
/** Budget spent on an unreadable status. Distinct from "status is readable". */
|
|
120
107
|
const UNREADABLE_REASK_EXHAUSTED = { unreadableReaskExhausted: true };
|
|
@@ -256,113 +243,11 @@ async function reaskUnreadablePostSubmissionStatus(admitted, terminal, env, io,
|
|
|
256
243
|
summons: { instructionEmpty: true },
|
|
257
244
|
}, next, io);
|
|
258
245
|
}
|
|
259
|
-
/**
|
|
260
|
-
* #1171: sealed submission still leaves the leg unbound → soft reask once.
|
|
261
|
-
* Does not reject the sealed receipt; exhaustion leaves unbound as filed.
|
|
262
|
-
* Reask copy lives in package resources (ADR 0073).
|
|
263
|
-
* #1171 F2-R7: ownership comes from this nested resume's settlement seam
|
|
264
|
-
* (softTicketReaskOwnership.sealedSubstitute set when the soft-reask turn itself seals),
|
|
265
|
-
* not full-leg sealed count / time-window deltas that can absorb another court's seal.
|
|
266
|
-
*/
|
|
267
|
-
async function reaskMissingTicketOnce(admitted, terminal, env, io) {
|
|
268
|
-
if ((env.ticketReasksSpent ?? 0) >= 1)
|
|
269
|
-
return { kind: "none" };
|
|
270
|
-
// #1192: a table lookup has no one to ask, and a second turn would re-seal.
|
|
271
|
-
if (isNavigatorSeat(admitted.role))
|
|
272
|
-
return { kind: "none" };
|
|
273
|
-
if (admitted.ticketNumber !== undefined)
|
|
274
|
-
return { kind: "none" };
|
|
275
|
-
if (!isUnboundRunDirectory(admitted.runDirectory))
|
|
276
|
-
return { kind: "none" };
|
|
277
|
-
if (terminal?.roleOutcome.kind !== "accepted" && terminal?.roleOutcome.kind !== "audit_escalation") {
|
|
278
|
-
return { kind: "none" };
|
|
279
|
-
}
|
|
280
|
-
const payloads = terminal.roleOutcome.payloads ?? [];
|
|
281
|
-
if (payloads.length === 0)
|
|
282
|
-
return { kind: "none" };
|
|
283
|
-
// Sealed-with-ticket skips via admitted.ticketNumber after bindSealedTicketNumber
|
|
284
|
-
// (post-admission). Do not re-parse payload.ticketNumber here — that would
|
|
285
|
-
// duplicate the existing ticket seam (#1171 notary: no rule copy).
|
|
286
|
-
const instruction = (await readPackageMaterial(MISSING_TICKET_REASK_MATERIAL)).trim();
|
|
287
|
-
// Spend budget and mark this turn as the soft reask (settlement identity).
|
|
288
|
-
// Ownership cell is set at that turn's settlement; env spreads keep the same
|
|
289
|
-
// ref through audit continue — see envForCourtContinue (#1171 F2-R5 / F2-R7).
|
|
290
|
-
const softTicketReaskOwnership = { sealedSubstitute: false };
|
|
291
|
-
const softReaskEnv = {
|
|
292
|
-
...env,
|
|
293
|
-
ticketReasksSpent: 1,
|
|
294
|
-
softTicketReaskTurn: true,
|
|
295
|
-
softTicketReaskOwnership,
|
|
296
|
-
};
|
|
297
|
-
// Named #1171 missing-ticket: summons opens a new court; message carries the
|
|
298
|
-
// package reask copy (not arbitrary summons.instruction passthrough).
|
|
299
|
-
const result = await runPublicInstructionSeatResume({
|
|
300
|
-
runId: admitted.runId,
|
|
301
|
-
runDirectory: admitted.runDirectory,
|
|
302
|
-
message: instruction,
|
|
303
|
-
summons: { instructionEmpty: true },
|
|
304
|
-
}, softReaskEnv, io);
|
|
305
|
-
if (softTicketReaskOwnership.sealedSubstitute
|
|
306
|
-
|| terminalCarriesSealedSubmission(result.terminal)) {
|
|
307
|
-
return { kind: "nested_owns", result };
|
|
308
|
-
}
|
|
309
|
-
return { kind: "no_substitute", result };
|
|
310
|
-
}
|
|
311
|
-
/** Court continue: keep cross-turn budgets + ownership cell; drop turn-scoped soft-reask identity. */
|
|
246
|
+
/** Court continue resets the unreadable-status budget. */
|
|
312
247
|
function envForCourtContinue(env) {
|
|
313
|
-
return { ...
|
|
248
|
+
return { ...env, unreadableReasksSpent: 0 };
|
|
314
249
|
}
|
|
315
|
-
/**
|
|
316
|
-
function terminalCarriesSealedSubmission(terminal) {
|
|
317
|
-
const kind = terminal?.roleOutcome.kind;
|
|
318
|
-
if (kind !== "accepted" && kind !== "audit_escalation")
|
|
319
|
-
return false;
|
|
320
|
-
return (terminal?.roleOutcome.payloads ?? []).length > 0;
|
|
321
|
-
}
|
|
322
|
-
/**
|
|
323
|
-
* #1171 F2-R2: kept original terminal may still name pre-relocate artifact
|
|
324
|
-
* paths after a report-only reask moved the leg. Project onto live admitted
|
|
325
|
-
* via the same rewrite seam post-admission uses after relocate.
|
|
326
|
-
*/
|
|
327
|
-
function projectKeptOriginalArtifactsOntoLiveAdmitted(original, kept) {
|
|
328
|
-
const oldRunDirectory = original.admitted?.runDirectory;
|
|
329
|
-
const newRunDirectory = kept.admitted?.runDirectory;
|
|
330
|
-
if (oldRunDirectory === undefined
|
|
331
|
-
|| newRunDirectory === undefined
|
|
332
|
-
|| oldRunDirectory === newRunDirectory
|
|
333
|
-
|| kept.terminal === undefined) {
|
|
334
|
-
return;
|
|
335
|
-
}
|
|
336
|
-
for (const artifact of kept.terminal.artifacts) {
|
|
337
|
-
artifact.path = rewriteRunDirectoryPathValue(artifact.path, oldRunDirectory, newRunDirectory);
|
|
338
|
-
}
|
|
339
|
-
}
|
|
340
|
-
/**
|
|
341
|
-
* #1171 F2: missing-ticket reask did not seal a substitute — keep original
|
|
342
|
-
* terminal; take live placement from the reask when it relocated.
|
|
343
|
-
* #1171 F2-R1: silence / report-only stays on the original chain; a real host
|
|
344
|
-
* failure (nonzero exit) must be delivered honestly — do not wash it into the
|
|
345
|
-
* original accepted result. Sealed original volume remains on disk either way.
|
|
346
|
-
* #1171 F2-R2: after keep, project report artifact paths onto the live
|
|
347
|
-
* admitted directory so public result, durable face, and artifact refs agree.
|
|
348
|
-
* Substitute ownership is decided once at the soft-reask call seam (F2-R6);
|
|
349
|
-
* this helper only finishes the keep path.
|
|
350
|
-
*/
|
|
351
|
-
function mergeMissingTicketReaskKeepOriginal(original, ticketReask) {
|
|
352
|
-
if (ticketReask.exitCode !== 0)
|
|
353
|
-
return ticketReask;
|
|
354
|
-
const admitted = ticketReask.admitted ?? original.admitted;
|
|
355
|
-
if (admitted === undefined)
|
|
356
|
-
return { ...original };
|
|
357
|
-
const kept = { ...original, admitted };
|
|
358
|
-
projectKeptOriginalArtifactsOntoLiveAdmitted(original, kept);
|
|
359
|
-
return kept;
|
|
360
|
-
}
|
|
361
|
-
/**
|
|
362
|
-
* Post-submission status reask, then missing-ticket soft reask, then audit.
|
|
363
|
-
* #1171 F3: status exhaustion must not skip the one missing-ticket reask.
|
|
364
|
-
* #1171 F2: ticket reask without a substitute seal continues the original chain.
|
|
365
|
-
*/
|
|
250
|
+
/** Post-submission status reask, then audit. */
|
|
366
251
|
async function continueAfterPostSubmissionGuards(result, admittedRole, env, io, held) {
|
|
367
252
|
const live = result.admitted;
|
|
368
253
|
if (live === undefined) {
|
|
@@ -370,38 +255,21 @@ async function continueAfterPostSubmissionGuards(result, admittedRole, env, io,
|
|
|
370
255
|
return result;
|
|
371
256
|
}
|
|
372
257
|
const unreadableReask = await reaskUnreadablePostSubmissionStatus(live, result.terminal, env, io);
|
|
373
|
-
let
|
|
258
|
+
let continued = result;
|
|
374
259
|
if (isUnreadableReaskExhausted(unreadableReask)) {
|
|
375
260
|
const terminal = result.terminal === undefined
|
|
376
261
|
? undefined
|
|
377
262
|
: withUnsettledDirection(result.terminal);
|
|
378
|
-
|
|
263
|
+
continued = terminal === undefined
|
|
379
264
|
? { ...result, admitted: live }
|
|
380
265
|
: { ...result, admitted: live, terminal };
|
|
381
|
-
// Fall through: missing-ticket reask still owed on the original sealed volume.
|
|
382
266
|
}
|
|
383
267
|
else if (unreadableReask !== undefined) {
|
|
384
268
|
return unreadableReask;
|
|
385
269
|
}
|
|
386
|
-
const forTicket = afterStatus.admitted ?? live;
|
|
387
|
-
// Ownership is decided once inside reaskMissingTicketOnce (#1171 F2-R6).
|
|
388
|
-
const softReask = await reaskMissingTicketOnce(forTicket, afterStatus.terminal ?? result.terminal, env, io);
|
|
389
|
-
if (softReask.kind === "nested_owns") {
|
|
390
|
-
// Nested resume already finished guards + audit/present for the substitute.
|
|
391
|
-
// Do not run a second outer settlement of the same public call (#1171 F2-R4b).
|
|
392
|
-
return softReask.result;
|
|
393
|
-
}
|
|
394
|
-
const continued = softReask.kind === "none"
|
|
395
|
-
? afterStatus
|
|
396
|
-
: mergeMissingTicketReaskKeepOriginal(afterStatus, softReask.result);
|
|
397
270
|
const continuedAdmitted = continued.admitted ?? live;
|
|
398
|
-
// Spent budget rides the outer audit/continue chain (#1171 F2-R4a). Soft-reask
|
|
399
|
-
// settlement identity does not — ordinary continue turns publish no_receipt (#1171 F2-R5).
|
|
400
|
-
const continuedEnv = softReask.kind !== "none"
|
|
401
|
-
? { ...env, ticketReasksSpent: 1 }
|
|
402
|
-
: env;
|
|
403
271
|
if (AUDITED_ROLES.has(admittedRole) && continued.terminal?.roleOutcome.kind === "accepted") {
|
|
404
|
-
return auditSubmittedRole({ ...continued, admitted: continuedAdmitted },
|
|
272
|
+
return auditSubmittedRole({ ...continued, admitted: continuedAdmitted }, env, io);
|
|
405
273
|
}
|
|
406
274
|
await presentOriginalVolume(held, continued.terminal, io, continuedAdmitted.runDirectory);
|
|
407
275
|
return { ...continued, admitted: continuedAdmitted };
|
|
@@ -863,8 +731,7 @@ export async function runPublicInstructionSeat(argv, env, io, role, parseArgv) {
|
|
|
863
731
|
const result = await runCountersignBody(parsed, env, {
|
|
864
732
|
stdout: (value) => held.push(value), stderr: io.stderr,
|
|
865
733
|
});
|
|
866
|
-
//
|
|
867
|
-
// soft reask once, then audit — no early return that skips the reask.
|
|
734
|
+
// Apply the same post-submission guards and audit as every other seat.
|
|
868
735
|
return continueAfterPostSubmissionGuards(result, "countersign", env, io, held);
|
|
869
736
|
}
|
|
870
737
|
if ("parallelLenses" in record && record.parallelLenses === true) {
|
|
@@ -1020,9 +887,7 @@ export async function runPublicInstructionSeat(argv, env, io, role, parseArgv) {
|
|
|
1020
887
|
await persistAdmittedSourceRunPath(admitted, auditorSource, auditorSubject);
|
|
1021
888
|
admitted = { ...admitted, sourceRunPath: auditorSource };
|
|
1022
889
|
}
|
|
1023
|
-
// #1208 C2: same helper as resume —
|
|
1024
|
-
// source binds and relocates before the missing-ticket soft reask can
|
|
1025
|
-
// fire. True no-ticket sources stay unbound (#1171 asks once).
|
|
890
|
+
// #1208 C2: same helper as resume — inherit the audited source's known ticket.
|
|
1026
891
|
admitted = await inheritKnownTicketFromSource(admitted, env.principalAuthority);
|
|
1027
892
|
const runAdmitted = async () => {
|
|
1028
893
|
await markRunAdmitted(admitted, env.principalAuthority);
|
|
@@ -1322,8 +1187,6 @@ chainOrder) {
|
|
|
1322
1187
|
}
|
|
1323
1188
|
/** Finished submissions enter the existing audit gate after their tool call has returned. */
|
|
1324
1189
|
async function auditSubmittedRole(turn, env, io, resumedOfficer, passedReceipt) {
|
|
1325
|
-
// Ordinary audit chain: drop soft-reask turn identity; keep budgets/ownership (#1171 F2-R9).
|
|
1326
|
-
env = withoutSoftTicketReaskTurn(env);
|
|
1327
1190
|
const admitted = turn.admitted;
|
|
1328
1191
|
if (admitted === undefined || !AUDITED_ROLES.has(admitted.role)
|
|
1329
1192
|
|| turn.terminal?.roleOutcome.kind !== "accepted")
|