@intentius/chant 0.124.24 → 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.
- package/dist/cli/commands/build.d.ts.map +1 -1
- package/dist/cli/commands/build.js +4 -2
- package/dist/cli/commands/lint.d.ts.map +1 -1
- package/dist/cli/commands/lint.js +4 -2
- package/dist/cli/handlers/approve.d.ts.map +1 -1
- package/dist/cli/handlers/approve.js +39 -4
- package/dist/cli/main.d.ts.map +1 -1
- package/dist/cli/main.js +21 -7
- package/dist/cli/mcp/workspace-tools.d.ts +3 -3
- package/dist/cli/mcp/workspace-tools.d.ts.map +1 -1
- package/dist/cli/mcp/workspace-tools.js +27 -4
- package/dist/effect-receipt.d.ts +13 -0
- package/dist/effect-receipt.d.ts.map +1 -1
- package/dist/effect-receipt.js +19 -0
- package/dist/gate-decision.d.ts +1 -1
- package/dist/gate-decision.d.ts.map +1 -1
- package/dist/gate-decision.js +1 -1
- package/dist/lexicon-module.d.ts +7 -1
- package/dist/lexicon-module.d.ts.map +1 -1
- package/dist/lexicon-module.js +7 -2
- package/dist/lifecycle/gate-audit.d.ts +7 -1
- package/dist/lifecycle/gate-audit.d.ts.map +1 -1
- package/dist/lifecycle/gate-audit.js +40 -3
- package/dist/lifecycle/gate-checkpoint.d.ts +78 -0
- package/dist/lifecycle/gate-checkpoint.d.ts.map +1 -0
- package/dist/lifecycle/gate-checkpoint.js +103 -0
- package/dist/lifecycle/gate-ledger.d.ts +41 -0
- package/dist/lifecycle/gate-ledger.d.ts.map +1 -1
- package/dist/lifecycle/gate-ledger.js +18 -0
- package/dist/lifecycle/receipt-plan.d.ts.map +1 -1
- package/dist/lifecycle/receipt-plan.js +4 -2
- package/dist/lifecycle/run-ledger.d.ts +2 -0
- package/dist/lifecycle/run-ledger.d.ts.map +1 -1
- package/dist/lifecycle/run-ledger.js +2 -0
- package/dist/lint/rules/op/index.d.ts +6 -2
- package/dist/lint/rules/op/index.d.ts.map +1 -1
- package/dist/lint/rules/op/index.js +7 -3
- package/dist/lint/rules/op/ops016-gate-resume.d.ts +14 -0
- package/dist/lint/rules/op/ops016-gate-resume.d.ts.map +1 -0
- package/dist/lint/rules/op/ops016-gate-resume.js +31 -0
- package/dist/lint/rules/op/ops017-gate-alias.d.ts +30 -0
- package/dist/lint/rules/op/ops017-gate-alias.d.ts.map +1 -0
- package/dist/lint/rules/op/ops017-gate-alias.js +67 -0
- package/dist/op/activity-contract.d.ts +14 -0
- package/dist/op/activity-contract.d.ts.map +1 -1
- package/dist/op/activity-contract.js +16 -0
- package/dist/op/builders.d.ts +7 -0
- package/dist/op/builders.d.ts.map +1 -1
- package/dist/op/builders.js +13 -0
- package/dist/op/gate-alias.d.ts +57 -0
- package/dist/op/gate-alias.d.ts.map +1 -0
- package/dist/op/gate-alias.js +127 -0
- package/dist/op/gate-checkpoint.d.ts +123 -0
- package/dist/op/gate-checkpoint.d.ts.map +1 -0
- package/dist/op/gate-checkpoint.js +280 -0
- package/dist/op/gate.d.ts +54 -2
- package/dist/op/gate.d.ts.map +1 -1
- package/dist/op/gate.js +142 -1
- package/dist/op/index.d.ts +4 -1
- package/dist/op/index.d.ts.map +1 -1
- package/dist/op/index.js +2 -1
- package/dist/op/local-executor.d.ts +57 -2
- package/dist/op/local-executor.d.ts.map +1 -1
- package/dist/op/local-executor.js +200 -11
- package/dist/op/local-output.d.ts.map +1 -1
- package/dist/op/local-output.js +20 -2
- package/dist/op/op-ir.d.ts +4 -0
- package/dist/op/op-ir.d.ts.map +1 -1
- package/dist/op/op-ir.js +4 -0
- package/dist/op/receipt-store.d.ts +5 -0
- package/dist/op/receipt-store.d.ts.map +1 -1
- package/dist/op/receipt-store.js +4 -3
- package/dist/op/runtime.d.ts +15 -0
- package/dist/op/runtime.d.ts.map +1 -1
- package/dist/op/runtimes/local.d.ts.map +1 -1
- package/dist/op/runtimes/local.js +5 -0
- package/dist/op/step-output-ref.d.ts +26 -18
- package/dist/op/step-output-ref.d.ts.map +1 -1
- package/dist/op/step-output-ref.js +86 -63
- package/dist/op/types.d.ts +31 -0
- package/dist/op/types.d.ts.map +1 -1
- package/dist/wave-runtime.mjs +223 -221
- package/dist/workspace/agent-cli.d.ts.map +1 -1
- package/dist/workspace/agent-cli.js +3 -0
- package/dist/workspace/conformance/__writer_fixture__/answers/answer.schema.json +16 -1
- package/dist/workspace/conformance/writer.js +1 -1
- package/dist/workspace/decide.d.ts +51 -9
- package/dist/workspace/decide.d.ts.map +1 -1
- package/dist/workspace/decide.js +125 -14
- package/dist/workspace/lineage-upgrade.d.ts.map +1 -1
- package/dist/workspace/lineage-upgrade.js +20 -11
- package/dist/workspace/point-answer.schema.json +16 -1
- package/dist/workspace/points-cli.d.ts +5 -3
- package/dist/workspace/points-cli.d.ts.map +1 -1
- package/dist/workspace/points-cli.js +16 -7
- package/dist/workspace/points-write.schema.json +39 -4
- package/dist/workspace/points.schema.json +42 -3
- package/dist/workspace/reason-codes.d.ts +2 -1
- package/dist/workspace/reason-codes.d.ts.map +1 -1
- package/dist/workspace/reason-codes.js +2 -1
- package/dist/workspace/records-cli.d.ts +12 -2
- package/dist/workspace/records-cli.d.ts.map +1 -1
- package/dist/workspace/records-cli.js +27 -7
- package/dist/workspace/records-write.d.ts.map +1 -1
- package/dist/workspace/records-write.js +2 -3
- package/dist/workspace/records.d.ts +10 -4
- package/dist/workspace/records.d.ts.map +1 -1
- package/dist/workspace/records.js +16 -3
- package/dist/workspace/records.schema.json +2 -1
- package/dist/workspace/trust/gate-seal.d.ts +32 -1
- package/dist/workspace/trust/gate-seal.d.ts.map +1 -1
- package/dist/workspace/trust/gate-seal.js +41 -2
- package/dist/workspace/trust/seal.d.ts +1 -1
- package/dist/workspace/trust/seal.d.ts.map +1 -1
- package/dist/workspace/trust/seal.js +1 -1
- package/dist/workspace/trust/verify-cli.d.ts.map +1 -1
- package/dist/workspace/trust/verify-cli.js +2 -1
- package/dist/workspace/trust/verify.d.ts +22 -0
- package/dist/workspace/trust/verify.d.ts.map +1 -1
- package/dist/workspace/trust/verify.js +94 -14
- package/dist/workspace/write-scope.d.ts +3 -1
- package/dist/workspace/write-scope.d.ts.map +1 -1
- package/dist/workspace/write-scope.js +11 -4
- package/package.json +1 -1
- package/src/cli/commands/build.ts +9 -2
- package/src/cli/commands/lint.ts +4 -2
- package/src/cli/compiled-cli.e2e.test.ts +45 -1
- package/src/cli/handlers/approve.ts +46 -4
- package/src/cli/handlers/operator.test.ts +91 -0
- package/src/cli/main.test.ts +10 -0
- package/src/cli/main.ts +21 -7
- package/src/cli/mcp/workspace-tools.e2e.test.ts +1 -1
- package/src/cli/mcp/workspace-tools.ts +27 -4
- package/src/effect-receipt.ts +22 -0
- package/src/gate-decision.ts +2 -0
- package/src/lexicon-module.ts +9 -2
- package/src/lifecycle/gate-audit.ts +41 -4
- package/src/lifecycle/gate-checkpoint.test.ts +128 -0
- package/src/lifecycle/gate-checkpoint.ts +133 -0
- package/src/lifecycle/gate-ledger.ts +61 -0
- package/src/lifecycle/receipt-plan.test.ts +9 -0
- package/src/lifecycle/receipt-plan.ts +4 -1
- package/src/lifecycle/run-ledger.ts +4 -0
- package/src/lint/rules/op/index.ts +9 -3
- package/src/lint/rules/op/ops016-gate-resume.test.ts +53 -0
- package/src/lint/rules/op/ops016-gate-resume.ts +48 -0
- package/src/lint/rules/op/ops017-gate-alias.test.ts +85 -0
- package/src/lint/rules/op/ops017-gate-alias.ts +89 -0
- package/src/op/activity-contract.ts +22 -1
- package/src/op/builders.ts +21 -1
- package/src/op/effect-step.test.ts +95 -1
- package/src/op/gate-alias.e2e.test.ts +78 -0
- package/src/op/gate-alias.test.ts +350 -0
- package/src/op/gate-alias.ts +137 -0
- package/src/op/gate-checkpoint.test.ts +284 -0
- package/src/op/gate-checkpoint.ts +322 -0
- package/src/op/gate.ts +198 -4
- package/src/op/index.ts +4 -1
- package/src/op/local-executor.test.ts +65 -0
- package/src/op/local-executor.ts +248 -12
- package/src/op/local-output.ts +18 -2
- package/src/op/op-ir.test.ts +25 -0
- package/src/op/op-ir.ts +8 -0
- package/src/op/receipt-store.ts +13 -3
- package/src/op/runtime.ts +8 -0
- package/src/op/runtimes/local.ts +5 -0
- package/src/op/step-output-ref.test.ts +68 -24
- package/src/op/step-output-ref.ts +85 -65
- package/src/op/types.ts +32 -0
- package/src/workspace/agent-cli.ts +2 -0
- package/src/workspace/conformance/__writer_fixture__/answers/answer.schema.json +16 -1
- package/src/workspace/conformance/writer.ts +1 -1
- package/src/workspace/decide.test.ts +87 -3
- package/src/workspace/decide.ts +142 -17
- package/src/workspace/lineage-upgrade.test.ts +21 -0
- package/src/workspace/lineage-upgrade.ts +19 -11
- package/src/workspace/point-answer.schema.json +16 -1
- package/src/workspace/points-cli.ts +16 -8
- package/src/workspace/points-write.schema.json +39 -4
- package/src/workspace/points.schema.json +42 -3
- package/src/workspace/reason-codes.ts +2 -1
- package/src/workspace/record-assets.test.ts +14 -0
- package/src/workspace/records-cli.ts +28 -7
- package/src/workspace/records-write-commands.e2e.test.ts +32 -0
- package/src/workspace/records-write.ts +2 -3
- package/src/workspace/records.schema.json +2 -1
- package/src/workspace/records.ts +17 -4
- package/src/workspace/trust/gate-seal.test.ts +29 -2
- package/src/workspace/trust/gate-seal.ts +46 -2
- package/src/workspace/trust/seal.ts +1 -1
- package/src/workspace/trust/trust.test.ts +105 -0
- package/src/workspace/trust/verify-cli.ts +2 -1
- package/src/workspace/trust/verify.ts +106 -13
- package/src/workspace/write-scope.test.ts +18 -0
- package/src/workspace/write-scope.ts +16 -5
|
@@ -48,6 +48,13 @@
|
|
|
48
48
|
* - `override`: an apply cites an override that no line holds.
|
|
49
49
|
* - `malformed-line`: a line that is not a gate record. Its content is lost
|
|
50
50
|
* to the trail, so it is said.
|
|
51
|
+
* - `carried-without-source`: an approval carried from a gate's alias
|
|
52
|
+
* (#3949, `carriedFrom`) whose cited line is not in the cited op's
|
|
53
|
+
* ledger. Checked only when that ledger is passed in.
|
|
54
|
+
*
|
|
55
|
+
* A carried approval's request is the pending fact of the name it was
|
|
56
|
+
* carried from, in that op's ledger. When that ledger is not passed in,
|
|
57
|
+
* neither gap is looked for, and the entry's `carriedFrom` says where to look.
|
|
51
58
|
*
|
|
52
59
|
* ## Sources and ids
|
|
53
60
|
*
|
|
@@ -96,7 +103,7 @@ export function isOverrideGate(op, gate) {
|
|
|
96
103
|
}
|
|
97
104
|
const KNOWN = new Set([
|
|
98
105
|
"version", "kind", "op", "gate", "resolvedBy", "relayedBy", "timestamp", "note", "url", "planDigest", "environment",
|
|
99
|
-
"approver", "seal", "review", "runId", "expiresAt", "description", "wave", "heldBy", "approvalMode", "rules", "pr", "head", "reviewers",
|
|
106
|
+
"approver", "seal", "review", "runId", "expiresAt", "description", "wave", "heldBy", "approvalMode", "rules", "pr", "head", "reviewers", "carriedFrom",
|
|
100
107
|
]);
|
|
101
108
|
const waveOf = (v) => {
|
|
102
109
|
const w = v;
|
|
@@ -145,6 +152,10 @@ function approverOf(r) {
|
|
|
145
152
|
const roles = strings(a.roles);
|
|
146
153
|
return { kind: a.kind, ...(roles ? { roles } : {}) };
|
|
147
154
|
}
|
|
155
|
+
const carriedOf = (v) => {
|
|
156
|
+
const c = v;
|
|
157
|
+
return c && typeof c === "object" && typeof c.op === "string" && typeof c.gate === "string" && typeof c.timestamp === "string" ? { op: c.op, gate: c.gate, at: c.timestamp } : undefined;
|
|
158
|
+
};
|
|
148
159
|
const drop = (o) => Object.fromEntries(Object.entries(o).filter(([, v]) => v !== undefined));
|
|
149
160
|
const idOf = (...parts) => contentDigest(canonicalJson(parts));
|
|
150
161
|
/** Whether two digests, either absent, can be the same plan: absent matches anything, as an old line records none. */
|
|
@@ -174,6 +185,21 @@ export function deriveGateAudit(input) {
|
|
|
174
185
|
const keyed = (e) => (rekey ? { ...e, id: rekey(e) } : e);
|
|
175
186
|
const entries = [];
|
|
176
187
|
const gaps = [];
|
|
188
|
+
// #3949: every ledger's requests and approvals by op, for an approval carried from another op's gate.
|
|
189
|
+
const byOp = new Map();
|
|
190
|
+
for (const ledger of input.ledgers) {
|
|
191
|
+
const held = byOp.get(ledger.op) ?? { requests: [], approvals: [] };
|
|
192
|
+
byOp.set(ledger.op, held);
|
|
193
|
+
for (const line of ledger.lines) {
|
|
194
|
+
const r = rowOf(line);
|
|
195
|
+
if (!r || line.removed || typeof r.gate !== "string" || typeof r.timestamp !== "string")
|
|
196
|
+
continue;
|
|
197
|
+
if (r.kind === "pending")
|
|
198
|
+
held.requests.push({ op: ledger.op, gate: r.gate, at: time(r.timestamp), ...(str(r.planDigest) ? { digest: str(r.planDigest) } : {}) });
|
|
199
|
+
else
|
|
200
|
+
held.approvals.push(r);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
177
203
|
for (const ledger of input.ledgers) {
|
|
178
204
|
const path = ledger.path ?? `_gates/${ledger.op}.jsonl`;
|
|
179
205
|
const parsed = [];
|
|
@@ -249,11 +275,22 @@ export function deriveGateAudit(input) {
|
|
|
249
275
|
at: String(r.timestamp),
|
|
250
276
|
by: String(r.resolvedBy),
|
|
251
277
|
seal,
|
|
252
|
-
...drop({ sealed, signer, committedBy: line.added?.by, relayedBy: str(r.relayedBy), approver: approverOf(r), note: str(r.note), url: str(r.url), review: reviewOf(r), rules }),
|
|
278
|
+
...drop({ sealed, signer, committedBy: line.added?.by, relayedBy: str(r.relayedBy), approver: approverOf(r), note: str(r.note), url: str(r.url), review: reviewOf(r), rules, carriedFrom: carriedOf(r.carriedFrom) }),
|
|
253
279
|
detail: extra,
|
|
254
280
|
});
|
|
255
281
|
entries.push(entry);
|
|
256
|
-
|
|
282
|
+
const carried = entry.carriedFrom;
|
|
283
|
+
if (!override && carried) {
|
|
284
|
+
const cited = byOp.get(carried.op);
|
|
285
|
+
const from = `${carried.op}/${carried.gate}`;
|
|
286
|
+
if (cited && !cited.approvals.some((a) => a.gate === carried.gate && time(String(a.timestamp)) === time(carried.at) && a.resolvedBy === r.resolvedBy)) {
|
|
287
|
+
gaps.push({ kind: "carried-without-source", op: ledger.op, gate, ...(digest ? { digest } : {}), detail: `${path} holds an approval of ${gate} by ${entry.by} carried from ${from} at ${carried.at}, and _gates/${carried.op}.jsonl holds no such approval` });
|
|
288
|
+
}
|
|
289
|
+
if (cited && !cited.requests.some((q) => q.gate === carried.gate && q.at <= time(carried.at) && compatible(q.digest, digest))) {
|
|
290
|
+
gaps.push({ kind: "approval-without-request", op: ledger.op, gate, ...(digest ? { digest } : {}), detail: `${path} holds an approval of ${gate} by ${entry.by} carried from ${from} at ${carried.at} with no pending fact of ${from}${digest ? " and digest" : ""} before it` });
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
else if (!override) {
|
|
257
294
|
const at = time(entry.at);
|
|
258
295
|
const env = str(r.environment);
|
|
259
296
|
const asked = requests.some((q) => q.gate === gate && q.at <= at && compatible(q.digest, digest) && (q.environment === undefined || env === undefined || q.environment === env));
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A gate's checkpoint (#3947): the step outputs a run held when it stopped at
|
|
3
|
+
* a gate that resumes, kept on `chant/lifecycle` at
|
|
4
|
+
* `_gates/<op>/checkpoints/<runId>.json`.
|
|
5
|
+
*
|
|
6
|
+
* The run writes the file just before it appends the pending fact, and puts
|
|
7
|
+
* the file's digest on that fact as `checkpointDigest`. `chant approve`
|
|
8
|
+
* copies the digest onto the approval, the way it copies the plan digest, and
|
|
9
|
+
* a seal covers it (`../workspace/trust/gate-seal.ts`). A later run that
|
|
10
|
+
* resumes at the gate reads the file back and checks it against the digest
|
|
11
|
+
* the approver saw, so a value pushed onto the branch after the approval is
|
|
12
|
+
* refused rather than carried into the steps after the gate.
|
|
13
|
+
*
|
|
14
|
+
* Only the outputs some step after the gate references are stored, worked
|
|
15
|
+
* out from the Op's references (`../op/gate-checkpoint.ts`). An output that
|
|
16
|
+
* an activity contract marks secret is never stored: the gate doesn't
|
|
17
|
+
* resume, and the next run starts at the first phase.
|
|
18
|
+
*
|
|
19
|
+
* Pure apart from the two git helpers at the bottom.
|
|
20
|
+
*/
|
|
21
|
+
/** One gate checkpoint file. */
|
|
22
|
+
export interface GateCheckpoint {
|
|
23
|
+
version: 1;
|
|
24
|
+
/** The op the gate belongs to. */
|
|
25
|
+
op: string;
|
|
26
|
+
/** The gate's name. */
|
|
27
|
+
gate: string;
|
|
28
|
+
/** The run that stopped at the gate, and the file's name. The pending fact names the same run. */
|
|
29
|
+
runId: string;
|
|
30
|
+
/** The commit the run ran at. A resumed run must be at the same one. */
|
|
31
|
+
commit: string;
|
|
32
|
+
/** The environment the run was started for (`--env`), when it named one. */
|
|
33
|
+
environment?: string;
|
|
34
|
+
/** The plan the run reached the gate with, when the gate binds one. */
|
|
35
|
+
planDigest?: string;
|
|
36
|
+
/** Step id to the output that step returned, for each step a later step references. */
|
|
37
|
+
outputs: Record<string, unknown>;
|
|
38
|
+
}
|
|
39
|
+
/** The prefix a checkpoint digest is written with: the JCS form of the file, hashed with SHA-256. */
|
|
40
|
+
export declare const CHECKPOINT_DIGEST_PREFIX = "jcs1-sha256:";
|
|
41
|
+
/** Whether `raw` is a checkpoint digest this code wrote. */
|
|
42
|
+
export declare function isCheckpointDigest(raw: unknown): raw is string;
|
|
43
|
+
/** The digest of a checkpoint: SHA-256 over its RFC 8785 (JCS) form. Throws when an output can't be put in JSON. */
|
|
44
|
+
export declare function gateCheckpointDigest(checkpoint: GateCheckpoint): string;
|
|
45
|
+
/**
|
|
46
|
+
* A run id is the checkpoint's file name, so it may hold only letters,
|
|
47
|
+
* digits, `.`, `_` and `-`, and may not start with a dot. A run named
|
|
48
|
+
* otherwise (a caller-chosen id with a slash in it) gets no checkpoint.
|
|
49
|
+
*/
|
|
50
|
+
export declare function isCheckpointRunId(runId: string): boolean;
|
|
51
|
+
/** Where the checkpoint of `runId` lives on `chant/lifecycle`: the directory and the file, as `writeBlobToPath` takes them. */
|
|
52
|
+
export declare function gateCheckpointPath(op: string, runId: string): {
|
|
53
|
+
dir: string;
|
|
54
|
+
file: string;
|
|
55
|
+
};
|
|
56
|
+
/** The file's text: the checkpoint as JSON, keys sorted, one value per line. */
|
|
57
|
+
export declare function gateCheckpointText(checkpoint: GateCheckpoint): string;
|
|
58
|
+
/**
|
|
59
|
+
* Put `outputs` in the form a checkpoint stores: each value as JSON would
|
|
60
|
+
* carry it. Returns the step whose output JSON can't hold (a cycle, a bigint)
|
|
61
|
+
* instead, so the caller can say which one blocks the gate's resume.
|
|
62
|
+
*/
|
|
63
|
+
export declare function checkpointOutputs(outputs: ReadonlyMap<string, unknown>, ids: readonly string[]): {
|
|
64
|
+
outputs: Record<string, unknown>;
|
|
65
|
+
} | {
|
|
66
|
+
unstorable: string;
|
|
67
|
+
};
|
|
68
|
+
/** A checkpoint file's text read back, or null when it isn't one. */
|
|
69
|
+
export declare function parseGateCheckpoint(text: string): GateCheckpoint | null;
|
|
70
|
+
/** Write a checkpoint to the local `chant/lifecycle` branch. Does not push: the pending fact appended after it does. */
|
|
71
|
+
export declare function writeGateCheckpoint(checkpoint: GateCheckpoint, opts?: {
|
|
72
|
+
cwd?: string;
|
|
73
|
+
}): Promise<void>;
|
|
74
|
+
/** The text of `runId`'s checkpoint for `op`, or null when there is none. */
|
|
75
|
+
export declare function readGateCheckpointText(op: string, runId: string, opts?: {
|
|
76
|
+
cwd?: string;
|
|
77
|
+
}): Promise<string | null>;
|
|
78
|
+
//# sourceMappingURL=gate-checkpoint.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gate-checkpoint.d.ts","sourceRoot":"","sources":["../../src/lifecycle/gate-checkpoint.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAOH,gCAAgC;AAChC,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,CAAC,CAAC;IACX,kCAAkC;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,uBAAuB;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,kGAAkG;IAClG,KAAK,EAAE,MAAM,CAAC;IACd,wEAAwE;IACxE,MAAM,EAAE,MAAM,CAAC;IACf,4EAA4E;IAC5E,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,uEAAuE;IACvE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,uFAAuF;IACvF,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAClC;AAED,qGAAqG;AACrG,eAAO,MAAM,wBAAwB,iBAAiB,CAAC;AAIvD,4DAA4D;AAC5D,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,OAAO,GAAG,GAAG,IAAI,MAAM,CAE9D;AAED,oHAAoH;AACpH,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,cAAc,GAAG,MAAM,CAEvE;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAExD;AAED,+HAA+H;AAC/H,wBAAgB,kBAAkB,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAE3F;AAED,gFAAgF;AAChF,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,cAAc,GAAG,MAAM,CAErE;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,WAAW,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,EAAE,SAAS,MAAM,EAAE,GAAG;IAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,GAAG;IAAE,UAAU,EAAE,MAAM,CAAA;CAAE,CAe9J;AAED,qEAAqE;AACrE,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,cAAc,GAAG,IAAI,CAkBvE;AAED,wHAAwH;AACxH,wBAAsB,mBAAmB,CAAC,UAAU,EAAE,cAAc,EAAE,IAAI,CAAC,EAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAG5G;AAED,6EAA6E;AAC7E,wBAAsB,sBAAsB,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAGvH"}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A gate's checkpoint (#3947): the step outputs a run held when it stopped at
|
|
3
|
+
* a gate that resumes, kept on `chant/lifecycle` at
|
|
4
|
+
* `_gates/<op>/checkpoints/<runId>.json`.
|
|
5
|
+
*
|
|
6
|
+
* The run writes the file just before it appends the pending fact, and puts
|
|
7
|
+
* the file's digest on that fact as `checkpointDigest`. `chant approve`
|
|
8
|
+
* copies the digest onto the approval, the way it copies the plan digest, and
|
|
9
|
+
* a seal covers it (`../workspace/trust/gate-seal.ts`). A later run that
|
|
10
|
+
* resumes at the gate reads the file back and checks it against the digest
|
|
11
|
+
* the approver saw, so a value pushed onto the branch after the approval is
|
|
12
|
+
* refused rather than carried into the steps after the gate.
|
|
13
|
+
*
|
|
14
|
+
* Only the outputs some step after the gate references are stored, worked
|
|
15
|
+
* out from the Op's references (`../op/gate-checkpoint.ts`). An output that
|
|
16
|
+
* an activity contract marks secret is never stored: the gate doesn't
|
|
17
|
+
* resume, and the next run starts at the first phase.
|
|
18
|
+
*
|
|
19
|
+
* Pure apart from the two git helpers at the bottom.
|
|
20
|
+
*/
|
|
21
|
+
import { canonicalJson } from "../effect-receipt.js";
|
|
22
|
+
import { contentDigest } from "../content-digest.js";
|
|
23
|
+
import { sortedJsonReplacer } from "../utils.js";
|
|
24
|
+
import { readBlobFromPath, writeBlobToPath } from "./git.js";
|
|
25
|
+
/** The prefix a checkpoint digest is written with: the JCS form of the file, hashed with SHA-256. */
|
|
26
|
+
export const CHECKPOINT_DIGEST_PREFIX = "jcs1-sha256:";
|
|
27
|
+
const CHECKPOINT_DIGEST_PATTERN = /^jcs1-sha256:[0-9a-f]{64}$/;
|
|
28
|
+
/** Whether `raw` is a checkpoint digest this code wrote. */
|
|
29
|
+
export function isCheckpointDigest(raw) {
|
|
30
|
+
return typeof raw === "string" && CHECKPOINT_DIGEST_PATTERN.test(raw);
|
|
31
|
+
}
|
|
32
|
+
/** The digest of a checkpoint: SHA-256 over its RFC 8785 (JCS) form. Throws when an output can't be put in JSON. */
|
|
33
|
+
export function gateCheckpointDigest(checkpoint) {
|
|
34
|
+
return CHECKPOINT_DIGEST_PREFIX + contentDigest(canonicalJson(checkpoint)).slice("sha256:".length);
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* A run id is the checkpoint's file name, so it may hold only letters,
|
|
38
|
+
* digits, `.`, `_` and `-`, and may not start with a dot. A run named
|
|
39
|
+
* otherwise (a caller-chosen id with a slash in it) gets no checkpoint.
|
|
40
|
+
*/
|
|
41
|
+
export function isCheckpointRunId(runId) {
|
|
42
|
+
return /^[A-Za-z0-9_-][A-Za-z0-9._-]*$/.test(runId) && runId.length <= 200;
|
|
43
|
+
}
|
|
44
|
+
/** Where the checkpoint of `runId` lives on `chant/lifecycle`: the directory and the file, as `writeBlobToPath` takes them. */
|
|
45
|
+
export function gateCheckpointPath(op, runId) {
|
|
46
|
+
return { dir: `_gates/${op}/checkpoints`, file: `${runId}.json` };
|
|
47
|
+
}
|
|
48
|
+
/** The file's text: the checkpoint as JSON, keys sorted, one value per line. */
|
|
49
|
+
export function gateCheckpointText(checkpoint) {
|
|
50
|
+
return `${JSON.stringify(checkpoint, sortedJsonReplacer, 2)}\n`;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Put `outputs` in the form a checkpoint stores: each value as JSON would
|
|
54
|
+
* carry it. Returns the step whose output JSON can't hold (a cycle, a bigint)
|
|
55
|
+
* instead, so the caller can say which one blocks the gate's resume.
|
|
56
|
+
*/
|
|
57
|
+
export function checkpointOutputs(outputs, ids) {
|
|
58
|
+
const out = {};
|
|
59
|
+
for (const id of ids) {
|
|
60
|
+
if (!outputs.has(id))
|
|
61
|
+
continue;
|
|
62
|
+
const value = outputs.get(id);
|
|
63
|
+
try {
|
|
64
|
+
const text = JSON.stringify(value === undefined ? null : value);
|
|
65
|
+
const parsed = JSON.parse(text);
|
|
66
|
+
canonicalJson(parsed);
|
|
67
|
+
out[id] = parsed;
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
return { unstorable: id };
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return { outputs: out };
|
|
74
|
+
}
|
|
75
|
+
/** A checkpoint file's text read back, or null when it isn't one. */
|
|
76
|
+
export function parseGateCheckpoint(text) {
|
|
77
|
+
let raw;
|
|
78
|
+
try {
|
|
79
|
+
raw = JSON.parse(text);
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
const r = raw;
|
|
85
|
+
if (r === null || typeof r !== "object" || r.version !== 1 || typeof r.op !== "string" || typeof r.gate !== "string" ||
|
|
86
|
+
typeof r.runId !== "string" || typeof r.commit !== "string" ||
|
|
87
|
+
r.outputs === null || typeof r.outputs !== "object" || Array.isArray(r.outputs) ||
|
|
88
|
+
(r.environment !== undefined && typeof r.environment !== "string") ||
|
|
89
|
+
(r.planDigest !== undefined && typeof r.planDigest !== "string")) {
|
|
90
|
+
return null;
|
|
91
|
+
}
|
|
92
|
+
return r;
|
|
93
|
+
}
|
|
94
|
+
/** Write a checkpoint to the local `chant/lifecycle` branch. Does not push: the pending fact appended after it does. */
|
|
95
|
+
export async function writeGateCheckpoint(checkpoint, opts) {
|
|
96
|
+
const { dir, file } = gateCheckpointPath(checkpoint.op, checkpoint.runId);
|
|
97
|
+
await writeBlobToPath(dir, file, gateCheckpointText(checkpoint), `Gate checkpoint for ${checkpoint.gate}`, opts);
|
|
98
|
+
}
|
|
99
|
+
/** The text of `runId`'s checkpoint for `op`, or null when there is none. */
|
|
100
|
+
export async function readGateCheckpointText(op, runId, opts) {
|
|
101
|
+
const { dir, file } = gateCheckpointPath(op, runId);
|
|
102
|
+
return readBlobFromPath(dir, file, opts);
|
|
103
|
+
}
|
|
@@ -75,6 +75,12 @@ export interface GateResolutionRecord {
|
|
|
75
75
|
* such a record proves is that somebody approved *something*.
|
|
76
76
|
*/
|
|
77
77
|
planDigest?: string;
|
|
78
|
+
/**
|
|
79
|
+
* The checkpoint this approval lets a run resume from (#3947), copied off
|
|
80
|
+
* the pending fact it answers. Set only on an approval of a gate that
|
|
81
|
+
* resumes (`resume: true`) whose run stored a checkpoint. A seal covers it.
|
|
82
|
+
*/
|
|
83
|
+
checkpointDigest?: string;
|
|
78
84
|
/**
|
|
79
85
|
* The environment this approval is for (#2574), copied off the pending fact
|
|
80
86
|
* it answers. Set for a component gate, whose ledger is keyed by component
|
|
@@ -145,12 +151,37 @@ export interface GateResolutionRecord {
|
|
|
145
151
|
* `constrains` names the gate back (`gate:<op>/<gate>`).
|
|
146
152
|
*/
|
|
147
153
|
answer?: GateAnswerRef;
|
|
154
|
+
/**
|
|
155
|
+
* The line this approval was carried from (#3949): an approval recorded
|
|
156
|
+
* under one of the gate's aliases, which a run counted toward the gate and
|
|
157
|
+
* wrote again under its new name. `op`, `gate` and `timestamp` name that
|
|
158
|
+
* line; `checkpointDigest` is the one it carried, if any, since a seal
|
|
159
|
+
* signs it. `resolvedBy`, the plan, the environment and the seal are the
|
|
160
|
+
* original's, and the seal verifies against the names in here. This
|
|
161
|
+
* record's own `timestamp` is when it was carried.
|
|
162
|
+
*/
|
|
163
|
+
carriedFrom?: GateCarriedFrom;
|
|
164
|
+
}
|
|
165
|
+
/** Where a carried approval came from (#3949): the original line's op, gate and time, and its checkpoint digest when it had one. */
|
|
166
|
+
export interface GateCarriedFrom {
|
|
167
|
+
op: string;
|
|
168
|
+
gate: string;
|
|
169
|
+
timestamp: string;
|
|
170
|
+
checkpointDigest?: string;
|
|
148
171
|
}
|
|
172
|
+
/** Whether `raw` is a {@link GateCarriedFrom}. */
|
|
173
|
+
export declare function isGateCarriedFrom(raw: unknown): raw is GateCarriedFrom;
|
|
149
174
|
/** A gate approval's seal (#3163): who signed, the key's fingerprint (reported, never trusted), and the armored signature. */
|
|
150
175
|
export interface GateApprovalSeal {
|
|
151
176
|
signer: string;
|
|
152
177
|
key: string;
|
|
153
178
|
signature: string;
|
|
179
|
+
/**
|
|
180
|
+
* The seal's version (#3947). `2` on a seal over an approval that carries a
|
|
181
|
+
* `checkpointDigest`, whose payload signs the digest as one more line.
|
|
182
|
+
* Absent on every other seal, which is version 1.
|
|
183
|
+
*/
|
|
184
|
+
version?: 2;
|
|
154
185
|
}
|
|
155
186
|
export type GateResolutionInput = Omit<GateResolutionRecord, "version" | "kind">;
|
|
156
187
|
/**
|
|
@@ -214,6 +245,16 @@ export interface PendingGateRecord {
|
|
|
214
245
|
* binds one since #2574.
|
|
215
246
|
*/
|
|
216
247
|
planDigest?: string;
|
|
248
|
+
/**
|
|
249
|
+
* The digest of the checkpoint the run stored when it stopped here (#3947),
|
|
250
|
+
* on a gate that resumes (`resume: true`). The file is at
|
|
251
|
+
* `_gates/<op>/checkpoints/<runId>.json` (`./gate-checkpoint.ts`). `chant
|
|
252
|
+
* approve` copies it onto the approval, and a run resumes at this gate only
|
|
253
|
+
* from a checkpoint that matches it. Absent when the gate doesn't resume,
|
|
254
|
+
* or when its run could not store one, such as when an output it needs is
|
|
255
|
+
* secret.
|
|
256
|
+
*/
|
|
257
|
+
checkpointDigest?: string;
|
|
217
258
|
/**
|
|
218
259
|
* The environment the run reached this gate in (#2574). Set by the
|
|
219
260
|
* component driver, whose gate ledger is keyed by component, so pending
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gate-ledger.d.ts","sourceRoot":"","sources":["../../src/lifecycle/gate-ledger.ts"],"names":[],"mappings":"AA6CA,OAAO,EAAqB,KAAK,UAAU,EAAE,MAAM,eAAe,CAAC;AACnE,OAAO,KAAK,EAAE,YAAY,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAClG,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AACzD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAI7D,OAAO,EAAE,mBAAmB,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAGxF,OAAO,EACL,oBAAoB,EACpB,iBAAiB,EACjB,uBAAuB,EACvB,qBAAqB,EACrB,KAAK,mBAAmB,GACzB,MAAM,sBAAsB,CAAC;AAI9B,sHAAsH;AACtH,eAAO,MAAM,SAAS,WAAM,CAAC;AAI7B;;;;;;GAMG;AACH,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAC1B,oCAAoC;IACpC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB;;;;;OAKG;IACH,IAAI,CAAC,EAAE,KAAK,CAAC,MAAM,GAAG,OAAO,CAAC,CAAC;CAChC;AAED,4CAA4C;AAC5C,MAAM,WAAW,oBAAoB;IACnC,wFAAwF;IACxF,OAAO,EAAE,CAAC,CAAC;IACX,8KAA8K;IAC9K,IAAI,CAAC,EAAE,YAAY,CAAC;IACpB,6CAA6C;IAC7C,EAAE,EAAE,MAAM,CAAC;IACX,uEAAuE;IACvE,IAAI,EAAE,MAAM,CAAC;IACb,0HAA0H;IAC1H,UAAU,EAAE,MAAM,CAAC;IACnB;;;;;OAKG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,8FAA8F;IAC9F,SAAS,EAAE,MAAM,CAAC;IAClB,oLAAoL;IACpL,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;;;;;;;OASG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;;;;;;;;;;OAUG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;;OAKG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;;;;;;;OAUG;IACH,MAAM,CAAC,EAAE,UAAU,CAAC;IACpB;;;;;;;OAOG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B;;;;;;;;OAQG;IACH,QAAQ,CAAC,EAAE,YAAY,CAAC;IACxB;;;OAGG;IACH,cAAc,CAAC,EAAE,kBAAkB,CAAC;IACpC;;;;;;;OAOG;IACH,IAAI,CAAC,EAAE,gBAAgB,CAAC;IACxB;;;;;OAKG;IACH,MAAM,CAAC,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;IAC3D;;;;;OAKG;IACH,MAAM,CAAC,EAAE,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"gate-ledger.d.ts","sourceRoot":"","sources":["../../src/lifecycle/gate-ledger.ts"],"names":[],"mappings":"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"}
|
|
@@ -53,6 +53,12 @@ const DIR = "_gates";
|
|
|
53
53
|
/** The directory on the `chant/lifecycle` branch that holds gate ledgers, under a member's prefix when it has one. */
|
|
54
54
|
export const GATES_DIR = DIR;
|
|
55
55
|
const APPEND_RETRY_ATTEMPTS = 5;
|
|
56
|
+
/** Whether `raw` is a {@link GateCarriedFrom}. */
|
|
57
|
+
export function isGateCarriedFrom(raw) {
|
|
58
|
+
const c = raw;
|
|
59
|
+
return (!!c && typeof c === "object" && !Array.isArray(c) && typeof c.op === "string" && typeof c.gate === "string" &&
|
|
60
|
+
typeof c.timestamp === "string" && (c.checkpointDigest === undefined || typeof c.checkpointDigest === "string"));
|
|
61
|
+
}
|
|
56
62
|
function filename(op) {
|
|
57
63
|
return `${op}.jsonl`;
|
|
58
64
|
}
|
|
@@ -166,6 +172,12 @@ export function parseGateLedger(content) {
|
|
|
166
172
|
malformed++;
|
|
167
173
|
continue;
|
|
168
174
|
}
|
|
175
|
+
// #3947: and for the checkpoint an approval lets a run resume from.
|
|
176
|
+
const rawCheckpoint = parsed.checkpointDigest;
|
|
177
|
+
if (rawCheckpoint !== undefined && typeof rawCheckpoint !== "string") {
|
|
178
|
+
malformed++;
|
|
179
|
+
continue;
|
|
180
|
+
}
|
|
169
181
|
if (parsed.kind === "pending") {
|
|
170
182
|
if (typeof parsed.expiresAt !== "string") {
|
|
171
183
|
malformed++;
|
|
@@ -186,6 +198,12 @@ export function parseGateLedger(content) {
|
|
|
186
198
|
malformed++;
|
|
187
199
|
continue;
|
|
188
200
|
}
|
|
201
|
+
// #3949: a carried approval's seal is checked against the line it cites, so the citation must be whole.
|
|
202
|
+
const rawCarried = parsed.carriedFrom;
|
|
203
|
+
if (rawCarried !== undefined && !isGateCarriedFrom(rawCarried)) {
|
|
204
|
+
malformed++;
|
|
205
|
+
continue;
|
|
206
|
+
}
|
|
189
207
|
resolutions.push(parsed);
|
|
190
208
|
}
|
|
191
209
|
catch {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"receipt-plan.d.ts","sourceRoot":"","sources":["../../src/lifecycle/receipt-plan.ts"],"names":[],"mappings":"AAkCA,OAAO,
|
|
1
|
+
{"version":3,"file":"receipt-plan.d.ts","sourceRoot":"","sources":["../../src/lifecycle/receipt-plan.ts"],"names":[],"mappings":"AAkCA,OAAO,EAIL,KAAK,wBAAwB,EAC7B,KAAK,oBAAoB,EAC1B,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AACnD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AACvD,OAAO,KAAK,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAE9D;;;;;GAKG;AACH,eAAO,MAAM,uBAAuB,UAAU,CAAC;AAE/C,0EAA0E;AAC1E,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,GAAG,OAAO,CAIzF;AAED;;;;;GAKG;AACH,MAAM,WAAW,cAAc;IAC7B,yEAAyE;IACzE,QAAQ,EAAE,OAAO,CAAC;IAClB,4EAA4E;IAC5E,OAAO,EAAE,OAAO,CAAC;IACjB,kEAAkE;IAClE,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,yCAAyC;IACzC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,oDAAoD;IACpD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,2DAA2D;IAC3D,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,2DAA2D;IAC3D,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;IACpC,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CACnC,SAAS,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC,GACpD,oBAAoB,CAiBtB;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAC1B,QAAQ,EAAE,WAAW,CAAC,MAAM,EAAE,wBAAwB,CAAC,EACvD,QAAQ,EAAE,WAAW,CAAC,MAAM,EAAE,cAAc,CAAC,EAC7C,QAAQ,EAAE,oBAAoB,GAC7B,cAAc,EAAE,CAsGlB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,mBAAmB,CACjC,EAAE,EAAE,SAAS,EACb,QAAQ,EAAE,WAAW,CAAC,MAAM,EAAE,wBAAwB,CAAC,EACvD,cAAc,EAAE,cAAc,EAAE,GAC/B,SAAS,CAMX"}
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
* plan's merged observed values).
|
|
33
33
|
*/
|
|
34
34
|
import { AttrRef } from "../attrref.js";
|
|
35
|
-
import { EXISTENCE_EXPECTATION, resolveReceiptExpectation, } from "../effect-receipt.js";
|
|
35
|
+
import { EXISTENCE_EXPECTATION, declaredExpectation, resolveReceiptExpectation, } from "../effect-receipt.js";
|
|
36
36
|
/**
|
|
37
37
|
* The attribute a materialized receipt's live value is read from. A lexicon
|
|
38
38
|
* receipt row's observation (#1835) maps the stored value onto
|
|
@@ -148,7 +148,9 @@ export function planReceipts(receipts, readings, resolver) {
|
|
|
148
148
|
});
|
|
149
149
|
continue;
|
|
150
150
|
}
|
|
151
|
-
|
|
151
|
+
// A value an effect step wrote with the digest of the step outputs it read
|
|
152
|
+
// (#3948) is compared on its declared part: outputs exist only at run.
|
|
153
|
+
if (typeof reading.value === "string" && declaredExpectation(reading.value) === expectation) {
|
|
152
154
|
entries.push({ ...base, action: "noop", evidence });
|
|
153
155
|
continue;
|
|
154
156
|
}
|
|
@@ -24,6 +24,8 @@ export declare function buildRunRecord(config: Pick<OpConfig, "name" | "labels">
|
|
|
24
24
|
gate?: OpRunRecord["gate"];
|
|
25
25
|
point?: OpRunRecord["point"];
|
|
26
26
|
steward?: string;
|
|
27
|
+
/** The gate the run resumed at, for a run that resumed (#3947). */
|
|
28
|
+
resumed?: OpRunRecord["resumed"];
|
|
27
29
|
/** Each phase's wall-clock time, by name, as the executor measured it. */
|
|
28
30
|
phaseDurations?: Record<string, number>;
|
|
29
31
|
}): OpRunRecordInput;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run-ledger.d.ts","sourceRoot":"","sources":["../../src/lifecycle/run-ledger.ts"],"names":[],"mappings":"AAsCA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,KAAK,EAAE,WAAW,EAAE,gBAAgB,EAAqC,MAAM,eAAe,CAAC;AAStG,0EAA0E;AAC1E,eAAO,MAAM,eAAe,UAAU,CAAC;AAMvC,8FAA8F;AAC9F,wBAAgB,QAAQ,CAAC,MAAM,EAAE,IAAI,CAAC,QAAQ,EAAE,QAAQ,CAAC,GAAG,MAAM,CAEjE;AAQD;;;;;;;;;;GAUG;AACH,wBAAgB,cAAc,CAC5B,MAAM,EAAE,IAAI,CAAC,QAAQ,EAAE,MAAM,GAAG,QAAQ,CAAC,EACzC,OAAO,EAAE,SAAS,UAAU,EAAE,EAC9B,KAAK,EAAE;IACL,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,WAAW,CAAC,QAAQ,CAAC,CAAC;IAC9B,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IAC3B,KAAK,CAAC,EAAE,WAAW,CAAC,OAAO,CAAC,CAAC;IAC7B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,0EAA0E;IAC1E,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACzC,GACA,gBAAgB,
|
|
1
|
+
{"version":3,"file":"run-ledger.d.ts","sourceRoot":"","sources":["../../src/lifecycle/run-ledger.ts"],"names":[],"mappings":"AAsCA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,KAAK,EAAE,WAAW,EAAE,gBAAgB,EAAqC,MAAM,eAAe,CAAC;AAStG,0EAA0E;AAC1E,eAAO,MAAM,eAAe,UAAU,CAAC;AAMvC,8FAA8F;AAC9F,wBAAgB,QAAQ,CAAC,MAAM,EAAE,IAAI,CAAC,QAAQ,EAAE,QAAQ,CAAC,GAAG,MAAM,CAEjE;AAQD;;;;;;;;;;GAUG;AACH,wBAAgB,cAAc,CAC5B,MAAM,EAAE,IAAI,CAAC,QAAQ,EAAE,MAAM,GAAG,QAAQ,CAAC,EACzC,OAAO,EAAE,SAAS,UAAU,EAAE,EAC9B,KAAK,EAAE;IACL,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,WAAW,CAAC,QAAQ,CAAC,CAAC;IAC9B,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IAC3B,KAAK,CAAC,EAAE,WAAW,CAAC,OAAO,CAAC,CAAC;IAC7B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,mEAAmE;IACnE,OAAO,CAAC,EAAE,WAAW,CAAC,SAAS,CAAC,CAAC;IACjC,0EAA0E;IAC1E,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACzC,GACA,gBAAgB,CA+ClB;AAED;;;;;;;;;GASG;AACH,wBAAsB,eAAe,CACnC,KAAK,EAAE,gBAAgB,EACvB,IAAI,CAAC,EAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,GACtB,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,WAAW,CAAA;CAAE,CAAC,CAsBlD;AAED;;;;GAIG;AACH,wBAAsB,aAAa,CACjC,WAAW,EAAE,MAAM,EACnB,EAAE,EAAE,MAAM,EACV,IAAI,CAAC,EAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,GACtB,OAAO,CAAC;IAAE,OAAO,EAAE,WAAW,EAAE,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC,CA4BxD"}
|
|
@@ -89,6 +89,7 @@ export function buildRunRecord(config, records, times) {
|
|
|
89
89
|
...(record.refusal !== undefined ? { refusal: record.refusal } : {}),
|
|
90
90
|
...(record.point ? { point: record.point } : {}),
|
|
91
91
|
...(record.gate ? { gate: record.gate } : {}),
|
|
92
|
+
...(record.resumed ? { resumed: record.resumed } : {}),
|
|
92
93
|
});
|
|
93
94
|
if (record.outcome)
|
|
94
95
|
outcomes[record.outcome.name] = record.outcome.value;
|
|
@@ -112,6 +113,7 @@ export function buildRunRecord(config, records, times) {
|
|
|
112
113
|
...(times.gate ? { gate: times.gate } : {}),
|
|
113
114
|
...(times.point ? { point: times.point } : {}),
|
|
114
115
|
...(times.steward ? { steward: times.steward } : {}),
|
|
116
|
+
...(times.resumed ? { resumed: times.resumed } : {}),
|
|
115
117
|
};
|
|
116
118
|
}
|
|
117
119
|
/**
|
|
@@ -14,15 +14,19 @@ export { ops012 } from "./ops012-activity-contract.js";
|
|
|
14
14
|
export { ops013 } from "./ops013-step-output-ref.js";
|
|
15
15
|
export { ops014 } from "./ops014-converge-rule-refusals.js";
|
|
16
16
|
export { ops015 } from "./ops015-gate-approval.js";
|
|
17
|
+
export { ops016 } from "./ops016-gate-resume.js";
|
|
18
|
+
export { ops017, ops017Check, workspaceIdentityGates } from "./ops017-gate-alias.js";
|
|
17
19
|
export { sys010, sys010Check } from "./sys010-key-over-plain-http.js";
|
|
18
20
|
export interface CoreOpCheckOptions {
|
|
19
21
|
/** `decide.backends` from the project's chant.config, for SYS010 (#2828). */
|
|
20
22
|
decideBackends?: Record<string, Pick<DecideBackend, "url" | "key">>;
|
|
23
|
+
/** The workspace's `identity.gates`, gate to class, for OPS017 (#3949): `workspaceIdentityGates`' answer. */
|
|
24
|
+
identityGates?: ReadonlyMap<string, string | null>;
|
|
21
25
|
}
|
|
22
26
|
/**
|
|
23
27
|
* Core's own post-synth checks over the Op model: OPS012, OPS013, OPS014,
|
|
24
|
-
* OPS015,
|
|
25
|
-
* backends.
|
|
28
|
+
* OPS015, OPS016, OPS017 over the workspace's `identity.gates`, and SYS010
|
|
29
|
+
* over the `decide` steps and the configured decide backends.
|
|
26
30
|
*/
|
|
27
31
|
export declare function coreOpChecks(opts?: CoreOpCheckOptions): PostSynthCheck[];
|
|
28
32
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/lint/rules/op/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/lint/rules/op/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAQvD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAE/D,OAAO,EAAE,MAAM,EAAE,MAAM,4BAA4B,CAAC;AACpD,OAAO,EAAE,MAAM,EAAE,MAAM,0BAA0B,CAAC;AAClD,OAAO,EAAE,MAAM,EAAE,MAAM,iCAAiC,CAAC;AACzD,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAChD,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAC9C,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAClF,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAEnE,MAAM,WAAW,kBAAkB;IACjC,6EAA6E;IAC7E,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,aAAa,EAAE,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC;IACpE,6GAA6G;IAC7G,aAAa,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC;CACpD;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,IAAI,GAAE,kBAAuB,GAAG,cAAc,EAAE,CAE5E"}
|
|
@@ -12,17 +12,21 @@ import { ops012 } from "./ops012-activity-contract.js";
|
|
|
12
12
|
import { ops013 } from "./ops013-step-output-ref.js";
|
|
13
13
|
import { ops014 } from "./ops014-converge-rule-refusals.js";
|
|
14
14
|
import { ops015 } from "./ops015-gate-approval.js";
|
|
15
|
+
import { ops016 } from "./ops016-gate-resume.js";
|
|
16
|
+
import { ops017Check } from "./ops017-gate-alias.js";
|
|
15
17
|
import { sys010Check } from "./sys010-key-over-plain-http.js";
|
|
16
18
|
export { ops012 } from "./ops012-activity-contract.js";
|
|
17
19
|
export { ops013 } from "./ops013-step-output-ref.js";
|
|
18
20
|
export { ops014 } from "./ops014-converge-rule-refusals.js";
|
|
19
21
|
export { ops015 } from "./ops015-gate-approval.js";
|
|
22
|
+
export { ops016 } from "./ops016-gate-resume.js";
|
|
23
|
+
export { ops017, ops017Check, workspaceIdentityGates } from "./ops017-gate-alias.js";
|
|
20
24
|
export { sys010, sys010Check } from "./sys010-key-over-plain-http.js";
|
|
21
25
|
/**
|
|
22
26
|
* Core's own post-synth checks over the Op model: OPS012, OPS013, OPS014,
|
|
23
|
-
* OPS015,
|
|
24
|
-
* backends.
|
|
27
|
+
* OPS015, OPS016, OPS017 over the workspace's `identity.gates`, and SYS010
|
|
28
|
+
* over the `decide` steps and the configured decide backends.
|
|
25
29
|
*/
|
|
26
30
|
export function coreOpChecks(opts = {}) {
|
|
27
|
-
return [ops012, ops013, ops014, ops015, sys010Check(opts.decideBackends)];
|
|
31
|
+
return [ops012, ops013, ops014, ops015, ops016, ops017Check(opts.identityGates), sys010Check(opts.decideBackends)];
|
|
28
32
|
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OPS016: a gate that resumes (`resume: true`, #3947) can. It sits at the top
|
|
3
|
+
* of a main phase, asks no decision point, is not in an Op with a
|
|
4
|
+
* `workLease`, names a plan step that runs before it when its plan is a
|
|
5
|
+
* reference, and no step after it reads an output an activity contract marks
|
|
6
|
+
* secret, since a checkpoint never stores one.
|
|
7
|
+
*
|
|
8
|
+
* The run itself treats a gate that fails one of these as one that doesn't
|
|
9
|
+
* resume. This check makes that a build error instead of a quiet re-run from
|
|
10
|
+
* the first phase. Contracts come from the same merged map OPS013 uses.
|
|
11
|
+
*/
|
|
12
|
+
import type { PostSynthCheck } from "../../post-synth.js";
|
|
13
|
+
export declare const ops016: PostSynthCheck;
|
|
14
|
+
//# sourceMappingURL=ops016-gate-resume.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ops016-gate-resume.d.ts","sourceRoot":"","sources":["../../../../src/lint/rules/op/ops016-gate-resume.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,KAAK,EAAE,cAAc,EAAyC,MAAM,kBAAkB,CAAC;AAW9F,eAAO,MAAM,MAAM,EAAE,cAyBpB,CAAC"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { mergeActivityContracts } from "../../../op/index.js";
|
|
2
|
+
import { validateGateResume } from "../../../op/gate-checkpoint.js";
|
|
3
|
+
import * as contracts from "../../../op/activities/activity-contracts.js";
|
|
4
|
+
import { isOpEntity } from "./support.js";
|
|
5
|
+
const CONTRACTS = new Map(Object.values(contracts).map((c) => [c.name, c]));
|
|
6
|
+
export const ops016 = {
|
|
7
|
+
id: "OPS016",
|
|
8
|
+
description: "A gate with resume: true can resume: at the top of a main phase, no decision point or workLease, a plan step before it, and no secret output read after it",
|
|
9
|
+
check(ctx) {
|
|
10
|
+
const diagnostics = [];
|
|
11
|
+
const activeContracts = mergeActivityContracts(CONTRACTS, ctx.activityContracts);
|
|
12
|
+
for (const [entityKey, entity] of ctx.entities) {
|
|
13
|
+
if (!isOpEntity(entity))
|
|
14
|
+
continue;
|
|
15
|
+
const rec = entity;
|
|
16
|
+
const props = (entity.props ?? {});
|
|
17
|
+
if (typeof props.name !== "string" || !Array.isArray(props.phases))
|
|
18
|
+
continue;
|
|
19
|
+
for (const issue of validateGateResume(props, activeContracts)) {
|
|
20
|
+
diagnostics.push({
|
|
21
|
+
checkId: "OPS016",
|
|
22
|
+
severity: "error",
|
|
23
|
+
message: `Op "${issue.opName}", phase "${issue.phase}", ${issue.fn}: ${issue.message}`,
|
|
24
|
+
entity: entityKey,
|
|
25
|
+
lexicon: typeof rec.lexicon === "string" ? rec.lexicon : undefined,
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return diagnostics;
|
|
30
|
+
},
|
|
31
|
+
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OPS017: a gate's aliases (#3949) can stand. An alias admits approvals of
|
|
3
|
+
* the plan a run planned, so the gate must bind a `plan`, and a gate that
|
|
4
|
+
* asks a decision point takes none. An alias must not name a gate that still
|
|
5
|
+
* exists in the build, or one approval would answer two gates, and two gates
|
|
6
|
+
* must not claim one alias. When the workspace's `identity.gates` names an
|
|
7
|
+
* alias, the new gate must be named too, with the alias's class, or
|
|
8
|
+
* approvals that needed a seal would count without one.
|
|
9
|
+
*
|
|
10
|
+
* The identity rules come from the caller, as SYS010's decide backends do:
|
|
11
|
+
* `chant build` and `chant lint` read them with
|
|
12
|
+
* {@link workspaceIdentityGates}, which loads workspace code only when an Op
|
|
13
|
+
* has aliases and the project sits in a workspace. Without them that part
|
|
14
|
+
* is skipped.
|
|
15
|
+
*/
|
|
16
|
+
import type { PostSynthCheck } from "../../post-synth.js";
|
|
17
|
+
/**
|
|
18
|
+
* The gates the workspace around `projectDir` names under `identity.gates`,
|
|
19
|
+
* each with its class (null for any signer), for OPS017. Undefined when no
|
|
20
|
+
* Op among `entities` has aliases, outside a workspace, or when the
|
|
21
|
+
* declaration can't be read, which `chant workspace check` reports. The
|
|
22
|
+
* workspace modules load only past the first two checks, so a level-0
|
|
23
|
+
* build loads none.
|
|
24
|
+
*/
|
|
25
|
+
export declare function workspaceIdentityGates(projectDir: string, entities: Iterable<[string, unknown]>): Promise<Map<string, string | null> | undefined>;
|
|
26
|
+
/** OPS017, judging `identity.gates` by `identityGates` when given. */
|
|
27
|
+
export declare function ops017Check(identityGates?: ReadonlyMap<string, string | null>): PostSynthCheck;
|
|
28
|
+
/** OPS017 without the workspace's identity rules. */
|
|
29
|
+
export declare const ops017: PostSynthCheck;
|
|
30
|
+
//# sourceMappingURL=ops017-gate-alias.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ops017-gate-alias.d.ts","sourceRoot":"","sources":["../../../../src/lint/rules/op/ops017-gate-alias.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,KAAK,EAAE,cAAc,EAAyC,MAAM,kBAAkB,CAAC;AAsB9F;;;;;;;GAOG;AACH,wBAAsB,sBAAsB,CAC1C,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,QAAQ,CAAC,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GACpC,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,GAAG,SAAS,CAAC,CAYjD;AAED,sEAAsE;AACtE,wBAAgB,WAAW,CAAC,aAAa,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,GAAG,cAAc,CAsB9F;AAED,qDAAqD;AACrD,eAAO,MAAM,MAAM,EAAE,cAA8B,CAAC"}
|