@akagilnc/pi-workflow-roles 0.1.2521 → 0.1.2653-next.71811ca

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.
Files changed (109) hide show
  1. package/README.md +129 -39
  2. package/README.zh-CN.md +128 -39
  3. package/dist/activation-ledger-topology.js +1 -1
  4. package/dist/archivist-record-entry.js +47 -26
  5. package/dist/auditor-dossier-tool.js +3 -1
  6. package/dist/compliance-transport.js +17 -26
  7. package/dist/doctor-contracts.js +1 -2
  8. package/dist/dossier-resolution.js +4 -8
  9. package/dist/engine-detour-tool.js +33 -8
  10. package/dist/engine-detour.js +1 -0
  11. package/dist/evidence-child-executor.js +277 -424
  12. package/dist/host-contracts.js +22 -0
  13. package/dist/institutional-resolution.js +88 -0
  14. package/dist/merger-contracts.js +1 -2
  15. package/dist/navigator-attendance.js +16 -0
  16. package/dist/notary-contracts.js +2 -3
  17. package/dist/package-contracts/fixer-output.js +1 -2
  18. package/dist/packaged-role-registry.js +102 -9
  19. package/dist/pi/in-process-session.js +671 -0
  20. package/dist/public-cli/config.js +7 -5
  21. package/dist/public-cli/main.js +3767 -4113
  22. package/dist/reviewer-child-executor.js +6 -1
  23. package/dist/session-opening-materials.js +10 -38
  24. package/dist/sitian-appender.js +146 -0
  25. package/dist/sitian-contracts.js +21 -0
  26. package/dist/sitian-facade.js +15 -0
  27. package/dist/sitian-reader.js +52 -0
  28. package/extensions/role-runtime.ts +9 -7
  29. package/package.json +5 -5
  30. package/resources/engines/cursor.md +12 -26
  31. package/resources/engines/hermes.md +2 -23
  32. package/resources/engines/opus.md +1 -16
  33. package/resources/navigator-route-playbook.md +2 -2
  34. package/scripts/build-package.mjs +0 -1
  35. package/souls/quality-law.md +1 -1
  36. package/src/activation-ledger-topology.ts +1 -1
  37. package/src/archivist-record-entry.ts +57 -45
  38. package/src/auditor-dossier-tool.ts +4 -2
  39. package/src/canonical-skill-binding.ts +37 -27
  40. package/src/collector-role.ts +11 -20
  41. package/src/collector-tool-schemas.ts +1 -4
  42. package/src/compliance-transport.ts +19 -44
  43. package/src/doctor-auditor.ts +1 -5
  44. package/src/doctor-contracts.ts +1 -4
  45. package/src/doctor-role.ts +31 -8
  46. package/src/dossier-resolution.ts +8 -8
  47. package/src/engine-detour-tool.ts +48 -19
  48. package/src/engine-detour.ts +3 -0
  49. package/src/evidence-child-executor.ts +277 -485
  50. package/src/factory-board.ts +3 -3
  51. package/src/gatekeeper-role.ts +21 -10
  52. package/src/host-contracts.ts +386 -0
  53. package/src/in-process-session.ts +1 -115
  54. package/src/institutional-resolution.ts +135 -0
  55. package/src/judge-auditor.ts +1 -5
  56. package/src/judge-role.ts +37 -51
  57. package/src/merger-contracts.ts +1 -4
  58. package/src/merger-role.ts +7 -11
  59. package/src/navigator-attendance.ts +20 -1
  60. package/src/notary-contracts.ts +8 -11
  61. package/src/notary-role.ts +7 -23
  62. package/src/notary-source-run.ts +4 -3
  63. package/src/package-contracts/fixer-output.ts +1 -4
  64. package/src/package-resources/method-skill-binding.ts +10 -34
  65. package/src/packaged-role-registry.ts +122 -12
  66. package/src/pi/adapter.ts +192 -0
  67. package/src/pi/durable-principal.ts +98 -0
  68. package/src/pi/in-process-session.ts +819 -0
  69. package/src/pi/known-failure.ts +77 -0
  70. package/src/pi/pi-normalization.ts +284 -0
  71. package/src/pi/role-turn-host.ts +459 -0
  72. package/src/public-cli/auto-resume.ts +42 -44
  73. package/src/public-cli/cli.ts +171 -257
  74. package/src/public-cli/coder-run.ts +115 -433
  75. package/src/public-cli/collector-run.ts +62 -314
  76. package/src/public-cli/config.ts +7 -5
  77. package/src/public-cli/doctor-run.ts +41 -52
  78. package/src/public-cli/fixer-run.ts +122 -427
  79. package/src/public-cli/invocation.ts +287 -96
  80. package/src/public-cli/judge-run.ts +92 -422
  81. package/src/public-cli/merger-run.ts +167 -429
  82. package/src/public-cli/notary-run.ts +41 -47
  83. package/src/public-cli/option-definitions.ts +136 -3
  84. package/src/public-cli/post-admission.ts +497 -0
  85. package/src/public-cli/public-run-credentials.ts +4 -4
  86. package/src/public-cli/reviewer-dispatch-rejection.ts +106 -0
  87. package/src/public-cli/reviewer-run.ts +132 -449
  88. package/src/public-cli/run-lifecycle.ts +339 -327
  89. package/src/public-cli/settlement.ts +251 -134
  90. package/src/public-cli/terminal.ts +3 -9
  91. package/src/public-cli/turn-request.ts +87 -0
  92. package/src/reviewer-child-executor.ts +9 -1
  93. package/src/reviewer-role.ts +11 -20
  94. package/src/role-runtime.ts +129 -78
  95. package/src/session-opening-materials.ts +25 -39
  96. package/src/sitian-appender.ts +171 -0
  97. package/src/sitian-contracts.ts +106 -0
  98. package/src/sitian-facade.ts +18 -0
  99. package/src/sitian-reader.ts +62 -0
  100. package/src/worker-role.ts +42 -40
  101. package/src/worker-submission-gates.ts +33 -0
  102. package/dist/archivist-role-run-coordinates.js +0 -28
  103. package/dist/package-contracts/terminating-infrastructure.js +0 -90
  104. package/resources/engines/sonnet.md +0 -27
  105. package/resources/engines/zcode.md +0 -63
  106. package/src/archivist-role-run-coordinates.ts +0 -45
  107. package/src/package-contracts/terminating-infrastructure.ts +0 -132
  108. package/src/public-cli/explicit-internal.ts +0 -427
  109. package/src/public-cli/one-shot-dispatch.ts +0 -300
@@ -19,7 +19,11 @@ import {
19
19
  resolveActivationLedgerHome,
20
20
  } from "../activation-ledger-topology.ts";
21
21
  import { resolveBookKeyFromGit } from "../activation-ledger-git.ts";
22
- import { roleRunSessionCoordinates } from "../archivist-role-run-coordinates.ts";
22
+ import type {
23
+ DurablePrincipal,
24
+ DurablePrincipalAuthority,
25
+ } from "../host-contracts.ts";
26
+ import { decodePiDurablePrincipal } from "../pi/durable-principal.ts";
23
27
  import { resolveTicketNumberFromAttachmentBodies } from "../ticket-frontmatter.ts";
24
28
  import {
25
29
  loadDoctorCase,
@@ -69,6 +73,12 @@ import {
69
73
  type OptionOwner,
70
74
  type PublicOptionDefinition,
71
75
  } from "./option-definitions.ts";
76
+ import { loadPublicCliConfig, THINKING_LEVELS } from "./config.ts";
77
+ import type { PublicThinkingLevel } from "./registry.ts";
78
+ import {
79
+ resolveInstitutionalSeatSelections,
80
+ writeInstitutionalResolutionPage,
81
+ } from "../institutional-resolution.ts";
72
82
 
73
83
  export type FrozenAttachment = {
74
84
  /** Original caller path retained only as provenance. */
@@ -91,9 +101,8 @@ export type AdmittedRoleInvocationBase = {
91
101
  readonly instructionEmpty: boolean;
92
102
  readonly attachments: readonly FrozenAttachment[];
93
103
  readonly runDirectory: string;
94
- readonly sessionDirectory: string;
95
- /** Exact Pi session file principal (bound at admission; reopened on resume). */
96
- readonly sessionFile: string;
104
+ /** Host-issued opaque durable principal (coordinates only via authority.decode). */
105
+ readonly principal: DurablePrincipal;
97
106
  readonly admittedRequestPath: string;
98
107
  /**
99
108
  * Optional opaque invocation correlation restored from a prior admitted page
@@ -105,6 +114,8 @@ export type AdmittedRoleInvocationBase = {
105
114
  * Absent when no attachment carries a valid contract field (unbound).
106
115
  */
107
116
  readonly ticketNumber?: number;
117
+ /** Effective model from invocation identity; restored on resume when no CLI model is given. */
118
+ readonly model?: InvocationEffectiveModel;
108
119
  };
109
120
 
110
121
  export type AdmittedJudgeInvocation = AdmittedRoleInvocationBase & {
@@ -197,19 +208,83 @@ export type AdmittedRoleInvocation =
197
208
  | AdmittedReviewerInvocation
198
209
  | AdmittedMergerInvocation;
199
210
 
211
+ /** Persistence projection only — not carried on Admitted (opaque principal owns identity). */
200
212
  type RoleInvocationLedgerSource = Pick<
201
213
  AdmittedRoleInvocationBase,
202
- "runId" | "bookKey" | "projectRoot" | "runDirectory" | "sessionDirectory" | "sessionFile" | "correlationId" | "ticketNumber"
203
- >;
214
+ "runId" | "bookKey" | "projectRoot" | "runDirectory" | "correlationId" | "ticketNumber"
215
+ > & {
216
+ readonly sessionDirectory: string;
217
+ readonly sessionFile: string;
218
+ };
219
+
220
+ /** Shared admission placement from an injected host authority (no consumer Pi default). */
221
+ export type AdmissionPlacement = {
222
+ readonly principal: DurablePrincipal;
223
+ readonly sessionDirectory: string;
224
+ readonly sessionFile: string;
225
+ readonly runDirectory: string;
226
+ readonly ledgerHome: string;
227
+ readonly bookKey: string;
228
+ };
229
+
230
+ /** Issue principal + derive ledger placement through the injected authority only. */
231
+ export function issueAdmissionPlacement(
232
+ authority: DurablePrincipalAuthority,
233
+ request: {
234
+ readonly cwd: string;
235
+ readonly runId: string;
236
+ readonly role: AdmittedRoleInvocation["role"];
237
+ readonly home?: string;
238
+ },
239
+ ): AdmissionPlacement {
240
+ const principal = authority.issue(request);
241
+ const { sessionDirectory, sessionFile } = decodePiDurablePrincipal(authority, principal);
242
+ const runDirectory = join(sessionDirectory, "..");
243
+ const ledgerHome = resolveActivationLedgerHome(
244
+ request.home === undefined ? undefined : () => request.home!,
245
+ );
246
+ const bookKey = resolveBookKeyFromGit(request.cwd);
247
+ return {
248
+ principal,
249
+ sessionDirectory,
250
+ sessionFile,
251
+ runDirectory,
252
+ ledgerHome,
253
+ bookKey,
254
+ };
255
+ }
256
+
257
+ /**
258
+ * Unique admitted-request.json persistence projection: top-level sessionDirectory/sessionFile
259
+ * (base wire shape). Memory Admitted keeps only the opaque principal — never dual-carry.
260
+ */
261
+ async function writeAdmittedRequestPersistence(
262
+ admittedRequestPath: string,
263
+ body: Record<string, unknown>,
264
+ coordinates: { readonly sessionDirectory: string; readonly sessionFile: string },
265
+ ): Promise<void> {
266
+ const { principal: _omitPrincipal, ...rest } = body;
267
+ const projection = {
268
+ ...rest,
269
+ sessionDirectory: coordinates.sessionDirectory,
270
+ sessionFile: coordinates.sessionFile,
271
+ };
272
+ await writeFile(
273
+ admittedRequestPath,
274
+ `${JSON.stringify(projection, null, 2)}\n`,
275
+ "utf8",
276
+ );
277
+ }
204
278
 
205
279
  /**
206
280
  * Effective provider/model selection recorded on the invocation identity page.
207
281
  * thinking is present only when the caller/seat supplied it — bare model omits it.
282
+ * Restored values are bounded to typed PublicThinkingLevel (never arbitrary string).
208
283
  */
209
284
  export type InvocationEffectiveModel = {
210
285
  readonly provider: string;
211
286
  readonly model: string;
212
- readonly thinking?: string;
287
+ readonly thinking?: PublicThinkingLevel;
213
288
  };
214
289
 
215
290
  /** Project effective model onto ledger fields; absent thinking stays absent. */
@@ -224,6 +299,24 @@ function effectiveModelLedgerFields(
224
299
  };
225
300
  }
226
301
 
302
+ function homeFromRunDirectory(runDirectory: string): string {
303
+ const marker = `${sep}.ak-roles${sep}`;
304
+ const idx = runDirectory.indexOf(marker);
305
+ if (idx !== -1) {
306
+ return runDirectory.slice(0, idx);
307
+ }
308
+ const altMarker = ".ak-roles";
309
+ const altIdx = runDirectory.indexOf(altMarker);
310
+ if (altIdx !== -1) {
311
+ const candidate = runDirectory.slice(0, altIdx);
312
+ return candidate.endsWith("/") || candidate.endsWith("\\") ? candidate.slice(0, -1) : candidate;
313
+ }
314
+ if (typeof process.env.HOME === "string" && process.env.HOME.length > 0) {
315
+ return process.env.HOME;
316
+ }
317
+ throw new Error(`cannot resolve home from runDirectory: ${runDirectory}`);
318
+ }
319
+
227
320
  /**
228
321
  * Persist one `invocation.json` identity page for the public run.
229
322
  * Admission is the sole source for every field; this is the only identity
@@ -253,6 +346,10 @@ async function writeRoleInvocationLedger(
253
346
  `${JSON.stringify(identity, null, 2)}\n`,
254
347
  "utf8",
255
348
  );
349
+ const home = homeFromRunDirectory(source.runDirectory);
350
+ const config = await loadPublicCliConfig(home);
351
+ const institutionalPage = resolveInstitutionalSeatSelections(config, effectiveModel);
352
+ await writeInstitutionalResolutionPage(source.runDirectory, institutionalPage);
256
353
  }
257
354
 
258
355
  /**
@@ -291,6 +388,21 @@ export async function recordEffectiveInvocationModel(
291
388
  `${JSON.stringify(next, null, 2)}\n`,
292
389
  "utf8",
293
390
  );
391
+ const effectiveModel: InvocationEffectiveModel | undefined =
392
+ typeof next.provider === "string" && typeof next.model === "string"
393
+ ? {
394
+ provider: next.provider,
395
+ model: next.model,
396
+ ...(typeof next.thinking === "string" &&
397
+ THINKING_LEVELS.has(next.thinking as PublicThinkingLevel)
398
+ ? { thinking: next.thinking as PublicThinkingLevel }
399
+ : {}),
400
+ }
401
+ : undefined;
402
+ const home = homeFromRunDirectory(runDirectory);
403
+ const config = await loadPublicCliConfig(home);
404
+ const institutionalPage = resolveInstitutionalSeatSelections(config, effectiveModel);
405
+ await writeInstitutionalResolutionPage(runDirectory, institutionalPage);
294
406
  }
295
407
 
296
408
  /** Merge observed launch-time fields into the single existing invocation.json identity page. */
@@ -763,6 +875,7 @@ export type AdmitJudgeInvocationOptions = {
763
875
  project?: string;
764
876
  /** Injectable clock/id for tests. */
765
877
  createRunId?: () => string;
878
+ principalAuthority: DurablePrincipalAuthority;
766
879
  /** Effective model for this invocation — written onto invocation.json. */
767
880
  model?: InvocationEffectiveModel;
768
881
  };
@@ -780,8 +893,19 @@ export async function admitJudgeInvocation(
780
893
  }
781
894
  const projectRoot = resolve(options.project ?? options.cwd);
782
895
  const runId = (options.createRunId ?? uuidv7)();
783
- const { ledgerHome, bookKey, runDirectory, sessionDirectory, sessionFile } =
784
- roleRunSessionCoordinates({ cwd: projectRoot, runId, role: "judge", home: options.home });
896
+ const {
897
+ principal,
898
+ sessionDirectory,
899
+ sessionFile,
900
+ runDirectory,
901
+ ledgerHome,
902
+ bookKey,
903
+ } = issueAdmissionPlacement(options.principalAuthority, {
904
+ cwd: projectRoot,
905
+ runId,
906
+ role: "judge",
907
+ home: options.home,
908
+ });
785
909
  const attachmentsDirectory = join(runDirectory, "attachments");
786
910
  ensureRealDirectoryTree(ledgerHome, sessionDirectory);
787
911
  ensureRealDirectoryTree(ledgerHome, attachmentsDirectory);
@@ -800,8 +924,7 @@ export async function admitJudgeInvocation(
800
924
  bookKey,
801
925
  projectRoot,
802
926
  runDirectory,
803
- sessionDirectory,
804
- sessionFile,
927
+ principal,
805
928
  ...ticketFields,
806
929
  instruction,
807
930
  instructionEmpty,
@@ -814,8 +937,11 @@ export async function admitJudgeInvocation(
814
937
  })),
815
938
  };
816
939
  const admittedRequestPath = join(runDirectory, "admitted-request.json");
817
- await writeFile(admittedRequestPath, `${JSON.stringify(admitted, null, 2)}\n`, "utf8");
818
- await writeRoleInvocationLedger(admitted, admitted.role, options.model);
940
+ await writeAdmittedRequestPersistence(admittedRequestPath, admitted, {
941
+ sessionDirectory,
942
+ sessionFile,
943
+ });
944
+ await writeRoleInvocationLedger({ ...admitted, sessionDirectory, sessionFile }, admitted.role, options.model);
819
945
 
820
946
  return {
821
947
  role: "judge",
@@ -826,8 +952,7 @@ export async function admitJudgeInvocation(
826
952
  instructionEmpty,
827
953
  attachments,
828
954
  runDirectory,
829
- sessionDirectory,
830
- sessionFile,
955
+ principal,
831
956
  admittedRequestPath,
832
957
  ...ticketFields,
833
958
  };
@@ -885,6 +1010,7 @@ export async function ensureRunArtifactsDir(runDirectory: string): Promise<strin
885
1010
 
886
1011
  export type AdmitCoderInvocationOptions = {
887
1012
  home: string;
1013
+ principalAuthority: DurablePrincipalAuthority;
888
1014
  cwd: string;
889
1015
  phase: CoderPhase;
890
1016
  instruction: string;
@@ -918,8 +1044,19 @@ export async function admitCoderInvocation(
918
1044
 
919
1045
  const projectRoot = resolve(options.project ?? options.cwd);
920
1046
  const runId = (options.createRunId ?? uuidv7)();
921
- const { ledgerHome, bookKey, runDirectory, sessionDirectory, sessionFile } =
922
- roleRunSessionCoordinates({ cwd: projectRoot, runId, role: "coder", home: options.home });
1047
+ const {
1048
+ principal,
1049
+ sessionDirectory,
1050
+ sessionFile,
1051
+ runDirectory,
1052
+ ledgerHome,
1053
+ bookKey,
1054
+ } = issueAdmissionPlacement(options.principalAuthority, {
1055
+ cwd: projectRoot,
1056
+ runId,
1057
+ role: "coder",
1058
+ home: options.home,
1059
+ });
923
1060
  const attachmentsDirectory = join(runDirectory, "attachments");
924
1061
  ensureRealDirectoryTree(ledgerHome, sessionDirectory);
925
1062
  ensureRealDirectoryTree(ledgerHome, attachmentsDirectory);
@@ -940,8 +1077,7 @@ export async function admitCoderInvocation(
940
1077
  bookKey,
941
1078
  projectRoot,
942
1079
  runDirectory,
943
- sessionDirectory,
944
- sessionFile,
1080
+ principal,
945
1081
  ...ticketFields,
946
1082
  instruction,
947
1083
  instructionEmpty: false,
@@ -955,8 +1091,11 @@ export async function admitCoderInvocation(
955
1091
  })),
956
1092
  };
957
1093
  const admittedRequestPath = join(runDirectory, "admitted-request.json");
958
- await writeFile(admittedRequestPath, `${JSON.stringify(admitted, null, 2)}\n`, "utf8");
959
- await writeRoleInvocationLedger(admitted, admitted.role, options.model);
1094
+ await writeAdmittedRequestPersistence(admittedRequestPath, admitted, {
1095
+ sessionDirectory,
1096
+ sessionFile,
1097
+ });
1098
+ await writeRoleInvocationLedger({ ...admitted, sessionDirectory, sessionFile }, admitted.role, options.model);
960
1099
 
961
1100
  return {
962
1101
  role: "coder",
@@ -968,8 +1107,7 @@ export async function admitCoderInvocation(
968
1107
  instructionEmpty: false,
969
1108
  attachments,
970
1109
  runDirectory,
971
- sessionDirectory,
972
- sessionFile,
1110
+ principal,
973
1111
  admittedRequestPath,
974
1112
  taskPath,
975
1113
  ...ticketFields,
@@ -998,6 +1136,7 @@ export function buildCoderTransportPrompt(
998
1136
 
999
1137
  export type AdmitFixerInvocationOptions = {
1000
1138
  home: string;
1139
+ principalAuthority: DurablePrincipalAuthority;
1001
1140
  cwd: string;
1002
1141
  phase: FixerPhase;
1003
1142
  instruction: string;
@@ -1058,8 +1197,19 @@ export async function admitFixerInvocation(
1058
1197
 
1059
1198
  const projectRoot = resolve(options.project ?? options.cwd);
1060
1199
  const runId = (options.createRunId ?? uuidv7)();
1061
- const { ledgerHome, bookKey, runDirectory, sessionDirectory, sessionFile } =
1062
- roleRunSessionCoordinates({ cwd: projectRoot, runId, role: "fixer", home: options.home });
1200
+ const {
1201
+ principal,
1202
+ sessionDirectory,
1203
+ sessionFile,
1204
+ runDirectory,
1205
+ ledgerHome,
1206
+ bookKey,
1207
+ } = issueAdmissionPlacement(options.principalAuthority, {
1208
+ cwd: projectRoot,
1209
+ runId,
1210
+ role: "fixer",
1211
+ home: options.home,
1212
+ });
1063
1213
  const attachmentsDirectory = join(runDirectory, "attachments");
1064
1214
  ensureRealDirectoryTree(ledgerHome, sessionDirectory);
1065
1215
  ensureRealDirectoryTree(ledgerHome, attachmentsDirectory);
@@ -1090,8 +1240,7 @@ export async function admitFixerInvocation(
1090
1240
  bookKey,
1091
1241
  projectRoot,
1092
1242
  runDirectory,
1093
- sessionDirectory,
1094
- sessionFile,
1243
+ principal,
1095
1244
  ...ticketFields,
1096
1245
  instruction,
1097
1246
  instructionEmpty: false,
@@ -1110,8 +1259,11 @@ export async function admitFixerInvocation(
1110
1259
  })),
1111
1260
  };
1112
1261
  const admittedRequestPath = join(runDirectory, "admitted-request.json");
1113
- await writeFile(admittedRequestPath, `${JSON.stringify(admitted, null, 2)}\n`, "utf8");
1114
- await writeRoleInvocationLedger(admitted, admitted.role, options.model);
1262
+ await writeAdmittedRequestPersistence(admittedRequestPath, admitted, {
1263
+ sessionDirectory,
1264
+ sessionFile,
1265
+ });
1266
+ await writeRoleInvocationLedger({ ...admitted, sessionDirectory, sessionFile }, admitted.role, options.model);
1115
1267
 
1116
1268
  return {
1117
1269
  role: "fixer",
@@ -1123,8 +1275,7 @@ export async function admitFixerInvocation(
1123
1275
  instructionEmpty: false,
1124
1276
  attachments,
1125
1277
  runDirectory,
1126
- sessionDirectory,
1127
- sessionFile,
1278
+ principal,
1128
1279
  admittedRequestPath,
1129
1280
  packetPath,
1130
1281
  ...(prerequisitesPath === undefined ? {} : { prerequisitesPath }),
@@ -1295,6 +1446,7 @@ function stripGitSuffix(name: string): string {
1295
1446
 
1296
1447
  export type AdmitCollectorInvocationOptions = {
1297
1448
  home: string;
1449
+ principalAuthority: DurablePrincipalAuthority;
1298
1450
  cwd: string;
1299
1451
  prNumber: number;
1300
1452
  instruction?: string;
@@ -1355,8 +1507,19 @@ export async function admitCollectorInvocation(
1355
1507
  const manifestDigest = manifest.digest;
1356
1508
 
1357
1509
  const runId = (options.createRunId ?? uuidv7)();
1358
- const { ledgerHome, bookKey, runDirectory, sessionDirectory, sessionFile } =
1359
- roleRunSessionCoordinates({ cwd: projectRoot, runId, role: "collector", home: options.home });
1510
+ const {
1511
+ principal,
1512
+ sessionDirectory,
1513
+ sessionFile,
1514
+ runDirectory,
1515
+ ledgerHome,
1516
+ bookKey,
1517
+ } = issueAdmissionPlacement(options.principalAuthority, {
1518
+ cwd: projectRoot,
1519
+ runId,
1520
+ role: "collector",
1521
+ home: options.home,
1522
+ });
1360
1523
  const attachmentsDirectory = join(runDirectory, "attachments");
1361
1524
  ensureRealDirectoryTree(ledgerHome, sessionDirectory);
1362
1525
  ensureRealDirectoryTree(ledgerHome, attachmentsDirectory);
@@ -1381,8 +1544,7 @@ export async function admitCollectorInvocation(
1381
1544
  bookKey,
1382
1545
  projectRoot,
1383
1546
  runDirectory,
1384
- sessionDirectory,
1385
- sessionFile,
1547
+ principal,
1386
1548
  ...ticketFields,
1387
1549
  instruction,
1388
1550
  instructionEmpty,
@@ -1400,12 +1562,11 @@ export async function admitCollectorInvocation(
1400
1562
  })),
1401
1563
  };
1402
1564
  const admittedRequestPath = join(runDirectory, "admitted-request.json");
1403
- await writeFile(
1404
- admittedRequestPath,
1405
- `${JSON.stringify(admitted, null, 2)}\n`,
1406
- "utf8",
1407
- );
1408
- await writeRoleInvocationLedger(admitted, admitted.role, options.model);
1565
+ await writeAdmittedRequestPersistence(admittedRequestPath, admitted, {
1566
+ sessionDirectory,
1567
+ sessionFile,
1568
+ });
1569
+ await writeRoleInvocationLedger({ ...admitted, sessionDirectory, sessionFile }, admitted.role, options.model);
1409
1570
 
1410
1571
  return {
1411
1572
  role: "collector",
@@ -1416,8 +1577,7 @@ export async function admitCollectorInvocation(
1416
1577
  instructionEmpty,
1417
1578
  attachments,
1418
1579
  runDirectory,
1419
- sessionDirectory,
1420
- sessionFile,
1580
+ principal,
1421
1581
  admittedRequestPath,
1422
1582
  prNumber,
1423
1583
  repository,
@@ -1533,6 +1693,7 @@ export function parseDoctorArgv(args: readonly string[]): ParseDoctorArgvResult
1533
1693
 
1534
1694
  export type AdmitDoctorInvocationOptions = {
1535
1695
  home: string;
1696
+ principalAuthority: DurablePrincipalAuthority;
1536
1697
  cwd: string;
1537
1698
  issueNumber: number;
1538
1699
  /** Optional project-relative retained runs root override. */
@@ -1639,8 +1800,19 @@ export async function admitDoctorInvocation(
1639
1800
 
1640
1801
  const projectRoot = resolve(options.project ?? options.cwd);
1641
1802
  const runId = (options.createRunId ?? uuidv7)();
1642
- const { ledgerHome, bookKey, runDirectory, sessionDirectory, sessionFile } =
1643
- roleRunSessionCoordinates({ cwd: projectRoot, runId, role: "doctor", home: options.home });
1803
+ const {
1804
+ principal,
1805
+ sessionDirectory,
1806
+ sessionFile,
1807
+ runDirectory,
1808
+ ledgerHome,
1809
+ bookKey,
1810
+ } = issueAdmissionPlacement(options.principalAuthority, {
1811
+ cwd: projectRoot,
1812
+ runId,
1813
+ role: "doctor",
1814
+ home: options.home,
1815
+ });
1644
1816
 
1645
1817
  let caseRunsPath: string;
1646
1818
  try {
@@ -1700,8 +1872,7 @@ export async function admitDoctorInvocation(
1700
1872
  bookKey,
1701
1873
  projectRoot,
1702
1874
  runDirectory,
1703
- sessionDirectory,
1704
- sessionFile,
1875
+ principal,
1705
1876
  ...ticketFields,
1706
1877
  instruction,
1707
1878
  instructionEmpty,
@@ -1717,12 +1888,11 @@ export async function admitDoctorInvocation(
1717
1888
  })),
1718
1889
  };
1719
1890
  const admittedRequestPath = join(runDirectory, "admitted-request.json");
1720
- await writeFile(
1721
- admittedRequestPath,
1722
- `${JSON.stringify(admitted, null, 2)}\n`,
1723
- "utf8",
1724
- );
1725
- await writeRoleInvocationLedger(admitted, admitted.role, options.model);
1891
+ await writeAdmittedRequestPersistence(admittedRequestPath, admitted, {
1892
+ sessionDirectory,
1893
+ sessionFile,
1894
+ });
1895
+ await writeRoleInvocationLedger({ ...admitted, sessionDirectory, sessionFile }, admitted.role, options.model);
1726
1896
 
1727
1897
  return {
1728
1898
  role: "doctor",
@@ -1733,8 +1903,7 @@ export async function admitDoctorInvocation(
1733
1903
  instructionEmpty,
1734
1904
  attachments,
1735
1905
  runDirectory,
1736
- sessionDirectory,
1737
- sessionFile,
1906
+ principal,
1738
1907
  admittedRequestPath,
1739
1908
  issueNumber: options.issueNumber,
1740
1909
  caseRunsPath,
@@ -1821,6 +1990,7 @@ export function parseNotaryArgv(args: readonly string[]): ParseNotaryArgvResult
1821
1990
 
1822
1991
  export async function admitNotaryInvocation(options: {
1823
1992
  readonly home: string;
1993
+ readonly principalAuthority: DurablePrincipalAuthority;
1824
1994
  readonly cwd: string;
1825
1995
  readonly sourceRun: string;
1826
1996
  readonly project?: string;
@@ -1848,13 +2018,19 @@ export async function admitNotaryInvocation(options: {
1848
2018
  }
1849
2019
 
1850
2020
  const runId = options.createRunId?.() ?? uuidv7();
1851
- const { ledgerHome, bookKey, runDirectory, sessionDirectory, sessionFile } =
1852
- roleRunSessionCoordinates({
1853
- cwd: projectRoot,
1854
- runId,
1855
- role: "notary",
1856
- home: options.home,
1857
- });
2021
+ const {
2022
+ principal,
2023
+ sessionDirectory,
2024
+ sessionFile,
2025
+ runDirectory,
2026
+ ledgerHome,
2027
+ bookKey,
2028
+ } = issueAdmissionPlacement(options.principalAuthority, {
2029
+ cwd: projectRoot,
2030
+ runId,
2031
+ role: "notary",
2032
+ home: options.home,
2033
+ });
1858
2034
  ensureRealDirectoryTree(ledgerHome, sessionDirectory);
1859
2035
 
1860
2036
  const admitted = {
@@ -1863,8 +2039,7 @@ export async function admitNotaryInvocation(options: {
1863
2039
  bookKey,
1864
2040
  projectRoot,
1865
2041
  runDirectory,
1866
- sessionDirectory,
1867
- sessionFile,
2042
+ principal,
1868
2043
  instruction: "",
1869
2044
  instructionEmpty: true,
1870
2045
  attachments: [] as const,
@@ -1875,12 +2050,11 @@ export async function admitNotaryInvocation(options: {
1875
2050
  : { correlationId: options.correlationId }),
1876
2051
  };
1877
2052
  const admittedRequestPath = join(runDirectory, "admitted-request.json");
1878
- await writeFile(
1879
- admittedRequestPath,
1880
- `${JSON.stringify(admitted, null, 2)}\n`,
1881
- "utf8",
1882
- );
1883
- await writeRoleInvocationLedger(admitted, admitted.role, options.model);
2053
+ await writeAdmittedRequestPersistence(admittedRequestPath, admitted, {
2054
+ sessionDirectory,
2055
+ sessionFile,
2056
+ });
2057
+ await writeRoleInvocationLedger({ ...admitted, sessionDirectory, sessionFile }, admitted.role, options.model);
1884
2058
 
1885
2059
  return {
1886
2060
  role: "notary",
@@ -1891,8 +2065,7 @@ export async function admitNotaryInvocation(options: {
1891
2065
  instructionEmpty: true,
1892
2066
  attachments: [],
1893
2067
  runDirectory,
1894
- sessionDirectory,
1895
- sessionFile,
2068
+ principal,
1896
2069
  admittedRequestPath,
1897
2070
  sourceRunPath: sourceRun.runDirectory,
1898
2071
  sourceRun,
@@ -1973,6 +2146,7 @@ export function parseReviewerArgv(
1973
2146
 
1974
2147
  export type AdmitReviewerInvocationOptions = {
1975
2148
  home: string;
2149
+ principalAuthority: DurablePrincipalAuthority;
1976
2150
  cwd: string;
1977
2151
  /** Optional caller prose retained only as admitted provenance — never semantic control. */
1978
2152
  instruction: string;
@@ -2006,8 +2180,19 @@ export async function admitReviewerInvocation(
2006
2180
 
2007
2181
  const projectRoot = resolve(options.project ?? options.cwd);
2008
2182
  const runId = (options.createRunId ?? uuidv7)();
2009
- const { ledgerHome, bookKey, runDirectory, sessionDirectory, sessionFile } =
2010
- roleRunSessionCoordinates({ cwd: projectRoot, runId, role: "reviewer", home: options.home });
2183
+ const {
2184
+ principal,
2185
+ sessionDirectory,
2186
+ sessionFile,
2187
+ runDirectory,
2188
+ ledgerHome,
2189
+ bookKey,
2190
+ } = issueAdmissionPlacement(options.principalAuthority, {
2191
+ cwd: projectRoot,
2192
+ runId,
2193
+ role: "reviewer",
2194
+ home: options.home,
2195
+ });
2011
2196
  const attachmentsDirectory = join(runDirectory, "attachments");
2012
2197
  ensureRealDirectoryTree(ledgerHome, sessionDirectory);
2013
2198
  ensureRealDirectoryTree(ledgerHome, attachmentsDirectory);
@@ -2027,8 +2212,7 @@ export async function admitReviewerInvocation(
2027
2212
  bookKey,
2028
2213
  projectRoot,
2029
2214
  runDirectory,
2030
- sessionDirectory,
2031
- sessionFile,
2215
+ principal,
2032
2216
  ...ticketFields,
2033
2217
  instruction,
2034
2218
  instructionEmpty,
@@ -2043,12 +2227,11 @@ export async function admitReviewerInvocation(
2043
2227
  })),
2044
2228
  };
2045
2229
  const admittedRequestPath = join(runDirectory, "admitted-request.json");
2046
- await writeFile(
2047
- admittedRequestPath,
2048
- `${JSON.stringify(admitted, null, 2)}\n`,
2049
- "utf8",
2050
- );
2051
- await writeRoleInvocationLedger(admitted, admitted.role, options.model);
2230
+ await writeAdmittedRequestPersistence(admittedRequestPath, admitted, {
2231
+ sessionDirectory,
2232
+ sessionFile,
2233
+ });
2234
+ await writeRoleInvocationLedger({ ...admitted, sessionDirectory, sessionFile }, admitted.role, options.model);
2052
2235
 
2053
2236
  return {
2054
2237
  role: "reviewer",
@@ -2059,8 +2242,7 @@ export async function admitReviewerInvocation(
2059
2242
  instructionEmpty,
2060
2243
  attachments,
2061
2244
  runDirectory,
2062
- sessionDirectory,
2063
- sessionFile,
2245
+ principal,
2064
2246
  admittedRequestPath,
2065
2247
  baseRevision: options.baseRevision,
2066
2248
  authorityRefs,
@@ -2190,6 +2372,7 @@ export async function deriveMergerEnvelopeFromActiveMerge(
2190
2372
 
2191
2373
  export type AdmitMergerInvocationOptions = {
2192
2374
  home: string;
2375
+ principalAuthority: DurablePrincipalAuthority;
2193
2376
  cwd: string;
2194
2377
  instruction: string;
2195
2378
  attachmentPaths: readonly string[];
@@ -2226,8 +2409,19 @@ export async function admitMergerInvocation(
2226
2409
  );
2227
2410
 
2228
2411
  const runId = (options.createRunId ?? uuidv7)();
2229
- const { ledgerHome, bookKey, runDirectory, sessionDirectory, sessionFile } =
2230
- roleRunSessionCoordinates({ cwd: projectRoot, runId, role: "merger", home: options.home });
2412
+ const {
2413
+ principal,
2414
+ sessionDirectory,
2415
+ sessionFile,
2416
+ runDirectory,
2417
+ ledgerHome,
2418
+ bookKey,
2419
+ } = issueAdmissionPlacement(options.principalAuthority, {
2420
+ cwd: projectRoot,
2421
+ runId,
2422
+ role: "merger",
2423
+ home: options.home,
2424
+ });
2231
2425
  const attachmentsDirectory = join(runDirectory, "attachments");
2232
2426
  ensureRealDirectoryTree(ledgerHome, sessionDirectory);
2233
2427
  ensureRealDirectoryTree(ledgerHome, attachmentsDirectory);
@@ -2279,8 +2473,7 @@ export async function admitMergerInvocation(
2279
2473
  bookKey,
2280
2474
  projectRoot,
2281
2475
  runDirectory,
2282
- sessionDirectory,
2283
- sessionFile,
2476
+ principal,
2284
2477
  ...ticketFields,
2285
2478
  instruction,
2286
2479
  instructionEmpty: false,
@@ -2301,12 +2494,11 @@ export async function admitMergerInvocation(
2301
2494
  })),
2302
2495
  };
2303
2496
  const admittedRequestPath = join(runDirectory, "admitted-request.json");
2304
- await writeFile(
2305
- admittedRequestPath,
2306
- `${JSON.stringify(admitted, null, 2)}\n`,
2307
- "utf8",
2308
- );
2309
- await writeRoleInvocationLedger(admitted, admitted.role, options.model);
2497
+ await writeAdmittedRequestPersistence(admittedRequestPath, admitted, {
2498
+ sessionDirectory,
2499
+ sessionFile,
2500
+ });
2501
+ await writeRoleInvocationLedger({ ...admitted, sessionDirectory, sessionFile }, admitted.role, options.model);
2310
2502
 
2311
2503
  return {
2312
2504
  role: "merger",
@@ -2317,8 +2509,7 @@ export async function admitMergerInvocation(
2317
2509
  instructionEmpty: false,
2318
2510
  attachments,
2319
2511
  runDirectory,
2320
- sessionDirectory,
2321
- sessionFile,
2512
+ principal,
2322
2513
  admittedRequestPath,
2323
2514
  mergerInputPath,
2324
2515
  derived: admitted.derived,