@intentius/chant 0.124.25 → 0.124.26

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 (104) hide show
  1. package/dist/cli/commands/build.d.ts.map +1 -1
  2. package/dist/cli/commands/build.js +4 -2
  3. package/dist/cli/commands/lint.d.ts.map +1 -1
  4. package/dist/cli/commands/lint.js +4 -2
  5. package/dist/cli/handlers/approve.d.ts.map +1 -1
  6. package/dist/cli/handlers/approve.js +39 -4
  7. package/dist/gate-decision.d.ts +1 -1
  8. package/dist/gate-decision.d.ts.map +1 -1
  9. package/dist/gate-decision.js +1 -1
  10. package/dist/lifecycle/gate-audit.d.ts +7 -1
  11. package/dist/lifecycle/gate-audit.d.ts.map +1 -1
  12. package/dist/lifecycle/gate-audit.js +40 -3
  13. package/dist/lifecycle/gate-checkpoint.d.ts +78 -0
  14. package/dist/lifecycle/gate-checkpoint.d.ts.map +1 -0
  15. package/dist/lifecycle/gate-checkpoint.js +103 -0
  16. package/dist/lifecycle/gate-ledger.d.ts +41 -0
  17. package/dist/lifecycle/gate-ledger.d.ts.map +1 -1
  18. package/dist/lifecycle/gate-ledger.js +18 -0
  19. package/dist/lifecycle/run-ledger.d.ts +2 -0
  20. package/dist/lifecycle/run-ledger.d.ts.map +1 -1
  21. package/dist/lifecycle/run-ledger.js +2 -0
  22. package/dist/lint/rules/op/index.d.ts +6 -2
  23. package/dist/lint/rules/op/index.d.ts.map +1 -1
  24. package/dist/lint/rules/op/index.js +7 -3
  25. package/dist/lint/rules/op/ops016-gate-resume.d.ts +14 -0
  26. package/dist/lint/rules/op/ops016-gate-resume.d.ts.map +1 -0
  27. package/dist/lint/rules/op/ops016-gate-resume.js +31 -0
  28. package/dist/lint/rules/op/ops017-gate-alias.d.ts +30 -0
  29. package/dist/lint/rules/op/ops017-gate-alias.d.ts.map +1 -0
  30. package/dist/lint/rules/op/ops017-gate-alias.js +67 -0
  31. package/dist/op/activity-contract.d.ts +14 -0
  32. package/dist/op/activity-contract.d.ts.map +1 -1
  33. package/dist/op/activity-contract.js +16 -0
  34. package/dist/op/builders.d.ts +7 -0
  35. package/dist/op/builders.d.ts.map +1 -1
  36. package/dist/op/builders.js +13 -0
  37. package/dist/op/gate-alias.d.ts +57 -0
  38. package/dist/op/gate-alias.d.ts.map +1 -0
  39. package/dist/op/gate-alias.js +127 -0
  40. package/dist/op/gate-checkpoint.d.ts +123 -0
  41. package/dist/op/gate-checkpoint.d.ts.map +1 -0
  42. package/dist/op/gate-checkpoint.js +280 -0
  43. package/dist/op/gate.d.ts +54 -2
  44. package/dist/op/gate.d.ts.map +1 -1
  45. package/dist/op/gate.js +142 -1
  46. package/dist/op/index.d.ts +4 -1
  47. package/dist/op/index.d.ts.map +1 -1
  48. package/dist/op/index.js +2 -1
  49. package/dist/op/local-executor.d.ts +57 -2
  50. package/dist/op/local-executor.d.ts.map +1 -1
  51. package/dist/op/local-executor.js +136 -6
  52. package/dist/op/local-output.d.ts.map +1 -1
  53. package/dist/op/local-output.js +20 -2
  54. package/dist/op/op-ir.d.ts +4 -0
  55. package/dist/op/op-ir.d.ts.map +1 -1
  56. package/dist/op/op-ir.js +4 -0
  57. package/dist/op/runtime.d.ts +15 -0
  58. package/dist/op/runtime.d.ts.map +1 -1
  59. package/dist/op/runtimes/local.d.ts.map +1 -1
  60. package/dist/op/runtimes/local.js +5 -0
  61. package/dist/op/types.d.ts +31 -0
  62. package/dist/op/types.d.ts.map +1 -1
  63. package/dist/wave-runtime.mjs +214 -212
  64. package/dist/workspace/trust/gate-seal.d.ts +32 -1
  65. package/dist/workspace/trust/gate-seal.d.ts.map +1 -1
  66. package/dist/workspace/trust/gate-seal.js +41 -2
  67. package/dist/workspace/trust/seal.d.ts +1 -1
  68. package/dist/workspace/trust/seal.d.ts.map +1 -1
  69. package/dist/workspace/trust/seal.js +1 -1
  70. package/package.json +1 -1
  71. package/src/cli/commands/build.ts +9 -2
  72. package/src/cli/commands/lint.ts +4 -2
  73. package/src/cli/handlers/approve.ts +46 -4
  74. package/src/cli/handlers/operator.test.ts +91 -0
  75. package/src/gate-decision.ts +2 -0
  76. package/src/lifecycle/gate-audit.ts +41 -4
  77. package/src/lifecycle/gate-checkpoint.test.ts +128 -0
  78. package/src/lifecycle/gate-checkpoint.ts +133 -0
  79. package/src/lifecycle/gate-ledger.ts +61 -0
  80. package/src/lifecycle/run-ledger.ts +4 -0
  81. package/src/lint/rules/op/index.ts +9 -3
  82. package/src/lint/rules/op/ops016-gate-resume.test.ts +53 -0
  83. package/src/lint/rules/op/ops016-gate-resume.ts +48 -0
  84. package/src/lint/rules/op/ops017-gate-alias.test.ts +85 -0
  85. package/src/lint/rules/op/ops017-gate-alias.ts +89 -0
  86. package/src/op/activity-contract.ts +22 -1
  87. package/src/op/builders.ts +21 -1
  88. package/src/op/gate-alias.e2e.test.ts +78 -0
  89. package/src/op/gate-alias.test.ts +350 -0
  90. package/src/op/gate-alias.ts +137 -0
  91. package/src/op/gate-checkpoint.test.ts +284 -0
  92. package/src/op/gate-checkpoint.ts +322 -0
  93. package/src/op/gate.ts +198 -4
  94. package/src/op/index.ts +4 -1
  95. package/src/op/local-executor.ts +180 -7
  96. package/src/op/local-output.ts +18 -2
  97. package/src/op/op-ir.test.ts +25 -0
  98. package/src/op/op-ir.ts +8 -0
  99. package/src/op/runtime.ts +8 -0
  100. package/src/op/runtimes/local.ts +5 -0
  101. package/src/op/types.ts +32 -0
  102. package/src/workspace/trust/gate-seal.test.ts +29 -2
  103. package/src/workspace/trust/gate-seal.ts +46 -2
  104. package/src/workspace/trust/seal.ts +1 -1
@@ -0,0 +1,127 @@
1
+ /**
2
+ * Gate aliases (#3949, epic #3946): the names a gate had before its Op was
3
+ * restructured, so the approvals already on the ledger under them still
4
+ * count.
5
+ *
6
+ * A gate's identity is its name and its Op's: the ledger is per Op
7
+ * (`_gates/<op>.jsonl`) and every decision filters by gate. Merging three
8
+ * per-tier Ops into one wave-driven Op renames every gate and orphans the
9
+ * approvals recorded under the old names. A gate declares those names as
10
+ * `aliases: [{ op?, gate }]`, `op` defaulting to its own Op.
11
+ *
12
+ * `evaluateGate` (`./gate.ts`) decides which approvals an alias admits, and
13
+ * writes each one it counts again under the new name with `carriedFrom`
14
+ * naming the line it came from. This module holds the parts that read only
15
+ * the Op's config: where its gates are, what an alias resolves to, what the
16
+ * builder and OPS017 refuse, and which gate aliases an old name, which
17
+ * `chant approve` asks before it records an approval under that name.
18
+ */
19
+ import { gateName } from "./gate-name.js";
20
+ /** Every gate step of `config`, main phases first, then `onFailure`, inside effects too, with the phase it sits in. */
21
+ export function gateStepsOf(config) {
22
+ const out = [];
23
+ const visit = (phase, step) => {
24
+ if (step.kind === "gate")
25
+ out.push({ phase, step });
26
+ else if (step.kind === "effect")
27
+ for (const nested of step.steps)
28
+ visit(phase, nested);
29
+ };
30
+ for (const phase of [...config.phases, ...(config.onFailure ?? [])])
31
+ for (const step of phase.steps)
32
+ visit(phase.name, step);
33
+ return out;
34
+ }
35
+ /** A gate's aliases with each `op` filled in from `op`, the gate's own Op. */
36
+ export function resolveGateAliases(step, op) {
37
+ return (step.aliases ?? []).map((a) => ({ op: a.op ?? op, gate: a.gate }));
38
+ }
39
+ /** Why a gate's `aliases` can't stand on the step itself, one line each. The builder throws the first. */
40
+ export function gateAliasProblems(aliases, step) {
41
+ const problems = [];
42
+ if (step.plan === undefined) {
43
+ problems.push("aliases need a plan: an alias admits only approvals of the plan this run planned, and a gate with no plan has none");
44
+ }
45
+ if (step.point !== undefined)
46
+ problems.push("a gate that asks a decision point can't take aliases");
47
+ const seen = new Set();
48
+ for (const a of aliases) {
49
+ if (typeof a?.gate !== "string" || a.gate === "") {
50
+ problems.push("each alias names a gate");
51
+ continue;
52
+ }
53
+ if (a.op !== undefined && (typeof a.op !== "string" || a.op === ""))
54
+ problems.push(`alias ${JSON.stringify(a.gate)} names an empty op`);
55
+ const key = `${a.op ?? ""}/${a.gate}`;
56
+ if (seen.has(key))
57
+ problems.push(`alias ${a.op ? `${a.op}/` : ""}${a.gate} is listed twice`);
58
+ seen.add(key);
59
+ }
60
+ return problems;
61
+ }
62
+ /** The gate of `ops` whose aliases include `op`/`gate`, or undefined when none does. */
63
+ export function aliasingGate(ops, op, gate) {
64
+ for (const config of ops) {
65
+ if (!config || !Array.isArray(config.phases))
66
+ continue;
67
+ for (const { step } of gateStepsOf(config)) {
68
+ if (resolveGateAliases(step, config.name).some((a) => a.op === op && a.gate === gate))
69
+ return { op: config.name, gate: gateName(step) };
70
+ }
71
+ }
72
+ return undefined;
73
+ }
74
+ /**
75
+ * OPS017's check (#3949) over every Op in a build. An alias must stand on a
76
+ * gate bound to a plan that asks no decision point, must not name a gate
77
+ * that still exists, must not name the gate itself, and must not be claimed
78
+ * by two gates, since an approval would then be carried twice. When the
79
+ * workspace's `identity.gates` names an alias, the new gate must be named
80
+ * too, with the alias's class when it has one: `identityGates` maps each
81
+ * gate the declaration names to its class (null for any signer). Absent,
82
+ * outside a workspace, that part is skipped.
83
+ */
84
+ export function validateGateAliases(ops, identityGates) {
85
+ const issues = [];
86
+ const existing = new Set();
87
+ for (const config of ops)
88
+ for (const { step } of gateStepsOf(config))
89
+ existing.add(`${config.name}/${gateName(step)}`);
90
+ const claimed = new Map();
91
+ for (const config of ops) {
92
+ for (const { phase, step } of gateStepsOf(config)) {
93
+ if (step.aliases === undefined)
94
+ continue;
95
+ const name = gateName(step);
96
+ const issue = (message) => issues.push({ opName: config.name, phase, gate: name, message });
97
+ for (const problem of gateAliasProblems(step.aliases, step))
98
+ issue(problem);
99
+ for (const alias of resolveGateAliases(step, config.name)) {
100
+ if (alias.gate === "")
101
+ continue;
102
+ const key = `${alias.op}/${alias.gate}`;
103
+ if (alias.op === config.name && alias.gate === name) {
104
+ issue(`alias ${key} is the gate's own name`);
105
+ continue;
106
+ }
107
+ if (existing.has(key))
108
+ issue(`alias ${key} is still a gate; remove that gate, or this alias, so one approval doesn't answer two gates`);
109
+ const owner = claimed.get(key);
110
+ if (owner !== undefined && owner !== `${config.name}/${name}`)
111
+ issue(`alias ${key} is also an alias of ${owner}, so its approvals would be carried twice`);
112
+ else
113
+ claimed.set(key, `${config.name}/${name}`);
114
+ if (identityGates?.has(alias.gate)) {
115
+ const want = identityGates.get(alias.gate) ?? null;
116
+ if (!identityGates.has(name)) {
117
+ issue(`identity.gates names its alias ${alias.gate}, so gate ${name} needs an identity.gates entry too, or approvals that needed a seal would count without one`);
118
+ }
119
+ else if (want !== null && identityGates.get(name) !== want) {
120
+ issue(`identity.gates.${alias.gate} needs class ${want}, and identity.gates.${name} needs ${identityGates.get(name) ?? "any signer"}; the gate must keep its alias's class`);
121
+ }
122
+ }
123
+ }
124
+ }
125
+ }
126
+ return issues;
127
+ }
@@ -0,0 +1,123 @@
1
+ /**
2
+ * Resuming a run at an approved gate (#3947, epic #3946).
3
+ *
4
+ * Before this, a run that stopped at a gate kept nothing but its record:
5
+ * after `chant approve`, the next `chant run <op>` began again at the first
6
+ * phase and recomputed every step before the gate, so a value could not be
7
+ * carried across a gate with `stepOutput`. A gate with `resume: true` keeps
8
+ * the outputs the steps after it need, and the next run starts at the gate.
9
+ *
10
+ * Stopping. The run works out which outputs cross the gate from the Op's own
11
+ * references ({@link resumeGatesOf}): an output of a step before the gate
12
+ * that a step at or after it references, in the main phases, `onFailure` or
13
+ * the gate's own `approval` context. It writes them to a checkpoint
14
+ * (`../lifecycle/gate-checkpoint.ts`) and puts the checkpoint's digest on
15
+ * the pending fact. An output an activity contract marks secret is never
16
+ * stored, and the gate then doesn't resume ({@link checkpointBlocked}).
17
+ *
18
+ * Resuming. {@link decideGateResume} picks the last resume gate whose
19
+ * standing pending fact carries a checkpoint and has an approval that copied
20
+ * it. It resumes there only when the fact hasn't expired, the checkpoint file
21
+ * matches the digest the approver saw and names the fact's run, and this run
22
+ * is at the same commit and environment. Any failed check starts the run at
23
+ * the first phase and the reason is reported. The executor then re-runs the
24
+ * step that produced the gate's `plan`, and starts at the first phase if the
25
+ * digest moved, so live drift between the approval and the apply is still
26
+ * caught (`./local-executor.ts`).
27
+ */
28
+ import type { ActivityStep, GateStep, OpConfig } from "./types.js";
29
+ import { type StepOutputRef } from "./step-output-ref.js";
30
+ import { type ActivityContract, type ActivityContractIssue } from "./activity-contract.js";
31
+ import type { GateLedgerPort } from "./gate.js";
32
+ import { type PendingGateRecord } from "../lifecycle/gate-ledger.js";
33
+ import { type GateCheckpoint } from "../lifecycle/gate-checkpoint.js";
34
+ /** A top-level activity step of a main phase, where it sits. */
35
+ interface Producer {
36
+ step: ActivityStep;
37
+ phaseIndex: number;
38
+ stepIndex: number;
39
+ }
40
+ /** A gate that resumes, and what resuming at it needs. */
41
+ export interface ResumeGate {
42
+ step: GateStep;
43
+ name: string;
44
+ phaseIndex: number;
45
+ /** The gate's index among its phase's steps. */
46
+ stepIndex: number;
47
+ /** The step the gate's `plan` names, which a resumed run runs again. Absent when the plan is a literal or there is none. */
48
+ planStep?: Producer;
49
+ /** Ids of the steps before the gate whose outputs the checkpoint stores, in authored order. The plan step is not among them. */
50
+ stored: string[];
51
+ /** The references that read a stored output, for the secret check. */
52
+ crossing: StepOutputRef[];
53
+ }
54
+ /**
55
+ * The gates of `config` that resume, at the top of a main phase, in authored
56
+ * order, each with the outputs a checkpoint at it stores. A gate that asks a
57
+ * decision point, or one in an Op with a `workLease`, is left out: OPS016
58
+ * refuses both, and a run treats them as gates that don't resume.
59
+ */
60
+ export declare function resumeGatesOf(config: Pick<OpConfig, "phases" | "onFailure" | "workLease">): ResumeGate[];
61
+ /**
62
+ * Why a checkpoint at `gate` can't hold what the steps after it read, or
63
+ * undefined when it can (#3947): a reference to an output the producer's
64
+ * contract marks secret. Secret outputs are never stored.
65
+ */
66
+ export declare function checkpointBlocked(config: Pick<OpConfig, "phases">, gate: ResumeGate, contracts: ReadonlyMap<string, Pick<ActivityContract, "secret">> | undefined): string | undefined;
67
+ /**
68
+ * OPS016's check (#3947): what is wrong with the gates of `config` that set
69
+ * `resume`. A gate that resumes must sit at the top of a main phase, must not
70
+ * ask a decision point, must not be in an Op with a `workLease`, must name a
71
+ * plan step that runs before it when its plan is a reference, and must not
72
+ * need a secret output after it.
73
+ */
74
+ export declare function validateGateResume(config: Pick<OpConfig, "name" | "phases" | "onFailure" | "workLease">, contracts?: ReadonlyMap<string, ActivityContract>): ActivityContractIssue[];
75
+ /**
76
+ * Build the checkpoint a run stores when it stops at `gate`, or say why it
77
+ * stores none: a secret output, an unknown commit, a run id that can't name
78
+ * a file, or an output JSON can't hold.
79
+ */
80
+ export declare function buildGateCheckpoint(config: Pick<OpConfig, "name" | "phases">, gate: ResumeGate, input: {
81
+ runId: string;
82
+ commit: string | undefined;
83
+ environment?: string;
84
+ planDigest?: string;
85
+ outputs: ReadonlyMap<string, unknown>;
86
+ contracts?: ReadonlyMap<string, Pick<ActivityContract, "secret">>;
87
+ }): {
88
+ checkpoint: GateCheckpoint;
89
+ } | {
90
+ blocked: string;
91
+ };
92
+ /** What {@link decideGateResume} found. */
93
+ export type GateResumeDecision = {
94
+ kind: "none";
95
+ } | {
96
+ kind: "refused";
97
+ gate: string;
98
+ reason: string;
99
+ } | {
100
+ kind: "resume";
101
+ gate: ResumeGate;
102
+ checkpoint: GateCheckpoint;
103
+ digest: string;
104
+ pending: PendingGateRecord;
105
+ };
106
+ /**
107
+ * Decide whether this run resumes, and at which gate. The last resume gate
108
+ * whose standing pending fact carries a checkpoint, and which an approval
109
+ * recorded since then copied, is the candidate. Approved gates are tried
110
+ * from the last one back, so a run that resumed at one gate and stopped at a
111
+ * later one resumes at the later one next time.
112
+ *
113
+ * Reads the gate ledger and the checkpoint file and writes nothing. A gate
114
+ * with no checkpoint, or none an approval copied, is not a candidate: the run
115
+ * starts at the first phase as before, and says nothing.
116
+ */
117
+ export declare function decideGateResume(port: GateLedgerPort, config: Pick<OpConfig, "name" | "phases" | "onFailure" | "workLease">, input: {
118
+ now: string;
119
+ commit: string | undefined;
120
+ environment?: string;
121
+ }): Promise<GateResumeDecision>;
122
+ export {};
123
+ //# sourceMappingURL=gate-checkpoint.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gate-checkpoint.d.ts","sourceRoot":"","sources":["../../src/op/gate-checkpoint.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,280 @@
1
+ /**
2
+ * Resuming a run at an approved gate (#3947, epic #3946).
3
+ *
4
+ * Before this, a run that stopped at a gate kept nothing but its record:
5
+ * after `chant approve`, the next `chant run <op>` began again at the first
6
+ * phase and recomputed every step before the gate, so a value could not be
7
+ * carried across a gate with `stepOutput`. A gate with `resume: true` keeps
8
+ * the outputs the steps after it need, and the next run starts at the gate.
9
+ *
10
+ * Stopping. The run works out which outputs cross the gate from the Op's own
11
+ * references ({@link resumeGatesOf}): an output of a step before the gate
12
+ * that a step at or after it references, in the main phases, `onFailure` or
13
+ * the gate's own `approval` context. It writes them to a checkpoint
14
+ * (`../lifecycle/gate-checkpoint.ts`) and puts the checkpoint's digest on
15
+ * the pending fact. An output an activity contract marks secret is never
16
+ * stored, and the gate then doesn't resume ({@link checkpointBlocked}).
17
+ *
18
+ * Resuming. {@link decideGateResume} picks the last resume gate whose
19
+ * standing pending fact carries a checkpoint and has an approval that copied
20
+ * it. It resumes there only when the fact hasn't expired, the checkpoint file
21
+ * matches the digest the approver saw and names the fact's run, and this run
22
+ * is at the same commit and environment. Any failed check starts the run at
23
+ * the first phase and the reason is reported. The executor then re-runs the
24
+ * step that produced the gate's `plan`, and starts at the first phase if the
25
+ * digest moved, so live drift between the approval and the apply is still
26
+ * caught (`./local-executor.ts`).
27
+ */
28
+ import { WORK_LEASE_STEP_ID } from "./types.js";
29
+ import { collectStepOutputRefs, isStepOutputRef } from "./step-output-ref.js";
30
+ import { gateName } from "./gate-name.js";
31
+ import { readsSecretOutput } from "./activity-contract.js";
32
+ import { isPendingGateExpired, latestPendingGate } from "../lifecycle/gate-ledger.js";
33
+ import { isApprovalSpent } from "../lifecycle/gate-applied.js";
34
+ import { samePlanDigest } from "../lifecycle/plan-digest.js";
35
+ import { checkpointOutputs, gateCheckpointDigest, gateCheckpointPath, isCheckpointRunId, parseGateCheckpoint, } from "../lifecycle/gate-checkpoint.js";
36
+ /** The step-output references a step reads when it runs: its args, a gate's plan, approval context and point inputs, and an effect's receipt and nested steps. */
37
+ function refsOfStep(step) {
38
+ if (step.kind === "activity")
39
+ return collectStepOutputRefs(step.args);
40
+ if (step.kind === "gate") {
41
+ const point = typeof step.point === "object" ? step.point.inputs : undefined;
42
+ return [
43
+ ...(isStepOutputRef(step.plan) ? [step.plan] : []),
44
+ ...collectStepOutputRefs(step.approval?.context),
45
+ ...collectStepOutputRefs(point),
46
+ ];
47
+ }
48
+ return [...collectStepOutputRefs(step.receipt), ...step.steps.flatMap(refsOfStep)];
49
+ }
50
+ /** Every gate step of `config` with `resume: true` that isn't at the top of a main phase. */
51
+ function misplacedResumeGates(config) {
52
+ const out = [];
53
+ for (const phase of config.phases) {
54
+ for (const step of phase.steps) {
55
+ if (step.kind === "effect")
56
+ for (const n of step.steps)
57
+ if (n.kind === "gate" && n.resume)
58
+ out.push({ phase: phase.name, gate: n });
59
+ }
60
+ }
61
+ for (const phase of config.onFailure ?? []) {
62
+ for (const step of phase.steps) {
63
+ if (step.kind === "gate" && step.resume)
64
+ out.push({ phase: phase.name, gate: step });
65
+ if (step.kind === "effect")
66
+ for (const n of step.steps)
67
+ if (n.kind === "gate" && n.resume)
68
+ out.push({ phase: phase.name, gate: n });
69
+ }
70
+ }
71
+ return out;
72
+ }
73
+ /**
74
+ * The gates of `config` that resume, at the top of a main phase, in authored
75
+ * order, each with the outputs a checkpoint at it stores. A gate that asks a
76
+ * decision point, or one in an Op with a `workLease`, is left out: OPS016
77
+ * refuses both, and a run treats them as gates that don't resume.
78
+ */
79
+ export function resumeGatesOf(config) {
80
+ if (config.workLease)
81
+ return [];
82
+ const out = [];
83
+ config.phases.forEach((phase, phaseIndex) => {
84
+ phase.steps.forEach((step, stepIndex) => {
85
+ if (step.kind !== "gate" || !step.resume || step.point !== undefined)
86
+ return;
87
+ // The steps that have finished when the run reaches the gate. In a
88
+ // parallel phase the gates are decided before any activity starts.
89
+ const before = new Map();
90
+ config.phases.forEach((p, pi) => {
91
+ if (pi > phaseIndex)
92
+ return;
93
+ p.steps.forEach((s, si) => {
94
+ if (s.kind !== "activity" || !s.id)
95
+ return;
96
+ if (pi === phaseIndex && (p.parallel || si >= stepIndex))
97
+ return;
98
+ before.set(s.id, { step: s, phaseIndex: pi, stepIndex: si });
99
+ });
100
+ });
101
+ const planStep = isStepOutputRef(step.plan) ? before.get(step.plan.step) : undefined;
102
+ // What reads them: the gate and every step after it, the compensation
103
+ // phases, the work lease, and the plan step, which runs again.
104
+ const after = [
105
+ ...(phase.parallel ? phase.steps : phase.steps.slice(stepIndex)),
106
+ ...config.phases.slice(phaseIndex + 1).flatMap((p) => p.steps),
107
+ ...(config.onFailure ?? []).flatMap((p) => p.steps),
108
+ ...(planStep ? [planStep.step] : []),
109
+ ];
110
+ const crossing = after.flatMap(refsOfStep).filter((ref) => ref.step !== WORK_LEASE_STEP_ID && ref.step !== planStep?.step.id && before.has(ref.step));
111
+ const ids = new Set(crossing.map((r) => r.step));
112
+ const stored = [...before.values()]
113
+ .filter((p) => ids.has(p.step.id))
114
+ .sort((a, b) => a.phaseIndex - b.phaseIndex || a.stepIndex - b.stepIndex)
115
+ .map((p) => p.step.id);
116
+ out.push({ step, name: gateName(step), phaseIndex, stepIndex, ...(planStep ? { planStep } : {}), stored, crossing });
117
+ });
118
+ });
119
+ return out;
120
+ }
121
+ /** The step id that produced `ref`, and its activity, among the steps before `gate`. */
122
+ function producerOf(config, ref) {
123
+ for (const phase of config.phases) {
124
+ for (const step of phase.steps)
125
+ if (step.kind === "activity" && step.id === ref.step)
126
+ return step;
127
+ }
128
+ return undefined;
129
+ }
130
+ /**
131
+ * Why a checkpoint at `gate` can't hold what the steps after it read, or
132
+ * undefined when it can (#3947): a reference to an output the producer's
133
+ * contract marks secret. Secret outputs are never stored.
134
+ */
135
+ export function checkpointBlocked(config, gate, contracts) {
136
+ if (!contracts)
137
+ return undefined;
138
+ for (const ref of gate.crossing) {
139
+ const producer = producerOf(config, ref);
140
+ if (producer && readsSecretOutput(contracts.get(producer.fn), ref.path)) {
141
+ const what = ref.path ? `output "${ref.path}"` : "output";
142
+ return `step "${ref.step}"'s ${what} is secret (the ${producer.fn} contract marks it), and a checkpoint never stores a secret`;
143
+ }
144
+ }
145
+ return undefined;
146
+ }
147
+ /**
148
+ * OPS016's check (#3947): what is wrong with the gates of `config` that set
149
+ * `resume`. A gate that resumes must sit at the top of a main phase, must not
150
+ * ask a decision point, must not be in an Op with a `workLease`, must name a
151
+ * plan step that runs before it when its plan is a reference, and must not
152
+ * need a secret output after it.
153
+ */
154
+ export function validateGateResume(config, contracts) {
155
+ const issues = [];
156
+ const issue = (phase, gate, message) => issues.push({ opName: config.name, phase, fn: `gate:${gateName(gate)}`, message });
157
+ for (const { phase, gate } of misplacedResumeGates(config)) {
158
+ issue(phase, gate, "resume is supported only on a gate at the top of a main phase, not in onFailure or inside an effect");
159
+ }
160
+ config.phases.forEach((phase) => {
161
+ for (const step of phase.steps) {
162
+ if (step.kind !== "gate" || !step.resume)
163
+ continue;
164
+ if (config.workLease)
165
+ issue(phase.name, step, "a gate can't resume in an Op that runs under a workLease");
166
+ if (step.point !== undefined)
167
+ issue(phase.name, step, "a gate that asks a decision point can't resume");
168
+ }
169
+ });
170
+ for (const gate of resumeGatesOf(config)) {
171
+ const phase = config.phases[gate.phaseIndex].name;
172
+ if (isStepOutputRef(gate.step.plan) && !gate.planStep) {
173
+ issue(phase, gate.step, `its plan names step "${gate.step.plan.step}", which must be an activity that runs before the gate at the top of a main phase, so a resumed run can run it again`);
174
+ }
175
+ const blocked = checkpointBlocked(config, gate, contracts);
176
+ if (blocked)
177
+ issue(phase, gate.step, `can't resume: ${blocked}`);
178
+ }
179
+ return issues;
180
+ }
181
+ /**
182
+ * Build the checkpoint a run stores when it stops at `gate`, or say why it
183
+ * stores none: a secret output, an unknown commit, a run id that can't name
184
+ * a file, or an output JSON can't hold.
185
+ */
186
+ export function buildGateCheckpoint(config, gate, input) {
187
+ const secret = checkpointBlocked(config, gate, input.contracts);
188
+ if (secret)
189
+ return { blocked: secret };
190
+ if (input.commit === undefined)
191
+ return { blocked: "the commit this run is at could not be read, and a resumed run must be at the same one" };
192
+ if (!isCheckpointRunId(input.runId))
193
+ return { blocked: `the run id "${input.runId}" can't name a checkpoint file` };
194
+ const stored = checkpointOutputs(input.outputs, gate.stored);
195
+ if ("unstorable" in stored)
196
+ return { blocked: `step "${stored.unstorable}"'s output can't be stored as JSON` };
197
+ return {
198
+ checkpoint: {
199
+ version: 1,
200
+ op: config.name,
201
+ gate: gate.name,
202
+ runId: input.runId,
203
+ commit: input.commit,
204
+ ...(input.environment !== undefined ? { environment: input.environment } : {}),
205
+ ...(input.planDigest !== undefined ? { planDigest: input.planDigest } : {}),
206
+ outputs: stored.outputs,
207
+ },
208
+ };
209
+ }
210
+ /**
211
+ * Decide whether this run resumes, and at which gate. The last resume gate
212
+ * whose standing pending fact carries a checkpoint, and which an approval
213
+ * recorded since then copied, is the candidate. Approved gates are tried
214
+ * from the last one back, so a run that resumed at one gate and stopped at a
215
+ * later one resumes at the later one next time.
216
+ *
217
+ * Reads the gate ledger and the checkpoint file and writes nothing. A gate
218
+ * with no checkpoint, or none an approval copied, is not a candidate: the run
219
+ * starts at the first phase as before, and says nothing.
220
+ */
221
+ export async function decideGateResume(port, config, input) {
222
+ const gates = resumeGatesOf(config);
223
+ if (gates.length === 0)
224
+ return { kind: "none" };
225
+ const ledger = await port.read(config.name);
226
+ const spent = port.readApplied ? await port.readApplied(config.name) : [];
227
+ const at = (iso) => new Date(iso).getTime();
228
+ for (const gate of [...gates].reverse()) {
229
+ const standing = latestPendingGate(ledger.pending, gate.name);
230
+ const digest = standing?.checkpointDigest;
231
+ if (!standing || digest === undefined)
232
+ continue;
233
+ // #3949: an approval carried from an alias never saw this gate's
234
+ // checkpoint, so it doesn't let the run resume. The run starts at the
235
+ // first phase and the carried approval passes the gate when it gets there.
236
+ const approved = ledger.resolutions.some((r) => r.gate === gate.name && r.carriedFrom === undefined && r.checkpointDigest === digest && at(r.timestamp) >= at(standing.timestamp) &&
237
+ samePlanDigest(r.planDigest, standing.planDigest) && !isApprovalSpent(spent, r));
238
+ if (!approved)
239
+ continue;
240
+ const refuse = (reason) => ({ kind: "refused", gate: gate.name, reason });
241
+ if (isPendingGateExpired(standing, input.now))
242
+ return refuse(`its pending fact expired at ${standing.expiresAt}`);
243
+ if (!standing.runId)
244
+ return refuse("its pending fact names no run");
245
+ const { dir, file } = gateCheckpointPath(config.name, standing.runId);
246
+ const text = port.readCheckpoint ? await port.readCheckpoint(config.name, standing.runId) : null;
247
+ if (text === null)
248
+ return refuse(`the checkpoint ${dir}/${file} is not on the ledger`);
249
+ const checkpoint = parseGateCheckpoint(text);
250
+ if (checkpoint === null)
251
+ return refuse(`${dir}/${file} is not a checkpoint`);
252
+ let actual;
253
+ try {
254
+ actual = gateCheckpointDigest(checkpoint);
255
+ }
256
+ catch {
257
+ return refuse(`${dir}/${file} is not a checkpoint`);
258
+ }
259
+ if (actual !== digest)
260
+ return refuse(`${dir}/${file} does not match the digest the approver saw (${digest}, the file is ${actual})`);
261
+ if (checkpoint.op !== config.name || checkpoint.gate !== gate.name || checkpoint.runId !== standing.runId) {
262
+ return refuse(`${dir}/${file} is for ${checkpoint.op} / ${checkpoint.gate}, run ${checkpoint.runId}`);
263
+ }
264
+ if (!samePlanDigest(checkpoint.planDigest, standing.planDigest))
265
+ return refuse(`${dir}/${file} names another plan than the pending fact`);
266
+ if (input.commit === undefined)
267
+ return refuse("the commit this run is at could not be read");
268
+ if (input.commit !== checkpoint.commit) {
269
+ return refuse(`the run that stopped there was at commit ${checkpoint.commit.slice(0, 12)}, and this one is at ${input.commit.slice(0, 12)}`);
270
+ }
271
+ if (input.environment !== checkpoint.environment) {
272
+ return refuse(`the run that stopped there was for environment ${checkpoint.environment ?? "(none)"}, and this one is for ${input.environment ?? "(none)"}`);
273
+ }
274
+ const missing = gate.stored.find((id) => !(id in checkpoint.outputs));
275
+ if (missing !== undefined)
276
+ return refuse(`${dir}/${file} holds no output for step "${missing}"`);
277
+ return { kind: "resume", gate, checkpoint, digest, pending: standing };
278
+ }
279
+ return { kind: "none" };
280
+ }
package/dist/op/gate.d.ts CHANGED
@@ -34,6 +34,8 @@
34
34
  import { type GateResolutionInput, type GateResolutionRecord, type PendingGateInput, type PendingGateRecord } from "../lifecycle/gate-ledger.js";
35
35
  import { type AppliedGateRecord } from "../lifecycle/gate-applied.js";
36
36
  import { type GateApprover, type ResolvedGateApproval } from "./gate-approval.js";
37
+ import { type GateCheckpoint } from "../lifecycle/gate-checkpoint.js";
38
+ import type { ResolvedGateAlias } from "./gate-alias.js";
37
39
  /**
38
40
  * What appending a pending fact learned about reaching the remote.
39
41
  *
@@ -89,6 +91,15 @@ export interface GateLedgerPort {
89
91
  pushed: boolean;
90
92
  pushWarning?: string;
91
93
  }>;
94
+ /**
95
+ * Store the checkpoint of a run that stops at a gate that resumes (#3947),
96
+ * at `_gates/<op>/checkpoints/<runId>.json`. Written before the pending
97
+ * fact that names its digest, and pushed with it. Absent on a port that
98
+ * keeps none, and the gate then doesn't resume.
99
+ */
100
+ writeCheckpoint?(checkpoint: GateCheckpoint): Promise<void>;
101
+ /** The text of a run's checkpoint, or null when there is none (#3947). */
102
+ readCheckpoint?(op: string, runId: string): Promise<string | null>;
92
103
  }
93
104
  /** A workspace's rule for which approvals of a gate count (#3163): a signed approval, from a class when it names one. */
94
105
  export interface GateApprovalRule {
@@ -123,6 +134,8 @@ export declare function memoryGateLedgerPort(seed?: {
123
134
  appended: PendingGateRecord[];
124
135
  resolved: GateResolutionRecord[];
125
136
  applied: AppliedGateRecord[];
137
+ /** Checkpoint texts by `<op>/<runId>` (#3947). */
138
+ checkpoints: Map<string, string>;
126
139
  };
127
140
  /** What a caller has to say about the gate it just reached. */
128
141
  export interface GateCheckInput {
@@ -178,6 +191,24 @@ export interface GateCheckInput {
178
191
  fields?: Record<string, unknown>;
179
192
  /** The pending fact it records carries `neverOverMcp` (#3821, chant#3485). */
180
193
  neverOverMcp?: boolean;
194
+ /**
195
+ * The checkpoint of a run at a gate that resumes (#3947). Given, a pending
196
+ * fact this records first stores it through the port's `writeCheckpoint`
197
+ * and carries its digest as `checkpointDigest`. A standing fact with no
198
+ * checkpoint is recorded again, so the gate gets one.
199
+ */
200
+ checkpoint?: GateCheckpoint;
201
+ /**
202
+ * The gate's old names (#3949), each with its Op filled in
203
+ * (`resolveGateAliases` in `./gate-alias.ts`). Read only on a gate bound
204
+ * to a plan. A person's approval recorded under one counts toward this
205
+ * gate when it answers that name's standing pending fact, the fact hasn't
206
+ * expired, it is for `planDigest` and `environment`, neither name has
207
+ * spent it, and it passes this gate's approval rule. An approval this
208
+ * counts is written again under this gate (`carriedFrom`), and a line
209
+ * carried earlier counts only while its alias is still declared.
210
+ */
211
+ aliases?: readonly ResolvedGateAlias[];
181
212
  }
182
213
  /**
183
214
  * A standing resolution that answers this gate but not this plan (#2300) —
@@ -221,11 +252,14 @@ export type GateCheck = {
221
252
  /**
222
253
  * Set on a gate that declares `approval` (#2508). `"quorum"` when enough
223
254
  * human approvals were recorded, `"policy"` when an `enforce`-mode permit
224
- * passed it on its own.
255
+ * passed it on its own. `"alias"` (#3949) when an approval recorded
256
+ * under one of the gate's aliases counted, on any gate.
225
257
  */
226
- via?: "quorum" | "policy";
258
+ via?: "quorum" | "policy" | "alias";
227
259
  /** Every approval that counted toward the quorum. Set with `via`. */
228
260
  approvals?: GateResolutionRecord[];
261
+ /** The approvals this run carried from an alias and wrote under the gate's name (#3949). Set when `via` is `"alias"`. */
262
+ carried?: GateResolutionRecord[];
229
263
  } | {
230
264
  satisfied: false;
231
265
  pending: PendingGateRecord;
@@ -306,6 +340,24 @@ export declare function tallyGateApprovals(records: GateResolutionRecord[], gate
306
340
  * and environment are read.
307
341
  */
308
342
  export declare function humanQuorumSince(pending: readonly PendingGateRecord[], standing: PendingGateRecord): string;
343
+ /**
344
+ * The approvals that answer `standing` (#3949): of its gate, environment and
345
+ * plan, recorded since it, or on a gate with an `approval` block since the
346
+ * human quorum's anchor ({@link humanQuorumSince}). The rule
347
+ * `resolutionAnswering` (`./gate-resume.ts`) decides by, without the tally:
348
+ * each one counts on its own toward a gate an alias names.
349
+ */
350
+ export declare function approvalsAnswering(resolutions: readonly GateResolutionRecord[], standing: PendingGateRecord, pending?: readonly PendingGateRecord[]): GateResolutionRecord[];
351
+ /**
352
+ * The line a run writes for an approval it carries from an alias (#3949):
353
+ * the approval under `op`/`gate` at `now`, citing the line it came from.
354
+ * The approver, plan, environment, relay and seal are the original's. A
355
+ * policy decision is left behind, since it was evaluated against another
356
+ * gate, and so is a checkpoint digest, which moves onto `carriedFrom`: the
357
+ * approver saw that checkpoint, not one this gate stores, so a carried
358
+ * approval never lets a run resume.
359
+ */
360
+ export declare function carriedApproval(r: GateResolutionRecord, op: string, gate: string, now: string): GateResolutionInput;
309
361
  /**
310
362
  * Decide a gate against the ledger, recording the pending fact when it isn't
311
363
  * answered.
@@ -1 +1 @@
1
- {"version":3,"file":"gate.d.ts","sourceRoot":"","sources":["../../src/op/gate.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"gate.d.ts","sourceRoot":"","sources":["../../src/op/gate.ts"],"names":[],"mappings":"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"}