@akagilnc/pi-workflow-roles 0.1.5483 → 0.1.5571

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 (112) hide show
  1. package/README.md +1 -1
  2. package/README.zh-CN.md +1 -1
  3. package/dist/acp-host/production-host.js +6312 -6376
  4. package/dist/analyst-gate-cycles-read.js +28 -78
  5. package/dist/analyst-ledger.js +26 -42
  6. package/dist/analyst-metric-families/acceptance-success-rework.js +25 -1
  7. package/dist/analyst-metric-families/round-timeline.js +2 -5
  8. package/dist/archivist-record-entry.js +4 -3
  9. package/dist/archivist-record-pointer.js +71 -36
  10. package/dist/atomic-write.js +2 -2
  11. package/dist/auditor-dossier-tool.js +11 -6
  12. package/dist/auditor-soul.js +5 -12
  13. package/dist/collector-config.js +6 -5
  14. package/dist/doctor-evidence.js +8 -4
  15. package/dist/engine-detour-usage.js +8 -22
  16. package/dist/headless-host/production-host.js +5969 -6011
  17. package/dist/host-descriptions.js +0 -4
  18. package/dist/host-session-record.js +266 -267
  19. package/dist/ledger-session-read.js +5 -0
  20. package/dist/migrate-book-topology.js +1369 -722
  21. package/dist/navigator-public-session.js +13 -17
  22. package/dist/notary-source-run.js +8 -16
  23. package/dist/packaged-role-registry.js +5 -56
  24. package/dist/pi/durable-principal.js +2 -3
  25. package/dist/pi/role-turn-host.js +79 -15
  26. package/dist/public-cli/auto-resume.js +8 -47
  27. package/dist/public-cli/instruction-seat-run.js +9 -7
  28. package/dist/public-cli/invocation.js +67 -100
  29. package/dist/public-cli/main.js +2689 -2532
  30. package/dist/public-cli/post-admission.js +96 -55
  31. package/dist/public-cli/run-lifecycle.js +44 -100
  32. package/dist/public-cli/settlement.js +184 -429
  33. package/dist/public-cli/terminal.js +0 -12
  34. package/dist/role-run-placement.js +53 -16
  35. package/dist/role-run-relocation.js +111 -52
  36. package/dist/run-dossier-files.js +30 -0
  37. package/dist/run-dossier.js +322 -0
  38. package/dist/run-terminal-artifacts.js +69 -202
  39. package/dist/run-ticket-number.js +49 -7
  40. package/dist/session-assistant-usage.js +9 -18
  41. package/dist/session-identity.js +49 -19
  42. package/dist/sitian-appender.js +29 -18
  43. package/dist/sitian-facade.js +11 -0
  44. package/dist/sitian-reader.js +44 -29
  45. package/dist/submission-gate.js +1 -1
  46. package/dist/submission-ledger.js +4 -4
  47. package/dist/ticket-provenance-contracts.js +2 -8
  48. package/dist/ticket-provenance.js +25 -9
  49. package/package.json +1 -1
  50. package/scripts/build-package.mjs +2 -0
  51. package/src/acp-host/production-host.ts +1 -1
  52. package/src/acp-host/role-turn-host.ts +11 -4
  53. package/src/analyst-gate-cycles-read.ts +31 -88
  54. package/src/analyst-ledger.ts +36 -51
  55. package/src/analyst-metric-families/acceptance-success-rework.ts +24 -1
  56. package/src/analyst-metric-families/gate-cycles.ts +1 -1
  57. package/src/analyst-metric-families/round-timeline.ts +2 -5
  58. package/src/analyst-page.ts +3 -3
  59. package/src/archivist-record-entry.ts +6 -5
  60. package/src/archivist-record-pointer.ts +92 -42
  61. package/src/atomic-write.ts +3 -1
  62. package/src/auditor-dossier-tool.ts +14 -8
  63. package/src/auditor-soul.ts +5 -10
  64. package/src/book-topology-migration-placement.ts +16 -3
  65. package/src/book-topology-record-class-migrators.ts +4 -2
  66. package/src/book-topology-runs-migrator.ts +6 -3
  67. package/src/collector-config.ts +5 -3
  68. package/src/doctor-contracts.ts +1 -1
  69. package/src/doctor-evidence.ts +7 -3
  70. package/src/engine-detour-tool.ts +1 -1
  71. package/src/engine-detour-usage.ts +12 -25
  72. package/src/external-host-turn-loop.ts +25 -0
  73. package/src/factory-board.ts +16 -81
  74. package/src/headless-host/production-host.ts +1 -4
  75. package/src/headless-host/role-turn-host.ts +56 -21
  76. package/src/host-descriptions.ts +0 -6
  77. package/src/host-session-record.ts +224 -140
  78. package/src/ledger-session-read.ts +6 -0
  79. package/src/navigator-public-session.ts +13 -18
  80. package/src/navigator-work-context.ts +3 -1
  81. package/src/notary-role.ts +2 -1
  82. package/src/notary-source-run.ts +8 -18
  83. package/src/packaged-role-registry.ts +1 -65
  84. package/src/pi/adapter.ts +50 -7
  85. package/src/pi/durable-principal.ts +2 -4
  86. package/src/pi/role-turn-host.ts +85 -14
  87. package/src/public-cli/auto-resume.ts +7 -43
  88. package/src/public-cli/instruction-seat-run.ts +13 -6
  89. package/src/public-cli/invocation.ts +90 -144
  90. package/src/public-cli/post-admission.ts +111 -72
  91. package/src/public-cli/run-lifecycle.ts +47 -115
  92. package/src/public-cli/settlement.ts +221 -589
  93. package/src/public-cli/terminal.ts +1 -61
  94. package/src/role-envelope.ts +4 -2
  95. package/src/role-run-placement.ts +65 -17
  96. package/src/role-run-relocation.ts +110 -70
  97. package/src/role-runtime.ts +46 -69
  98. package/src/run-dossier-files.ts +33 -0
  99. package/src/run-dossier.ts +357 -0
  100. package/src/run-terminal-artifacts.ts +84 -240
  101. package/src/run-ticket-number.ts +82 -14
  102. package/src/session-assistant-usage.ts +8 -20
  103. package/src/session-identity.ts +52 -21
  104. package/src/sitian-appender.ts +33 -26
  105. package/src/sitian-facade.ts +22 -0
  106. package/src/sitian-reader.ts +62 -32
  107. package/src/submission-gate.ts +1 -1
  108. package/src/submission-ledger.ts +4 -4
  109. package/src/ticket-provenance-contracts.ts +3 -6
  110. package/src/ticket-provenance.ts +23 -11
  111. package/src/ticket-snapshot.ts +3 -2
  112. package/src/ticket-trajectory.ts +95 -109
@@ -85,18 +85,6 @@ export function formatTerminalResult(result) {
85
85
  for (const artifact of result.artifacts) {
86
86
  lines.push(`artifact\t${artifact.kind}\t${encodeTerminalField(artifact.path)}`);
87
87
  }
88
- // Gate region is unfrozen presentation of typed facts (ADR 0052) — machines
89
- // read result.gate, never these row labels.
90
- if (result.gate !== undefined) {
91
- lines.push(`gate\t${encodeTerminalField(result.gate.actualSeats.join(","))}\t${result.gate.rounds.length}`);
92
- for (const round of result.gate.rounds) {
93
- const reason = round.dispatch.kind === "historical_dispatch"
94
- && round.dispatch.reason !== undefined
95
- ? encodeTerminalField(round.dispatch.reason)
96
- : "";
97
- lines.push(`gate-round\t${round.roundIndex}\t${round.dispatch.kind}\t${round.dispatch.officer}\t${reason}\t${round.officer.seat}\t${encodeTerminalField(round.officer.status)}\t${encodeTerminalField(JSON.stringify(round.officer.findings))}`);
98
- }
99
- }
100
88
  if (result.reviewerChildOutcomes !== undefined) {
101
89
  for (const axis of ["completeness", "correctness"]) {
102
90
  const child = result.reviewerChildOutcomes[axis];
@@ -1,11 +1,35 @@
1
1
  import { readdir } from "node:fs/promises";
2
- import { join } from "node:path";
2
+ import { basename, dirname, join } from "node:path";
3
3
  import {
4
4
  activationBookDirectory,
5
5
  ensureRealDirectoryTree
6
6
  } from "./activation-ledger-topology.js";
7
7
  import { requireSafePositiveTicketNumber } from "./run-ticket-number.js";
8
8
  import { isEnoent } from "./unknown-value.js";
9
+ function formatRunLeaf(runId, role) {
10
+ return `${runId}@${role}`;
11
+ }
12
+ function parseRunLeaf(name) {
13
+ const at = name.lastIndexOf("@");
14
+ if (at <= 0 || at === name.length - 1) return void 0;
15
+ return { runId: name.slice(0, at), role: name.slice(at + 1) };
16
+ }
17
+ function sessionDirectoryOf(runDirectory) {
18
+ return join(runDirectory, "session");
19
+ }
20
+ const ROLE_RUN_SESSION_FILENAME = "session.jsonl";
21
+ function sessionFileIn(sessionDirectory) {
22
+ return join(sessionDirectory, ROLE_RUN_SESSION_FILENAME);
23
+ }
24
+ function sessionFileOf(runDirectory) {
25
+ return sessionFileIn(sessionDirectoryOf(runDirectory));
26
+ }
27
+ function runDirectoryOfSessionFile(sessionFile) {
28
+ return dirname(dirname(sessionFile));
29
+ }
30
+ function runDirectoryFromSessionDirectory(sessionDirectory) {
31
+ return dirname(sessionDirectory);
32
+ }
9
33
  async function listBookRunDirectories(bookDir) {
10
34
  const out = [];
11
35
  const seen = /* @__PURE__ */ new Set();
@@ -39,6 +63,20 @@ async function listBookRunDirectories(bookDir) {
39
63
  }
40
64
  return out.sort();
41
65
  }
66
+ async function findRoleRunDirectory(bookDirectories, runId, onlyRole) {
67
+ const matches = [];
68
+ for (const bookDirectory of bookDirectories) {
69
+ for (const runDirectory of await listBookRunDirectories(bookDirectory)) {
70
+ const parsed = parseRunLeaf(basename(runDirectory));
71
+ if (parsed === void 0 || parsed.runId !== runId) continue;
72
+ if (onlyRole !== void 0 && parsed.role !== onlyRole) continue;
73
+ matches.push(runDirectory);
74
+ }
75
+ }
76
+ if (matches.length === 0) return void 0;
77
+ if (matches.length === 1) return matches[0];
78
+ throw new Error(`ambiguous role run id ${runId}: ${matches.join(", ")}`);
79
+ }
42
80
  function roleRunPlacement(ledgerHome, input) {
43
81
  const subjectDirectory = "ticketNumber" in input.subject ? String(requireSafePositiveTicketNumber(
44
82
  input.subject.ticketNumber,
@@ -48,20 +86,16 @@ function roleRunPlacement(ledgerHome, input) {
48
86
  activationBookDirectory(ledgerHome, input.bookKey),
49
87
  subjectDirectory,
50
88
  "runs",
51
- `${input.runId}@${input.role}`
89
+ formatRunLeaf(input.runId, input.role)
52
90
  );
53
- const sessionDirectory = join(runDirectory, "session");
91
+ const sessionDirectory = sessionDirectoryOf(runDirectory);
54
92
  return {
55
93
  runDirectory,
56
94
  sessionDirectory,
57
- sessionFile: join(sessionDirectory, "session.jsonl"),
58
- artifactsDirectory: roleRunArtifactsDirectory(runDirectory),
95
+ sessionFile: sessionFileIn(sessionDirectory),
59
96
  attachmentsDirectory: join(runDirectory, "attachments")
60
97
  };
61
98
  }
62
- function roleRunArtifactsDirectory(runDirectory) {
63
- return join(runDirectory, "artifacts");
64
- }
65
99
  function isUnboundRunDirectory(runDirectory) {
66
100
  return runDirectory.replaceAll("\\", "/").includes("/unbound/runs/");
67
101
  }
@@ -69,18 +103,21 @@ function ensureRoleRunDirectory(ledgerHome, directory) {
69
103
  return ensureRealDirectoryTree(ledgerHome, directory);
70
104
  }
71
105
  function ensureRoleRunPlacement(ledgerHome, placement) {
72
- for (const directory of [
73
- placement.sessionDirectory,
74
- placement.attachmentsDirectory
75
- ]) {
76
- ensureRoleRunDirectory(ledgerHome, directory);
77
- }
106
+ ensureRoleRunDirectory(ledgerHome, placement.sessionDirectory);
78
107
  }
79
108
  export {
109
+ ROLE_RUN_SESSION_FILENAME,
80
110
  ensureRoleRunDirectory,
81
111
  ensureRoleRunPlacement,
112
+ findRoleRunDirectory,
113
+ formatRunLeaf,
82
114
  isUnboundRunDirectory,
83
115
  listBookRunDirectories,
84
- roleRunArtifactsDirectory,
85
- roleRunPlacement
116
+ parseRunLeaf,
117
+ roleRunPlacement,
118
+ runDirectoryFromSessionDirectory,
119
+ runDirectoryOfSessionFile,
120
+ sessionDirectoryOf,
121
+ sessionFileIn,
122
+ sessionFileOf
86
123
  };
@@ -1,19 +1,22 @@
1
1
  /**
2
2
  * Single authority for rewriting durable run pages after a run directory moves.
3
- * Live unbound→ticket relocate and book-topology migration both call this.
3
+ * Live callers project typed fields; only historical migrators walk durable pages.
4
4
  *
5
5
  * Scope is typed machine-consumed path fields only — never free text, never
6
6
  * frozen attachment/artifact bytes. Nested walk is confined to package-owned
7
7
  * `session/` seams.
8
8
  */
9
- import { existsSync } from "node:fs";
10
9
  import { readdir, readFile, writeFile } from "node:fs/promises";
11
- import { join, sep } from "node:path";
10
+ import { dirname, join, sep } from "node:path";
11
+ import { activationBookDirectory, physicalPathIdentity } from "./activation-ledger-topology.js";
12
+ import { readRoleRunIdentity } from "./public-cli/run-lifecycle.js";
13
+ import { findRoleRunDirectory, roleRunPlacement } from "./role-run-placement.js";
12
14
  import { AUDITOR_PARENT_ATTEMPT_BINDING_ENTRY_TYPE } from "./compliance-transport.js";
15
+ import { readPageSync, updateSectionSync } from "./run-dossier.js";
13
16
  import { isRecord, isEnoent } from "./unknown-value.js";
14
17
  const ADMITTED_PAGE_FIELDS = [
15
18
  "runDirectory",
16
- "admittedRequestPath",
19
+ "admittedRequestPath", // pre-#1161 pages only
17
20
  "sessionDirectory",
18
21
  "sessionFile",
19
22
  "taskPath",
@@ -30,7 +33,7 @@ const INVOCATION_PAGE_FIELDS = [
30
33
  ];
31
34
  const RUN_STATE_PAGE_FIELDS = [
32
35
  "runDirectory",
33
- "admittedRequestPath",
36
+ "admittedRequestPath", // pre-#1161 pages only
34
37
  "sessionDirectory",
35
38
  "sessionFile",
36
39
  ];
@@ -52,6 +55,40 @@ export function rewriteRunDirectoryPathValue(value, oldRunDirectory, newRunDirec
52
55
  }
53
56
  return value;
54
57
  }
58
+ /** Match physical aliases or a normal unbound→ticket bind, never historical migration layouts. */
59
+ export async function retainedRunPathsMatch(recordedPath, currentPath, currentRunDirectory) {
60
+ if (recordedPath === currentPath)
61
+ return true;
62
+ if (typeof recordedPath !== "string")
63
+ return false;
64
+ const recordedPathIdentity = physicalPathIdentity(recordedPath);
65
+ const currentPathIdentity = physicalPathIdentity(currentPath);
66
+ if (recordedPathIdentity === currentPathIdentity)
67
+ return true;
68
+ if (currentRunDirectory === undefined)
69
+ return false;
70
+ const runDirectory = physicalPathIdentity(currentRunDirectory);
71
+ const identity = await readRoleRunIdentity(runDirectory);
72
+ if (identity === undefined)
73
+ return false;
74
+ for (let directory = runDirectory; dirname(directory) !== directory; directory = dirname(directory)) {
75
+ const ledgerHome = dirname(dirname(directory));
76
+ if (directory !== activationBookDirectory(ledgerHome, identity.bookKey))
77
+ continue;
78
+ const unbound = roleRunPlacement(ledgerHome, {
79
+ bookKey: identity.bookKey,
80
+ subject: { unbound: true },
81
+ runId: identity.runId,
82
+ role: identity.role,
83
+ });
84
+ if (rewriteRunDirectoryPathValue(recordedPathIdentity, unbound.runDirectory, runDirectory) !== currentPathIdentity) {
85
+ return false;
86
+ }
87
+ const placed = await findRoleRunDirectory([directory], identity.runId, identity.role);
88
+ return placed !== undefined && physicalPathIdentity(placed) === runDirectory;
89
+ }
90
+ return false;
91
+ }
55
92
  /**
56
93
  * Apply the longest matching oldRunDirectory rewrite. Longer keys win so a
57
94
  * nested run path is not partially claimed by a shorter sibling prefix.
@@ -139,25 +176,26 @@ export function rewriteAdmittedRoleRunPage(page, rewrites) {
139
176
  rewriteRunDirectoryPathFieldsAgainstRewrites(page.principal, ["sessionDirectory", "sessionFile"], rewrites);
140
177
  }
141
178
  }
142
- async function rewriteOfficerPointerFile(path, rewrites) {
143
- if (!existsSync(path))
144
- return;
179
+ /** Pre-#1161 `session/auditor-roles/<officer>.pointer.json` (migrator input only). */
180
+ async function rewriteLegacyOfficerPointerFile(path, rewrites) {
145
181
  const page = JSON.parse(await readFile(path, "utf8"));
146
- if (!isRecord(page))
147
- return;
148
- // Only the typed direct-officer pointer shape — never arbitrary .pointer.json.
149
- if (page.kind !== "direct-officer-run-pointer")
182
+ if (!isRecord(page) || page.kind !== "direct-officer-run-pointer")
150
183
  return;
151
184
  const before = JSON.stringify(page);
152
185
  rewriteRunDirectoryPathFieldsAgainstRewrites(page, OFFICER_POINTER_FIELDS, rewrites);
153
- if (JSON.stringify(page) !== before) {
186
+ if (JSON.stringify(page) !== before)
154
187
  await writeFile(path, `${JSON.stringify(page)}\n`, "utf8");
155
- }
156
188
  }
157
189
  async function rewriteSitianRecordsJsonl(path, rewrites) {
158
- if (!existsSync(path))
159
- return;
160
- const raw = await readFile(path, "utf8");
190
+ let raw;
191
+ try {
192
+ raw = await readFile(path, "utf8");
193
+ }
194
+ catch (error) {
195
+ if (isEnoent(error))
196
+ return;
197
+ throw error;
198
+ }
161
199
  if (raw.length === 0)
162
200
  return;
163
201
  const endsWithNewline = raw.endsWith("\n");
@@ -207,9 +245,15 @@ async function rewriteSitianRecordsJsonl(path, rewrites) {
207
245
  * ak_auditor_parent_attempt_binding data.parent.sessionFile. Never message text.
208
246
  */
209
247
  async function rewriteSessionTranscriptBindings(path, rewrites) {
210
- if (!existsSync(path))
211
- return;
212
- const raw = await readFile(path, "utf8");
248
+ let raw;
249
+ try {
250
+ raw = await readFile(path, "utf8");
251
+ }
252
+ catch (error) {
253
+ if (isEnoent(error))
254
+ return;
255
+ throw error;
256
+ }
213
257
  if (raw.length === 0)
214
258
  return;
215
259
  const endsWithNewline = raw.endsWith("\n");
@@ -266,8 +310,8 @@ async function rewriteSessionTranscriptBindings(path, rewrites) {
266
310
  }
267
311
  /**
268
312
  * Package-owned nested seams under session/ only:
269
- * direct-officer *.pointer.json, sitian records.jsonl,
270
- * session transcript typed parent bindings. Never walks attachments/ or artifacts/.
313
+ * sitian records.jsonl,
314
+ * session transcript typed parent bindings. Never walks attachments/.
271
315
  */
272
316
  async function rewriteNestedMachinePathPages(pagesDirectory, rewrites) {
273
317
  const sessionRoot = join(pagesDirectory, "session");
@@ -290,7 +334,7 @@ async function rewriteNestedMachinePathPages(pagesDirectory, rewrites) {
290
334
  if (!entry.isFile())
291
335
  continue;
292
336
  if (entry.name.endsWith(".pointer.json")) {
293
- await rewriteOfficerPointerFile(path, rewrites);
337
+ await rewriteLegacyOfficerPointerFile(path, rewrites);
294
338
  }
295
339
  else if (entry.name === "records.jsonl") {
296
340
  await rewriteSitianRecordsJsonl(path, rewrites);
@@ -303,7 +347,7 @@ async function rewriteNestedMachinePathPages(pagesDirectory, rewrites) {
303
347
  await walk(sessionRoot);
304
348
  }
305
349
  /**
306
- * Rewrite admitted-request / invocation / run-state path fields (attachment
350
+ * Rewrite the admitted / invocation / runState fact rows (path fields: attachment
307
351
  * frozenPath / summons.attachmentPaths pointers only), then nested package-owned
308
352
  * session seams. Callers may rewrite before or after the filesystem move/copy:
309
353
  * `pagesDirectory` is where the pages currently live on disk; path strings that
@@ -313,38 +357,53 @@ async function rewriteNestedMachinePathPages(pagesDirectory, rewrites) {
313
357
  export async function rewriteRoleRunDurablePages(input) {
314
358
  const { pagesDirectory } = input;
315
359
  const rewrites = collectRewrites(input);
316
- const admittedPath = join(pagesDirectory, "admitted-request.json");
317
- if (existsSync(admittedPath)) {
318
- const page = JSON.parse(await readFile(admittedPath, "utf8"));
319
- const before = JSON.stringify(page);
320
- rewriteAdmittedRoleRunPage(page, rewrites);
321
- if (JSON.stringify(page) !== before) {
322
- await writeFile(admittedPath, `${JSON.stringify(page, null, 2)}\n`, "utf8");
323
- }
324
- }
325
- const invocationPath = join(pagesDirectory, "invocation.json");
326
- if (existsSync(invocationPath)) {
327
- const page = JSON.parse(await readFile(invocationPath, "utf8"));
328
- const before = JSON.stringify(page);
329
- rewriteRunDirectoryPathFieldsAgainstRewrites(page, INVOCATION_PAGE_FIELDS, rewrites);
330
- if (JSON.stringify(page) !== before) {
331
- await writeFile(invocationPath, `${JSON.stringify(page, null, 2)}\n`, "utf8");
332
- }
360
+ // One rewriter per page kind; each keeps its own field list.
361
+ const pageRewriters = {
362
+ admitted: (page) => rewriteAdmittedRoleRunPage(page, rewrites),
363
+ invocation: (page) => rewriteRunDirectoryPathFieldsAgainstRewrites(page, INVOCATION_PAGE_FIELDS, rewrites),
364
+ runState: (page) => {
365
+ rewriteRunDirectoryPathFieldsAgainstRewrites(page, RUN_STATE_PAGE_FIELDS, rewrites);
366
+ if (isRecord(page.principal)) {
367
+ rewriteRunDirectoryPathFieldsAgainstRewrites(page.principal, ["sessionDirectory", "sessionFile"], rewrites);
368
+ }
369
+ // Open court summons: source-run locators + frozen attachment path pointers.
370
+ if (isRecord(page.currentCourt)) {
371
+ rewriteSummonsMaterials(page.currentCourt.summons, rewrites);
372
+ }
373
+ },
374
+ };
375
+ // A page is rewritten only when its fact row exists — never gate on the rendering.
376
+ for (const [section, rewrite] of Object.entries(pageRewriters)) {
377
+ if (readPageSync(pagesDirectory, section) === undefined)
378
+ continue;
379
+ updateSectionSync(pagesDirectory, section, (current) => {
380
+ const page = structuredClone(current);
381
+ rewrite(page);
382
+ return JSON.stringify(page) === JSON.stringify(current) ? undefined : page;
383
+ });
333
384
  }
334
- const statePath = join(pagesDirectory, "run-state.json");
335
- if (existsSync(statePath)) {
336
- const page = JSON.parse(await readFile(statePath, "utf8"));
337
- const before = JSON.stringify(page);
338
- rewriteRunDirectoryPathFieldsAgainstRewrites(page, RUN_STATE_PAGE_FIELDS, rewrites);
339
- if (isRecord(page.principal)) {
340
- rewriteRunDirectoryPathFieldsAgainstRewrites(page.principal, ["sessionDirectory", "sessionFile"], rewrites);
385
+ // Runs from before #1161 (the one-shot book-topology migrator's input) keep these
386
+ // as separate page files; the same rewriters apply. Nothing live writes them.
387
+ for (const [file, rewrite] of [
388
+ ["admitted-request.json", pageRewriters.admitted],
389
+ ["invocation.json", pageRewriters.invocation],
390
+ ["run-state.json", pageRewriters.runState],
391
+ ]) {
392
+ const path = join(pagesDirectory, file);
393
+ let raw;
394
+ try {
395
+ raw = await readFile(path, "utf8");
341
396
  }
342
- // Open court summons: source-run locators + frozen attachment path pointers.
343
- if (isRecord(page.currentCourt)) {
344
- rewriteSummonsMaterials(page.currentCourt.summons, rewrites);
397
+ catch (error) {
398
+ if (isEnoent(error))
399
+ continue;
400
+ throw error;
345
401
  }
402
+ const page = JSON.parse(raw);
403
+ const before = JSON.stringify(page);
404
+ rewrite(page);
346
405
  if (JSON.stringify(page) !== before) {
347
- await writeFile(statePath, `${JSON.stringify(page, null, 2)}\n`, "utf8");
406
+ await writeFile(path, `${JSON.stringify(page, null, 2)}\n`, "utf8");
348
407
  }
349
408
  }
350
409
  await rewriteNestedMachinePathPages(pagesDirectory, rewrites);
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Names in a run directory (docs/dossier-topology.md, #1161). Constants only, so
3
+ * the appender and the `current.json` renderer can both import them.
4
+ */
5
+ export const RUN_CURRENT_FILE = "current.json";
6
+ export const RUN_HISTORY_FILE = "history.jsonl";
7
+ export const RUN_LOG_FILE = "log.jsonl";
8
+ export const RUN_STATE_FILE = "state.jsonl";
9
+ /**
10
+ * Record kinds that make a leg's history: they land in `history.jsonl`. The
11
+ * original submission ledger and attempt history, the prompt/schema each turn was
12
+ * started with, and officer pointers.
13
+ */
14
+ export const RUN_HISTORY_KINDS = new Set([
15
+ "candidate", "roundContext", "outcome", "sealed", "post-seal-anomaly",
16
+ "attempt-history", "turn-delivery", "officer-pointer",
17
+ ]);
18
+ /** History record kind of a booked officer pointer (appender routes it to history.jsonl). */
19
+ export const OFFICER_POINTER_RECORD_KIND = "officer-pointer";
20
+ /**
21
+ * The facts a run cannot go on without land in `state.jsonl`: the four whole pages only the
22
+ * public call knows, and the native session id a host binds (a resume needs it). A
23
+ * different volume than the submission ledger and than the auxiliary stream, as the
24
+ * files they replaced were (a page write failure throws; a ledger volume that cannot
25
+ * be written does not stop a resume; a stream line that cannot be written is noted).
26
+ * Every other kind lands in `log.jsonl`.
27
+ */
28
+ export const RUN_STATE_KINDS = new Set([
29
+ "invocation", "admitted-request", "run-state", "terminal", "host-session-id",
30
+ ]);