@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.
Files changed (195) 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/cli/main.d.ts.map +1 -1
  8. package/dist/cli/main.js +21 -7
  9. package/dist/cli/mcp/workspace-tools.d.ts +3 -3
  10. package/dist/cli/mcp/workspace-tools.d.ts.map +1 -1
  11. package/dist/cli/mcp/workspace-tools.js +27 -4
  12. package/dist/effect-receipt.d.ts +13 -0
  13. package/dist/effect-receipt.d.ts.map +1 -1
  14. package/dist/effect-receipt.js +19 -0
  15. package/dist/gate-decision.d.ts +1 -1
  16. package/dist/gate-decision.d.ts.map +1 -1
  17. package/dist/gate-decision.js +1 -1
  18. package/dist/lexicon-module.d.ts +7 -1
  19. package/dist/lexicon-module.d.ts.map +1 -1
  20. package/dist/lexicon-module.js +7 -2
  21. package/dist/lifecycle/gate-audit.d.ts +7 -1
  22. package/dist/lifecycle/gate-audit.d.ts.map +1 -1
  23. package/dist/lifecycle/gate-audit.js +40 -3
  24. package/dist/lifecycle/gate-checkpoint.d.ts +78 -0
  25. package/dist/lifecycle/gate-checkpoint.d.ts.map +1 -0
  26. package/dist/lifecycle/gate-checkpoint.js +103 -0
  27. package/dist/lifecycle/gate-ledger.d.ts +41 -0
  28. package/dist/lifecycle/gate-ledger.d.ts.map +1 -1
  29. package/dist/lifecycle/gate-ledger.js +18 -0
  30. package/dist/lifecycle/receipt-plan.d.ts.map +1 -1
  31. package/dist/lifecycle/receipt-plan.js +4 -2
  32. package/dist/lifecycle/run-ledger.d.ts +2 -0
  33. package/dist/lifecycle/run-ledger.d.ts.map +1 -1
  34. package/dist/lifecycle/run-ledger.js +2 -0
  35. package/dist/lint/rules/op/index.d.ts +6 -2
  36. package/dist/lint/rules/op/index.d.ts.map +1 -1
  37. package/dist/lint/rules/op/index.js +7 -3
  38. package/dist/lint/rules/op/ops016-gate-resume.d.ts +14 -0
  39. package/dist/lint/rules/op/ops016-gate-resume.d.ts.map +1 -0
  40. package/dist/lint/rules/op/ops016-gate-resume.js +31 -0
  41. package/dist/lint/rules/op/ops017-gate-alias.d.ts +30 -0
  42. package/dist/lint/rules/op/ops017-gate-alias.d.ts.map +1 -0
  43. package/dist/lint/rules/op/ops017-gate-alias.js +67 -0
  44. package/dist/op/activity-contract.d.ts +14 -0
  45. package/dist/op/activity-contract.d.ts.map +1 -1
  46. package/dist/op/activity-contract.js +16 -0
  47. package/dist/op/builders.d.ts +7 -0
  48. package/dist/op/builders.d.ts.map +1 -1
  49. package/dist/op/builders.js +13 -0
  50. package/dist/op/gate-alias.d.ts +57 -0
  51. package/dist/op/gate-alias.d.ts.map +1 -0
  52. package/dist/op/gate-alias.js +127 -0
  53. package/dist/op/gate-checkpoint.d.ts +123 -0
  54. package/dist/op/gate-checkpoint.d.ts.map +1 -0
  55. package/dist/op/gate-checkpoint.js +280 -0
  56. package/dist/op/gate.d.ts +54 -2
  57. package/dist/op/gate.d.ts.map +1 -1
  58. package/dist/op/gate.js +142 -1
  59. package/dist/op/index.d.ts +4 -1
  60. package/dist/op/index.d.ts.map +1 -1
  61. package/dist/op/index.js +2 -1
  62. package/dist/op/local-executor.d.ts +57 -2
  63. package/dist/op/local-executor.d.ts.map +1 -1
  64. package/dist/op/local-executor.js +200 -11
  65. package/dist/op/local-output.d.ts.map +1 -1
  66. package/dist/op/local-output.js +20 -2
  67. package/dist/op/op-ir.d.ts +4 -0
  68. package/dist/op/op-ir.d.ts.map +1 -1
  69. package/dist/op/op-ir.js +4 -0
  70. package/dist/op/receipt-store.d.ts +5 -0
  71. package/dist/op/receipt-store.d.ts.map +1 -1
  72. package/dist/op/receipt-store.js +4 -3
  73. package/dist/op/runtime.d.ts +15 -0
  74. package/dist/op/runtime.d.ts.map +1 -1
  75. package/dist/op/runtimes/local.d.ts.map +1 -1
  76. package/dist/op/runtimes/local.js +5 -0
  77. package/dist/op/step-output-ref.d.ts +26 -18
  78. package/dist/op/step-output-ref.d.ts.map +1 -1
  79. package/dist/op/step-output-ref.js +86 -63
  80. package/dist/op/types.d.ts +31 -0
  81. package/dist/op/types.d.ts.map +1 -1
  82. package/dist/wave-runtime.mjs +223 -221
  83. package/dist/workspace/agent-cli.d.ts.map +1 -1
  84. package/dist/workspace/agent-cli.js +3 -0
  85. package/dist/workspace/conformance/__writer_fixture__/answers/answer.schema.json +16 -1
  86. package/dist/workspace/conformance/writer.js +1 -1
  87. package/dist/workspace/decide.d.ts +51 -9
  88. package/dist/workspace/decide.d.ts.map +1 -1
  89. package/dist/workspace/decide.js +125 -14
  90. package/dist/workspace/lineage-upgrade.d.ts.map +1 -1
  91. package/dist/workspace/lineage-upgrade.js +20 -11
  92. package/dist/workspace/point-answer.schema.json +16 -1
  93. package/dist/workspace/points-cli.d.ts +5 -3
  94. package/dist/workspace/points-cli.d.ts.map +1 -1
  95. package/dist/workspace/points-cli.js +16 -7
  96. package/dist/workspace/points-write.schema.json +39 -4
  97. package/dist/workspace/points.schema.json +42 -3
  98. package/dist/workspace/reason-codes.d.ts +2 -1
  99. package/dist/workspace/reason-codes.d.ts.map +1 -1
  100. package/dist/workspace/reason-codes.js +2 -1
  101. package/dist/workspace/records-cli.d.ts +12 -2
  102. package/dist/workspace/records-cli.d.ts.map +1 -1
  103. package/dist/workspace/records-cli.js +27 -7
  104. package/dist/workspace/records-write.d.ts.map +1 -1
  105. package/dist/workspace/records-write.js +2 -3
  106. package/dist/workspace/records.d.ts +10 -4
  107. package/dist/workspace/records.d.ts.map +1 -1
  108. package/dist/workspace/records.js +16 -3
  109. package/dist/workspace/records.schema.json +2 -1
  110. package/dist/workspace/trust/gate-seal.d.ts +32 -1
  111. package/dist/workspace/trust/gate-seal.d.ts.map +1 -1
  112. package/dist/workspace/trust/gate-seal.js +41 -2
  113. package/dist/workspace/trust/seal.d.ts +1 -1
  114. package/dist/workspace/trust/seal.d.ts.map +1 -1
  115. package/dist/workspace/trust/seal.js +1 -1
  116. package/dist/workspace/trust/verify-cli.d.ts.map +1 -1
  117. package/dist/workspace/trust/verify-cli.js +2 -1
  118. package/dist/workspace/trust/verify.d.ts +22 -0
  119. package/dist/workspace/trust/verify.d.ts.map +1 -1
  120. package/dist/workspace/trust/verify.js +94 -14
  121. package/dist/workspace/write-scope.d.ts +3 -1
  122. package/dist/workspace/write-scope.d.ts.map +1 -1
  123. package/dist/workspace/write-scope.js +11 -4
  124. package/package.json +1 -1
  125. package/src/cli/commands/build.ts +9 -2
  126. package/src/cli/commands/lint.ts +4 -2
  127. package/src/cli/compiled-cli.e2e.test.ts +45 -1
  128. package/src/cli/handlers/approve.ts +46 -4
  129. package/src/cli/handlers/operator.test.ts +91 -0
  130. package/src/cli/main.test.ts +10 -0
  131. package/src/cli/main.ts +21 -7
  132. package/src/cli/mcp/workspace-tools.e2e.test.ts +1 -1
  133. package/src/cli/mcp/workspace-tools.ts +27 -4
  134. package/src/effect-receipt.ts +22 -0
  135. package/src/gate-decision.ts +2 -0
  136. package/src/lexicon-module.ts +9 -2
  137. package/src/lifecycle/gate-audit.ts +41 -4
  138. package/src/lifecycle/gate-checkpoint.test.ts +128 -0
  139. package/src/lifecycle/gate-checkpoint.ts +133 -0
  140. package/src/lifecycle/gate-ledger.ts +61 -0
  141. package/src/lifecycle/receipt-plan.test.ts +9 -0
  142. package/src/lifecycle/receipt-plan.ts +4 -1
  143. package/src/lifecycle/run-ledger.ts +4 -0
  144. package/src/lint/rules/op/index.ts +9 -3
  145. package/src/lint/rules/op/ops016-gate-resume.test.ts +53 -0
  146. package/src/lint/rules/op/ops016-gate-resume.ts +48 -0
  147. package/src/lint/rules/op/ops017-gate-alias.test.ts +85 -0
  148. package/src/lint/rules/op/ops017-gate-alias.ts +89 -0
  149. package/src/op/activity-contract.ts +22 -1
  150. package/src/op/builders.ts +21 -1
  151. package/src/op/effect-step.test.ts +95 -1
  152. package/src/op/gate-alias.e2e.test.ts +78 -0
  153. package/src/op/gate-alias.test.ts +350 -0
  154. package/src/op/gate-alias.ts +137 -0
  155. package/src/op/gate-checkpoint.test.ts +284 -0
  156. package/src/op/gate-checkpoint.ts +322 -0
  157. package/src/op/gate.ts +198 -4
  158. package/src/op/index.ts +4 -1
  159. package/src/op/local-executor.test.ts +65 -0
  160. package/src/op/local-executor.ts +248 -12
  161. package/src/op/local-output.ts +18 -2
  162. package/src/op/op-ir.test.ts +25 -0
  163. package/src/op/op-ir.ts +8 -0
  164. package/src/op/receipt-store.ts +13 -3
  165. package/src/op/runtime.ts +8 -0
  166. package/src/op/runtimes/local.ts +5 -0
  167. package/src/op/step-output-ref.test.ts +68 -24
  168. package/src/op/step-output-ref.ts +85 -65
  169. package/src/op/types.ts +32 -0
  170. package/src/workspace/agent-cli.ts +2 -0
  171. package/src/workspace/conformance/__writer_fixture__/answers/answer.schema.json +16 -1
  172. package/src/workspace/conformance/writer.ts +1 -1
  173. package/src/workspace/decide.test.ts +87 -3
  174. package/src/workspace/decide.ts +142 -17
  175. package/src/workspace/lineage-upgrade.test.ts +21 -0
  176. package/src/workspace/lineage-upgrade.ts +19 -11
  177. package/src/workspace/point-answer.schema.json +16 -1
  178. package/src/workspace/points-cli.ts +16 -8
  179. package/src/workspace/points-write.schema.json +39 -4
  180. package/src/workspace/points.schema.json +42 -3
  181. package/src/workspace/reason-codes.ts +2 -1
  182. package/src/workspace/record-assets.test.ts +14 -0
  183. package/src/workspace/records-cli.ts +28 -7
  184. package/src/workspace/records-write-commands.e2e.test.ts +32 -0
  185. package/src/workspace/records-write.ts +2 -3
  186. package/src/workspace/records.schema.json +2 -1
  187. package/src/workspace/records.ts +17 -4
  188. package/src/workspace/trust/gate-seal.test.ts +29 -2
  189. package/src/workspace/trust/gate-seal.ts +46 -2
  190. package/src/workspace/trust/seal.ts +1 -1
  191. package/src/workspace/trust/trust.test.ts +105 -0
  192. package/src/workspace/trust/verify-cli.ts +2 -1
  193. package/src/workspace/trust/verify.ts +106 -13
  194. package/src/workspace/write-scope.test.ts +18 -0
  195. 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
- if (!override) {
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":"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"}
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,EAGL,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,CAoGlB;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"}
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
- if (reading.value === expectation) {
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,CA6ClB;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"}
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, and SYS010 over the `decide` steps and the configured decide
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;AAMvD,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,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;CACrE;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,IAAI,GAAE,kBAAuB,GAAG,cAAc,EAAE,CAE5E"}
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, and SYS010 over the `decide` steps and the configured decide
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"}