@intentius/chant 0.124.1 → 0.124.3

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 (80) hide show
  1. package/dist/cli/handlers/override-approve.d.ts +3 -1
  2. package/dist/cli/handlers/override-approve.d.ts.map +1 -1
  3. package/dist/cli/main.d.ts.map +1 -1
  4. package/dist/cli/mcp/workspace-tools.d.ts +5 -1
  5. package/dist/cli/mcp/workspace-tools.d.ts.map +1 -1
  6. package/dist/cli/registry.d.ts +2 -0
  7. package/dist/cli/registry.d.ts.map +1 -1
  8. package/dist/lifecycle/gate-audit.d.ts +37 -13
  9. package/dist/lifecycle/gate-audit.d.ts.map +1 -1
  10. package/dist/lifecycle/gate-ledger.d.ts +1 -33
  11. package/dist/lifecycle/gate-ledger.d.ts.map +1 -1
  12. package/dist/lifecycle/gate-origin.d.ts +14 -2
  13. package/dist/lifecycle/gate-origin.d.ts.map +1 -1
  14. package/dist/lifecycle/gate-pending.d.ts +41 -0
  15. package/dist/lifecycle/gate-pending.d.ts.map +1 -0
  16. package/dist/op/activities/activity-contracts.d.ts +1 -0
  17. package/dist/op/activities/activity-contracts.d.ts.map +1 -1
  18. package/dist/op/activities/decide.d.ts +2 -0
  19. package/dist/op/activities/decide.d.ts.map +1 -1
  20. package/dist/op/gate-point-run.d.ts +5 -77
  21. package/dist/op/gate-point-run.d.ts.map +1 -1
  22. package/dist/op/gate-point.d.ts +18 -0
  23. package/dist/op/gate-point.d.ts.map +1 -1
  24. package/dist/op/gate.d.ts +8 -0
  25. package/dist/op/gate.d.ts.map +1 -1
  26. package/dist/op/index.d.ts +4 -4
  27. package/dist/op/index.d.ts.map +1 -1
  28. package/dist/op/op-waves-run.d.ts +37 -6
  29. package/dist/op/op-waves-run.d.ts.map +1 -1
  30. package/dist/op/op-waves.d.ts +38 -4
  31. package/dist/op/op-waves.d.ts.map +1 -1
  32. package/dist/op/steward-points.d.ts +7 -0
  33. package/dist/op/steward-points.d.ts.map +1 -1
  34. package/dist/override-gate.d.ts +8 -2
  35. package/dist/override-gate.d.ts.map +1 -1
  36. package/dist/point-decision.d.ts +134 -0
  37. package/dist/point-decision.d.ts.map +1 -0
  38. package/dist/pr-forge.d.ts +37 -2
  39. package/dist/pr-forge.d.ts.map +1 -1
  40. package/dist/workspace/decide.d.ts +14 -2
  41. package/dist/workspace/decide.d.ts.map +1 -1
  42. package/dist/workspace/reason-codes.d.ts +2 -1
  43. package/dist/workspace/reason-codes.d.ts.map +1 -1
  44. package/package.json +1 -1
  45. package/src/cli/handlers/override-approve.test.ts +16 -0
  46. package/src/cli/handlers/override-approve.ts +6 -2
  47. package/src/cli/main.test.ts +3 -0
  48. package/src/cli/main.ts +9 -2
  49. package/src/cli/mcp/workspace-tools.ts +7 -3
  50. package/src/cli/registry.ts +2 -0
  51. package/src/lifecycle/gate-audit.test.ts +42 -0
  52. package/src/lifecycle/gate-audit.ts +102 -34
  53. package/src/lifecycle/gate-ledger.ts +3 -53
  54. package/src/lifecycle/gate-origin.ts +20 -3
  55. package/src/lifecycle/gate-pending.ts +62 -0
  56. package/src/op/activities/activity-contracts.ts +1 -0
  57. package/src/op/activities/decide.ts +3 -0
  58. package/src/op/gate-point-ci.e2e.test.ts +171 -0
  59. package/src/op/gate-point-mcp.e2e.test.ts +163 -0
  60. package/src/op/gate-point-run.ts +18 -149
  61. package/src/op/gate-point.e2e.test.ts +2 -0
  62. package/src/op/gate-point.test.ts +1 -1
  63. package/src/op/gate-point.ts +27 -3
  64. package/src/op/gate.ts +10 -0
  65. package/src/op/index.ts +10 -1
  66. package/src/op/op-waves-run.ts +84 -19
  67. package/src/op/op-waves.test.ts +96 -0
  68. package/src/op/op-waves.ts +60 -4
  69. package/src/op/steward-points.ts +8 -0
  70. package/src/override-gate.test.ts +5 -0
  71. package/src/override-gate.ts +8 -2
  72. package/src/point-decision-bundle.test.ts +62 -0
  73. package/src/point-decision.e2e.test.ts +95 -0
  74. package/src/point-decision.ts +280 -0
  75. package/src/pr-forge.test.ts +62 -0
  76. package/src/pr-forge.ts +60 -9
  77. package/src/workspace/decide.ts +92 -8
  78. package/src/workspace/points-cli.ts +1 -1
  79. package/src/workspace/points-write.schema.json +1 -0
  80. package/src/workspace/reason-codes.ts +2 -1
@@ -46,11 +46,12 @@ import { type KindView } from "./records-write.js";
46
46
  import { type Asked, type Escalation, type ModelAsk, type Point } from "./points.js";
47
47
  import { type TrustPolicy } from "./trust/policy.js";
48
48
  import type { SourceVia } from "./source-block.js";
49
+ import { type GateOrigin } from "../lifecycle/gate-origin.js";
49
50
  /** The version of the write documents `points ask`, `points answer` and `points retract` print. */
50
51
  export declare const POINTS_WRITE_CONTRACT_VERSION = 1;
51
52
  export declare const POINTS_WRITE_SCHEMA_ID = "https://intentius.io/chant/schemas/workspace/points-write/v1/points-write.schema.json";
52
53
  /** Why `points ask`, `points answer` or `points retract` wrote nothing. Closed: a reader may switch on it. */
53
- export declare const POINTS_WRITE_ERROR_CODES: readonly ["kind-unreadable", "kind-invalid", "schema-unreadable", "schema-id-mismatch", "schema-invalid", "location-missing", "write-usage-invalid", "write-input-invalid", "points-undeclared", "points-invalid", "point-unknown", "point-inputs-invalid", "point-decider-failed", "answer-not-candidate", "quorum-not-met", "record-not-found", "record-closed", "record-id-taken", "answer-in-steward-turn", "principal-unidentified", "answer-not-answered", "answer-field-unsupported", "point-candidates-invalid", "write-lock-timeout", "write-lock-not-held", "record-unparseable", "record-schema-invalid", "record-id-duplicate", "record-supersedes-unknown", "record-supersedes-conflict", "record-remediates-unknown", "record-remediates-not-closed", "record-seal-mismatch", "session-seal-mismatch", "session-verdict-unknown-record"];
54
+ export declare const POINTS_WRITE_ERROR_CODES: readonly ["kind-unreadable", "kind-invalid", "schema-unreadable", "schema-id-mismatch", "schema-invalid", "location-missing", "write-usage-invalid", "write-input-invalid", "points-undeclared", "points-invalid", "point-unknown", "point-inputs-invalid", "point-decider-failed", "answer-not-candidate", "quorum-not-met", "record-not-found", "record-closed", "record-id-taken", "answer-in-steward-turn", "answer-never-over-mcp", "principal-unidentified", "answer-not-answered", "answer-field-unsupported", "point-candidates-invalid", "write-lock-timeout", "write-lock-not-held", "record-unparseable", "record-schema-invalid", "record-id-duplicate", "record-supersedes-unknown", "record-supersedes-conflict", "record-remediates-unknown", "record-remediates-not-closed", "record-seal-mismatch", "session-seal-mismatch", "session-verdict-unknown-record"];
54
55
  export type PointsWriteErrorCode = (typeof POINTS_WRITE_ERROR_CODES)[number];
55
56
  export declare class PointsWriteError extends Error {
56
57
  readonly code: PointsWriteErrorCode;
@@ -235,7 +236,9 @@ export interface AskPointOptions {
235
236
  * or the lifecycle ledger (#2786). Defaults to the ledger in a steward's
236
237
  * turn (`steward` given, or this process a steward's turn), since a steward
237
238
  * never writes the checkout, and to the tree otherwise. A question already
238
- * held on the ledger is rewritten there whatever this says.
239
+ * held on the ledger is rewritten there whatever this says. Outside a
240
+ * steward's turn, `points ask --store ledger` and a gate's `point.store`
241
+ * reach it (#3815), for a checkout that does not outlive the run.
239
242
  */
240
243
  store?: "tree" | "ledger";
241
244
  /** The date written as asked_on, and answered_on for a table's answer, YYYY-MM-DD. Defaults to today, in UTC. */
@@ -277,6 +280,13 @@ export interface AnswerPointOptions {
277
280
  kind?: string;
278
281
  on?: string;
279
282
  dryRun?: boolean;
283
+ /**
284
+ * The channel the answer came through (#3817). Defaults to this process's
285
+ * (`currentGateOrigin`). Over MCP or ACP nobody `by` names counts toward
286
+ * the quorum, and a question that constrains a `neverOverMcp` gate is
287
+ * refused outright.
288
+ */
289
+ origin?: GateOrigin;
280
290
  }
281
291
  /**
282
292
  * Whether an answer kind's schema copy takes the fields of #3351 (`note` on an
@@ -328,6 +338,8 @@ export interface RetractAnswerOptions {
328
338
  kind?: string;
329
339
  on?: string;
330
340
  dryRun?: boolean;
341
+ /** The channel the retraction came through, counted as for an answer (#3817). */
342
+ origin?: GateOrigin;
331
343
  }
332
344
  /**
333
345
  * People take an answer back: `points retract` (#3351, ws-084). The answer
@@ -1 +1 @@
1
- {"version":3,"file":"decide.d.ts","sourceRoot":"","sources":["../../src/workspace/decide.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"decide.d.ts","sourceRoot":"","sources":["../../src/workspace/decide.ts"],"names":[],"mappings":"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"}
@@ -132,8 +132,9 @@ export declare const REASONS: {
132
132
  readonly "point-inputs-invalid": "The inputs given to an ask are not a JSON object of the point's declared inputs.";
133
133
  readonly "point-decider-failed": "A model decider that fails closed (unreachable: fail) could not answer, so the ask wrote nothing.";
134
134
  readonly "answer-not-candidate": "The people's answer is not one of the question's candidates.";
135
- readonly "quorum-not-met": "Too few of the people who answered count toward the point's quorum: distinct, not holding the agent role, not the steward that asked, and holding one of its roles when it names any.";
135
+ readonly "quorum-not-met": "Too few of the people who answered count toward the point's quorum: distinct, not holding the agent role, not the steward that asked, and holding one of its roles when it names any. Nobody named over MCP or ACP counts (#3817).";
136
136
  readonly "answer-in-steward-turn": "The answer was given during a steward's turn, or by a process it started: a steward never answers a decision point, and a person answers it through hud or at a shell.";
137
+ readonly "answer-never-over-mcp": "The answer or retraction came over MCP or ACP, or from a process a session on one started, and the question constrains a gate that is never resolved there: a person answers it at a shell or through hud (#3817).";
137
138
  readonly "answer-not-answered": "points retract names a question that has no answer to retract: it is escalated or proposed, and people answer it instead (#3351).";
138
139
  readonly "answer-field-unsupported": "The answer kind's copy of point-answer.schema.json predates a field the write needs, a note, a relay, a retraction or an ad-hoc question's asked: copy the schema anew to turn it on (#3351, #3402, #3403).";
139
140
  readonly "point-candidates-invalid": "points ask names an ad-hoc point without --candidates, a declared point with them, or candidates that are not a question and criteria of the point's question type (#3403).";
@@ -1 +1 @@
1
- {"version":3,"file":"reason-codes.d.ts","sourceRoot":"","sources":["../../src/workspace/reason-codes.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"reason-codes.d.ts","sourceRoot":"","sources":["../../src/workspace/reason-codes.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@intentius/chant",
3
- "version": "0.124.1",
3
+ "version": "0.124.3",
4
4
  "description": "Declarative infrastructure-as-code toolkit — TypeScript on Node.js",
5
5
  "license": "Apache-2.0",
6
6
  "homepage": "https://intentius.io/chant",
@@ -84,4 +84,20 @@ describe("chant approve policy-override", () => {
84
84
  expect(await runOverrideApprove(ctx({ rules: ["no-drop", "no-lock"], reason: "why", plan: PLAN }))).toBe(0);
85
85
  expect(await runOverrideApprove(ctx({ rules: ["no-drop", "no-lock"], reason: "why", plan: DENIAL.planDigest }))).toBe(0);
86
86
  });
87
+
88
+ describe("the overriders check (#3824)", () => {
89
+ const args = { rules: ["no-drop", "no-lock"], reason: "why" };
90
+ test("warns when this checkout lists no overriders", async () => {
91
+ vi.stubEnv("CHANT_OVERRIDERS_FROM", "");
92
+ expect(await runOverrideApprove(ctx(args))).toBe(0);
93
+ expect(printed()).toMatch(/has no \.chant\/overriders/);
94
+ });
95
+ test("is skipped when the caller says where it reads its overriders", async () => {
96
+ vi.stubEnv("CHANT_OVERRIDERS_FROM", "policy.override in terragucci.config.ts");
97
+ expect(await runOverrideApprove(ctx(args))).toBe(0);
98
+ expect(printed()).toMatch(/overrides the denial of prod/);
99
+ expect(printed()).not.toMatch(/overriders/);
100
+ vi.unstubAllEnvs();
101
+ });
102
+ });
87
103
  });
@@ -10,7 +10,9 @@
10
10
  * recorded: the approver says what they are letting through. Whether the
11
11
  * override counts is decided by the run, against the overriders and signers
12
12
  * at base; this command only warns when the checkout's own overriders file
13
- * would not count it.
13
+ * would not count it. A product that keeps its overriders in its own config
14
+ * sets `CHANT_OVERRIDERS_FROM` (to where it reads them, e.g. `policy.override
15
+ * in terragucci.config.ts`), and the checkout check is skipped (#3824).
14
16
  */
15
17
 
16
18
  import { currentGateOrigin, isModelAuthored } from "../../lifecycle/gate-origin";
@@ -93,9 +95,11 @@ export async function runOverrideApprove(ctx: CommandContext): Promise<number> {
93
95
  `This overrides the denial of ${subject} by ${rules.join(", ")} for the plan ${denial.plan || denial.planDigest}. ` +
94
96
  `The next run that plans it applies it once; a plan that moves, or rules that change, need their own override.`,
95
97
  ));
98
+ const from = process.env.CHANT_OVERRIDERS_FROM?.trim();
99
+ if (from) return 0;
96
100
  const here = overridersAt(process.cwd(), "HEAD");
97
101
  if (!here.active) {
98
- console.error(formatWarning({ message: `This checkout has no ${OVERRIDERS_PATH}: unless the run reads its overriders from elsewhere at base, no override counts` }));
102
+ console.error(formatWarning({ message: `This checkout has no ${OVERRIDERS_PATH}: unless the run reads its overriders from elsewhere at base, no override counts (a tool that does sets CHANT_OVERRIDERS_FROM to say so)` }));
99
103
  } else if (!here.principals.map(norm).includes(norm(outcome.record.resolvedBy))) {
100
104
  console.error(formatWarning({ message: `${outcome.record.resolvedBy} is not in ${OVERRIDERS_PATH} here (${here.principals.join(", ") || "nobody"}), so a run that reads it at base does not count this override` }));
101
105
  }
@@ -874,6 +874,9 @@ describe("workspace points (ws-058, #2739)", () => {
874
874
  expect(answer).toMatchObject({ extraPositional: "answer", answer: "medium", bys: ["alice", "bob"] });
875
875
  expect(parseArgs(["workspace", "points", "--open", "--json"])).toMatchObject({ open: true, json: true });
876
876
  expect(() => parseArgs(["workspace", "points", "ask", "p", "--response", "--json"])).toThrow(/--response needs a JSON file/);
877
+ // #3815: --store ledger holds the question on chant/lifecycle.
878
+ expect(parseArgs(["workspace", "points", "ask", "p", "--inputs", "-", "--store", "ledger"]).store).toBe("ledger");
879
+ expect(() => parseArgs(["workspace", "points", "ask", "p", "--store", "git"])).toThrow(/--store is tree .* or ledger/);
877
880
  });
878
881
  });
879
882
 
package/src/cli/main.ts CHANGED
@@ -546,6 +546,11 @@ export function parseArgs(args: string[]): ParsedArgs {
546
546
  // `chant workspace points ask <point> --subject <id>` (#2739): what the question is about.
547
547
  result.subject = args[++i];
548
548
  if (!result.subject || result.subject.startsWith("-")) throw new Error("--subject needs what the question is about, such as a work item id: --subject <id>");
549
+ } else if (arg === "--store") {
550
+ // `chant workspace points ask <point> --store ledger` (#3815): where a new question goes.
551
+ const store = args[++i];
552
+ if (store !== "tree" && store !== "ledger") throw new Error("--store is tree (the answer kind's directory in the working tree) or ledger (chant/lifecycle): --store <tree|ledger>");
553
+ result.store = store;
549
554
  } else if (arg === "--answer") {
550
555
  // `chant workspace points answer <id> --answer <value>` (#2739)
551
556
  result.answer = args[++i];
@@ -1212,13 +1217,15 @@ Workspace (level 1, #2524):
1212
1217
  List the decision points the declared answer kinds'
1213
1218
  points files declare, and the questions asked of them;
1214
1219
  --open keeps the escalated and proposed ones (ws-058)
1215
- workspace points ask <point> --inputs <file|-|json> [--candidates <file|-|json>] [--response <file>] [--subject <id>] [--kind <kind file>] [--dry-run]
1220
+ workspace points ask <point> --inputs <file|-|json> [--candidates <file|-|json>] [--response <file>] [--subject <id>] [--store <tree|ledger>] [--kind <kind file>] [--dry-run]
1216
1221
  Ask a point's table, model and quorum deciders and
1217
1222
  record the answer: proposed from a model, escalated to
1218
1223
  people below its threshold. --response is a POST
1219
1224
  /v1/systemone response the caller got; chant calls no model.
1220
1225
  --candidates gives an ad-hoc point's question and
1221
- candidates, { question, criteria }
1226
+ candidates, { question, criteria }. --store ledger
1227
+ holds the question on chant/lifecycle and pushes it,
1228
+ for a checkout that does not outlive the run (CI)
1222
1229
  workspace points answer <id> --answer <value> --by <name>... [--note <text>] [--relayed-by <principal>] [--kind <kind file>] [--dry-run]
1223
1230
  Record people's answer to an open question, or confirm
1224
1231
  a model's proposal, once the point's quorum is met,
@@ -28,7 +28,11 @@
28
28
  * `clientInfo`. Computed provenance, from git, is unchanged.
29
29
  *
30
30
  * Nothing here listens on a port or authenticates anyone (ws-052): the server
31
- * speaks over stdio, and `by` is recorded as given, as `--by` is.
31
+ * speaks over stdio, and `by` is recorded as given, as `--by` is. A decision
32
+ * point's answer is the exception (#3817): `chant serve mcp` makes every call
33
+ * the model's (`lifecycle/gate-origin.ts`), so `points-answer` and
34
+ * `points-retract` count nobody `by` names toward a point's quorum, as
35
+ * `op-approve` records its approver as an agent.
32
36
  *
33
37
  * An agent session (#2548): a server started with `CHANT_AGENT` set writes in
34
38
  * that session, bound to its one member, and its writes are refused outside
@@ -289,7 +293,7 @@ export const workspaceWriteTools: ToolDefinition[] = [
289
293
  {
290
294
  name: "points-answer",
291
295
  description:
292
- "Record people's answer to an open decision point question, or confirm a model's proposal: chant workspace points answer. Refused unless the point's quorum is met: distinct people, none holding the agent role, each holding one of the quorum's roles when it names any. An answered question never changes in place: points-retract takes it back. " +
296
+ "Record people's answer to an open decision point question, or confirm a model's proposal: chant workspace points answer. Refused unless the point's quorum is met: distinct people, none holding the agent role, each holding one of the quorum's roles when it names any. On a server started with `chant serve mcp`, every call is the model's, so nobody named in by counts toward the quorum (quorum-not-met), and a question whose gate is neverOverMcp is refused outright (answer-never-over-mcp): people answer at a shell or through hud. An answered question never changes in place: points-retract takes it back. " +
293
297
  PROTOCOL,
294
298
  inputSchema: {
295
299
  type: "object",
@@ -308,7 +312,7 @@ export const workspaceWriteTools: ToolDefinition[] = [
308
312
  {
309
313
  name: "points-retract",
310
314
  description:
311
- "Take back people's answer to a decision point question: chant workspace points retract. The question is escalated to people again, and the answer, who gave it and its note stay in the record's retractions with who retracted it, when and why. Refused unless the point's quorum is met, counted as for an answer. " +
315
+ "Take back people's answer to a decision point question: chant workspace points retract. The question is escalated to people again, and the answer, who gave it and its note stay in the record's retractions with who retracted it, when and why. Refused unless the point's quorum is met, counted as for an answer, so over MCP it is refused as an answer is. " +
312
316
  PROTOCOL,
313
317
  inputSchema: {
314
318
  type: "object",
@@ -366,6 +366,8 @@ export interface ParsedArgs {
366
366
  response?: string;
367
367
  /** `chant workspace points ask <point> --subject <id>` (#2739): what the question is about. */
368
368
  subject?: string;
369
+ /** `chant workspace points ask <point> --store ledger` (#3815): hold the question on chant/lifecycle rather than in the working tree. */
370
+ store?: "tree" | "ledger";
369
371
  /** `chant workspace points answer <id> --answer <value>` (#2739): the people's answer. */
370
372
  answer?: string;
371
373
  /** `chant workspace graph --no-cache` (#2876): read every member, bypassing the per-member cache. */
@@ -84,6 +84,48 @@ describe("lifecycle/gate-audit", () => {
84
84
  expect(entries.filter((e) => e.kind === "approved")).toHaveLength(1);
85
85
  });
86
86
 
87
+ test("each ledger entry names its line: path, number and text as passed in", () => {
88
+ const text = `${pending()}\n\n${resolution()}\n`;
89
+ const { entries } = deriveGateAudit({ ledgers: [{ op: "tf-apply", path: "gates/tf.jsonl", lines: gateLedgerLines(text) }] });
90
+ expect(entries.map((e) => [e.source.path, e.source.line, e.source.text])).toEqual([
91
+ ["gates/tf.jsonl", 1, pending()],
92
+ ["gates/tf.jsonl", 3, resolution()],
93
+ ]);
94
+ const records = deriveGateAudit({ ledgers: [{ op: "tf-apply", lines: [{ record: JSON.parse(pending()) }, { record: JSON.parse(resolution()) }] }] });
95
+ expect(records.entries.map((e) => [e.source.line, e.source.text])).toEqual([[1, undefined], [2, undefined]]);
96
+ });
97
+
98
+ test("a caller's id replaces the default, and applies run under it", () => {
99
+ const ledgers = [ledger("tf-apply", pending(), resolution())];
100
+ const id = (e: { source: { path: string; text?: string }; kind: string; id: string }) => (e.source.text ? `mine:${e.source.path}:${e.source.text.length}` : e.id);
101
+ const plain = deriveGateAudit({ ledgers });
102
+ const { entries } = deriveGateAudit({ ledgers, id, applies: [{ ref: "reports/1", at: "2026-10-01T12:00:00.000Z", gate: "wave-1", digest: D1 }] });
103
+ const approved = entries.find((e) => e.kind === "approved")!;
104
+ expect(approved.id).toBe(`mine:_gates/tf-apply.jsonl:${resolution().length}`);
105
+ expect(entries.find((e) => e.kind === "applied")?.under).toBe(approved.id);
106
+ expect(plain.entries.map((e) => e.id)).not.toContain(approved.id);
107
+ });
108
+
109
+ test("an approval read from history names who committed it", () => {
110
+ const log = `\x1ec1\x1fmallory\x1f2026-10-01T11:05:00+00:00\x1fm@x.io\n\ndiff --git a/x b/x\n+${pending()}\n+${resolution()}\n`;
111
+ const lines = gateLedgerLinesFromLog(log);
112
+ expect(lines[1]).toEqual({ text: resolution(), commit: "c1", added: { at: "2026-10-01T11:05:00.000Z", by: "mallory", email: "m@x.io" } });
113
+ const { entries } = deriveGateAudit({ ledgers: [{ op: "tf-apply", lines }] });
114
+ const approved = entries.find((e) => e.kind === "approved")!;
115
+ expect(approved).toMatchObject({ by: "alex", committedBy: "mallory", source: { commit: "c1", author: { by: "mallory", email: "m@x.io", at: "2026-10-01T11:05:00.000Z" } } });
116
+ expect(entries.find((e) => e.kind === "approval-requested")?.source.author?.by).toBe("mallory");
117
+ const noEmail = gateLedgerLinesFromLog(`\x1ec2\x1fbo\x1f2026-10-01T11:05:00+00:00\n\n+${resolution()}\n`);
118
+ expect(noEmail[0]?.added).toEqual({ at: "2026-10-01T11:05:00.000Z", by: "bo" });
119
+ });
120
+
121
+ test("a sealed pull request approval is a review, with the seal beside it", () => {
122
+ const seal = { signer: "bot", signature: "-----BEGIN" };
123
+ const { entries } = deriveGateAudit({ ledgers: [ledger("tf-apply", pending(), resolution({ seal, via: "pr-review", pr: 4 }), resolution({ seal, timestamp: "2026-10-01T12:00:00.000Z" }))] });
124
+ const approved = entries.filter((e) => e.kind === "approved");
125
+ expect(approved.map((e) => [e.seal, e.sealed, e.signer])).toEqual([["review", true, "bot"], ["sealed", true, "bot"]]);
126
+ expect(approved[0]?.review).toEqual({ pr: 4 });
127
+ });
128
+
87
129
  test("applies: under an approval, without one, waived, and spending an override", () => {
88
130
  const ledgers = [ledger("tf-apply", pending(), resolution()), ledger("policy-override", resolution({ op: "policy-override", gate: "root/a", planDigest: "sha256:ov" }))];
89
131
  const ok = { ref: "reports/1", at: "2026-10-01T12:00:00.000Z", gate: "wave-1", digest: D1 };
@@ -47,6 +47,33 @@
47
47
  * - `override`: an apply cites an override that no line holds.
48
48
  * - `malformed-line`: a line that is not a gate record. Its content is lost
49
49
  * to the trail, so it is said.
50
+ *
51
+ * ## Sources and ids
52
+ *
53
+ * Every ledger entry's `source` names the line it came from: `path`, `line`
54
+ * (the line's own `line` when given, which {@link gateLedgerLines} fills
55
+ * with the file's line number, else its 1-based place in `ledger.lines`),
56
+ * and `text`, exactly as passed in, when the line was given as text. When the
57
+ * line came from {@link gateLedgerLinesFromLog}, `source.author` is the
58
+ * author of the commit that added it (or, for a revocation, removed it), and
59
+ * resolutions also carry it as `committedBy`. Under `approval: ledger` that
60
+ * is the only check on who pushed an approval: anyone who can push may write
61
+ * any `resolvedBy`.
62
+ *
63
+ * The default `id` is a digest over the source and the record. A product
64
+ * that already holds ids of its own (an append-only record whose ids
65
+ * customers keep) passes {@link GateAuditOptions.id}, which gets each entry
66
+ * with its default id and returns the id to use. `under` links follow it.
67
+ *
68
+ * ## Seal and review
69
+ *
70
+ * `seal` names how the approval came to be: `review` when the line came
71
+ * through a forge review (`via: "pr-review"`, or a `review` field), else
72
+ * `sealed` when it carries an ssh seal, else `unsigned`. A pull request
73
+ * approval that `chant approve` also sealed is still `review`: the review is
74
+ * what authorised it, and the seal attests who wrote the line. That fact is
75
+ * kept apart as `sealed: true` with its `signer`, on any entry whose line
76
+ * holds a seal. terragucci classifies the same way.
50
77
  */
51
78
  import { canonicalJson } from "../effect-receipt";
52
79
  import { contentDigest } from "../content-digest";
@@ -64,19 +91,29 @@ export const GATE_AUDIT_KINDS = [
64
91
  ] as const;
65
92
  export type GateAuditKind = (typeof GATE_AUDIT_KINDS)[number];
66
93
 
67
- /** How an approval was authenticated: an ssh seal, a forge review, or neither. */
94
+ /** How an approval was authorised: a forge review, an ssh seal, or neither. A review wins; a review that is also sealed has `sealed: true` beside it. */
68
95
  export type GateAuditSeal = "sealed" | "review" | "unsigned";
69
96
 
97
+ /** A commit that added or removed a ledger line: its date and its author's name and email. */
98
+ export interface GateLedgerCommit {
99
+ at: string;
100
+ by?: string;
101
+ email?: string;
102
+ }
103
+
70
104
  /**
71
105
  * One line of a ledger file. Give the `text` as it is on disk, or the parsed
72
- * `record` a {@link GateLedgerPort} returns. A line a commit removed carries
73
- * `removed`, with when and by whom (the commit's date and author).
106
+ * `record` a {@link GateLedgerPort} returns. `line` is its line number in the
107
+ * file, when known. A line read from history carries the commit that `added`
108
+ * it, or, if a commit removed it, `removed`, each with when and by whom.
74
109
  */
75
110
  export interface GateLedgerLine {
76
111
  text?: string;
77
112
  record?: unknown;
113
+ line?: number;
78
114
  commit?: string;
79
- removed?: { at: string; by?: string };
115
+ added?: GateLedgerCommit;
116
+ removed?: GateLedgerCommit;
80
117
  }
81
118
 
82
119
  /** One op's ledger file. */
@@ -111,7 +148,13 @@ export interface GateAuditSource {
111
148
  /** The ledger file, or the apply's `ref` for an apply. */
112
149
  path: string;
113
150
  op?: string;
151
+ /** Ledger entries: the line's `line`, else its 1-based place in the ledger's `lines`. */
152
+ line?: number;
153
+ /** Ledger entries: the line's text exactly as passed in, when it was passed as text. */
154
+ text?: string;
114
155
  commit?: string;
156
+ /** The commit that added the line, or for a revocation removed it, when the line came from history. */
157
+ author?: GateLedgerCommit;
115
158
  change: "added" | "removed" | "apply";
116
159
  }
117
160
 
@@ -127,10 +170,14 @@ export interface GateAuditEntry {
127
170
  digest?: string;
128
171
  /** Who: the approver or overrider, whoever removed the line, or for an apply, whoever ran it. */
129
172
  by?: string;
130
- /** Resolutions and revocations: sealed, reviewed, or unsigned. */
173
+ /** Resolutions and revocations: reviewed, sealed, or unsigned. */
131
174
  seal?: GateAuditSeal;
175
+ /** The line holds an ssh seal, whatever `seal` says (a sealed review is `seal: "review"`). */
176
+ sealed?: true;
132
177
  /** The ssh signer, when sealed. */
133
178
  signer?: string;
179
+ /** Resolutions read from history: the author of the commit that added the line, who may not be `by`. */
180
+ committedBy?: string;
134
181
  /** Who carried the approval to chant (`chant approve --relayed-by`). */
135
182
  relayedBy?: string;
136
183
  /** A person or an agent, and the roles claimed. */
@@ -168,6 +215,12 @@ export interface GateAuditOptions {
168
215
  isOverride?: (op: string, gate: string) => boolean;
169
216
  /** Whether approvals of a gate need a seal or a review. Default none. */
170
217
  sealed?: (op: string, gate: string) => boolean;
218
+ /**
219
+ * The id to give an entry, from the entry with its default id. Default
220
+ * that id. A product with ids of its own keys by `entry.source` (its
221
+ * `path`, `line`, `text`). `under` refers to the ids this returns.
222
+ */
223
+ id?: (entry: GateAuditEntry) => string;
171
224
  }
172
225
 
173
226
  export interface GateAuditInput extends GateAuditOptions {
@@ -205,11 +258,11 @@ function rowOf(line: GateLedgerLine): Row | undefined {
205
258
  return v && typeof v === "object" && !Array.isArray(v) ? (v as Row) : undefined;
206
259
  }
207
260
 
208
- function sealOf(r: Row): { seal: GateAuditSeal; signer?: string } {
261
+ function sealOf(r: Row): { seal: GateAuditSeal; sealed?: true; signer?: string } {
209
262
  const s = r.seal as { signature?: unknown; signer?: unknown } | null | undefined;
210
- if (s && s.signature) return { seal: "sealed", ...(str(s.signer) ? { signer: str(s.signer) } : {}) };
211
- if (r.review || r.via === "pr-review") return { seal: "review" };
212
- return { seal: "unsigned" };
263
+ const signed = s && s.signature ? { sealed: true as const, ...(str(s.signer) ? { signer: str(s.signer) } : {}) } : undefined;
264
+ if (r.review || r.via === "pr-review") return { seal: "review", ...signed };
265
+ return signed ? { seal: "sealed", ...signed } : { seal: "unsigned" };
213
266
  }
214
267
 
215
268
  function reviewOf(r: Row): GateAuditEntry["review"] {
@@ -246,13 +299,15 @@ const compatible = (a: string | undefined, b: string | undefined): boolean => a
246
299
  /** The entries `input` adds up to, oldest first, and the gaps they show. */
247
300
  export function deriveGateAudit(input: GateAuditInput): { entries: GateAuditEntry[]; gaps: GateAuditGap[] } {
248
301
  const isOverride = input.isOverride ?? isOverrideGate;
302
+ const rekey = input.id;
303
+ const keyed = (e: GateAuditEntry): GateAuditEntry => (rekey ? { ...e, id: rekey(e) } : e);
249
304
  const entries: GateAuditEntry[] = [];
250
305
  const gaps: GateAuditGap[] = [];
251
306
 
252
307
  for (const ledger of input.ledgers) {
253
308
  const path = ledger.path ?? `_gates/${ledger.op}.jsonl`;
254
- const parsed: { line: GateLedgerLine; r: Row; pending: boolean }[] = [];
255
- for (const line of ledger.lines) {
309
+ const parsed: { line: GateLedgerLine; n: number; r: Row; pending: boolean }[] = [];
310
+ for (const [i, line] of ledger.lines.entries()) {
256
311
  const r = rowOf(line);
257
312
  const pending = r?.kind === "pending";
258
313
  const ok = r && r.version === 1 && typeof r.gate === "string" && typeof r.timestamp === "string" && (pending || typeof r.resolvedBy === "string");
@@ -260,7 +315,7 @@ export function deriveGateAudit(input: GateAuditInput): { entries: GateAuditEntr
260
315
  gaps.push({ kind: "malformed-line", op: ledger.op, detail: `${path} holds a line that is not a gate record${line.commit ? ` (commit ${line.commit})` : ""}: ${(line.text ?? JSON.stringify(line.record) ?? "").slice(0, 80)}` });
261
316
  continue;
262
317
  }
263
- parsed.push({ line, r, pending });
318
+ parsed.push({ line, n: line.line ?? i + 1, r, pending });
264
319
  }
265
320
 
266
321
  // Each denial an override answers: the newest pending fact of its gate and digest.
@@ -273,53 +328,63 @@ export function deriveGateAudit(input: GateAuditInput): { entries: GateAuditEntr
273
328
  requests.push({ op: ledger.op, gate: String(p.r.gate), at: time(String(p.r.timestamp)), ...(digest ? { digest } : {}), ...(str(p.r.environment) ? { environment: str(p.r.environment) } : {}) });
274
329
  }
275
330
 
276
- for (const { line, r, pending } of parsed) {
331
+ for (const { line, n, r, pending } of parsed) {
277
332
  const gate = String(r.gate);
278
333
  const override = isOverride(ledger.op, gate);
279
334
  const removed = line.removed;
280
335
  if (pending && removed) continue;
281
336
  const digest = str(r.planDigest);
282
- const source: GateAuditSource = { path, op: ledger.op, ...(line.commit ? { commit: line.commit } : {}), change: removed ? "removed" : "added" };
337
+ const author = removed ?? line.added;
338
+ const source: GateAuditSource = {
339
+ path,
340
+ op: ledger.op,
341
+ line: n,
342
+ ...(line.text !== undefined ? { text: line.text } : {}),
343
+ ...(line.commit ? { commit: line.commit } : {}),
344
+ ...(author ? { author } : {}),
345
+ change: removed ? "removed" : "added",
346
+ };
283
347
  const id = idOf(removed ? "removed" : "ledger", path, line.commit ?? null, r);
284
348
  const extra = Object.fromEntries(Object.entries(r).filter(([k]) => !KNOWN.has(k)));
285
349
  const base = { id, gate, op: ledger.op, ...(digest ? { digest } : {}), source } as const;
286
350
 
287
351
  if (pending) {
288
- entries.push({
352
+ entries.push(keyed({
289
353
  ...base,
290
354
  kind: override ? "override-requested" : "approval-requested",
291
355
  at: String(r.timestamp),
292
356
  ...drop({ runId: str(r.runId), expiresAt: str(r.expiresAt), description: str(r.description), url: str(r.url), rules: strings(r.rules) }),
293
357
  detail: extra,
294
- });
358
+ }));
295
359
  continue;
296
360
  }
297
361
 
298
- const { seal, signer } = sealOf(r);
362
+ const { seal, sealed, signer } = sealOf(r);
299
363
  if (removed) {
300
- entries.push({
364
+ entries.push(keyed({
301
365
  ...base,
302
366
  kind: "revoked",
303
367
  at: removed.at,
304
368
  ...(removed.by ? { by: removed.by } : {}),
305
369
  subject: override ? "override" : "approval",
306
370
  seal,
371
+ ...(sealed ? { sealed } : {}),
307
372
  detail: { ...extra, approvedBy: r.resolvedBy, approvedAt: r.timestamp, ...(signer ? { signer } : {}) },
308
- });
373
+ }));
309
374
  continue;
310
375
  }
311
376
 
312
377
  const denial = override ? denials.get(`${gate}\n${digest ?? ""}`) : undefined;
313
378
  const rules = strings(denial?.rules) ?? (override && gate.startsWith("override-") ? [gate.slice("override-".length)] : undefined);
314
- const entry: GateAuditEntry = {
379
+ const entry: GateAuditEntry = keyed({
315
380
  ...base,
316
381
  kind: override ? "override-recorded" : "approved",
317
382
  at: String(r.timestamp),
318
383
  by: String(r.resolvedBy),
319
384
  seal,
320
- ...drop({ signer, relayedBy: str(r.relayedBy), approver: approverOf(r), note: str(r.note), url: str(r.url), review: reviewOf(r), rules }),
385
+ ...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 }),
321
386
  detail: extra,
322
- };
387
+ });
323
388
  entries.push(entry);
324
389
 
325
390
  if (!override) {
@@ -349,7 +414,7 @@ export function deriveGateAudit(input: GateAuditInput): { entries: GateAuditEntr
349
414
  if (a.digest !== undefined && a.approval !== "not-required" && !approval) {
350
415
  gaps.push({ kind: "approval", ...(a.op ? { op: a.op } : {}), gate: a.gate, digest: a.digest, detail: `${a.ref} applied under ${a.digest}, but the ledger holds no approval of ${a.gate} for that digest before ${a.at}` });
351
416
  }
352
- entries.push({
417
+ entries.push(keyed({
353
418
  ...base,
354
419
  id: idOf("apply", a.ref, a.at, a.gate, a.digest ?? null),
355
420
  kind: "applied",
@@ -357,7 +422,7 @@ export function deriveGateAudit(input: GateAuditInput): { entries: GateAuditEntr
357
422
  ...(a.by ? { by: a.by } : {}),
358
423
  ...(approval ? { under: approval.id } : {}),
359
424
  detail: { ...(a.detail ?? {}), approval: a.approval ?? "required" },
360
- });
425
+ }));
361
426
 
362
427
  for (const o of a.overrides ?? []) {
363
428
  const recorded = find("override-recorded", o.gate, o.digest, false);
@@ -365,7 +430,7 @@ export function deriveGateAudit(input: GateAuditInput): { entries: GateAuditEntr
365
430
  gaps.push({ kind: "override", ...(a.op ? { op: a.op } : {}), gate: o.gate, ...(o.digest ? { digest: o.digest } : {}), detail: `${a.ref} cites the override ${o.gate}${o.digest ? ` for ${o.digest}` : ""}, but the ledger holds none` });
366
431
  continue;
367
432
  }
368
- entries.push({
433
+ entries.push(keyed({
369
434
  ...base,
370
435
  id: idOf("spent", a.ref, a.at, recorded.id),
371
436
  kind: "override-spent",
@@ -375,7 +440,7 @@ export function deriveGateAudit(input: GateAuditInput): { entries: GateAuditEntr
375
440
  ...(recorded.digest ? { digest: recorded.digest } : {}),
376
441
  under: recorded.id,
377
442
  detail: {},
378
- });
443
+ }));
379
444
  }
380
445
  }
381
446
 
@@ -383,24 +448,26 @@ export function deriveGateAudit(input: GateAuditInput): { entries: GateAuditEntr
383
448
  return { entries, gaps };
384
449
  }
385
450
 
386
- /** The lines of one ledger file's text, all added. Blank lines are skipped. */
451
+ /** The lines of one ledger file's text, all added, each with its line number. Blank lines are skipped. */
387
452
  export function gateLedgerLines(content: string): GateLedgerLine[] {
388
- return content.split("\n").map((l) => l.trim()).filter(Boolean).map((text) => ({ text }));
453
+ return content.split("\n").flatMap((l, i) => (l.trim() ? [{ text: l.trim(), line: i + 1 }] : []));
389
454
  }
390
455
 
391
456
  /**
392
457
  * The lines each commit added to and removed from a ledger file, oldest first,
393
458
  * from `git log -p --unified=0 --no-renames` written with
394
- * `--format=%x1e%H%x1f%an%x1f%aI` over the file. The caller runs git; this
395
- * reads the text. A line removed and added again in one commit (a newline
396
- * fixed at the end of the file) is neither. A removed line is what
397
- * {@link deriveGateAudit} reports as a revocation.
459
+ * `--format=%x1e%H%x1f%an%x1f%aI` over the file (append `%x1f%ae` for the
460
+ * author's email). The caller runs git; this reads the text. Each line keeps
461
+ * its commit and that commit's date and author, as `added` or `removed`. A
462
+ * line removed and added again in one commit (a newline fixed at the end of
463
+ * the file) is neither. A removed line is what {@link deriveGateAudit}
464
+ * reports as a revocation.
398
465
  */
399
466
  export function gateLedgerLinesFromLog(log: string): GateLedgerLine[] {
400
467
  const out: GateLedgerLine[] = [];
401
468
  for (const block of log.split("\x1e").slice(1)) {
402
469
  const [head = "", ...rest] = block.split("\n");
403
- const [commit = "", author = "", date = ""] = head.split("\x1f");
470
+ const [commit = "", author = "", date = "", email = ""] = head.split("\x1f");
404
471
  const net = new Map<string, number>();
405
472
  const order: string[] = [];
406
473
  for (const l of rest) {
@@ -412,10 +479,11 @@ export function gateLedgerLinesFromLog(log: string): GateLedgerLine[] {
412
479
  }
413
480
  const when = Date.parse(date.trim());
414
481
  const at = Number.isNaN(when) ? date.trim() : new Date(when).toISOString();
482
+ const by: GateLedgerCommit = { at, ...(author ? { by: author } : {}), ...(email.trim() ? { email: email.trim() } : {}) };
415
483
  for (const text of order) {
416
484
  const n = net.get(text)!;
417
485
  for (let i = 0; i < Math.abs(n); i++) {
418
- out.push(n > 0 ? { text, commit: commit.trim() } : { text, commit: commit.trim(), removed: { at, ...(author ? { by: author } : {}) } });
486
+ out.push({ text, commit: commit.trim(), ...(n > 0 ? { added: { ...by } } : { removed: { ...by } }) });
419
487
  }
420
488
  }
421
489
  }