@akagilnc/pi-workflow-roles 0.1.4062 → 0.1.4196
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 +2075 -1088
- 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-evidence.js +3 -2
- package/dist/headless-host/production-host.js +2215 -1228
- 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/pi/durable-principal.js +9 -6
- package/dist/public-cli/auto-resume.js +2 -5
- package/dist/public-cli/diarist-run.js +27 -25
- package/dist/public-cli/instruction-seat-run.js +8 -11
- package/dist/public-cli/invocation.js +127 -63
- package/dist/public-cli/main.js +1507 -645
- package/dist/public-cli/option-definitions.js +2 -2
- package/dist/public-cli/post-admission.js +47 -12
- package/dist/public-cli/run-lifecycle.js +206 -58
- package/dist/public-cli/seat-ticket-binding.js +3 -6
- package/dist/public-cli/settlement.js +5 -3
- 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 +78 -19
- package/dist/ticket-provenance.js +3 -1
- package/package.json +3 -2
- package/scripts/build-package.mjs +34 -2
- package/souls/countersign.md +2 -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-evidence.ts +4 -1
- package/src/doctor-role.ts +1 -1
- package/src/navigator-public-session.ts +33 -30
- package/src/notary-source-run.ts +9 -4
- package/src/pi/durable-principal.ts +9 -13
- package/src/public-cli/auto-resume.ts +2 -6
- package/src/public-cli/countersign-run.ts +182 -32
- package/src/public-cli/diarist-run.ts +34 -26
- package/src/public-cli/instruction-seat-run.ts +7 -11
- package/src/public-cli/invocation.ts +192 -58
- package/src/public-cli/option-definitions.ts +2 -2
- package/src/public-cli/post-admission.ts +73 -13
- package/src/public-cli/run-lifecycle.ts +255 -65
- package/src/public-cli/seat-ticket-binding.ts +3 -6
- package/src/public-cli/settlement.ts +6 -4
- package/src/role-run-placement.ts +128 -0
- package/src/role-run-relocation.ts +491 -0
- package/src/role-runtime.ts +11 -5
- 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 +102 -19
- package/src/ticket-provenance.ts +4 -1
- package/src/ticket-trajectory.ts +22 -35
- package/src/worker-role.ts +4 -4
- package/src/worker-submission-gates.ts +6 -6
|
@@ -4,12 +4,15 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import { execFileSync } from "node:child_process";
|
|
6
6
|
import { existsSync } from "node:fs";
|
|
7
|
-
import { lstat,
|
|
8
|
-
import { basename, isAbsolute, join, resolve, sep } from "node:path";
|
|
7
|
+
import { lstat, readFile, realpath, rename, writeFile, } from "node:fs/promises";
|
|
8
|
+
import { basename, dirname, isAbsolute, join, resolve, sep } from "node:path";
|
|
9
9
|
import { activationBookDirectory, ensureRealDirectoryTree, homeFromRunDirectory, pathContainedIn, resolveActivationLedgerHome, } from "../activation-ledger-topology.js";
|
|
10
10
|
import { resolveBookKeyFromGit } from "../activation-ledger-git.js";
|
|
11
|
-
import {
|
|
11
|
+
import { ensureRoleRunDirectory, ensureRoleRunPlacement, roleRunArtifactsDirectory, roleRunPlacement, } from "../role-run-placement.js";
|
|
12
|
+
import { isSafePositiveTicketNumber, readBoardTicketNumber, requireSafePositiveTicketNumber, } from "../run-ticket-number.js";
|
|
13
|
+
import { rewriteRoleRunDurablePages, rewriteRunDirectoryPathFields, rewriteRunDirectoryPathValue, } from "../role-run-relocation.js";
|
|
12
14
|
import { loadDoctorCase, } from "../doctor-evidence.js";
|
|
15
|
+
import { projectCourtTicketNumbers } from "../diarist-contracts.js";
|
|
13
16
|
import { emptyCollectorManifest, loadCollectorManifest, parseCollectorPrNumber, parseCollectorRepository, } from "../collector-config.js";
|
|
14
17
|
import { resolveCollectorTarget } from "../collector-target.js";
|
|
15
18
|
import { ownerRepoFromGitHubRemoteUrl } from "./github-remote.js";
|
|
@@ -23,18 +26,20 @@ import { NotarySourceRunError, resolveNotarySourceRunLocator, } from "../notary-
|
|
|
23
26
|
import { appendEngineSessionMaterial, } from "../package-resources/engine-material.js";
|
|
24
27
|
import { CliUsageError } from "./cli-errors.js";
|
|
25
28
|
import { REJECTED_PUBLIC_SPELLINGS, createTypedOptionConsumer, evaluateAnalystModeOptionContract, optionsForOwner, resolveAnalystMode, } from "./option-definitions.js";
|
|
26
|
-
/** Issue principal
|
|
29
|
+
/** Issue a principal from the single authoritative role-run placement. */
|
|
27
30
|
export function issueAdmissionPlacement(authority, request) {
|
|
28
|
-
const principal = authority.issue(request);
|
|
29
|
-
const { sessionDirectory, sessionFile } = authority.decode(principal);
|
|
30
|
-
const runDirectory = join(sessionDirectory, "..");
|
|
31
31
|
const ledgerHome = resolveActivationLedgerHome(request.home);
|
|
32
32
|
const bookKey = resolveBookKeyFromGit(request.cwd);
|
|
33
|
+
const placement = roleRunPlacement(ledgerHome, {
|
|
34
|
+
bookKey,
|
|
35
|
+
subject: request.subject,
|
|
36
|
+
runId: request.runId,
|
|
37
|
+
role: request.role,
|
|
38
|
+
});
|
|
39
|
+
ensureRoleRunPlacement(ledgerHome, placement);
|
|
33
40
|
return {
|
|
34
|
-
principal,
|
|
35
|
-
|
|
36
|
-
sessionFile,
|
|
37
|
-
runDirectory,
|
|
41
|
+
principal: authority.seal(placement),
|
|
42
|
+
...placement,
|
|
38
43
|
ledgerHome,
|
|
39
44
|
bookKey,
|
|
40
45
|
};
|
|
@@ -159,19 +164,81 @@ export async function persistAdmittedSourceRunPath(admitted, sourceRunPath) {
|
|
|
159
164
|
* Never clears an existing binding.
|
|
160
165
|
*/
|
|
161
166
|
export async function bindAdmittedTicketNumber(admitted, ticketNumber) {
|
|
162
|
-
if (!Number.isSafeInteger(ticketNumber) || ticketNumber < 1) {
|
|
163
|
-
throw new Error(`bindAdmittedTicketNumber requires a safe positive integer, got ${String(ticketNumber)}`);
|
|
164
|
-
}
|
|
165
167
|
if (admitted.ticketNumber !== undefined) {
|
|
166
168
|
if (admitted.ticketNumber === ticketNumber)
|
|
167
169
|
return;
|
|
168
170
|
throw new Error(`bindAdmittedTicketNumber refuses to replace existing ticket #${admitted.ticketNumber} with #${ticketNumber}`);
|
|
169
171
|
}
|
|
172
|
+
await bindTicketNumberOnRunDirectory(admitted.runDirectory, ticketNumber);
|
|
170
173
|
admitted.ticketNumber = ticketNumber;
|
|
171
|
-
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* #871: persist the typed co-review set as a countersign run fact (admitted-request +
|
|
177
|
+
* invocation.json). Whole-set replace — never union with a prior set. Main ticket
|
|
178
|
+
* binding stays on `ticketNumber` alone. Projection reuses the sole contract helper;
|
|
179
|
+
* principal membership is mandatory.
|
|
180
|
+
*/
|
|
181
|
+
export async function bindCourtTicketNumbersOnAdmitted(admitted, courtTicketNumbers) {
|
|
182
|
+
if (admitted.ticketNumber === undefined) {
|
|
183
|
+
throw new Error("bindCourtTicketNumbersOnAdmitted requires a bound principal ticketNumber");
|
|
184
|
+
}
|
|
185
|
+
const principal = requireSafePositiveTicketNumber(admitted.ticketNumber, "bindCourtTicketNumbersOnAdmitted principal ticketNumber");
|
|
186
|
+
// Strict write path: every member must already be a lawful number (no soft filter).
|
|
187
|
+
for (const item of courtTicketNumbers) {
|
|
188
|
+
if (!isSafePositiveTicketNumber(item)) {
|
|
189
|
+
throw new Error(`bindCourtTicketNumbersOnAdmitted requires safe positive integers, got ${String(item)}`);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
const projected = projectCourtTicketNumbers(courtTicketNumbers, {
|
|
193
|
+
principalTicket: principal,
|
|
194
|
+
});
|
|
195
|
+
if (projected === null || projected.length === 0) {
|
|
196
|
+
throw new Error("bindCourtTicketNumbersOnAdmitted requires a non-empty ticket set");
|
|
197
|
+
}
|
|
198
|
+
const frozen = Object.freeze([...projected]);
|
|
172
199
|
const admittedPath = admitted.admittedRequestPath;
|
|
173
200
|
const current = JSON.parse(await readFile(admittedPath, "utf8"));
|
|
174
|
-
await writeFile(admittedPath, `${JSON.stringify({ ...current,
|
|
201
|
+
await writeFile(admittedPath, `${JSON.stringify({ ...current, courtTicketNumbers: frozen }, null, 2)}\n`, "utf8");
|
|
202
|
+
await mergeInvocationIdentityPage(admitted.runDirectory, {
|
|
203
|
+
courtTicketNumbers: frozen,
|
|
204
|
+
});
|
|
205
|
+
admitted.courtTicketNumbers = frozen;
|
|
206
|
+
}
|
|
207
|
+
/** Move a settled first-entry run from unbound to its asserted ticket directory. */
|
|
208
|
+
export async function relocateAdmittedRunToTicket(admitted, authority, heldLease) {
|
|
209
|
+
if (admitted.ticketNumber === undefined || !admitted.runDirectory.includes(`${sep}unbound${sep}runs${sep}`))
|
|
210
|
+
return;
|
|
211
|
+
const oldRunDirectory = admitted.runDirectory;
|
|
212
|
+
const ledgerHome = resolveActivationLedgerHome(homeFromRunDirectory(oldRunDirectory));
|
|
213
|
+
const target = roleRunPlacement(ledgerHome, {
|
|
214
|
+
bookKey: admitted.bookKey,
|
|
215
|
+
subject: { ticketNumber: admitted.ticketNumber },
|
|
216
|
+
runId: admitted.runId,
|
|
217
|
+
role: admitted.role,
|
|
218
|
+
});
|
|
219
|
+
ensureRoleRunDirectory(ledgerHome, dirname(target.runDirectory));
|
|
220
|
+
await rename(oldRunDirectory, target.runDirectory);
|
|
221
|
+
heldLease?.relocate(target.runDirectory);
|
|
222
|
+
const admittedRecord = admitted;
|
|
223
|
+
rewriteRunDirectoryPathFields(admittedRecord, [
|
|
224
|
+
"runDirectory",
|
|
225
|
+
"admittedRequestPath",
|
|
226
|
+
"taskPath",
|
|
227
|
+
"packetPath",
|
|
228
|
+
"prerequisitesPath",
|
|
229
|
+
"requestManifestPath",
|
|
230
|
+
"mergerInputPath",
|
|
231
|
+
], oldRunDirectory, target.runDirectory);
|
|
232
|
+
for (const attachment of admitted.attachments) {
|
|
233
|
+
attachment.frozenPath = rewriteRunDirectoryPathValue(attachment.frozenPath, oldRunDirectory, target.runDirectory);
|
|
234
|
+
}
|
|
235
|
+
const principal = authority.seal(target);
|
|
236
|
+
admitted.principal = principal;
|
|
237
|
+
await rewriteRoleRunDurablePages({
|
|
238
|
+
pagesDirectory: target.runDirectory,
|
|
239
|
+
oldRunDirectory,
|
|
240
|
+
newRunDirectory: target.runDirectory,
|
|
241
|
+
});
|
|
175
242
|
}
|
|
176
243
|
/**
|
|
177
244
|
* Bind ticket identity onto a run directory's durable pages when the admitted
|
|
@@ -179,9 +246,7 @@ export async function bindAdmittedTicketNumber(admitted, ticketNumber) {
|
|
|
179
246
|
* Idempotent when the same number is already on the pages.
|
|
180
247
|
*/
|
|
181
248
|
export async function bindTicketNumberOnRunDirectory(runDirectory, ticketNumber) {
|
|
182
|
-
|
|
183
|
-
throw new Error(`bindTicketNumberOnRunDirectory requires a safe positive integer, got ${String(ticketNumber)}`);
|
|
184
|
-
}
|
|
249
|
+
requireSafePositiveTicketNumber(ticketNumber, "bindTicketNumberOnRunDirectory");
|
|
185
250
|
const admittedPath = join(runDirectory, "admitted-request.json");
|
|
186
251
|
const invocationPath = join(runDirectory, "invocation.json");
|
|
187
252
|
const admitted = JSON.parse(await readFile(admittedPath, "utf8"));
|
|
@@ -526,7 +591,11 @@ export async function freezeAttachmentsIntoRun(attachmentPaths, runDirectory, su
|
|
|
526
591
|
return freezeAttachments(attachmentPaths, attachmentsDirectory);
|
|
527
592
|
}
|
|
528
593
|
function ticketAdmissionFields(ticketNumber) {
|
|
529
|
-
|
|
594
|
+
if (ticketNumber === undefined)
|
|
595
|
+
return {};
|
|
596
|
+
return {
|
|
597
|
+
ticketNumber: requireSafePositiveTicketNumber(ticketNumber, "assertedTicketNumber"),
|
|
598
|
+
};
|
|
530
599
|
}
|
|
531
600
|
/**
|
|
532
601
|
* Shared instruction-seat admission for Judge and Inspector: project check,
|
|
@@ -541,15 +610,17 @@ async function admitStandardMaterialInvocation(role, options) {
|
|
|
541
610
|
}
|
|
542
611
|
const projectRoot = resolve(options.project ?? options.cwd);
|
|
543
612
|
const runId = (options.createRunId ?? uuidv7)();
|
|
544
|
-
|
|
613
|
+
// Validate asserted ticket before placement so 0/NaN never become subjects.
|
|
614
|
+
const ticketFields = ticketAdmissionFields(options.assertedTicketNumber);
|
|
615
|
+
const { principal, sessionDirectory, sessionFile, runDirectory, attachmentsDirectory, ledgerHome, bookKey, } = issueAdmissionPlacement(options.principalAuthority, {
|
|
545
616
|
cwd: projectRoot,
|
|
546
617
|
runId,
|
|
547
618
|
role,
|
|
619
|
+
subject: ticketFields.ticketNumber === undefined
|
|
620
|
+
? { unbound: true }
|
|
621
|
+
: { ticketNumber: ticketFields.ticketNumber },
|
|
548
622
|
home: options.home,
|
|
549
623
|
});
|
|
550
|
-
const attachmentsDirectory = join(runDirectory, "attachments");
|
|
551
|
-
ensureRealDirectoryTree(ledgerHome, sessionDirectory);
|
|
552
|
-
ensureRealDirectoryTree(ledgerHome, attachmentsDirectory);
|
|
553
624
|
const attachments = await freezeAttachments(options.attachmentPaths, attachmentsDirectory);
|
|
554
625
|
const correlationFields = options.correlationId === undefined
|
|
555
626
|
? {}
|
|
@@ -573,6 +644,7 @@ async function admitStandardMaterialInvocation(role, options) {
|
|
|
573
644
|
sha256: a.sha256,
|
|
574
645
|
mediaKind: a.mediaKind,
|
|
575
646
|
})),
|
|
647
|
+
...ticketFields,
|
|
576
648
|
};
|
|
577
649
|
const admittedRequestPath = join(runDirectory, "admitted-request.json");
|
|
578
650
|
await writeAdmittedRequestPersistence(admittedRequestPath, admitted, {
|
|
@@ -592,6 +664,7 @@ async function admitStandardMaterialInvocation(role, options) {
|
|
|
592
664
|
principal,
|
|
593
665
|
admittedRequestPath,
|
|
594
666
|
...correlationFields,
|
|
667
|
+
...ticketFields,
|
|
595
668
|
};
|
|
596
669
|
}
|
|
597
670
|
/**
|
|
@@ -664,15 +737,13 @@ export async function admitCountersignInvocation(options) {
|
|
|
664
737
|
}
|
|
665
738
|
const projectRoot = resolve(options.project ?? options.cwd);
|
|
666
739
|
const runId = (options.createRunId ?? uuidv7)();
|
|
667
|
-
const { principal, sessionDirectory, sessionFile, runDirectory, ledgerHome, bookKey, } = issueAdmissionPlacement(options.principalAuthority, {
|
|
740
|
+
const { principal, sessionDirectory, sessionFile, runDirectory, attachmentsDirectory, ledgerHome, bookKey, } = issueAdmissionPlacement(options.principalAuthority, {
|
|
668
741
|
cwd: projectRoot,
|
|
669
742
|
runId,
|
|
670
743
|
role: "countersign",
|
|
744
|
+
subject: { unbound: true },
|
|
671
745
|
home: options.home,
|
|
672
746
|
});
|
|
673
|
-
const attachmentsDirectory = join(runDirectory, "attachments");
|
|
674
|
-
ensureRealDirectoryTree(ledgerHome, sessionDirectory);
|
|
675
|
-
ensureRealDirectoryTree(ledgerHome, attachmentsDirectory);
|
|
676
747
|
const attachments = await freezeAttachments(options.attachmentPaths, attachmentsDirectory);
|
|
677
748
|
// Ticket binding is LLM-only post-admission (#635); admission stays unbound.
|
|
678
749
|
const instruction = options.instruction;
|
|
@@ -745,9 +816,8 @@ export async function loadAdmittedJudgeRequest(runDirectory) {
|
|
|
745
816
|
}
|
|
746
817
|
}
|
|
747
818
|
export async function ensureRunArtifactsDir(runDirectory) {
|
|
748
|
-
const
|
|
749
|
-
|
|
750
|
-
return dir;
|
|
819
|
+
const directory = roleRunArtifactsDirectory(runDirectory);
|
|
820
|
+
return ensureRoleRunDirectory(resolveActivationLedgerHome(homeFromRunDirectory(runDirectory)), directory);
|
|
751
821
|
}
|
|
752
822
|
/**
|
|
753
823
|
* Admit a Coder Role run on the common Invocation request.
|
|
@@ -767,15 +837,13 @@ export async function admitCoderInvocation(options) {
|
|
|
767
837
|
}
|
|
768
838
|
const projectRoot = resolve(options.project ?? options.cwd);
|
|
769
839
|
const runId = (options.createRunId ?? uuidv7)();
|
|
770
|
-
const { principal, sessionDirectory, sessionFile, runDirectory, ledgerHome, bookKey, } = issueAdmissionPlacement(options.principalAuthority, {
|
|
840
|
+
const { principal, sessionDirectory, sessionFile, runDirectory, attachmentsDirectory, ledgerHome, bookKey, } = issueAdmissionPlacement(options.principalAuthority, {
|
|
771
841
|
cwd: projectRoot,
|
|
772
842
|
runId,
|
|
773
843
|
role: "coder",
|
|
844
|
+
subject: { unbound: true },
|
|
774
845
|
home: options.home,
|
|
775
846
|
});
|
|
776
|
-
const attachmentsDirectory = join(runDirectory, "attachments");
|
|
777
|
-
ensureRealDirectoryTree(ledgerHome, sessionDirectory);
|
|
778
|
-
ensureRealDirectoryTree(ledgerHome, attachmentsDirectory);
|
|
779
847
|
const attachments = await freezeAttachments(options.attachmentPaths, attachmentsDirectory);
|
|
780
848
|
const taskPath = join(runDirectory, "task.md");
|
|
781
849
|
await writeFile(taskPath, instruction, "utf8");
|
|
@@ -876,15 +944,13 @@ export async function admitFixerInvocation(options) {
|
|
|
876
944
|
}
|
|
877
945
|
const projectRoot = resolve(options.project ?? options.cwd);
|
|
878
946
|
const runId = (options.createRunId ?? uuidv7)();
|
|
879
|
-
const { principal, sessionDirectory, sessionFile, runDirectory, ledgerHome, bookKey, } = issueAdmissionPlacement(options.principalAuthority, {
|
|
947
|
+
const { principal, sessionDirectory, sessionFile, runDirectory, attachmentsDirectory, ledgerHome, bookKey, } = issueAdmissionPlacement(options.principalAuthority, {
|
|
880
948
|
cwd: projectRoot,
|
|
881
949
|
runId,
|
|
882
950
|
role: "fixer",
|
|
951
|
+
subject: { unbound: true },
|
|
883
952
|
home: options.home,
|
|
884
953
|
});
|
|
885
|
-
const attachmentsDirectory = join(runDirectory, "attachments");
|
|
886
|
-
ensureRealDirectoryTree(ledgerHome, sessionDirectory);
|
|
887
|
-
ensureRealDirectoryTree(ledgerHome, attachmentsDirectory);
|
|
888
954
|
const attachments = await freezeAttachments(options.attachmentPaths, attachmentsDirectory);
|
|
889
955
|
let prerequisitesPath;
|
|
890
956
|
if (prerequisitesSource !== undefined) {
|
|
@@ -1138,15 +1204,13 @@ export async function admitCollectorInvocation(options) {
|
|
|
1138
1204
|
}
|
|
1139
1205
|
const manifestDigest = manifest.digest;
|
|
1140
1206
|
const runId = (options.createRunId ?? uuidv7)();
|
|
1141
|
-
const { principal, sessionDirectory, sessionFile, runDirectory, ledgerHome, bookKey, } = issueAdmissionPlacement(options.principalAuthority, {
|
|
1207
|
+
const { principal, sessionDirectory, sessionFile, runDirectory, attachmentsDirectory, ledgerHome, bookKey, } = issueAdmissionPlacement(options.principalAuthority, {
|
|
1142
1208
|
cwd: projectRoot,
|
|
1143
1209
|
runId,
|
|
1144
1210
|
role: "collector",
|
|
1211
|
+
subject: { unbound: true },
|
|
1145
1212
|
home: options.home,
|
|
1146
1213
|
});
|
|
1147
|
-
const attachmentsDirectory = join(runDirectory, "attachments");
|
|
1148
|
-
ensureRealDirectoryTree(ledgerHome, sessionDirectory);
|
|
1149
|
-
ensureRealDirectoryTree(ledgerHome, attachmentsDirectory);
|
|
1150
1214
|
// #676 A: freeze task materials BEFORE target resolution so the role receives
|
|
1151
1215
|
// real instruction + attachments. Admission binds only explicit --pr or unique
|
|
1152
1216
|
// head/commit association — task-text scrape is not a target lock.
|
|
@@ -1223,7 +1287,8 @@ export function buildCollectorTransportPrompt(admitted, engineMaterial) {
|
|
|
1223
1287
|
/** Positive Issue number grammar shared with Doctor case path identity. */
|
|
1224
1288
|
const DOCTOR_ISSUE_NUMBER_PATTERN = /^[1-9]\d*$/;
|
|
1225
1289
|
/** Match retained Doctor case runs roots (ADR 0017 / loadDoctorCase). */
|
|
1226
|
-
|
|
1290
|
+
/** Canonical Doctor case: `<book>/<ticket>/runs`. Legacy `issues/<n>/runs` is read-only compat. */
|
|
1291
|
+
const DOCTOR_CASE_RUNS_PATH_PATTERN = /\/\.ak-roles\/books\/[^/]+\/(?:issues\/)?([1-9]\d*)\/runs$/;
|
|
1227
1292
|
/**
|
|
1228
1293
|
* Parse a positive Issue number for public Doctor admission.
|
|
1229
1294
|
* Leading zeros and non-integers are structural rejects.
|
|
@@ -1308,7 +1373,8 @@ export function parseDoctorArgv(args) {
|
|
|
1308
1373
|
*/
|
|
1309
1374
|
export async function resolveDoctorCaseRunsPath(options) {
|
|
1310
1375
|
const ledgerHome = resolveActivationLedgerHome(options.home);
|
|
1311
|
-
|
|
1376
|
+
// Canonical topology: <book>/<ticket>/runs (docs/dossier-topology.md).
|
|
1377
|
+
const defaultRuns = join(activationBookDirectory(ledgerHome, options.bookKey), String(options.issueNumber), "runs");
|
|
1312
1378
|
if (options.runs === undefined) {
|
|
1313
1379
|
return defaultRuns;
|
|
1314
1380
|
}
|
|
@@ -1336,7 +1402,7 @@ export async function resolveDoctorCaseRunsPath(options) {
|
|
|
1336
1402
|
const normalized = real.split(sep).join("/");
|
|
1337
1403
|
const match = normalized.match(DOCTOR_CASE_RUNS_PATH_PATTERN);
|
|
1338
1404
|
if (!match) {
|
|
1339
|
-
throw new CliUsageError("doctor --runs must be an .ak-roles/books/<book
|
|
1405
|
+
throw new CliUsageError("doctor --runs must be an .ak-roles/books/<book>/<n>/runs directory");
|
|
1340
1406
|
}
|
|
1341
1407
|
if (Number(match[1]) !== options.issueNumber) {
|
|
1342
1408
|
throw new CliUsageError(`doctor --runs issue ${match[1]} does not match --issue ${options.issueNumber}`);
|
|
@@ -1360,10 +1426,11 @@ export async function admitDoctorInvocation(options) {
|
|
|
1360
1426
|
}
|
|
1361
1427
|
const projectRoot = resolve(options.project ?? options.cwd);
|
|
1362
1428
|
const runId = (options.createRunId ?? uuidv7)();
|
|
1363
|
-
const { principal, sessionDirectory, sessionFile, runDirectory, ledgerHome, bookKey, } = issueAdmissionPlacement(options.principalAuthority, {
|
|
1429
|
+
const { principal, sessionDirectory, sessionFile, runDirectory, attachmentsDirectory, ledgerHome, bookKey, } = issueAdmissionPlacement(options.principalAuthority, {
|
|
1364
1430
|
cwd: projectRoot,
|
|
1365
1431
|
runId,
|
|
1366
1432
|
role: "doctor",
|
|
1433
|
+
subject: { unbound: true },
|
|
1367
1434
|
home: options.home,
|
|
1368
1435
|
});
|
|
1369
1436
|
let caseRunsPath;
|
|
@@ -1402,9 +1469,6 @@ export async function admitDoctorInvocation(options) {
|
|
|
1402
1469
|
const detail = error instanceof Error ? error.message : String(error);
|
|
1403
1470
|
throw new CliUsageError(`doctor case could not be constructed from retained evidence: ${detail}`, { cause: error });
|
|
1404
1471
|
}
|
|
1405
|
-
const attachmentsDirectory = join(runDirectory, "attachments");
|
|
1406
|
-
ensureRealDirectoryTree(ledgerHome, sessionDirectory);
|
|
1407
|
-
ensureRealDirectoryTree(ledgerHome, attachmentsDirectory);
|
|
1408
1472
|
const attachments = await freezeAttachments(options.attachmentPaths ?? [], attachmentsDirectory);
|
|
1409
1473
|
const instruction = options.instruction ?? "";
|
|
1410
1474
|
const instructionEmpty = instruction.trim() === "";
|
|
@@ -1529,15 +1593,19 @@ export async function admitNotaryInvocation(options) {
|
|
|
1529
1593
|
}
|
|
1530
1594
|
throw error;
|
|
1531
1595
|
}
|
|
1596
|
+
// Notary inherits board identity only — migration-derived stays display/placement.
|
|
1597
|
+
const inheritedTicketNumber = await readBoardTicketNumber(sourceRun.runDirectory);
|
|
1532
1598
|
const runId = options.createRunId?.() ?? uuidv7();
|
|
1533
|
-
const { principal, sessionDirectory, sessionFile, runDirectory, ledgerHome, bookKey, } = issueAdmissionPlacement(options.principalAuthority, {
|
|
1599
|
+
const { principal, sessionDirectory, sessionFile, runDirectory, attachmentsDirectory, ledgerHome, bookKey, } = issueAdmissionPlacement(options.principalAuthority, {
|
|
1534
1600
|
cwd: projectRoot,
|
|
1535
1601
|
runId,
|
|
1536
1602
|
role: "notary",
|
|
1603
|
+
subject: inheritedTicketNumber === undefined
|
|
1604
|
+
? { unbound: true }
|
|
1605
|
+
: { ticketNumber: inheritedTicketNumber },
|
|
1537
1606
|
home: options.home,
|
|
1538
1607
|
});
|
|
1539
|
-
|
|
1540
|
-
const ticketFields = ticketAdmissionFields(await readRunTicketNumber(sourceRun.runDirectory));
|
|
1608
|
+
const ticketFields = ticketAdmissionFields(inheritedTicketNumber);
|
|
1541
1609
|
const admitted = {
|
|
1542
1610
|
role: "notary",
|
|
1543
1611
|
runId,
|
|
@@ -1647,13 +1715,13 @@ export async function admitGleanerLeftInvocation(options) {
|
|
|
1647
1715
|
}
|
|
1648
1716
|
const projectRoot = resolve(options.project ?? options.cwd);
|
|
1649
1717
|
const runId = (options.createRunId ?? uuidv7)();
|
|
1650
|
-
const { principal, sessionDirectory, sessionFile, runDirectory, ledgerHome, bookKey, } = issueAdmissionPlacement(options.principalAuthority, {
|
|
1718
|
+
const { principal, sessionDirectory, sessionFile, runDirectory, attachmentsDirectory, ledgerHome, bookKey, } = issueAdmissionPlacement(options.principalAuthority, {
|
|
1651
1719
|
cwd: projectRoot,
|
|
1652
1720
|
runId,
|
|
1653
1721
|
role: "gleaner-left",
|
|
1722
|
+
subject: { unbound: true },
|
|
1654
1723
|
home: options.home,
|
|
1655
1724
|
});
|
|
1656
|
-
ensureRealDirectoryTree(ledgerHome, sessionDirectory);
|
|
1657
1725
|
const instruction = options.instruction;
|
|
1658
1726
|
const instructionEmpty = instruction.trim() === "";
|
|
1659
1727
|
const admitted = {
|
|
@@ -1767,15 +1835,13 @@ export async function admitReviewerInvocation(options) {
|
|
|
1767
1835
|
const authorityRefs = Object.freeze((options.authorityRefs ?? []).map((ref) => requireAuthorityRef(ref)));
|
|
1768
1836
|
const projectRoot = resolve(options.project ?? options.cwd);
|
|
1769
1837
|
const runId = (options.createRunId ?? uuidv7)();
|
|
1770
|
-
const { principal, sessionDirectory, sessionFile, runDirectory, ledgerHome, bookKey, } = issueAdmissionPlacement(options.principalAuthority, {
|
|
1838
|
+
const { principal, sessionDirectory, sessionFile, runDirectory, attachmentsDirectory, ledgerHome, bookKey, } = issueAdmissionPlacement(options.principalAuthority, {
|
|
1771
1839
|
cwd: projectRoot,
|
|
1772
1840
|
runId,
|
|
1773
1841
|
role: "reviewer",
|
|
1842
|
+
subject: { unbound: true },
|
|
1774
1843
|
home: options.home,
|
|
1775
1844
|
});
|
|
1776
|
-
const attachmentsDirectory = join(runDirectory, "attachments");
|
|
1777
|
-
ensureRealDirectoryTree(ledgerHome, sessionDirectory);
|
|
1778
|
-
ensureRealDirectoryTree(ledgerHome, attachmentsDirectory);
|
|
1779
1845
|
// Public parse already rejects attachments; keep freeze loop for structural symmetry.
|
|
1780
1846
|
const attachments = await freezeAttachments(options.attachmentPaths, attachmentsDirectory);
|
|
1781
1847
|
const instruction = options.instruction;
|
|
@@ -1928,15 +1994,13 @@ export async function admitMergerInvocation(options) {
|
|
|
1928
1994
|
const projectRoot = resolve(options.project ?? options.cwd);
|
|
1929
1995
|
const derived = await deriveMergerEnvelopeFromActiveMerge(projectRoot, options.gitState ?? createProductionMergerGitState(projectRoot));
|
|
1930
1996
|
const runId = (options.createRunId ?? uuidv7)();
|
|
1931
|
-
const { principal, sessionDirectory, sessionFile, runDirectory, ledgerHome, bookKey, } = issueAdmissionPlacement(options.principalAuthority, {
|
|
1997
|
+
const { principal, sessionDirectory, sessionFile, runDirectory, attachmentsDirectory, ledgerHome, bookKey, } = issueAdmissionPlacement(options.principalAuthority, {
|
|
1932
1998
|
cwd: projectRoot,
|
|
1933
1999
|
runId,
|
|
1934
2000
|
role: "merger",
|
|
2001
|
+
subject: { unbound: true },
|
|
1935
2002
|
home: options.home,
|
|
1936
2003
|
});
|
|
1937
|
-
const attachmentsDirectory = join(runDirectory, "attachments");
|
|
1938
|
-
ensureRealDirectoryTree(ledgerHome, sessionDirectory);
|
|
1939
|
-
ensureRealDirectoryTree(ledgerHome, attachmentsDirectory);
|
|
1940
2004
|
const attachments = await freezeAttachments(options.attachmentPaths, attachmentsDirectory);
|
|
1941
2005
|
// Intent materials seed primary-source investigation; the method owns the work.
|
|
1942
2006
|
const targetLabel = derived.targetObjectId === "" ? "(none observed)" : derived.targetObjectId;
|