@akagilnc/pi-workflow-roles 0.1.4802 → 0.1.4870
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 +19434 -18218
- package/dist/analyst-book-key.js +63 -0
- package/dist/analyst-cohort.js +167 -0
- package/dist/analyst-entry.js +320 -0
- package/dist/analyst-index.js +247 -0
- package/dist/analyst-ledger.js +561 -0
- package/dist/analyst-median.js +16 -0
- package/dist/analyst-metric-families/acceptance-success-rework.js +249 -0
- package/dist/analyst-metric-families/b2-frame-buckets-actions.js +189 -0
- package/dist/analyst-metric-families/gate-cycles.js +77 -0
- package/dist/analyst-metric-families/leg-wall-clock.js +56 -0
- package/dist/analyst-metric-families/round-timeline.js +126 -0
- package/dist/analyst-metric-families.js +23 -0
- package/dist/analyst-metric-family.js +11 -0
- package/dist/analyst-model-groups.js +135 -0
- package/dist/analyst-page.js +182 -0
- package/dist/atomic-write.js +23 -0
- package/dist/auditor-soul.js +1 -1
- package/dist/countersign-contracts.js +0 -2
- package/dist/diarist-contracts.js +0 -1
- package/dist/doctor-contracts.js +2 -2
- package/dist/gatekeeper-role.js +15 -16
- package/dist/gleaner-left-contracts.js +0 -2
- package/dist/headless-host/production-host.js +16967 -15749
- package/dist/host-contracts.js +0 -4
- package/dist/inspector-contracts.js +0 -2
- package/dist/institutional-resolution.js +4 -2
- package/dist/merger-contracts.js +0 -2
- package/dist/migrate-book-topology.js +3908 -3089
- package/dist/navigator-public-session.js +4 -3
- package/dist/notary-contracts.js +0 -2
- package/dist/package-contracts/auditor-output.js +0 -1
- package/dist/package-contracts/collector-output.js +0 -2
- package/dist/package-contracts/fixer-output.js +0 -2
- package/dist/package-contracts/gatekeeper-output.js +0 -2
- package/dist/package-contracts/judge-output.js +0 -2
- package/dist/package-contracts/navigator-output.js +0 -2
- package/dist/package-contracts/reviewer-output.js +0 -2
- package/dist/package-contracts/terminating-tools.js +32 -92
- package/dist/package-contracts/worker-output.js +0 -4
- package/dist/packaged-role-registry.js +518 -36
- package/dist/pi/role-turn-host.js +2 -1
- package/dist/public-cli/analyst-run.js +185 -0
- package/dist/public-cli/cli.js +885 -0
- package/dist/public-cli/config.js +12 -9
- package/dist/public-cli/countersign-run.js +4 -311
- package/dist/public-cli/instruction-seat-run.js +628 -158
- package/dist/public-cli/invocation.js +806 -1550
- package/dist/public-cli/main.js +6962 -9882
- package/dist/public-cli/option-definitions.js +51 -99
- package/dist/public-cli/post-admission.js +30 -2
- package/dist/public-cli/run-lifecycle.js +234 -353
- package/dist/public-cli/seat-ticket-binding.js +6 -0
- package/dist/public-cli/settlement.js +261 -675
- package/dist/public-cli/turn-request.js +76 -0
- package/dist/public-role-summons.js +38 -112
- package/dist/role-activation-flags.js +23 -45
- package/dist/secretariat-contracts.js +0 -2
- package/dist/session-identity.js +17 -8
- package/dist/session-opening-materials.js +3 -2
- package/extensions/role-runtime.ts +6 -80
- package/package.json +1 -1
- package/src/acp-host/role-turn-host.ts +4 -1
- package/src/analyst-metric-families/acceptance-success-rework.ts +3 -2
- package/src/auditor-role.ts +1 -2
- package/src/auditor-soul.ts +1 -1
- package/src/collector-role.ts +2 -2
- package/src/countersign-contracts.ts +0 -1
- package/src/countersign-role.ts +1 -1
- package/src/diarist-contracts.ts +0 -1
- package/src/diarist-role.ts +0 -1
- package/src/doctor-auditor.ts +1 -2
- package/src/doctor-contracts.ts +1 -1
- package/src/doctor-role.ts +3 -2
- package/src/external-host-turn-loop.ts +1 -1
- package/src/factory-board.ts +10 -7
- package/src/gatekeeper-role.ts +16 -10
- package/src/gleaner-left-contracts.ts +0 -1
- package/src/gleaner-left-role.ts +0 -1
- package/src/headless-host/role-turn-host.ts +7 -1
- package/src/host-contracts.ts +10 -6
- package/src/inspector-contracts.ts +0 -1
- package/src/inspector-role.ts +0 -2
- package/src/institutional-resolution.ts +6 -4
- package/src/judge-role.ts +3 -3
- package/src/merger-contracts.ts +0 -1
- package/src/merger-role.ts +2 -2
- package/src/navigator-public-session.ts +7 -6
- package/src/navigator-work-context.ts +6 -8
- package/src/notary-contracts.ts +0 -1
- package/src/notary-role.ts +2 -3
- package/src/package-contracts/auditor-output.ts +0 -1
- package/src/package-contracts/collector-output.ts +0 -1
- package/src/package-contracts/fixer-output.ts +0 -1
- package/src/package-contracts/gatekeeper-output.ts +0 -1
- package/src/package-contracts/judge-output.ts +0 -1
- package/src/package-contracts/navigator-output.ts +0 -1
- package/src/package-contracts/reviewer-output.ts +0 -1
- package/src/package-contracts/terminating-tools.ts +27 -99
- package/src/package-contracts/worker-output.ts +0 -2
- package/src/packaged-role-registry.ts +604 -35
- package/src/pi/role-turn-host.ts +2 -1
- package/src/public-cli/cli.ts +64 -259
- package/src/public-cli/config.ts +18 -10
- package/src/public-cli/countersign-run.ts +14 -449
- package/src/public-cli/instruction-seat-run.ts +758 -277
- package/src/public-cli/invocation.ts +1097 -2051
- package/src/public-cli/option-definitions.ts +62 -127
- package/src/public-cli/post-admission.ts +47 -2
- package/src/public-cli/run-lifecycle.ts +303 -613
- package/src/public-cli/seat-ticket-binding.ts +6 -0
- package/src/public-cli/settlement.ts +399 -1185
- package/src/public-cli/turn-request.ts +92 -1
- package/src/public-role-summons.ts +44 -128
- package/src/reviewer-role.ts +3 -2
- package/src/role-activation-flags.ts +20 -41
- package/src/role-runtime-dependencies.ts +25 -26
- package/src/role-runtime.ts +121 -232
- package/src/secretariat-contracts.ts +0 -1
- package/src/secretariat-role.ts +0 -2
- package/src/session-identity.ts +23 -8
- package/src/session-opening-materials.ts +2 -1
- package/src/worker-role.ts +3 -4
- package/dist/doctor-auditor.js +0 -25
- package/dist/public-cli/diarist-run.js +0 -130
- package/dist/public-cli/doctor-run.js +0 -87
- package/dist/public-cli/inspector-run.js +0 -151
- package/dist/public-cli/judge-run.js +0 -114
- package/dist/public-cli/notary-run.js +0 -174
- package/dist/public-cli/reviewer-run.js +0 -339
- package/src/public-cli/coder-run.ts +0 -255
- package/src/public-cli/collector-run.ts +0 -189
- package/src/public-cli/diarist-run.ts +0 -233
- package/src/public-cli/doctor-run.ts +0 -167
- package/src/public-cli/fixer-run.ts +0 -265
- package/src/public-cli/gleaner-left-run.ts +0 -167
- package/src/public-cli/inspector-run.ts +0 -261
- package/src/public-cli/judge-run.ts +0 -196
- package/src/public-cli/merger-run.ts +0 -294
- package/src/public-cli/notary-run.ts +0 -279
- package/src/public-cli/reviewer-run.ts +0 -480
- package/src/public-cli/secretariat-run.ts +0 -265
|
@@ -47,6 +47,11 @@ import {
|
|
|
47
47
|
pickEngineAxis,
|
|
48
48
|
} from "../package-resources/engine-material.ts";
|
|
49
49
|
import type { PublicThinkingLevel } from "./registry.ts";
|
|
50
|
+
import {
|
|
51
|
+
packagedResumeSourcePath,
|
|
52
|
+
packagedRoleMetadata,
|
|
53
|
+
type PackagedRole,
|
|
54
|
+
} from "../packaged-role-registry.ts";
|
|
50
55
|
import {
|
|
51
56
|
recordEffectiveInvocationModel,
|
|
52
57
|
requireAuthorityRef,
|
|
@@ -54,15 +59,11 @@ import {
|
|
|
54
59
|
type AdmittedCoderInvocation,
|
|
55
60
|
type AdmittedCountersignInvocation,
|
|
56
61
|
type AdmittedCollectorInvocation,
|
|
57
|
-
type AdmittedDiaristInvocation,
|
|
58
62
|
type AdmittedDoctorInvocation,
|
|
59
63
|
type AdmittedInspectorInvocation,
|
|
60
64
|
type AdmittedNotaryInvocation,
|
|
61
65
|
type AdmittedFixerInvocation,
|
|
62
66
|
type AdmittedGleanerLeftInvocation,
|
|
63
|
-
type AdmittedGatekeeperInvocation,
|
|
64
|
-
type AdmittedJudgeInvocation,
|
|
65
|
-
type AdmittedNavigatorInvocation,
|
|
66
67
|
type AdmittedMergerInvocation,
|
|
67
68
|
type AdmittedReviewerInvocation,
|
|
68
69
|
type AdmittedRoleInvocation,
|
|
@@ -94,23 +95,7 @@ export const AUTO_RESUME_LIMIT = 2 as const;
|
|
|
94
95
|
|
|
95
96
|
export type RoleRunRecord = {
|
|
96
97
|
readonly runId: string;
|
|
97
|
-
readonly role:
|
|
98
|
-
| "judge"
|
|
99
|
-
| "coder"
|
|
100
|
-
| "fixer"
|
|
101
|
-
| "collector"
|
|
102
|
-
| "doctor"
|
|
103
|
-
| "reviewer"
|
|
104
|
-
| "merger"
|
|
105
|
-
| "notary"
|
|
106
|
-
| "countersign"
|
|
107
|
-
| "gleaner-left"
|
|
108
|
-
| "inspector"
|
|
109
|
-
| "gatekeeper"
|
|
110
|
-
| "navigator"
|
|
111
|
-
| "auditor"
|
|
112
|
-
| "diarist"
|
|
113
|
-
| "secretariat";
|
|
98
|
+
readonly role: PackagedRole;
|
|
114
99
|
readonly state: RoleRunState;
|
|
115
100
|
readonly bookKey: string;
|
|
116
101
|
readonly projectRoot: string;
|
|
@@ -350,24 +335,8 @@ async function readRoleRunStateDisk(
|
|
|
350
335
|
if (typeof record.runId !== "string" || record.runId.trim() === "") {
|
|
351
336
|
return undefined;
|
|
352
337
|
}
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
record.role !== "coder" &&
|
|
356
|
-
record.role !== "fixer" &&
|
|
357
|
-
record.role !== "collector" &&
|
|
358
|
-
record.role !== "doctor" &&
|
|
359
|
-
record.role !== "reviewer" &&
|
|
360
|
-
record.role !== "merger" &&
|
|
361
|
-
record.role !== "notary" &&
|
|
362
|
-
record.role !== "countersign" &&
|
|
363
|
-
record.role !== "gleaner-left" &&
|
|
364
|
-
record.role !== "inspector" &&
|
|
365
|
-
record.role !== "gatekeeper" &&
|
|
366
|
-
record.role !== "navigator" &&
|
|
367
|
-
record.role !== "auditor" &&
|
|
368
|
-
record.role !== "diarist" &&
|
|
369
|
-
record.role !== "secretariat"
|
|
370
|
-
) {
|
|
338
|
+
const role = typeof record.role === "string" ? packagedRoleMetadata(record.role)?.role : undefined;
|
|
339
|
+
if (role === undefined) {
|
|
371
340
|
return undefined;
|
|
372
341
|
}
|
|
373
342
|
if (
|
|
@@ -421,7 +390,7 @@ async function readRoleRunStateDisk(
|
|
|
421
390
|
const currentCourt = parseCurrentCourtState(record.currentCourt);
|
|
422
391
|
return {
|
|
423
392
|
runId: record.runId,
|
|
424
|
-
role
|
|
393
|
+
role,
|
|
425
394
|
state: record.state,
|
|
426
395
|
bookKey: record.bookKey,
|
|
427
396
|
projectRoot: record.projectRoot,
|
|
@@ -538,6 +507,10 @@ export async function markRunAdmitted(
|
|
|
538
507
|
authority: DurablePrincipalAuthority,
|
|
539
508
|
): Promise<void> {
|
|
540
509
|
const { sessionDirectory, sessionFile } = authority.decode(admitted.principal);
|
|
510
|
+
const record = packagedRoleMetadata(admitted.role);
|
|
511
|
+
const workerPhase = record !== undefined && "worker" in record && record.worker === true && "phase" in admitted
|
|
512
|
+
? admitted.phase
|
|
513
|
+
: undefined;
|
|
541
514
|
await writeRoleRunState(admitted.runDirectory, {
|
|
542
515
|
runId: admitted.runId,
|
|
543
516
|
role: admitted.role,
|
|
@@ -547,11 +520,7 @@ export async function markRunAdmitted(
|
|
|
547
520
|
sessionDirectory,
|
|
548
521
|
sessionFile,
|
|
549
522
|
admittedRequestPath: admitted.admittedRequestPath,
|
|
550
|
-
...(
|
|
551
|
-
admitted.role === "coder" || admitted.role === "fixer"
|
|
552
|
-
? { phase: admitted.phase }
|
|
553
|
-
: {}
|
|
554
|
-
),
|
|
523
|
+
...(workerPhase === undefined ? {} : { phase: workerPhase }),
|
|
555
524
|
});
|
|
556
525
|
}
|
|
557
526
|
|
|
@@ -1141,10 +1110,11 @@ async function runHasFormedSessionPrincipal(runDirectory: string): Promise<boole
|
|
|
1141
1110
|
/**
|
|
1142
1111
|
* Locate the latest retained run for one seat under a book (#637 / #747).
|
|
1143
1112
|
* Same walk surface as findRunDirectoryById (listBookRunDirectories). Match by
|
|
1144
|
-
* parent run path (officer / gate seats, #747 / #987).
|
|
1145
|
-
*
|
|
1146
|
-
* parallel index. Public ticket-number
|
|
1147
|
-
* (#987 Result 7); callers use explicit
|
|
1113
|
+
* parent run path (officer / gate seats, #747 / #987). A typed ticket number
|
|
1114
|
+
* does not select a run. runId is UUIDv7 — lexicographic max is latest among
|
|
1115
|
+
* runs that formed a session principal. No parallel index. Public ticket-number
|
|
1116
|
+
* selection of a prior run was deleted (#987 Result 7); callers use explicit
|
|
1117
|
+
* `ak-role resume <runId>`.
|
|
1148
1118
|
* Only a truly missing book directory means no history; damage/permission errors propagate.
|
|
1149
1119
|
*/
|
|
1150
1120
|
export async function findLatestRunIdForSeatTicket(input: {
|
|
@@ -1679,68 +1649,9 @@ async function loadResumableRunRecord(
|
|
|
1679
1649
|
};
|
|
1680
1650
|
}
|
|
1681
1651
|
|
|
1682
|
-
export type LoadedResumableJudgeRun = {
|
|
1683
|
-
readonly admitted: AdmittedJudgeInvocation;
|
|
1684
|
-
readonly run: RoleRunRecord;
|
|
1685
|
-
/** @deprecated #416: resumable observation no longer gates resume; may be undefined. */
|
|
1686
|
-
readonly observation?: TypedHttp429Observation;
|
|
1687
|
-
};
|
|
1688
|
-
|
|
1689
|
-
export type LoadedResumableCoderRun = {
|
|
1690
|
-
readonly admitted: AdmittedCoderInvocation;
|
|
1691
|
-
readonly run: RoleRunRecord;
|
|
1692
|
-
readonly observation?: TypedHttp429Observation;
|
|
1693
|
-
};
|
|
1694
|
-
|
|
1695
|
-
export type LoadedResumableFixerRun = {
|
|
1696
|
-
readonly admitted: AdmittedFixerInvocation;
|
|
1697
|
-
readonly run: RoleRunRecord;
|
|
1698
|
-
readonly observation?: TypedHttp429Observation;
|
|
1699
|
-
};
|
|
1700
|
-
|
|
1701
|
-
export type LoadedResumableReviewerRun = {
|
|
1702
|
-
readonly admitted: AdmittedReviewerInvocation;
|
|
1703
|
-
readonly run: RoleRunRecord;
|
|
1704
|
-
readonly observation?: TypedHttp429Observation;
|
|
1705
|
-
};
|
|
1706
|
-
|
|
1707
|
-
export type LoadedResumableCountersignRun = {
|
|
1708
|
-
readonly admitted: AdmittedCountersignInvocation;
|
|
1709
|
-
readonly run: RoleRunRecord;
|
|
1710
|
-
readonly observation?: TypedHttp429Observation;
|
|
1711
|
-
};
|
|
1712
|
-
|
|
1713
|
-
export type LoadedResumableGleanerLeftRun = {
|
|
1714
|
-
readonly admitted: AdmittedGleanerLeftInvocation;
|
|
1715
|
-
readonly run: RoleRunRecord;
|
|
1716
|
-
readonly observation?: TypedHttp429Observation;
|
|
1717
|
-
};
|
|
1718
|
-
|
|
1719
|
-
export type LoadedResumableDiaristRun = {
|
|
1720
|
-
readonly admitted: AdmittedDiaristInvocation;
|
|
1721
|
-
readonly run: RoleRunRecord;
|
|
1722
|
-
readonly observation?: TypedHttp429Observation;
|
|
1723
|
-
};
|
|
1724
|
-
|
|
1725
|
-
export type LoadedResumableSecretariatRun = {
|
|
1726
|
-
readonly admitted: import("./invocation.ts").AdmittedSecretariatInvocation;
|
|
1727
|
-
readonly run: RoleRunRecord;
|
|
1728
|
-
readonly observation?: TypedHttp429Observation;
|
|
1729
|
-
};
|
|
1730
|
-
|
|
1731
|
-
export type LoadedResumableInstructionSeatRun = {
|
|
1732
|
-
readonly admitted:
|
|
1733
|
-
| AdmittedGatekeeperInvocation
|
|
1734
|
-
| AdmittedNavigatorInvocation
|
|
1735
|
-
| import("./invocation.ts").AdmittedAuditorInvocation
|
|
1736
|
-
readonly run: RoleRunRecord;
|
|
1737
|
-
readonly observation?: TypedHttp429Observation;
|
|
1738
|
-
};
|
|
1739
|
-
|
|
1740
1652
|
/**
|
|
1741
|
-
* Base admitted projection
|
|
1742
|
-
*
|
|
1743
|
-
* Seat loaders add only their seat-specific fields on top.
|
|
1653
|
+
* Base admitted projection: durable identity, instruction, attachments, principal, ticket, and model.
|
|
1654
|
+
* Seat restore adds only that seat's fields.
|
|
1744
1655
|
*/
|
|
1745
1656
|
function resumedBaseAdmitted(loaded: {
|
|
1746
1657
|
readonly run: RoleRunRecord;
|
|
@@ -1762,7 +1673,7 @@ function resumedBaseAdmitted(loaded: {
|
|
|
1762
1673
|
};
|
|
1763
1674
|
}
|
|
1764
1675
|
|
|
1765
|
-
/** Loaded-run envelope
|
|
1676
|
+
/** Loaded-run envelope. */
|
|
1766
1677
|
function seatLoadedResult<R extends AdmittedRoleInvocation>(
|
|
1767
1678
|
loaded: {
|
|
1768
1679
|
readonly run: RoleRunRecord;
|
|
@@ -1777,508 +1688,6 @@ function seatLoadedResult<R extends AdmittedRoleInvocation>(
|
|
|
1777
1688
|
};
|
|
1778
1689
|
}
|
|
1779
1690
|
|
|
1780
|
-
/**
|
|
1781
|
-
* Load a resumable Judge run for resume. Rejects unknown, terminal,
|
|
1782
|
-
* non-resumable, and non-Judge IDs without replaying dispatch.
|
|
1783
|
-
*/
|
|
1784
|
-
export async function loadResumableJudgeRun(
|
|
1785
|
-
home: string,
|
|
1786
|
-
runId: string,
|
|
1787
|
-
authority: DurablePrincipalAuthority,
|
|
1788
|
-
): Promise<LoadedResumableJudgeRun> {
|
|
1789
|
-
const loaded = await loadResumableRunRecord(home, runId, authority);
|
|
1790
|
-
if (loaded.run.role !== "judge") {
|
|
1791
|
-
throw new CliUsageError(
|
|
1792
|
-
`role run ${runId} belongs to ${loaded.run.role}, not judge`,
|
|
1793
|
-
);
|
|
1794
|
-
}
|
|
1795
|
-
const admitted: AdmittedJudgeInvocation = {
|
|
1796
|
-
role: "judge",
|
|
1797
|
-
...resumedBaseAdmitted(loaded),
|
|
1798
|
-
};
|
|
1799
|
-
return seatLoadedResult(loaded, admitted);
|
|
1800
|
-
}
|
|
1801
|
-
|
|
1802
|
-
/**
|
|
1803
|
-
* Load a resumable Coder run for resume. Phase and task path are restored from
|
|
1804
|
-
* the admitted request so continuation stays role-correct (#109).
|
|
1805
|
-
*/
|
|
1806
|
-
export async function loadResumableCoderRun(
|
|
1807
|
-
home: string,
|
|
1808
|
-
runId: string,
|
|
1809
|
-
authority: DurablePrincipalAuthority,
|
|
1810
|
-
): Promise<LoadedResumableCoderRun> {
|
|
1811
|
-
const loaded = await loadResumableRunRecord(home, runId, authority);
|
|
1812
|
-
if (loaded.run.role !== "coder") {
|
|
1813
|
-
throw new CliUsageError(
|
|
1814
|
-
`role run ${runId} belongs to ${loaded.run.role}, not coder`,
|
|
1815
|
-
);
|
|
1816
|
-
}
|
|
1817
|
-
const phase = loaded.admittedFields.phase ?? loaded.run.phase;
|
|
1818
|
-
if (phase !== "plan" && phase !== "apply") {
|
|
1819
|
-
throw new CliUsageError(
|
|
1820
|
-
`role run admitted coder phase is missing: ${runId}`,
|
|
1821
|
-
);
|
|
1822
|
-
}
|
|
1823
|
-
const taskPath = loaded.admittedFields.taskPath;
|
|
1824
|
-
if (taskPath === undefined) {
|
|
1825
|
-
throw new CliUsageError(
|
|
1826
|
-
`role run admitted coder task path is missing: ${runId}`,
|
|
1827
|
-
);
|
|
1828
|
-
}
|
|
1829
|
-
if (loaded.admittedFields.instruction.trim() === "") {
|
|
1830
|
-
throw new CliUsageError(
|
|
1831
|
-
`role run admitted coder task is blank: ${runId}`,
|
|
1832
|
-
);
|
|
1833
|
-
}
|
|
1834
|
-
const admitted: AdmittedCoderInvocation = {
|
|
1835
|
-
role: "coder",
|
|
1836
|
-
phase,
|
|
1837
|
-
...resumedBaseAdmitted(loaded),
|
|
1838
|
-
instructionEmpty: false,
|
|
1839
|
-
taskPath,
|
|
1840
|
-
};
|
|
1841
|
-
return seatLoadedResult(loaded, admitted);
|
|
1842
|
-
}
|
|
1843
|
-
|
|
1844
|
-
/**
|
|
1845
|
-
* Load a resumable Fixer run for resume. Phase, packet, and prerequisites are
|
|
1846
|
-
* restored from the admitted request so continuation stays role-correct (#110).
|
|
1847
|
-
*/
|
|
1848
|
-
export async function loadResumableFixerRun(
|
|
1849
|
-
home: string,
|
|
1850
|
-
runId: string,
|
|
1851
|
-
authority: DurablePrincipalAuthority,
|
|
1852
|
-
): Promise<LoadedResumableFixerRun> {
|
|
1853
|
-
const loaded = await loadResumableRunRecord(home, runId, authority);
|
|
1854
|
-
if (loaded.run.role !== "fixer") {
|
|
1855
|
-
throw new CliUsageError(
|
|
1856
|
-
`role run ${runId} belongs to ${loaded.run.role}, not fixer`,
|
|
1857
|
-
);
|
|
1858
|
-
}
|
|
1859
|
-
const phase = loaded.admittedFields.phase ?? loaded.run.phase;
|
|
1860
|
-
if (phase !== "plan" && phase !== "apply") {
|
|
1861
|
-
throw new CliUsageError(
|
|
1862
|
-
`role run admitted fixer phase is missing: ${runId}`,
|
|
1863
|
-
);
|
|
1864
|
-
}
|
|
1865
|
-
const packetPath = loaded.admittedFields.packetPath;
|
|
1866
|
-
if (packetPath === undefined) {
|
|
1867
|
-
throw new CliUsageError(
|
|
1868
|
-
`role run admitted fixer packet path is missing: ${runId}`,
|
|
1869
|
-
);
|
|
1870
|
-
}
|
|
1871
|
-
if (loaded.admittedFields.instruction.trim() === "") {
|
|
1872
|
-
throw new CliUsageError(
|
|
1873
|
-
`role run admitted fixer instruction is blank: ${runId}`,
|
|
1874
|
-
);
|
|
1875
|
-
}
|
|
1876
|
-
const prerequisites = loaded.admittedFields.prerequisites ?? Object.freeze([]);
|
|
1877
|
-
const admitted: AdmittedFixerInvocation = {
|
|
1878
|
-
role: "fixer",
|
|
1879
|
-
phase,
|
|
1880
|
-
...resumedBaseAdmitted(loaded),
|
|
1881
|
-
instructionEmpty: false,
|
|
1882
|
-
packetPath,
|
|
1883
|
-
...(loaded.admittedFields.prerequisitesPath === undefined
|
|
1884
|
-
? {}
|
|
1885
|
-
: { prerequisitesPath: loaded.admittedFields.prerequisitesPath }),
|
|
1886
|
-
prerequisites,
|
|
1887
|
-
};
|
|
1888
|
-
return seatLoadedResult(loaded, admitted);
|
|
1889
|
-
}
|
|
1890
|
-
|
|
1891
|
-
/**
|
|
1892
|
-
* Peek the durable role of a run id without enforcing resumable state.
|
|
1893
|
-
* Used by public resume dispatch to pick the role-correct seat and path.
|
|
1894
|
-
*/
|
|
1895
|
-
/**
|
|
1896
|
-
* Load a resumable Reviewer run for resume. Fixed base is restored from the
|
|
1897
|
-
* admitted request; caller instruction remains optional provenance only.
|
|
1898
|
-
*/
|
|
1899
|
-
export async function loadResumableReviewerRun(
|
|
1900
|
-
home: string,
|
|
1901
|
-
runId: string,
|
|
1902
|
-
authority: DurablePrincipalAuthority,
|
|
1903
|
-
): Promise<LoadedResumableReviewerRun> {
|
|
1904
|
-
const loaded = await loadResumableRunRecord(home, runId, authority);
|
|
1905
|
-
if (loaded.run.role !== "reviewer") {
|
|
1906
|
-
throw new CliUsageError(
|
|
1907
|
-
`role run ${runId} belongs to ${loaded.run.role}, not reviewer`,
|
|
1908
|
-
);
|
|
1909
|
-
}
|
|
1910
|
-
// Durable restore keeps run identity — never rebrand record damage as fresh --base/--lens.
|
|
1911
|
-
const rawBase = loaded.admittedFields.baseRevision;
|
|
1912
|
-
if (rawBase === undefined || rawBase.trim() === "") {
|
|
1913
|
-
throw new CliUsageError(
|
|
1914
|
-
`role run admitted reviewer base revision is missing: ${runId}`,
|
|
1915
|
-
);
|
|
1916
|
-
}
|
|
1917
|
-
if (/\s/.test(rawBase) || rawBase.startsWith("-")) {
|
|
1918
|
-
throw new CliUsageError(
|
|
1919
|
-
`role run admitted reviewer base revision is damaged: ${runId}`,
|
|
1920
|
-
);
|
|
1921
|
-
}
|
|
1922
|
-
const baseRevision = rawBase;
|
|
1923
|
-
const lens = loaded.admittedFields.lens;
|
|
1924
|
-
if (!isReviewerLens(lens)) {
|
|
1925
|
-
throw new CliUsageError(
|
|
1926
|
-
`role run admitted reviewer lens is missing: ${runId}`,
|
|
1927
|
-
);
|
|
1928
|
-
}
|
|
1929
|
-
const authorityRefs = Object.freeze([
|
|
1930
|
-
...(loaded.admittedFields.authorityRefs ?? []),
|
|
1931
|
-
]);
|
|
1932
|
-
if (authorityRefs.length === 0) {
|
|
1933
|
-
throw new CliUsageError(
|
|
1934
|
-
`role run admitted reviewer authority refs are missing: ${runId}`,
|
|
1935
|
-
);
|
|
1936
|
-
}
|
|
1937
|
-
const admitted: AdmittedReviewerInvocation = {
|
|
1938
|
-
role: "reviewer",
|
|
1939
|
-
...resumedBaseAdmitted(loaded),
|
|
1940
|
-
baseRevision,
|
|
1941
|
-
lens,
|
|
1942
|
-
authorityRefs,
|
|
1943
|
-
};
|
|
1944
|
-
return seatLoadedResult(loaded, admitted);
|
|
1945
|
-
}
|
|
1946
|
-
|
|
1947
|
-
/**
|
|
1948
|
-
* Load a resumable Countersign run for resume (#599). Ticket binding and
|
|
1949
|
-
* attachments restore from the admitted request.
|
|
1950
|
-
*/
|
|
1951
|
-
export async function loadResumableCountersignRun(
|
|
1952
|
-
home: string,
|
|
1953
|
-
runId: string,
|
|
1954
|
-
authority: DurablePrincipalAuthority,
|
|
1955
|
-
): Promise<LoadedResumableCountersignRun> {
|
|
1956
|
-
const loaded = await loadResumableRunRecord(home, runId, authority);
|
|
1957
|
-
if (loaded.run.role !== "countersign") {
|
|
1958
|
-
throw new CliUsageError(
|
|
1959
|
-
`role run ${runId} belongs to ${loaded.run.role}, not countersign`,
|
|
1960
|
-
);
|
|
1961
|
-
}
|
|
1962
|
-
const base = resumedBaseAdmitted(loaded);
|
|
1963
|
-
const admitted: AdmittedCountersignInvocation = {
|
|
1964
|
-
role: "countersign",
|
|
1965
|
-
...base,
|
|
1966
|
-
...(base.courtTicketNumbers === undefined
|
|
1967
|
-
? {}
|
|
1968
|
-
: { courtTicketNumbers: base.courtTicketNumbers }),
|
|
1969
|
-
...(loaded.admittedFields.courtTicketNumbersDamage === undefined
|
|
1970
|
-
? {}
|
|
1971
|
-
: {
|
|
1972
|
-
courtTicketNumbersDamage:
|
|
1973
|
-
loaded.admittedFields.courtTicketNumbersDamage,
|
|
1974
|
-
}),
|
|
1975
|
-
};
|
|
1976
|
-
return seatLoadedResult(loaded, admitted);
|
|
1977
|
-
}
|
|
1978
|
-
|
|
1979
|
-
/**
|
|
1980
|
-
* Load a resumable Gleaner-Left run for resume (#599). Fixed base restores from
|
|
1981
|
-
* the admitted request so continuation stays comparison-correct.
|
|
1982
|
-
*/
|
|
1983
|
-
export async function loadResumableInstructionSeatRun(
|
|
1984
|
-
home: string,
|
|
1985
|
-
runId: string,
|
|
1986
|
-
authority: DurablePrincipalAuthority,
|
|
1987
|
-
): Promise<LoadedResumableInstructionSeatRun> {
|
|
1988
|
-
const loaded = await loadResumableRunRecord(home, runId, authority);
|
|
1989
|
-
if (
|
|
1990
|
-
loaded.run.role !== "gatekeeper"
|
|
1991
|
-
&& loaded.run.role !== "navigator"
|
|
1992
|
-
&& loaded.run.role !== "auditor"
|
|
1993
|
-
) {
|
|
1994
|
-
throw new CliUsageError(
|
|
1995
|
-
`role run ${runId} belongs to ${loaded.run.role}, not an instruction seat`,
|
|
1996
|
-
);
|
|
1997
|
-
}
|
|
1998
|
-
const admitted = {
|
|
1999
|
-
role: loaded.run.role,
|
|
2000
|
-
...resumedBaseAdmitted(loaded),
|
|
2001
|
-
} as
|
|
2002
|
-
| AdmittedGatekeeperInvocation
|
|
2003
|
-
| AdmittedNavigatorInvocation
|
|
2004
|
-
| import("./invocation.ts").AdmittedAuditorInvocation
|
|
2005
|
-
return seatLoadedResult(loaded, admitted);
|
|
2006
|
-
}
|
|
2007
|
-
|
|
2008
|
-
export async function loadResumableGleanerLeftRun(
|
|
2009
|
-
home: string,
|
|
2010
|
-
runId: string,
|
|
2011
|
-
authority: DurablePrincipalAuthority,
|
|
2012
|
-
): Promise<LoadedResumableGleanerLeftRun> {
|
|
2013
|
-
const loaded = await loadResumableRunRecord(home, runId, authority);
|
|
2014
|
-
if (loaded.run.role !== "gleaner-left") {
|
|
2015
|
-
throw new CliUsageError(
|
|
2016
|
-
`role run ${runId} belongs to ${loaded.run.role}, not gleaner-left`,
|
|
2017
|
-
);
|
|
2018
|
-
}
|
|
2019
|
-
const baseRevision = loaded.admittedFields.baseRevision;
|
|
2020
|
-
if (baseRevision === undefined || baseRevision.trim() === "") {
|
|
2021
|
-
throw new CliUsageError(
|
|
2022
|
-
`role run admitted gleaner-left base revision is missing: ${runId}`,
|
|
2023
|
-
);
|
|
2024
|
-
}
|
|
2025
|
-
const admitted: AdmittedGleanerLeftInvocation = {
|
|
2026
|
-
role: "gleaner-left",
|
|
2027
|
-
...resumedBaseAdmitted(loaded),
|
|
2028
|
-
baseRevision,
|
|
2029
|
-
};
|
|
2030
|
-
return seatLoadedResult(loaded, admitted);
|
|
2031
|
-
}
|
|
2032
|
-
|
|
2033
|
-
export async function loadResumableDiaristRun(
|
|
2034
|
-
home: string,
|
|
2035
|
-
runId: string,
|
|
2036
|
-
authority: DurablePrincipalAuthority,
|
|
2037
|
-
): Promise<LoadedResumableDiaristRun> {
|
|
2038
|
-
const loaded = await loadResumableRunRecord(home, runId, authority);
|
|
2039
|
-
if (loaded.run.role !== "diarist") {
|
|
2040
|
-
throw new CliUsageError(
|
|
2041
|
-
`role run ${runId} belongs to ${loaded.run.role}, not diarist`,
|
|
2042
|
-
);
|
|
2043
|
-
}
|
|
2044
|
-
const admitted: AdmittedDiaristInvocation = {
|
|
2045
|
-
role: "diarist",
|
|
2046
|
-
...resumedBaseAdmitted(loaded),
|
|
2047
|
-
};
|
|
2048
|
-
return seatLoadedResult(loaded, admitted);
|
|
2049
|
-
}
|
|
2050
|
-
|
|
2051
|
-
export async function loadResumableSecretariatRun(
|
|
2052
|
-
home: string,
|
|
2053
|
-
runId: string,
|
|
2054
|
-
authority: DurablePrincipalAuthority,
|
|
2055
|
-
): Promise<LoadedResumableSecretariatRun> {
|
|
2056
|
-
const loaded = await loadResumableRunRecord(home, runId, authority);
|
|
2057
|
-
if (loaded.run.role !== "secretariat") {
|
|
2058
|
-
throw new CliUsageError(
|
|
2059
|
-
`role run ${runId} belongs to ${loaded.run.role}, not secretariat`,
|
|
2060
|
-
);
|
|
2061
|
-
}
|
|
2062
|
-
const admitted: import("./invocation.ts").AdmittedSecretariatInvocation = {
|
|
2063
|
-
role: "secretariat",
|
|
2064
|
-
...resumedBaseAdmitted(loaded),
|
|
2065
|
-
};
|
|
2066
|
-
return seatLoadedResult(loaded, admitted);
|
|
2067
|
-
}
|
|
2068
|
-
|
|
2069
|
-
export type LoadedResumableMergerRun = {
|
|
2070
|
-
readonly admitted: AdmittedMergerInvocation;
|
|
2071
|
-
readonly run: RoleRunRecord;
|
|
2072
|
-
readonly observation?: TypedHttp429Observation;
|
|
2073
|
-
};
|
|
2074
|
-
|
|
2075
|
-
/**
|
|
2076
|
-
* Load a resumable Merger run for resume. Derived envelope + internal input path
|
|
2077
|
-
* are restored from the admitted request (#114).
|
|
2078
|
-
*/
|
|
2079
|
-
export async function loadResumableMergerRun(
|
|
2080
|
-
home: string,
|
|
2081
|
-
runId: string,
|
|
2082
|
-
authority: DurablePrincipalAuthority,
|
|
2083
|
-
): Promise<LoadedResumableMergerRun> {
|
|
2084
|
-
const loaded = await loadResumableRunRecord(home, runId, authority);
|
|
2085
|
-
if (loaded.run.role !== "merger") {
|
|
2086
|
-
throw new CliUsageError(
|
|
2087
|
-
`role run ${runId} belongs to ${loaded.run.role}, not merger`,
|
|
2088
|
-
);
|
|
2089
|
-
}
|
|
2090
|
-
const mergerInputPath = loaded.admittedFields.mergerInputPath;
|
|
2091
|
-
if (mergerInputPath === undefined) {
|
|
2092
|
-
throw new CliUsageError(
|
|
2093
|
-
`role run admitted merger input path is missing: ${runId}`,
|
|
2094
|
-
);
|
|
2095
|
-
}
|
|
2096
|
-
const derived = loaded.admittedFields.derived;
|
|
2097
|
-
if (derived === undefined) {
|
|
2098
|
-
throw new CliUsageError(
|
|
2099
|
-
`role run admitted merger envelope is missing: ${runId}`,
|
|
2100
|
-
);
|
|
2101
|
-
}
|
|
2102
|
-
if (loaded.admittedFields.instruction.trim() === "") {
|
|
2103
|
-
throw new CliUsageError(
|
|
2104
|
-
`role run admitted merger task is blank: ${runId}`,
|
|
2105
|
-
);
|
|
2106
|
-
}
|
|
2107
|
-
const admitted: AdmittedMergerInvocation = {
|
|
2108
|
-
role: "merger",
|
|
2109
|
-
...resumedBaseAdmitted(loaded),
|
|
2110
|
-
instructionEmpty: false,
|
|
2111
|
-
mergerInputPath,
|
|
2112
|
-
derived,
|
|
2113
|
-
};
|
|
2114
|
-
return seatLoadedResult(loaded, admitted);
|
|
2115
|
-
}
|
|
2116
|
-
|
|
2117
|
-
export type LoadedResumableCollectorRun = {
|
|
2118
|
-
readonly admitted: AdmittedCollectorInvocation;
|
|
2119
|
-
readonly run: RoleRunRecord;
|
|
2120
|
-
readonly observation?: TypedHttp429Observation;
|
|
2121
|
-
};
|
|
2122
|
-
|
|
2123
|
-
/**
|
|
2124
|
-
* Load a resumable Collector run for resume (#633). Admitted repository/PR
|
|
2125
|
-
* identity restores from the durable admitted request so the continuation
|
|
2126
|
-
* stays binding-correct.
|
|
2127
|
-
*/
|
|
2128
|
-
export async function loadResumableCollectorRun(
|
|
2129
|
-
home: string,
|
|
2130
|
-
runId: string,
|
|
2131
|
-
authority: DurablePrincipalAuthority,
|
|
2132
|
-
): Promise<LoadedResumableCollectorRun> {
|
|
2133
|
-
const loaded = await loadResumableRunRecord(home, runId, authority);
|
|
2134
|
-
if (loaded.run.role !== "collector") {
|
|
2135
|
-
throw new CliUsageError(
|
|
2136
|
-
`role run ${runId} belongs to ${loaded.run.role}, not collector`,
|
|
2137
|
-
);
|
|
2138
|
-
}
|
|
2139
|
-
const { prNumber, repository, repositoryDisplay, manifestDigest } = loaded.admittedFields;
|
|
2140
|
-
// #676 A: prNumber may be unbound at admission (role bind-target). Repository is required.
|
|
2141
|
-
if (
|
|
2142
|
-
repository === undefined ||
|
|
2143
|
-
repositoryDisplay === undefined ||
|
|
2144
|
-
manifestDigest === undefined
|
|
2145
|
-
) {
|
|
2146
|
-
throw new CliUsageError(
|
|
2147
|
-
`role run admitted collector repository identity is missing: ${runId}`,
|
|
2148
|
-
);
|
|
2149
|
-
}
|
|
2150
|
-
let parsedRepository;
|
|
2151
|
-
try {
|
|
2152
|
-
parsedRepository = parseCollectorRepository(repositoryDisplay);
|
|
2153
|
-
} catch (error) {
|
|
2154
|
-
const detail = error instanceof Error ? error.message : String(error);
|
|
2155
|
-
throw new CliUsageError(detail, { cause: error });
|
|
2156
|
-
}
|
|
2157
|
-
if (parsedRepository.canonical !== repository) {
|
|
2158
|
-
throw new CliUsageError(
|
|
2159
|
-
`role run admitted collector repository does not match its canonical form: ${runId}`,
|
|
2160
|
-
);
|
|
2161
|
-
}
|
|
2162
|
-
const admitted: AdmittedCollectorInvocation = {
|
|
2163
|
-
role: "collector",
|
|
2164
|
-
...resumedBaseAdmitted(loaded),
|
|
2165
|
-
...(prNumber === undefined ? {} : { prNumber }),
|
|
2166
|
-
repository: parsedRepository,
|
|
2167
|
-
...(loaded.admittedFields.requestManifestPath === undefined
|
|
2168
|
-
? {}
|
|
2169
|
-
: { requestManifestPath: loaded.admittedFields.requestManifestPath }),
|
|
2170
|
-
...(loaded.admittedFields.waitWindowMs === undefined
|
|
2171
|
-
? {}
|
|
2172
|
-
: { waitWindowMs: loaded.admittedFields.waitWindowMs }),
|
|
2173
|
-
manifestDigest,
|
|
2174
|
-
};
|
|
2175
|
-
return seatLoadedResult(loaded, admitted);
|
|
2176
|
-
}
|
|
2177
|
-
|
|
2178
|
-
export type LoadedResumableDoctorRun = {
|
|
2179
|
-
readonly admitted: AdmittedDoctorInvocation;
|
|
2180
|
-
readonly run: RoleRunRecord;
|
|
2181
|
-
readonly observation?: TypedHttp429Observation;
|
|
2182
|
-
};
|
|
2183
|
-
|
|
2184
|
-
/**
|
|
2185
|
-
* Load a resumable Doctor run for resume (#633). Issue + retained case
|
|
2186
|
-
* identity restore from the durable admitted request.
|
|
2187
|
-
*/
|
|
2188
|
-
export async function loadResumableDoctorRun(
|
|
2189
|
-
home: string,
|
|
2190
|
-
runId: string,
|
|
2191
|
-
authority: DurablePrincipalAuthority,
|
|
2192
|
-
): Promise<LoadedResumableDoctorRun> {
|
|
2193
|
-
const loaded = await loadResumableRunRecord(home, runId, authority);
|
|
2194
|
-
if (loaded.run.role !== "doctor") {
|
|
2195
|
-
throw new CliUsageError(
|
|
2196
|
-
`role run ${runId} belongs to ${loaded.run.role}, not doctor`,
|
|
2197
|
-
);
|
|
2198
|
-
}
|
|
2199
|
-
const { issueNumber, caseRunsPath, caseIdentity } = loaded.admittedFields;
|
|
2200
|
-
if (
|
|
2201
|
-
issueNumber === undefined ||
|
|
2202
|
-
caseRunsPath === undefined ||
|
|
2203
|
-
caseIdentity === undefined
|
|
2204
|
-
) {
|
|
2205
|
-
throw new CliUsageError(
|
|
2206
|
-
`role run admitted doctor case identity is missing: ${runId}`,
|
|
2207
|
-
);
|
|
2208
|
-
}
|
|
2209
|
-
const admitted: AdmittedDoctorInvocation = {
|
|
2210
|
-
role: "doctor",
|
|
2211
|
-
...resumedBaseAdmitted(loaded),
|
|
2212
|
-
issueNumber,
|
|
2213
|
-
caseRunsPath,
|
|
2214
|
-
caseIdentity,
|
|
2215
|
-
};
|
|
2216
|
-
return seatLoadedResult(loaded, admitted);
|
|
2217
|
-
}
|
|
2218
|
-
|
|
2219
|
-
export type LoadedResumableNotaryRun = {
|
|
2220
|
-
readonly admitted: AdmittedNotaryInvocation;
|
|
2221
|
-
readonly run: RoleRunRecord;
|
|
2222
|
-
readonly observation?: TypedHttp429Observation;
|
|
2223
|
-
};
|
|
2224
|
-
|
|
2225
|
-
/**
|
|
2226
|
-
* Load a resumable Notary run for resume (#633). Source-run locator restores
|
|
2227
|
-
* from the durable admitted request; the locator is not re-resolved.
|
|
2228
|
-
*/
|
|
2229
|
-
export async function loadResumableNotaryRun(
|
|
2230
|
-
home: string,
|
|
2231
|
-
runId: string,
|
|
2232
|
-
authority: DurablePrincipalAuthority,
|
|
2233
|
-
): Promise<LoadedResumableNotaryRun> {
|
|
2234
|
-
const loaded = await loadResumableRunRecord(home, runId, authority);
|
|
2235
|
-
if (loaded.run.role !== "notary") {
|
|
2236
|
-
throw new CliUsageError(
|
|
2237
|
-
`role run ${runId} belongs to ${loaded.run.role}, not notary`,
|
|
2238
|
-
);
|
|
2239
|
-
}
|
|
2240
|
-
const { sourceRunPath, sourceRun } = loaded.admittedFields;
|
|
2241
|
-
if (sourceRunPath === undefined || sourceRun === undefined) {
|
|
2242
|
-
throw new CliUsageError(
|
|
2243
|
-
`role run admitted notary source-run locator is missing: ${runId}`,
|
|
2244
|
-
);
|
|
2245
|
-
}
|
|
2246
|
-
const admitted: AdmittedNotaryInvocation = {
|
|
2247
|
-
role: "notary",
|
|
2248
|
-
...resumedBaseAdmitted(loaded),
|
|
2249
|
-
sourceRunPath,
|
|
2250
|
-
sourceRun,
|
|
2251
|
-
};
|
|
2252
|
-
return seatLoadedResult(loaded, admitted);
|
|
2253
|
-
}
|
|
2254
|
-
|
|
2255
|
-
export type LoadedResumableInspectorRun = {
|
|
2256
|
-
readonly admitted: AdmittedInspectorInvocation;
|
|
2257
|
-
readonly run: RoleRunRecord;
|
|
2258
|
-
readonly observation?: TypedHttp429Observation;
|
|
2259
|
-
};
|
|
2260
|
-
|
|
2261
|
-
/** Load a resumable Inspector run for resume (#633); base admitted identity only. */
|
|
2262
|
-
export async function loadResumableInspectorRun(
|
|
2263
|
-
home: string,
|
|
2264
|
-
runId: string,
|
|
2265
|
-
authority: DurablePrincipalAuthority,
|
|
2266
|
-
): Promise<LoadedResumableInspectorRun> {
|
|
2267
|
-
const loaded = await loadResumableRunRecord(home, runId, authority);
|
|
2268
|
-
if (loaded.run.role !== "inspector") {
|
|
2269
|
-
throw new CliUsageError(
|
|
2270
|
-
`role run ${runId} belongs to ${loaded.run.role}, not inspector`,
|
|
2271
|
-
);
|
|
2272
|
-
}
|
|
2273
|
-
const admitted: AdmittedInspectorInvocation = {
|
|
2274
|
-
role: "inspector",
|
|
2275
|
-
...resumedBaseAdmitted(loaded),
|
|
2276
|
-
...(loaded.admittedFields.sourceRunPath === undefined
|
|
2277
|
-
? {}
|
|
2278
|
-
: { sourceRunPath: loaded.admittedFields.sourceRunPath }),
|
|
2279
|
-
};
|
|
2280
|
-
return seatLoadedResult(loaded, admitted);
|
|
2281
|
-
}
|
|
2282
1691
|
|
|
2283
1692
|
export async function peekRoleRunRole(
|
|
2284
1693
|
home: string,
|
|
@@ -2307,3 +1716,284 @@ export async function peekRoleRunRole(
|
|
|
2307
1716
|
const run = await readRoleRunIdentity(runDirectory);
|
|
2308
1717
|
return run?.role;
|
|
2309
1718
|
}
|
|
1719
|
+
|
|
1720
|
+
|
|
1721
|
+
export type LoadedResumablePublicRole = {
|
|
1722
|
+
readonly admitted: AdmittedRoleInvocation;
|
|
1723
|
+
readonly run: RoleRunRecord;
|
|
1724
|
+
readonly observation?: TypedHttp429Observation;
|
|
1725
|
+
};
|
|
1726
|
+
|
|
1727
|
+
/**
|
|
1728
|
+
* One resume load. The caller supplies the package run id; the disk role
|
|
1729
|
+
* selects the existing restore checks. The stored native host session id is
|
|
1730
|
+
* read on the public explicit resume seam, not from this load.
|
|
1731
|
+
*/
|
|
1732
|
+
export async function loadResumablePublicRole(
|
|
1733
|
+
home: string,
|
|
1734
|
+
runId: string,
|
|
1735
|
+
authority: DurablePrincipalAuthority,
|
|
1736
|
+
): Promise<LoadedResumablePublicRole> {
|
|
1737
|
+
const loaded = await loadResumableRunRecord(home, runId, authority);
|
|
1738
|
+
return seatLoadedResult(loaded, admitResumedRole(loaded));
|
|
1739
|
+
}
|
|
1740
|
+
|
|
1741
|
+
/**
|
|
1742
|
+
* One resume restore. Admission kind comes from the composition-root record;
|
|
1743
|
+
* seat-only required fields stay on that kind. Instruction seats share one face.
|
|
1744
|
+
*/
|
|
1745
|
+
function admitResumedRole(loaded: {
|
|
1746
|
+
readonly run: RoleRunRecord;
|
|
1747
|
+
readonly principal: DurablePrincipal;
|
|
1748
|
+
readonly observation?: TypedHttp429Observation;
|
|
1749
|
+
readonly admittedFields: LoadedAdmittedRequestFields;
|
|
1750
|
+
}): AdmittedRoleInvocation {
|
|
1751
|
+
const role = loaded.run.role;
|
|
1752
|
+
const runId = loaded.run.runId;
|
|
1753
|
+
const record = packagedRoleMetadata(role);
|
|
1754
|
+
if (record === undefined) {
|
|
1755
|
+
throw new CliUsageError(`unknown role: ${role}`);
|
|
1756
|
+
}
|
|
1757
|
+
const fields = loaded.admittedFields;
|
|
1758
|
+
const base = resumedBaseAdmitted(loaded);
|
|
1759
|
+
switch (record.admission) {
|
|
1760
|
+
case "instruction": {
|
|
1761
|
+
if (packagedResumeSourcePath(role)) {
|
|
1762
|
+
const admitted: AdmittedInspectorInvocation = {
|
|
1763
|
+
role: "inspector",
|
|
1764
|
+
...base,
|
|
1765
|
+
...(fields.sourceRunPath === undefined
|
|
1766
|
+
? {}
|
|
1767
|
+
: { sourceRunPath: fields.sourceRunPath }),
|
|
1768
|
+
};
|
|
1769
|
+
return admitted;
|
|
1770
|
+
}
|
|
1771
|
+
return {
|
|
1772
|
+
role,
|
|
1773
|
+
...base,
|
|
1774
|
+
} as AdmittedRoleInvocation;
|
|
1775
|
+
}
|
|
1776
|
+
case "court-materials": {
|
|
1777
|
+
const admitted: AdmittedCountersignInvocation = {
|
|
1778
|
+
role: "countersign",
|
|
1779
|
+
...base,
|
|
1780
|
+
...(base.courtTicketNumbers === undefined
|
|
1781
|
+
? {}
|
|
1782
|
+
: { courtTicketNumbers: base.courtTicketNumbers }),
|
|
1783
|
+
...(fields.courtTicketNumbersDamage === undefined
|
|
1784
|
+
? {}
|
|
1785
|
+
: { courtTicketNumbersDamage: fields.courtTicketNumbersDamage }),
|
|
1786
|
+
};
|
|
1787
|
+
return admitted;
|
|
1788
|
+
}
|
|
1789
|
+
case "worker-task": {
|
|
1790
|
+
const phase = resumedWorkerPhase(fields.phase ?? loaded.run.phase, record.phases, role, runId);
|
|
1791
|
+
const taskPath = fields.taskPath;
|
|
1792
|
+
if (taskPath === undefined) {
|
|
1793
|
+
throw new CliUsageError(
|
|
1794
|
+
`role run admitted coder task path is missing: ${runId}`,
|
|
1795
|
+
);
|
|
1796
|
+
}
|
|
1797
|
+
if (fields.instruction.trim() === "") {
|
|
1798
|
+
throw new CliUsageError(
|
|
1799
|
+
`role run admitted coder task is blank: ${runId}`,
|
|
1800
|
+
);
|
|
1801
|
+
}
|
|
1802
|
+
const admitted: AdmittedCoderInvocation = {
|
|
1803
|
+
role: "coder",
|
|
1804
|
+
phase,
|
|
1805
|
+
...base,
|
|
1806
|
+
instructionEmpty: false,
|
|
1807
|
+
taskPath,
|
|
1808
|
+
};
|
|
1809
|
+
return admitted;
|
|
1810
|
+
}
|
|
1811
|
+
case "worker-packet": {
|
|
1812
|
+
const phase = resumedWorkerPhase(fields.phase ?? loaded.run.phase, record.phases, role, runId);
|
|
1813
|
+
const packetPath = fields.packetPath;
|
|
1814
|
+
if (packetPath === undefined) {
|
|
1815
|
+
throw new CliUsageError(
|
|
1816
|
+
`role run admitted fixer packet path is missing: ${runId}`,
|
|
1817
|
+
);
|
|
1818
|
+
}
|
|
1819
|
+
if (fields.instruction.trim() === "") {
|
|
1820
|
+
throw new CliUsageError(
|
|
1821
|
+
`role run admitted fixer instruction is blank: ${runId}`,
|
|
1822
|
+
);
|
|
1823
|
+
}
|
|
1824
|
+
const prerequisites = fields.prerequisites ?? Object.freeze([]);
|
|
1825
|
+
const admitted: AdmittedFixerInvocation = {
|
|
1826
|
+
role: "fixer",
|
|
1827
|
+
phase,
|
|
1828
|
+
...base,
|
|
1829
|
+
instructionEmpty: false,
|
|
1830
|
+
packetPath,
|
|
1831
|
+
...(fields.prerequisitesPath === undefined
|
|
1832
|
+
? {}
|
|
1833
|
+
: { prerequisitesPath: fields.prerequisitesPath }),
|
|
1834
|
+
prerequisites,
|
|
1835
|
+
};
|
|
1836
|
+
return admitted;
|
|
1837
|
+
}
|
|
1838
|
+
case "review-basis": {
|
|
1839
|
+
const rawBase = fields.baseRevision;
|
|
1840
|
+
if (rawBase === undefined || rawBase.trim() === "") {
|
|
1841
|
+
throw new CliUsageError(
|
|
1842
|
+
`role run admitted reviewer base revision is missing: ${runId}`,
|
|
1843
|
+
);
|
|
1844
|
+
}
|
|
1845
|
+
if (/\s/.test(rawBase) || rawBase.startsWith("-")) {
|
|
1846
|
+
throw new CliUsageError(
|
|
1847
|
+
`role run admitted reviewer base revision is damaged: ${runId}`,
|
|
1848
|
+
);
|
|
1849
|
+
}
|
|
1850
|
+
const lens = fields.lens;
|
|
1851
|
+
if (!isReviewerLens(lens)) {
|
|
1852
|
+
throw new CliUsageError(
|
|
1853
|
+
`role run admitted reviewer lens is missing: ${runId}`,
|
|
1854
|
+
);
|
|
1855
|
+
}
|
|
1856
|
+
const authorityRefs = Object.freeze([...(fields.authorityRefs ?? [])]);
|
|
1857
|
+
if (authorityRefs.length === 0) {
|
|
1858
|
+
throw new CliUsageError(
|
|
1859
|
+
`role run admitted reviewer authority refs are missing: ${runId}`,
|
|
1860
|
+
);
|
|
1861
|
+
}
|
|
1862
|
+
const admitted: AdmittedReviewerInvocation = {
|
|
1863
|
+
role: "reviewer",
|
|
1864
|
+
...base,
|
|
1865
|
+
baseRevision: rawBase,
|
|
1866
|
+
lens,
|
|
1867
|
+
authorityRefs,
|
|
1868
|
+
};
|
|
1869
|
+
return admitted;
|
|
1870
|
+
}
|
|
1871
|
+
case "gleaner": {
|
|
1872
|
+
const baseRevision = fields.baseRevision;
|
|
1873
|
+
if (baseRevision === undefined || baseRevision.trim() === "") {
|
|
1874
|
+
throw new CliUsageError(
|
|
1875
|
+
`role run admitted gleaner-left base revision is missing: ${runId}`,
|
|
1876
|
+
);
|
|
1877
|
+
}
|
|
1878
|
+
const admitted: AdmittedGleanerLeftInvocation = {
|
|
1879
|
+
role: "gleaner-left",
|
|
1880
|
+
...base,
|
|
1881
|
+
baseRevision,
|
|
1882
|
+
};
|
|
1883
|
+
return admitted;
|
|
1884
|
+
}
|
|
1885
|
+
case "merge-envelope": {
|
|
1886
|
+
const mergerInputPath = fields.mergerInputPath;
|
|
1887
|
+
if (mergerInputPath === undefined) {
|
|
1888
|
+
throw new CliUsageError(
|
|
1889
|
+
`role run admitted merger input path is missing: ${runId}`,
|
|
1890
|
+
);
|
|
1891
|
+
}
|
|
1892
|
+
const derived = fields.derived;
|
|
1893
|
+
if (derived === undefined) {
|
|
1894
|
+
throw new CliUsageError(
|
|
1895
|
+
`role run admitted merger envelope is missing: ${runId}`,
|
|
1896
|
+
);
|
|
1897
|
+
}
|
|
1898
|
+
if (fields.instruction.trim() === "") {
|
|
1899
|
+
throw new CliUsageError(
|
|
1900
|
+
`role run admitted merger task is blank: ${runId}`,
|
|
1901
|
+
);
|
|
1902
|
+
}
|
|
1903
|
+
const admitted: AdmittedMergerInvocation = {
|
|
1904
|
+
role: "merger",
|
|
1905
|
+
...base,
|
|
1906
|
+
instructionEmpty: false,
|
|
1907
|
+
mergerInputPath,
|
|
1908
|
+
derived,
|
|
1909
|
+
};
|
|
1910
|
+
return admitted;
|
|
1911
|
+
}
|
|
1912
|
+
case "collect-target": {
|
|
1913
|
+
const { prNumber, repository, repositoryDisplay, manifestDigest } = fields;
|
|
1914
|
+
if (
|
|
1915
|
+
repository === undefined ||
|
|
1916
|
+
repositoryDisplay === undefined ||
|
|
1917
|
+
manifestDigest === undefined
|
|
1918
|
+
) {
|
|
1919
|
+
throw new CliUsageError(
|
|
1920
|
+
`role run admitted collector repository identity is missing: ${runId}`,
|
|
1921
|
+
);
|
|
1922
|
+
}
|
|
1923
|
+
let parsedRepository;
|
|
1924
|
+
try {
|
|
1925
|
+
parsedRepository = parseCollectorRepository(repositoryDisplay);
|
|
1926
|
+
} catch (error) {
|
|
1927
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
1928
|
+
throw new CliUsageError(detail, { cause: error });
|
|
1929
|
+
}
|
|
1930
|
+
if (parsedRepository.canonical !== repository) {
|
|
1931
|
+
throw new CliUsageError(
|
|
1932
|
+
`role run admitted collector repository does not match its canonical form: ${runId}`,
|
|
1933
|
+
);
|
|
1934
|
+
}
|
|
1935
|
+
const admitted: AdmittedCollectorInvocation = {
|
|
1936
|
+
role: "collector",
|
|
1937
|
+
...base,
|
|
1938
|
+
...(prNumber === undefined ? {} : { prNumber }),
|
|
1939
|
+
repository: parsedRepository,
|
|
1940
|
+
...(fields.requestManifestPath === undefined
|
|
1941
|
+
? {}
|
|
1942
|
+
: { requestManifestPath: fields.requestManifestPath }),
|
|
1943
|
+
...(fields.waitWindowMs === undefined ? {} : { waitWindowMs: fields.waitWindowMs }),
|
|
1944
|
+
manifestDigest,
|
|
1945
|
+
};
|
|
1946
|
+
return admitted;
|
|
1947
|
+
}
|
|
1948
|
+
case "case-identity": {
|
|
1949
|
+
const { issueNumber, caseRunsPath, caseIdentity } = fields;
|
|
1950
|
+
if (
|
|
1951
|
+
issueNumber === undefined ||
|
|
1952
|
+
caseRunsPath === undefined ||
|
|
1953
|
+
caseIdentity === undefined
|
|
1954
|
+
) {
|
|
1955
|
+
throw new CliUsageError(
|
|
1956
|
+
`role run admitted doctor case identity is missing: ${runId}`,
|
|
1957
|
+
);
|
|
1958
|
+
}
|
|
1959
|
+
const admitted: AdmittedDoctorInvocation = {
|
|
1960
|
+
role: "doctor",
|
|
1961
|
+
...base,
|
|
1962
|
+
issueNumber,
|
|
1963
|
+
caseRunsPath,
|
|
1964
|
+
caseIdentity,
|
|
1965
|
+
};
|
|
1966
|
+
return admitted;
|
|
1967
|
+
}
|
|
1968
|
+
case "source-locator": {
|
|
1969
|
+
const { sourceRunPath, sourceRun } = fields;
|
|
1970
|
+
if (sourceRunPath === undefined || sourceRun === undefined) {
|
|
1971
|
+
throw new CliUsageError(
|
|
1972
|
+
`role run admitted notary source-run locator is missing: ${runId}`,
|
|
1973
|
+
);
|
|
1974
|
+
}
|
|
1975
|
+
const admitted: AdmittedNotaryInvocation = {
|
|
1976
|
+
role: "notary",
|
|
1977
|
+
...base,
|
|
1978
|
+
sourceRunPath,
|
|
1979
|
+
sourceRun,
|
|
1980
|
+
};
|
|
1981
|
+
return admitted;
|
|
1982
|
+
}
|
|
1983
|
+
}
|
|
1984
|
+
}
|
|
1985
|
+
|
|
1986
|
+
/** Worker phase on resume: value must belong to the registry phase set. */
|
|
1987
|
+
function resumedWorkerPhase(
|
|
1988
|
+
phase: string | undefined,
|
|
1989
|
+
phases: readonly (string | null)[],
|
|
1990
|
+
role: string,
|
|
1991
|
+
runId: string,
|
|
1992
|
+
): "plan" | "apply" {
|
|
1993
|
+
if (phase === "plan" || phase === "apply") {
|
|
1994
|
+
if (phases.some((item) => item === phase)) {
|
|
1995
|
+
return phase;
|
|
1996
|
+
}
|
|
1997
|
+
}
|
|
1998
|
+
throw new CliUsageError(`role run admitted ${role} phase is missing: ${runId}`);
|
|
1999
|
+
}
|