@akagilnc/pi-workflow-roles 0.1.4035 → 0.1.4193
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 +2368 -1155
- package/dist/archivist-record-entry.js +204 -20
- package/dist/archivist-record-topology.js +36 -16
- package/dist/auditor-dossier-tool.js +2 -1
- package/dist/diarist-contracts.js +96 -0
- package/dist/doctor-auditor.js +1 -1
- package/dist/doctor-evidence.js +3 -2
- package/dist/dossier-resolution.js +21 -8
- package/dist/gatekeeper-role.js +34 -27
- package/dist/headless-host/description.js +7 -8
- package/dist/headless-host/production-host.js +2375 -1149
- package/dist/host-contracts.js +16 -0
- package/dist/inspector-contracts.js +8 -0
- package/dist/migrate-book-topology.js +278917 -0
- package/dist/navigator-public-session.js +22 -25
- package/dist/notary-source-run.js +7 -4
- package/dist/packaged-role-registry.js +1 -1
- package/dist/pi/durable-principal.js +9 -6
- package/dist/pi/role-turn-host.js +43 -13
- package/dist/public-cli/auto-resume.js +2 -5
- package/dist/public-cli/case-dossier-delivery.js +60 -1
- package/dist/public-cli/diarist-run.js +27 -25
- package/dist/public-cli/inspector-run.js +17 -3
- package/dist/public-cli/instruction-seat-run.js +17 -17
- package/dist/public-cli/invocation.js +127 -63
- package/dist/public-cli/main.js +1685 -696
- package/dist/public-cli/notary-run.js +7 -4
- package/dist/public-cli/option-definitions.js +2 -2
- package/dist/public-cli/post-admission.js +113 -71
- package/dist/public-cli/run-lifecycle.js +209 -58
- package/dist/public-cli/seat-ticket-binding.js +3 -6
- package/dist/public-cli/settlement.js +29 -10
- package/dist/public-role-summons.js +8 -0
- package/dist/role-run-placement.js +84 -0
- package/dist/role-run-relocation.js +358 -0
- package/dist/run-terminal-artifacts.js +2 -1
- package/dist/run-ticket-number.js +51 -32
- package/dist/sitian-appender.js +11 -26
- package/dist/submission-ledger.js +106 -25
- package/dist/ticket-provenance.js +3 -1
- package/dist/user-dialogue-stdin.js +33 -0
- package/extensions/role-runtime.ts +1 -0
- package/package.json +3 -2
- package/resources/836-deleted-machine-instruction-inventory.md +1 -1
- package/scripts/build-package.mjs +34 -2
- package/souls/fixer.md +3 -2
- package/src/analyst-ledger.ts +14 -15
- package/src/archivist-record-entry.ts +285 -38
- package/src/archivist-record-topology.ts +43 -18
- package/src/auditor-dossier-tool.ts +2 -1
- package/src/book-topology-migration-placement.ts +493 -0
- package/src/book-topology-migration.ts +220 -0
- package/src/book-topology-migrators-t11.ts +856 -0
- package/src/book-topology-mixed-volume-migrators.ts +470 -0
- package/src/book-topology-partition-migrators.ts +25 -0
- package/src/book-topology-record-class-migrators.ts +779 -0
- package/src/book-topology-runs-migrator.ts +244 -0
- package/src/diarist-contracts.ts +116 -0
- package/src/diarist-role.ts +6 -0
- package/src/diarist.ts +2 -0
- package/src/doctor-auditor.ts +1 -1
- package/src/doctor-evidence.ts +4 -1
- package/src/doctor-role.ts +1 -1
- package/src/dossier-resolution.ts +26 -8
- package/src/external-host-turn-loop.ts +9 -0
- package/src/gatekeeper-pass-envelope.ts +6 -0
- package/src/gatekeeper-role.ts +47 -28
- package/src/headless-host/description.ts +8 -11
- package/src/headless-host/role-turn-host.ts +20 -5
- package/src/host-contracts.ts +22 -3
- package/src/inspector-contracts.ts +7 -0
- package/src/judge-role.ts +4 -0
- package/src/navigator-public-session.ts +33 -30
- package/src/navigator-work-context.ts +3 -4
- package/src/notary-role.ts +1 -0
- package/src/notary-source-run.ts +9 -4
- package/src/packaged-role-registry.ts +1 -1
- package/src/pi/adapter.ts +19 -4
- package/src/pi/durable-principal.ts +9 -13
- package/src/pi/role-turn-host.ts +48 -14
- package/src/public-cli/auto-resume.ts +2 -6
- package/src/public-cli/case-dossier-delivery.ts +86 -1
- package/src/public-cli/countersign-run.ts +182 -32
- package/src/public-cli/diarist-run.ts +34 -26
- package/src/public-cli/inspector-run.ts +26 -2
- package/src/public-cli/instruction-seat-run.ts +24 -20
- package/src/public-cli/invocation.ts +194 -58
- package/src/public-cli/notary-run.ts +13 -4
- package/src/public-cli/option-definitions.ts +2 -2
- package/src/public-cli/post-admission.ts +147 -78
- package/src/public-cli/run-lifecycle.ts +258 -65
- package/src/public-cli/seat-ticket-binding.ts +3 -6
- package/src/public-cli/settlement.ts +38 -10
- package/src/public-role-summons.ts +31 -7
- package/src/role-envelope.ts +9 -30
- package/src/role-run-placement.ts +128 -0
- package/src/role-run-relocation.ts +491 -0
- package/src/role-runtime-dependencies.ts +1 -0
- package/src/role-runtime.ts +106 -24
- package/src/run-terminal-artifacts.ts +3 -1
- package/src/run-ticket-number.ts +80 -20
- package/src/sitian-appender.ts +25 -28
- package/src/submission-ledger.ts +148 -30
- package/src/ticket-provenance.ts +4 -1
- package/src/ticket-trajectory.ts +22 -35
- package/src/user-dialogue-stdin.ts +37 -0
- package/src/worker-role.ts +8 -4
- package/src/worker-submission-gates.ts +6 -6
|
@@ -6,12 +6,12 @@ import { execFileSync } from "node:child_process";
|
|
|
6
6
|
import { existsSync } from "node:fs";
|
|
7
7
|
import {
|
|
8
8
|
lstat,
|
|
9
|
-
mkdir,
|
|
10
9
|
readFile,
|
|
11
10
|
realpath,
|
|
11
|
+
rename,
|
|
12
12
|
writeFile,
|
|
13
13
|
} from "node:fs/promises";
|
|
14
|
-
import { basename, isAbsolute, join, resolve, sep } from "node:path";
|
|
14
|
+
import { basename, dirname, isAbsolute, join, resolve, sep } from "node:path";
|
|
15
15
|
|
|
16
16
|
import {
|
|
17
17
|
activationBookDirectory,
|
|
@@ -21,14 +21,31 @@ import {
|
|
|
21
21
|
resolveActivationLedgerHome,
|
|
22
22
|
} from "../activation-ledger-topology.ts";
|
|
23
23
|
import { resolveBookKeyFromGit } from "../activation-ledger-git.ts";
|
|
24
|
+
import {
|
|
25
|
+
ensureRoleRunDirectory,
|
|
26
|
+
ensureRoleRunPlacement,
|
|
27
|
+
roleRunArtifactsDirectory,
|
|
28
|
+
roleRunPlacement,
|
|
29
|
+
type RoleRunSubject,
|
|
30
|
+
} from "../role-run-placement.ts";
|
|
24
31
|
import type {
|
|
25
32
|
DurablePrincipal,
|
|
26
33
|
DurablePrincipalAuthority,
|
|
27
34
|
} from "../host-contracts.ts";
|
|
28
|
-
import {
|
|
35
|
+
import {
|
|
36
|
+
isSafePositiveTicketNumber,
|
|
37
|
+
readBoardTicketNumber,
|
|
38
|
+
requireSafePositiveTicketNumber,
|
|
39
|
+
} from "../run-ticket-number.ts";
|
|
40
|
+
import {
|
|
41
|
+
rewriteRoleRunDurablePages,
|
|
42
|
+
rewriteRunDirectoryPathFields,
|
|
43
|
+
rewriteRunDirectoryPathValue,
|
|
44
|
+
} from "../role-run-relocation.ts";
|
|
29
45
|
import {
|
|
30
46
|
loadDoctorCase,
|
|
31
47
|
} from "../doctor-evidence.ts";
|
|
48
|
+
import { projectCourtTicketNumbers } from "../diarist-contracts.ts";
|
|
32
49
|
import type { DoctorCaseIdentity } from "../doctor-contracts.ts";
|
|
33
50
|
import {
|
|
34
51
|
emptyCollectorManifest,
|
|
@@ -121,6 +138,17 @@ export type AdmittedJudgeInvocation = AdmittedRoleInvocationBase & {
|
|
|
121
138
|
|
|
122
139
|
export type AdmittedCountersignInvocation = AdmittedRoleInvocationBase & {
|
|
123
140
|
readonly role: "countersign";
|
|
141
|
+
/**
|
|
142
|
+
* #871 typed co-review set for this countersign run (durable run fact).
|
|
143
|
+
* Main ticket remains `ticketNumber`; this set drives per-ticket court diarist refresh.
|
|
144
|
+
* Whole-set replace on new typed submission — never union with history.
|
|
145
|
+
*/
|
|
146
|
+
courtTicketNumbers?: readonly number[];
|
|
147
|
+
/**
|
|
148
|
+
* Load-time durable set damage diagnostic (#871 B7). Resume must settle as
|
|
149
|
+
* countersign controlled failure with this text — never structural exit 2 or main-only.
|
|
150
|
+
*/
|
|
151
|
+
courtTicketNumbersDamage?: string;
|
|
124
152
|
};
|
|
125
153
|
|
|
126
154
|
export type AdmittedGleanerLeftInvocation = AdmittedRoleInvocationBase & {
|
|
@@ -131,6 +159,8 @@ export type AdmittedGleanerLeftInvocation = AdmittedRoleInvocationBase & {
|
|
|
131
159
|
|
|
132
160
|
export type AdmittedInspectorInvocation = AdmittedRoleInvocationBase & {
|
|
133
161
|
readonly role: "inspector";
|
|
162
|
+
/** Parent run directory (#747 / #879); independent of dialogue instruction. */
|
|
163
|
+
readonly sourceRunPath?: string;
|
|
134
164
|
};
|
|
135
165
|
|
|
136
166
|
export type AdmittedGatekeeperInvocation = AdmittedRoleInvocationBase & {
|
|
@@ -259,30 +289,36 @@ export type AdmissionPlacement = {
|
|
|
259
289
|
readonly sessionDirectory: string;
|
|
260
290
|
readonly sessionFile: string;
|
|
261
291
|
readonly runDirectory: string;
|
|
292
|
+
readonly artifactsDirectory: string;
|
|
293
|
+
readonly attachmentsDirectory: string;
|
|
262
294
|
readonly ledgerHome: string;
|
|
263
295
|
readonly bookKey: string;
|
|
264
296
|
};
|
|
265
297
|
|
|
266
|
-
/** Issue principal
|
|
298
|
+
/** Issue a principal from the single authoritative role-run placement. */
|
|
267
299
|
export function issueAdmissionPlacement(
|
|
268
300
|
authority: DurablePrincipalAuthority,
|
|
269
301
|
request: {
|
|
270
302
|
readonly cwd: string;
|
|
271
303
|
readonly runId: string;
|
|
272
304
|
readonly role: AdmittedRoleInvocation["role"];
|
|
305
|
+
/** Identity already asserted by 起居郎; never derive this from CLI parameters. */
|
|
306
|
+
readonly subject: RoleRunSubject;
|
|
273
307
|
readonly home?: string;
|
|
274
308
|
},
|
|
275
309
|
): AdmissionPlacement {
|
|
276
|
-
const principal = authority.issue(request);
|
|
277
|
-
const { sessionDirectory, sessionFile } = authority.decode(principal);
|
|
278
|
-
const runDirectory = join(sessionDirectory, "..");
|
|
279
310
|
const ledgerHome = resolveActivationLedgerHome(request.home);
|
|
280
311
|
const bookKey = resolveBookKeyFromGit(request.cwd);
|
|
312
|
+
const placement = roleRunPlacement(ledgerHome, {
|
|
313
|
+
bookKey,
|
|
314
|
+
subject: request.subject,
|
|
315
|
+
runId: request.runId,
|
|
316
|
+
role: request.role,
|
|
317
|
+
});
|
|
318
|
+
ensureRoleRunPlacement(ledgerHome, placement);
|
|
281
319
|
return {
|
|
282
|
-
principal,
|
|
283
|
-
|
|
284
|
-
sessionFile,
|
|
285
|
-
runDirectory,
|
|
320
|
+
principal: authority.seal(placement),
|
|
321
|
+
...placement,
|
|
286
322
|
ledgerHome,
|
|
287
323
|
bookKey,
|
|
288
324
|
};
|
|
@@ -474,17 +510,50 @@ export async function bindAdmittedTicketNumber(
|
|
|
474
510
|
admitted: AdmittedRoleInvocation,
|
|
475
511
|
ticketNumber: number,
|
|
476
512
|
): Promise<void> {
|
|
477
|
-
if (!Number.isSafeInteger(ticketNumber) || ticketNumber < 1) {
|
|
478
|
-
throw new Error(`bindAdmittedTicketNumber requires a safe positive integer, got ${String(ticketNumber)}`);
|
|
479
|
-
}
|
|
480
513
|
if (admitted.ticketNumber !== undefined) {
|
|
481
514
|
if (admitted.ticketNumber === ticketNumber) return;
|
|
482
515
|
throw new Error(
|
|
483
516
|
`bindAdmittedTicketNumber refuses to replace existing ticket #${admitted.ticketNumber} with #${ticketNumber}`,
|
|
484
517
|
);
|
|
485
518
|
}
|
|
519
|
+
await bindTicketNumberOnRunDirectory(admitted.runDirectory, ticketNumber);
|
|
486
520
|
(admitted as { ticketNumber?: number }).ticketNumber = ticketNumber;
|
|
487
|
-
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
/**
|
|
524
|
+
* #871: persist the typed co-review set as a countersign run fact (admitted-request +
|
|
525
|
+
* invocation.json). Whole-set replace — never union with a prior set. Main ticket
|
|
526
|
+
* binding stays on `ticketNumber` alone. Projection reuses the sole contract helper;
|
|
527
|
+
* principal membership is mandatory.
|
|
528
|
+
*/
|
|
529
|
+
export async function bindCourtTicketNumbersOnAdmitted(
|
|
530
|
+
admitted: AdmittedCountersignInvocation,
|
|
531
|
+
courtTicketNumbers: readonly number[],
|
|
532
|
+
): Promise<void> {
|
|
533
|
+
if (admitted.ticketNumber === undefined) {
|
|
534
|
+
throw new Error(
|
|
535
|
+
"bindCourtTicketNumbersOnAdmitted requires a bound principal ticketNumber",
|
|
536
|
+
);
|
|
537
|
+
}
|
|
538
|
+
const principal = requireSafePositiveTicketNumber(
|
|
539
|
+
admitted.ticketNumber,
|
|
540
|
+
"bindCourtTicketNumbersOnAdmitted principal ticketNumber",
|
|
541
|
+
);
|
|
542
|
+
// Strict write path: every member must already be a lawful number (no soft filter).
|
|
543
|
+
for (const item of courtTicketNumbers) {
|
|
544
|
+
if (!isSafePositiveTicketNumber(item)) {
|
|
545
|
+
throw new Error(
|
|
546
|
+
`bindCourtTicketNumbersOnAdmitted requires safe positive integers, got ${String(item)}`,
|
|
547
|
+
);
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
const projected = projectCourtTicketNumbers(courtTicketNumbers, {
|
|
551
|
+
principalTicket: principal,
|
|
552
|
+
});
|
|
553
|
+
if (projected === null || projected.length === 0) {
|
|
554
|
+
throw new Error("bindCourtTicketNumbersOnAdmitted requires a non-empty ticket set");
|
|
555
|
+
}
|
|
556
|
+
const frozen = Object.freeze([...projected]);
|
|
488
557
|
const admittedPath = admitted.admittedRequestPath;
|
|
489
558
|
const current = JSON.parse(await readFile(admittedPath, "utf8")) as Record<
|
|
490
559
|
string,
|
|
@@ -492,9 +561,64 @@ export async function bindAdmittedTicketNumber(
|
|
|
492
561
|
>;
|
|
493
562
|
await writeFile(
|
|
494
563
|
admittedPath,
|
|
495
|
-
`${JSON.stringify({ ...current,
|
|
564
|
+
`${JSON.stringify({ ...current, courtTicketNumbers: frozen }, null, 2)}\n`,
|
|
496
565
|
"utf8",
|
|
497
566
|
);
|
|
567
|
+
await mergeInvocationIdentityPage(admitted.runDirectory, {
|
|
568
|
+
courtTicketNumbers: frozen,
|
|
569
|
+
});
|
|
570
|
+
admitted.courtTicketNumbers = frozen;
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
/** Move a settled first-entry run from unbound to its asserted ticket directory. */
|
|
574
|
+
export async function relocateAdmittedRunToTicket(
|
|
575
|
+
admitted: AdmittedRoleInvocation,
|
|
576
|
+
authority: DurablePrincipalAuthority,
|
|
577
|
+
heldLease?: { relocate(runDirectory: string): void },
|
|
578
|
+
): Promise<void> {
|
|
579
|
+
if (admitted.ticketNumber === undefined || !admitted.runDirectory.includes(`${sep}unbound${sep}runs${sep}`)) return;
|
|
580
|
+
const oldRunDirectory = admitted.runDirectory;
|
|
581
|
+
const ledgerHome = resolveActivationLedgerHome(homeFromRunDirectory(oldRunDirectory));
|
|
582
|
+
const target = roleRunPlacement(ledgerHome, {
|
|
583
|
+
bookKey: admitted.bookKey,
|
|
584
|
+
subject: { ticketNumber: admitted.ticketNumber },
|
|
585
|
+
runId: admitted.runId,
|
|
586
|
+
role: admitted.role,
|
|
587
|
+
});
|
|
588
|
+
ensureRoleRunDirectory(ledgerHome, dirname(target.runDirectory));
|
|
589
|
+
await rename(oldRunDirectory, target.runDirectory);
|
|
590
|
+
heldLease?.relocate(target.runDirectory);
|
|
591
|
+
|
|
592
|
+
const admittedRecord = admitted as unknown as Record<string, unknown>;
|
|
593
|
+
rewriteRunDirectoryPathFields(
|
|
594
|
+
admittedRecord,
|
|
595
|
+
[
|
|
596
|
+
"runDirectory",
|
|
597
|
+
"admittedRequestPath",
|
|
598
|
+
"taskPath",
|
|
599
|
+
"packetPath",
|
|
600
|
+
"prerequisitesPath",
|
|
601
|
+
"requestManifestPath",
|
|
602
|
+
"mergerInputPath",
|
|
603
|
+
],
|
|
604
|
+
oldRunDirectory,
|
|
605
|
+
target.runDirectory,
|
|
606
|
+
);
|
|
607
|
+
for (const attachment of admitted.attachments) {
|
|
608
|
+
(attachment as { frozenPath: string }).frozenPath = rewriteRunDirectoryPathValue(
|
|
609
|
+
attachment.frozenPath,
|
|
610
|
+
oldRunDirectory,
|
|
611
|
+
target.runDirectory,
|
|
612
|
+
) as string;
|
|
613
|
+
}
|
|
614
|
+
const principal = authority.seal(target);
|
|
615
|
+
(admitted as { principal: DurablePrincipal }).principal = principal;
|
|
616
|
+
|
|
617
|
+
await rewriteRoleRunDurablePages({
|
|
618
|
+
pagesDirectory: target.runDirectory,
|
|
619
|
+
oldRunDirectory,
|
|
620
|
+
newRunDirectory: target.runDirectory,
|
|
621
|
+
});
|
|
498
622
|
}
|
|
499
623
|
|
|
500
624
|
/**
|
|
@@ -506,11 +630,10 @@ export async function bindTicketNumberOnRunDirectory(
|
|
|
506
630
|
runDirectory: string,
|
|
507
631
|
ticketNumber: number,
|
|
508
632
|
): Promise<void> {
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
}
|
|
633
|
+
requireSafePositiveTicketNumber(
|
|
634
|
+
ticketNumber,
|
|
635
|
+
"bindTicketNumberOnRunDirectory",
|
|
636
|
+
);
|
|
514
637
|
const admittedPath = join(runDirectory, "admitted-request.json");
|
|
515
638
|
const invocationPath = join(runDirectory, "invocation.json");
|
|
516
639
|
const admitted = JSON.parse(await readFile(admittedPath, "utf8")) as Record<
|
|
@@ -1087,7 +1210,13 @@ export async function freezeAttachmentsIntoRun(
|
|
|
1087
1210
|
function ticketAdmissionFields(
|
|
1088
1211
|
ticketNumber: number | undefined,
|
|
1089
1212
|
): { ticketNumber?: number } {
|
|
1090
|
-
|
|
1213
|
+
if (ticketNumber === undefined) return {};
|
|
1214
|
+
return {
|
|
1215
|
+
ticketNumber: requireSafePositiveTicketNumber(
|
|
1216
|
+
ticketNumber,
|
|
1217
|
+
"assertedTicketNumber",
|
|
1218
|
+
),
|
|
1219
|
+
};
|
|
1091
1220
|
}
|
|
1092
1221
|
|
|
1093
1222
|
export type AdmitJudgeInvocationOptions = {
|
|
@@ -1105,6 +1234,8 @@ export type AdmitJudgeInvocationOptions = {
|
|
|
1105
1234
|
|
|
1106
1235
|
export type AdmitInspectorInvocationOptions = AdmitJudgeInvocationOptions & {
|
|
1107
1236
|
correlationId?: string;
|
|
1237
|
+
/** Typed identity handed off by 起居郎 or inherited from an already-bound run. */
|
|
1238
|
+
assertedTicketNumber?: number;
|
|
1108
1239
|
};
|
|
1109
1240
|
|
|
1110
1241
|
export type AdmitGatekeeperInvocationOptions = AdmitInspectorInvocationOptions;
|
|
@@ -1121,7 +1252,7 @@ async function admitStandardMaterialInvocation<
|
|
|
1121
1252
|
R extends "judge" | "inspector" | "gatekeeper" | "navigator" | "auditor" | "diarist",
|
|
1122
1253
|
>(
|
|
1123
1254
|
role: R,
|
|
1124
|
-
options:
|
|
1255
|
+
options: AdmitInspectorInvocationOptions,
|
|
1125
1256
|
): Promise<AdmittedRoleInvocationBase & { readonly role: R }> {
|
|
1126
1257
|
// Empty project override must not reach resolve("") → cwd (silent default).
|
|
1127
1258
|
if (options.project !== undefined) {
|
|
@@ -1129,22 +1260,25 @@ async function admitStandardMaterialInvocation<
|
|
|
1129
1260
|
}
|
|
1130
1261
|
const projectRoot = resolve(options.project ?? options.cwd);
|
|
1131
1262
|
const runId = (options.createRunId ?? uuidv7)();
|
|
1263
|
+
// Validate asserted ticket before placement so 0/NaN never become subjects.
|
|
1264
|
+
const ticketFields = ticketAdmissionFields(options.assertedTicketNumber);
|
|
1132
1265
|
const {
|
|
1133
1266
|
principal,
|
|
1134
1267
|
sessionDirectory,
|
|
1135
1268
|
sessionFile,
|
|
1136
1269
|
runDirectory,
|
|
1270
|
+
attachmentsDirectory,
|
|
1137
1271
|
ledgerHome,
|
|
1138
1272
|
bookKey,
|
|
1139
1273
|
} = issueAdmissionPlacement(options.principalAuthority, {
|
|
1140
1274
|
cwd: projectRoot,
|
|
1141
1275
|
runId,
|
|
1142
1276
|
role,
|
|
1277
|
+
subject: ticketFields.ticketNumber === undefined
|
|
1278
|
+
? { unbound: true }
|
|
1279
|
+
: { ticketNumber: ticketFields.ticketNumber },
|
|
1143
1280
|
home: options.home,
|
|
1144
1281
|
});
|
|
1145
|
-
const attachmentsDirectory = join(runDirectory, "attachments");
|
|
1146
|
-
ensureRealDirectoryTree(ledgerHome, sessionDirectory);
|
|
1147
|
-
ensureRealDirectoryTree(ledgerHome, attachmentsDirectory);
|
|
1148
1282
|
|
|
1149
1283
|
const attachments = await freezeAttachments(options.attachmentPaths, attachmentsDirectory);
|
|
1150
1284
|
const correlationFields =
|
|
@@ -1171,6 +1305,7 @@ async function admitStandardMaterialInvocation<
|
|
|
1171
1305
|
sha256: a.sha256,
|
|
1172
1306
|
mediaKind: a.mediaKind,
|
|
1173
1307
|
})),
|
|
1308
|
+
...ticketFields,
|
|
1174
1309
|
};
|
|
1175
1310
|
const admittedRequestPath = join(runDirectory, "admitted-request.json");
|
|
1176
1311
|
await writeAdmittedRequestPersistence(admittedRequestPath, admitted, {
|
|
@@ -1195,6 +1330,7 @@ async function admitStandardMaterialInvocation<
|
|
|
1195
1330
|
principal,
|
|
1196
1331
|
admittedRequestPath,
|
|
1197
1332
|
...correlationFields,
|
|
1333
|
+
...ticketFields,
|
|
1198
1334
|
};
|
|
1199
1335
|
}
|
|
1200
1336
|
|
|
@@ -1322,17 +1458,16 @@ export async function admitCountersignInvocation(
|
|
|
1322
1458
|
sessionDirectory,
|
|
1323
1459
|
sessionFile,
|
|
1324
1460
|
runDirectory,
|
|
1461
|
+
attachmentsDirectory,
|
|
1325
1462
|
ledgerHome,
|
|
1326
1463
|
bookKey,
|
|
1327
1464
|
} = issueAdmissionPlacement(options.principalAuthority, {
|
|
1328
1465
|
cwd: projectRoot,
|
|
1329
1466
|
runId,
|
|
1330
1467
|
role: "countersign",
|
|
1468
|
+
subject: { unbound: true },
|
|
1331
1469
|
home: options.home,
|
|
1332
1470
|
});
|
|
1333
|
-
const attachmentsDirectory = join(runDirectory, "attachments");
|
|
1334
|
-
ensureRealDirectoryTree(ledgerHome, sessionDirectory);
|
|
1335
|
-
ensureRealDirectoryTree(ledgerHome, attachmentsDirectory);
|
|
1336
1471
|
|
|
1337
1472
|
const attachments = await freezeAttachments(options.attachmentPaths, attachmentsDirectory);
|
|
1338
1473
|
// Ticket binding is LLM-only post-admission (#635); admission stays unbound.
|
|
@@ -1416,9 +1551,11 @@ export async function loadAdmittedJudgeRequest(
|
|
|
1416
1551
|
}
|
|
1417
1552
|
|
|
1418
1553
|
export async function ensureRunArtifactsDir(runDirectory: string): Promise<string> {
|
|
1419
|
-
const
|
|
1420
|
-
|
|
1421
|
-
|
|
1554
|
+
const directory = roleRunArtifactsDirectory(runDirectory);
|
|
1555
|
+
return ensureRoleRunDirectory(
|
|
1556
|
+
resolveActivationLedgerHome(homeFromRunDirectory(runDirectory)),
|
|
1557
|
+
directory,
|
|
1558
|
+
);
|
|
1422
1559
|
}
|
|
1423
1560
|
|
|
1424
1561
|
export type AdmitCoderInvocationOptions = {
|
|
@@ -1462,17 +1599,16 @@ export async function admitCoderInvocation(
|
|
|
1462
1599
|
sessionDirectory,
|
|
1463
1600
|
sessionFile,
|
|
1464
1601
|
runDirectory,
|
|
1602
|
+
attachmentsDirectory,
|
|
1465
1603
|
ledgerHome,
|
|
1466
1604
|
bookKey,
|
|
1467
1605
|
} = issueAdmissionPlacement(options.principalAuthority, {
|
|
1468
1606
|
cwd: projectRoot,
|
|
1469
1607
|
runId,
|
|
1470
1608
|
role: "coder",
|
|
1609
|
+
subject: { unbound: true },
|
|
1471
1610
|
home: options.home,
|
|
1472
1611
|
});
|
|
1473
|
-
const attachmentsDirectory = join(runDirectory, "attachments");
|
|
1474
|
-
ensureRealDirectoryTree(ledgerHome, sessionDirectory);
|
|
1475
|
-
ensureRealDirectoryTree(ledgerHome, attachmentsDirectory);
|
|
1476
1612
|
|
|
1477
1613
|
const attachments = await freezeAttachments(options.attachmentPaths, attachmentsDirectory);
|
|
1478
1614
|
|
|
@@ -1609,17 +1745,16 @@ export async function admitFixerInvocation(
|
|
|
1609
1745
|
sessionDirectory,
|
|
1610
1746
|
sessionFile,
|
|
1611
1747
|
runDirectory,
|
|
1748
|
+
attachmentsDirectory,
|
|
1612
1749
|
ledgerHome,
|
|
1613
1750
|
bookKey,
|
|
1614
1751
|
} = issueAdmissionPlacement(options.principalAuthority, {
|
|
1615
1752
|
cwd: projectRoot,
|
|
1616
1753
|
runId,
|
|
1617
1754
|
role: "fixer",
|
|
1755
|
+
subject: { unbound: true },
|
|
1618
1756
|
home: options.home,
|
|
1619
1757
|
});
|
|
1620
|
-
const attachmentsDirectory = join(runDirectory, "attachments");
|
|
1621
|
-
ensureRealDirectoryTree(ledgerHome, sessionDirectory);
|
|
1622
|
-
ensureRealDirectoryTree(ledgerHome, attachmentsDirectory);
|
|
1623
1758
|
|
|
1624
1759
|
const attachments = await freezeAttachments(options.attachmentPaths, attachmentsDirectory);
|
|
1625
1760
|
|
|
@@ -1916,17 +2051,16 @@ export async function admitCollectorInvocation(
|
|
|
1916
2051
|
sessionDirectory,
|
|
1917
2052
|
sessionFile,
|
|
1918
2053
|
runDirectory,
|
|
2054
|
+
attachmentsDirectory,
|
|
1919
2055
|
ledgerHome,
|
|
1920
2056
|
bookKey,
|
|
1921
2057
|
} = issueAdmissionPlacement(options.principalAuthority, {
|
|
1922
2058
|
cwd: projectRoot,
|
|
1923
2059
|
runId,
|
|
1924
2060
|
role: "collector",
|
|
2061
|
+
subject: { unbound: true },
|
|
1925
2062
|
home: options.home,
|
|
1926
2063
|
});
|
|
1927
|
-
const attachmentsDirectory = join(runDirectory, "attachments");
|
|
1928
|
-
ensureRealDirectoryTree(ledgerHome, sessionDirectory);
|
|
1929
|
-
ensureRealDirectoryTree(ledgerHome, attachmentsDirectory);
|
|
1930
2064
|
|
|
1931
2065
|
// #676 A: freeze task materials BEFORE target resolution so the role receives
|
|
1932
2066
|
// real instruction + attachments. Admission binds only explicit --pr or unique
|
|
@@ -2013,8 +2147,9 @@ export function buildCollectorTransportPrompt(
|
|
|
2013
2147
|
const DOCTOR_ISSUE_NUMBER_PATTERN = /^[1-9]\d*$/;
|
|
2014
2148
|
|
|
2015
2149
|
/** Match retained Doctor case runs roots (ADR 0017 / loadDoctorCase). */
|
|
2150
|
+
/** Canonical Doctor case: `<book>/<ticket>/runs`. Legacy `issues/<n>/runs` is read-only compat. */
|
|
2016
2151
|
const DOCTOR_CASE_RUNS_PATH_PATTERN =
|
|
2017
|
-
/\/\.ak-roles\/books\/[^/]+\/issues\/([1-9]\d*)\/runs$/;
|
|
2152
|
+
/\/\.ak-roles\/books\/[^/]+\/(?:issues\/)?([1-9]\d*)\/runs$/;
|
|
2018
2153
|
|
|
2019
2154
|
/**
|
|
2020
2155
|
* Parse a positive Issue number for public Doctor admission.
|
|
@@ -2129,9 +2264,9 @@ export async function resolveDoctorCaseRunsPath(options: {
|
|
|
2129
2264
|
runs?: string;
|
|
2130
2265
|
}): Promise<string> {
|
|
2131
2266
|
const ledgerHome = resolveActivationLedgerHome(options.home);
|
|
2267
|
+
// Canonical topology: <book>/<ticket>/runs (docs/dossier-topology.md).
|
|
2132
2268
|
const defaultRuns = join(
|
|
2133
2269
|
activationBookDirectory(ledgerHome, options.bookKey),
|
|
2134
|
-
"issues",
|
|
2135
2270
|
String(options.issueNumber),
|
|
2136
2271
|
"runs",
|
|
2137
2272
|
);
|
|
@@ -2175,7 +2310,7 @@ export async function resolveDoctorCaseRunsPath(options: {
|
|
|
2175
2310
|
const match = normalized.match(DOCTOR_CASE_RUNS_PATH_PATTERN);
|
|
2176
2311
|
if (!match) {
|
|
2177
2312
|
throw new CliUsageError(
|
|
2178
|
-
"doctor --runs must be an .ak-roles/books/<book
|
|
2313
|
+
"doctor --runs must be an .ak-roles/books/<book>/<n>/runs directory",
|
|
2179
2314
|
);
|
|
2180
2315
|
}
|
|
2181
2316
|
if (Number(match[1]) !== options.issueNumber) {
|
|
@@ -2215,12 +2350,14 @@ export async function admitDoctorInvocation(
|
|
|
2215
2350
|
sessionDirectory,
|
|
2216
2351
|
sessionFile,
|
|
2217
2352
|
runDirectory,
|
|
2353
|
+
attachmentsDirectory,
|
|
2218
2354
|
ledgerHome,
|
|
2219
2355
|
bookKey,
|
|
2220
2356
|
} = issueAdmissionPlacement(options.principalAuthority, {
|
|
2221
2357
|
cwd: projectRoot,
|
|
2222
2358
|
runId,
|
|
2223
2359
|
role: "doctor",
|
|
2360
|
+
subject: { unbound: true },
|
|
2224
2361
|
home: options.home,
|
|
2225
2362
|
});
|
|
2226
2363
|
|
|
@@ -2264,9 +2401,6 @@ export async function admitDoctorInvocation(
|
|
|
2264
2401
|
);
|
|
2265
2402
|
}
|
|
2266
2403
|
|
|
2267
|
-
const attachmentsDirectory = join(runDirectory, "attachments");
|
|
2268
|
-
ensureRealDirectoryTree(ledgerHome, sessionDirectory);
|
|
2269
|
-
ensureRealDirectoryTree(ledgerHome, attachmentsDirectory);
|
|
2270
2404
|
|
|
2271
2405
|
const attachments = await freezeAttachments(options.attachmentPaths ?? [], attachmentsDirectory);
|
|
2272
2406
|
|
|
@@ -2421,24 +2555,27 @@ export async function admitNotaryInvocation(options: {
|
|
|
2421
2555
|
throw error;
|
|
2422
2556
|
}
|
|
2423
2557
|
|
|
2558
|
+
// Notary inherits board identity only — migration-derived stays display/placement.
|
|
2559
|
+
const inheritedTicketNumber = await readBoardTicketNumber(sourceRun.runDirectory);
|
|
2424
2560
|
const runId = options.createRunId?.() ?? uuidv7();
|
|
2425
2561
|
const {
|
|
2426
2562
|
principal,
|
|
2427
2563
|
sessionDirectory,
|
|
2428
2564
|
sessionFile,
|
|
2429
2565
|
runDirectory,
|
|
2566
|
+
attachmentsDirectory,
|
|
2430
2567
|
ledgerHome,
|
|
2431
2568
|
bookKey,
|
|
2432
2569
|
} = issueAdmissionPlacement(options.principalAuthority, {
|
|
2433
2570
|
cwd: projectRoot,
|
|
2434
2571
|
runId,
|
|
2435
2572
|
role: "notary",
|
|
2573
|
+
subject: inheritedTicketNumber === undefined
|
|
2574
|
+
? { unbound: true }
|
|
2575
|
+
: { ticketNumber: inheritedTicketNumber },
|
|
2436
2576
|
home: options.home,
|
|
2437
2577
|
});
|
|
2438
|
-
|
|
2439
|
-
const ticketFields = ticketAdmissionFields(
|
|
2440
|
-
await readRunTicketNumber(sourceRun.runDirectory),
|
|
2441
|
-
);
|
|
2578
|
+
const ticketFields = ticketAdmissionFields(inheritedTicketNumber);
|
|
2442
2579
|
|
|
2443
2580
|
const admitted = {
|
|
2444
2581
|
role: "notary" as const,
|
|
@@ -2580,15 +2717,16 @@ export async function admitGleanerLeftInvocation(
|
|
|
2580
2717
|
sessionDirectory,
|
|
2581
2718
|
sessionFile,
|
|
2582
2719
|
runDirectory,
|
|
2720
|
+
attachmentsDirectory,
|
|
2583
2721
|
ledgerHome,
|
|
2584
2722
|
bookKey,
|
|
2585
2723
|
} = issueAdmissionPlacement(options.principalAuthority, {
|
|
2586
2724
|
cwd: projectRoot,
|
|
2587
2725
|
runId,
|
|
2588
2726
|
role: "gleaner-left",
|
|
2727
|
+
subject: { unbound: true },
|
|
2589
2728
|
home: options.home,
|
|
2590
2729
|
});
|
|
2591
|
-
ensureRealDirectoryTree(ledgerHome, sessionDirectory);
|
|
2592
2730
|
|
|
2593
2731
|
const instruction = options.instruction;
|
|
2594
2732
|
const instructionEmpty = instruction.trim() === "";
|
|
@@ -2744,17 +2882,16 @@ export async function admitReviewerInvocation(
|
|
|
2744
2882
|
sessionDirectory,
|
|
2745
2883
|
sessionFile,
|
|
2746
2884
|
runDirectory,
|
|
2885
|
+
attachmentsDirectory,
|
|
2747
2886
|
ledgerHome,
|
|
2748
2887
|
bookKey,
|
|
2749
2888
|
} = issueAdmissionPlacement(options.principalAuthority, {
|
|
2750
2889
|
cwd: projectRoot,
|
|
2751
2890
|
runId,
|
|
2752
2891
|
role: "reviewer",
|
|
2892
|
+
subject: { unbound: true },
|
|
2753
2893
|
home: options.home,
|
|
2754
2894
|
});
|
|
2755
|
-
const attachmentsDirectory = join(runDirectory, "attachments");
|
|
2756
|
-
ensureRealDirectoryTree(ledgerHome, sessionDirectory);
|
|
2757
|
-
ensureRealDirectoryTree(ledgerHome, attachmentsDirectory);
|
|
2758
2895
|
|
|
2759
2896
|
// Public parse already rejects attachments; keep freeze loop for structural symmetry.
|
|
2760
2897
|
const attachments = await freezeAttachments(options.attachmentPaths, attachmentsDirectory);
|
|
@@ -2953,17 +3090,16 @@ export async function admitMergerInvocation(
|
|
|
2953
3090
|
sessionDirectory,
|
|
2954
3091
|
sessionFile,
|
|
2955
3092
|
runDirectory,
|
|
3093
|
+
attachmentsDirectory,
|
|
2956
3094
|
ledgerHome,
|
|
2957
3095
|
bookKey,
|
|
2958
3096
|
} = issueAdmissionPlacement(options.principalAuthority, {
|
|
2959
3097
|
cwd: projectRoot,
|
|
2960
3098
|
runId,
|
|
2961
3099
|
role: "merger",
|
|
3100
|
+
subject: { unbound: true },
|
|
2962
3101
|
home: options.home,
|
|
2963
3102
|
});
|
|
2964
|
-
const attachmentsDirectory = join(runDirectory, "attachments");
|
|
2965
|
-
ensureRealDirectoryTree(ledgerHome, sessionDirectory);
|
|
2966
|
-
ensureRealDirectoryTree(ledgerHome, attachmentsDirectory);
|
|
2967
3103
|
|
|
2968
3104
|
const attachments = await freezeAttachments(options.attachmentPaths, attachmentsDirectory);
|
|
2969
3105
|
|
|
@@ -52,6 +52,12 @@ export type NotaryRunEnv = PostAdmissionEnv & {
|
|
|
52
52
|
* Never a public CLI argv — external callers still have zero prompt.
|
|
53
53
|
*/
|
|
54
54
|
reviewReask?: string;
|
|
55
|
+
/**
|
|
56
|
+
* #879 gate summons: verbatim parent-submission body for officer dialogue content.
|
|
57
|
+
* Rides summons.instruction / first-mint prompt when reviewReask is absent.
|
|
58
|
+
* Binding pointer stays --source-run (independent machine material).
|
|
59
|
+
*/
|
|
60
|
+
gateReviewInstruction?: string;
|
|
55
61
|
};
|
|
56
62
|
|
|
57
63
|
/** Project admitted invocation onto the host-neutral turn request. */
|
|
@@ -115,10 +121,10 @@ export async function runPublicNotary(
|
|
|
115
121
|
throw error;
|
|
116
122
|
}
|
|
117
123
|
// #747: officer resume key is this parent source-run path (not ticket number).
|
|
118
|
-
// #753/#
|
|
119
|
-
// (reask wins when both present; no parallel stack).
|
|
124
|
+
// #753/#879: gate re-ask and verbatim submission body share summons.instruction
|
|
125
|
+
// (reask wins when both present; no parallel stack). Binding stays sourceRunPath.
|
|
120
126
|
{
|
|
121
|
-
const resumeInstruction = env.reviewReask;
|
|
127
|
+
const resumeInstruction = env.reviewReask ?? env.gateReviewInstruction;
|
|
122
128
|
const summons: SameTicketSummonsMaterials = {
|
|
123
129
|
sourceRunPath: source.runDirectory,
|
|
124
130
|
sourceRun: source,
|
|
@@ -181,7 +187,10 @@ export async function runPublicNotary(
|
|
|
181
187
|
: { correlationId: env.correlationId }),
|
|
182
188
|
continuation: {
|
|
183
189
|
kind: "initial",
|
|
184
|
-
|
|
190
|
+
// #879: gate path first mint carries parent payload as dialogue content;
|
|
191
|
+
// external zero-prompt kickoff unchanged when no body/reask.
|
|
192
|
+
prompt: (env.reviewReask ?? env.gateReviewInstruction)
|
|
193
|
+
?? buildNotaryTransportPrompt(admitted, engineMaterial),
|
|
185
194
|
},
|
|
186
195
|
});
|
|
187
196
|
|
|
@@ -645,8 +645,8 @@ const DOCTOR_OPTIONS = [
|
|
|
645
645
|
repeatable: false,
|
|
646
646
|
form: "option",
|
|
647
647
|
description: {
|
|
648
|
-
en: "Optional project-relative .ak-roles/books/<book
|
|
649
|
-
zh: "可选项目相对 .ak-roles/books/<book
|
|
648
|
+
en: "Optional project-relative .ak-roles/books/<book>/<n>/runs override matching --issue.",
|
|
649
|
+
zh: "可选项目相对 .ak-roles/books/<book>/<n>/runs 覆盖,且须匹配 --issue。",
|
|
650
650
|
},
|
|
651
651
|
},
|
|
652
652
|
] as const satisfies readonly PublicOptionDefinition[];
|