@intentius/chant-lexicon-cedar 0.44.9 → 0.44.12

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 (70) hide show
  1. package/README.md +48 -2
  2. package/dist/agentcore/embed.d.ts +189 -0
  3. package/dist/agentcore/embed.d.ts.map +1 -0
  4. package/dist/agentcore/enforcement.d.ts +76 -0
  5. package/dist/agentcore/enforcement.d.ts.map +1 -0
  6. package/dist/agentcore/scan.d.ts +46 -0
  7. package/dist/agentcore/scan.d.ts.map +1 -0
  8. package/dist/avp/client.d.ts +85 -8
  9. package/dist/avp/client.d.ts.map +1 -1
  10. package/dist/codegen/docs-dogwood.d.ts +21 -0
  11. package/dist/codegen/docs-dogwood.d.ts.map +1 -0
  12. package/dist/codegen/docs.d.ts.map +1 -1
  13. package/dist/dogwood/cli.d.ts +41 -0
  14. package/dist/dogwood/cli.d.ts.map +1 -1
  15. package/dist/dogwood/index.d.ts +10 -4
  16. package/dist/dogwood/index.d.ts.map +1 -1
  17. package/dist/dogwood/replay-activity.d.ts +196 -0
  18. package/dist/dogwood/replay-activity.d.ts.map +1 -0
  19. package/dist/dogwood/replay-op.d.ts +165 -0
  20. package/dist/dogwood/replay-op.d.ts.map +1 -0
  21. package/dist/dogwood/serialize.d.ts +20 -0
  22. package/dist/dogwood/serialize.d.ts.map +1 -1
  23. package/dist/dogwood/trace.d.ts +215 -0
  24. package/dist/dogwood/trace.d.ts.map +1 -0
  25. package/dist/index.d.ts +8 -0
  26. package/dist/index.d.ts.map +1 -1
  27. package/dist/integrity.json +5 -3
  28. package/dist/lint/audit-catalog.d.ts.map +1 -1
  29. package/dist/lint/post-synth/dwdc013.d.ts +33 -0
  30. package/dist/lint/post-synth/dwdc013.d.ts.map +1 -0
  31. package/dist/lint/post-synth/index.d.ts.map +1 -1
  32. package/dist/manifest.json +1 -1
  33. package/dist/okf/index.md +1 -0
  34. package/dist/okf/rules/DWDC013.md +15 -0
  35. package/dist/okf/types/Policy.md +1 -0
  36. package/dist/op/activities/index.d.ts +18 -0
  37. package/dist/op/activities/index.d.ts.map +1 -0
  38. package/dist/plugin.d.ts.map +1 -1
  39. package/dist/rules/dwdc013.ts +64 -0
  40. package/dist/skills/chant-cedar-dogwood.md +327 -0
  41. package/package.json +7 -2
  42. package/src/agentcore/embed.test.ts +254 -0
  43. package/src/agentcore/embed.ts +399 -0
  44. package/src/agentcore/enforcement.test.ts +43 -0
  45. package/src/agentcore/enforcement.ts +92 -0
  46. package/src/agentcore/scan.ts +119 -0
  47. package/src/avp/OWNERSHIP.md +38 -0
  48. package/src/avp/client.test.ts +271 -0
  49. package/src/avp/client.ts +150 -16
  50. package/src/codegen/docs-dogwood.ts +1119 -0
  51. package/src/codegen/docs.ts +66 -1
  52. package/src/dogwood/cli.test.ts +122 -1
  53. package/src/dogwood/cli.ts +122 -1
  54. package/src/dogwood/index.ts +74 -1
  55. package/src/dogwood/replay-activity.test.ts +481 -0
  56. package/src/dogwood/replay-activity.ts +506 -0
  57. package/src/dogwood/replay-op.ts +242 -0
  58. package/src/dogwood/serialize.ts +37 -0
  59. package/src/dogwood/trace.test.ts +231 -0
  60. package/src/dogwood/trace.ts +471 -0
  61. package/src/index.ts +52 -0
  62. package/src/lint/audit-catalog.ts +8 -0
  63. package/src/lint/post-synth/dwd-post-synth.test.ts +119 -1
  64. package/src/lint/post-synth/dwdc013.ts +64 -0
  65. package/src/lint/post-synth/dwde-post-synth.test.ts +1 -1
  66. package/src/lint/post-synth/index.ts +2 -0
  67. package/src/op/activities/index.ts +27 -0
  68. package/src/plugin.test.ts +3 -2
  69. package/src/plugin.ts +30 -0
  70. package/src/skills/chant-cedar-dogwood.md +327 -0
@@ -21,6 +21,13 @@
21
21
  import { dirname, join } from "path";
22
22
  import { fileURLToPath } from "url";
23
23
  import { docsPipeline, writeDocsSite, type DocsConfig } from "@intentius/chant/codegen/docs";
24
+ import {
25
+ dogwoodEventSchemas,
26
+ dogwoodOverview,
27
+ dogwoodReplay,
28
+ dogwoodTemporalPolicies,
29
+ dogwoodValidation,
30
+ } from "./docs-dogwood";
24
31
 
25
32
  const pkgDir = dirname(dirname(dirname(fileURLToPath(import.meta.url))));
26
33
 
@@ -67,7 +74,14 @@ any evaluator with chant nowhere in sight.
67
74
  There is no \`cedarGate()\` and there will not be one.
68
75
  [Organizational policy](/chant/guide/organizational-policy/) in chant is
69
76
  TypeScript post-synth checks; a second policy engine would duplicate the lint
70
- engine. chant compiles *to* Cedar; it is not governed *by* Cedar.`;
77
+ engine. chant compiles *to* Cedar; it is not governed *by* Cedar.
78
+
79
+ ## The dogwood dialect
80
+
81
+ Cedar with temporal operators, shipping inside this lexicon as a pre-release
82
+ surface under the \`DWD\` id family: a policy that can depend on what already
83
+ happened in a session. Start at [The Dogwood Dialect](./dogwood), which is
84
+ honest about upstream's governance before it shows you a builder.`;
71
85
 
72
86
  // ── getting-started ───────────────────────────────────────────────
73
87
 
@@ -858,6 +872,57 @@ export async function generateDocs(options?: { verbose?: boolean }): Promise<voi
858
872
  description: "The AVP statement seam, and the other Cedar evaluators.",
859
873
  content: avpPage,
860
874
  },
875
+ // The dogwood dialect (#1662). `sidebar: false` on each, because these
876
+ // five belong under one group rather than flat after the cedar pages —
877
+ // the group is declared in `sidebarExtra` below, and `buildSidebar`
878
+ // would otherwise list them twice.
879
+ {
880
+ slug: "dogwood",
881
+ title: "The Dogwood Dialect",
882
+ description: "Cedar with temporal operators — what ships, and what pre-release means here.",
883
+ content: dogwoodOverview,
884
+ sidebar: false,
885
+ },
886
+ {
887
+ slug: "dogwood-temporal-policies",
888
+ title: "Temporal Policies",
889
+ description: "The typed builders, the parser primitives, and which operators are really macros.",
890
+ content: dogwoodTemporalPolicies,
891
+ sidebar: false,
892
+ },
893
+ {
894
+ slug: "dogwood-event-schemas",
895
+ title: "Event Schemas",
896
+ description: "The .dwschema surface, the callerPrincipal pin, and what opting out of it widens.",
897
+ content: dogwoodEventSchemas,
898
+ sidebar: false,
899
+ },
900
+ {
901
+ slug: "dogwood-validation",
902
+ title: "Dogwood Validation",
903
+ description: "The DWD walls that always run, and the CLI-gated checks that need the binary.",
904
+ content: dogwoodValidation,
905
+ sidebar: false,
906
+ },
907
+ {
908
+ slug: "dogwood-replay",
909
+ title: "Replay",
910
+ description: "Typed traces, PolicyReplayOp, and the both-bags trap that makes half a trace pass.",
911
+ content: dogwoodReplay,
912
+ sidebar: false,
913
+ },
914
+ ],
915
+ sidebarExtra: [
916
+ {
917
+ label: "Dogwood",
918
+ items: [
919
+ { label: "The Dialect", slug: "dogwood" },
920
+ { label: "Temporal Policies", slug: "dogwood-temporal-policies" },
921
+ { label: "Event Schemas", slug: "dogwood-event-schemas" },
922
+ { label: "Validation", slug: "dogwood-validation" },
923
+ { label: "Replay", slug: "dogwood-replay" },
924
+ ],
925
+ },
861
926
  ],
862
927
  };
863
928
 
@@ -10,7 +10,7 @@
10
10
  * sync.
11
11
  */
12
12
  import { describe, test, expect, afterEach } from "vitest";
13
- import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "fs";
13
+ import { existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "fs";
14
14
  import { tmpdir } from "os";
15
15
  import { join } from "path";
16
16
  import { fileURLToPath } from "url";
@@ -20,9 +20,11 @@ import {
20
20
  findDogwoodBinary,
21
21
  formatDogwoodDiagnostic,
22
22
  parseLowerOutput,
23
+ parseReplayOutput,
23
24
  parseValidateOutput,
24
25
  resetDogwoodCli,
25
26
  runDogwoodLower,
27
+ runDogwoodReplay,
26
28
  runDogwoodValidate,
27
29
  type DogwoodRun,
28
30
  type DogwoodRunner,
@@ -261,6 +263,125 @@ describe("parseLowerOutput", () => {
261
263
  });
262
264
  });
263
265
 
266
+ // ── replay ─────────────────────────────────────────────────────────
267
+
268
+ describe("parseReplayOutput", () => {
269
+ /** The stream #1657 recorded for `read_after_login`, exit 0. */
270
+ const RECORDED = {
271
+ verdicts: [
272
+ { index: 0, timestamp: 0, verdict: "deny", determining_rules: [], errors: [] },
273
+ { index: 1, timestamp: 10, verdict: "allow", determining_rules: [0], errors: [] },
274
+ { index: 2, timestamp: 7200, verdict: "deny", determining_rules: [], errors: [] },
275
+ ],
276
+ };
277
+
278
+ test("reads the verdict stream, rules included", () => {
279
+ const result = parseReplayOutput(json(RECORDED));
280
+ expect(result.kind).toBe("replayed");
281
+ if (result.kind !== "replayed") return;
282
+ expect(result.verdicts).toHaveLength(3);
283
+ expect(result.verdicts[1]).toEqual({
284
+ index: 1,
285
+ timestamp: 10,
286
+ verdict: "allow",
287
+ determiningRules: [0],
288
+ errors: [],
289
+ });
290
+ });
291
+
292
+ test("every verdict DENY at exit 0 is a result, not a failure", () => {
293
+ // The sharpest edge in the replay contract: a nonzero exit means the trace
294
+ // or the policy set failed to load, never that a policy denied.
295
+ const allDeny = { verdicts: RECORDED.verdicts.map((v) => ({ ...v, verdict: "deny" })) };
296
+ const result = parseReplayOutput(json(allDeny));
297
+ expect(result.kind).toBe("replayed");
298
+ });
299
+
300
+ test("an unrecognised verdict reads as a deny rather than being dropped", () => {
301
+ // Dropping it would shift every later index; treating it as a permit would
302
+ // be a permission upstream never granted.
303
+ const result = parseReplayOutput(json({ verdicts: [{ index: 0, timestamp: 0, verdict: "maybe" }] }));
304
+ expect(result.kind).toBe("replayed");
305
+ if (result.kind !== "replayed") return;
306
+ expect(result.verdicts[0].verdict).toBe("deny");
307
+ });
308
+
309
+ test("a malformed trace line comes back through the fatal channel", () => {
310
+ const result = parseReplayOutput(
311
+ json({ severity: "error", message: "trace parse: line 1: timepoint must start with `@`", spanned: false }, 2),
312
+ );
313
+ expect(result.kind).toBe("fatal");
314
+ if (result.kind !== "fatal") return;
315
+ expect(result.error.message).toMatch(/timepoint must start with/);
316
+ });
317
+
318
+ test("no JSON at all is unusable, never a verdict", () => {
319
+ const result = parseReplayOutput(run({ status: 2, stderr: "error: unexpected argument '--nope'" }));
320
+ expect(result.kind).toBe("unusable");
321
+ });
322
+
323
+ test("per-evaluation errors are carried through in either shape", () => {
324
+ const result = parseReplayOutput(
325
+ json({
326
+ verdicts: [
327
+ { index: 0, timestamp: 0, verdict: "deny", determining_rules: [], errors: ["no script"] },
328
+ {
329
+ index: 1,
330
+ timestamp: 1,
331
+ verdict: "deny",
332
+ determining_rules: [],
333
+ errors: [{ message: "provider failed at line 1 column 4" }],
334
+ },
335
+ ],
336
+ }),
337
+ );
338
+ expect(result.kind).toBe("replayed");
339
+ if (result.kind !== "replayed") return;
340
+ expect(result.verdicts[0].errors).toEqual(["no script"]);
341
+ // The internal position is scrubbed for the same reason as everywhere else.
342
+ expect(result.verdicts[1].errors).toEqual(["provider failed"]);
343
+ });
344
+ });
345
+
346
+ describe("runDogwoodReplay", () => {
347
+ test("passes the trace as --trace beside the bundle, and asks for JSON", () => {
348
+ let seen: { args: string[]; trace: string } | undefined;
349
+ const runner: DogwoodRunner = (_binary, args) => {
350
+ const at = args.indexOf("--trace");
351
+ seen = { args, trace: readFileSync(args[at + 1], "utf-8") };
352
+ return run({ status: 0, stdout: JSON.stringify({ verdicts: [] }) });
353
+ };
354
+ configureDogwoodCli({ runner });
355
+
356
+ const result = runDogwoodReplay("/bin/dogwood", { policies: "p", policySchema: "s" }, "@0 A::Action::\"B\"::request()");
357
+ expect(result.kind).toBe("replayed");
358
+ expect(seen?.args[0]).toBe("replay");
359
+ expect(seen?.args.slice(-2)).toEqual(["--format", "json"]);
360
+ expect(seen?.trace).toBe('@0 A::Action::"B"::request()');
361
+ });
362
+
363
+ test("the scratch directory, trace included, does not outlive the run", () => {
364
+ let tracePath = "";
365
+ const runner: DogwoodRunner = (_binary, args) => {
366
+ tracePath = args[args.indexOf("--trace") + 1];
367
+ return run({ status: 0, stdout: JSON.stringify({ verdicts: [] }) });
368
+ };
369
+ configureDogwoodCli({ runner });
370
+ runDogwoodReplay("/bin/dogwood", { policies: "p", policySchema: "s" }, "@0 A::Action::\"B\"::request()");
371
+ expect(existsSync(tracePath)).toBe(false);
372
+ });
373
+
374
+ test("a throwing runner is an unusable run, not an exception", () => {
375
+ configureDogwoodCli({
376
+ runner: () => {
377
+ throw new Error("spawn blew up");
378
+ },
379
+ });
380
+ const result = runDogwoodReplay("/bin/dogwood", { policies: "p", policySchema: "s" }, "@0 x");
381
+ expect(result.kind).toBe("unusable");
382
+ });
383
+ });
384
+
264
385
  // ── Invocation ─────────────────────────────────────────────────────
265
386
 
266
387
  describe("the invocation itself", () => {
@@ -347,6 +347,29 @@ export interface DogwoodLowered {
347
347
 
348
348
  export type DogwoodLowerResult = { kind: "lowered"; value: DogwoodLowered } | DogwoodFatal | DogwoodUnusable;
349
349
 
350
+ /**
351
+ * One decision point out of `replay --format json`.
352
+ *
353
+ * `index` is the 0-based position in the *decision* stream, not the trace line
354
+ * number: a history-only event (any kind the event schema does not mark
355
+ * `decision`) contributes history and no verdict, so the two do not line up.
356
+ */
357
+ export interface DogwoodVerdict {
358
+ index: number;
359
+ /** The `@<timestamp>` of the line that produced this decision. */
360
+ timestamp: number;
361
+ verdict: "allow" | "deny";
362
+ /** `.dw` rule indices that determined the decision — upstream's `[rules: 0, 2]`. */
363
+ determiningRules: number[];
364
+ /** Per-evaluation errors, such as a provider with no inlined Rhai script. */
365
+ errors: string[];
366
+ }
367
+
368
+ export type DogwoodReplayResult =
369
+ | { kind: "replayed"; verdicts: DogwoodVerdict[] }
370
+ | DogwoodFatal
371
+ | DogwoodUnusable;
372
+
350
373
  function unusable(reason: string): DogwoodUnusable {
351
374
  return { kind: "unusable", reason };
352
375
  }
@@ -430,6 +453,69 @@ export function parseLowerOutput(run: DogwoodRun): DogwoodLowerResult {
430
453
  return unusable("`dogwood lower --format json` returned JSON in neither the artifact nor the error shape");
431
454
  }
432
455
 
456
+ /**
457
+ * Read a `replay --format json` run.
458
+ *
459
+ * The one place the exit-code discipline matters most: **replay exits 0 even
460
+ * when every verdict is DENY.** A nonzero exit means the trace or the policy
461
+ * set failed to load, never that a policy denied — so a caller that read the
462
+ * exit code as a verdict would report a working deny-by-default policy set as
463
+ * a broken one. As everywhere else in this module, the JSON decides: a body
464
+ * carrying `verdicts` is the report, a body carrying `message` is the fatal
465
+ * `OpError` (a malformed trace line lands here), anything else is unusable.
466
+ */
467
+ export function parseReplayOutput(run: DogwoodRun): DogwoodReplayResult {
468
+ if (run.error) return unusable(`the dogwood binary could not be run: ${run.error}`);
469
+
470
+ const parsed = readJson(run.stdout);
471
+ if (!parsed) {
472
+ return unusable(
473
+ `\`dogwood replay --format json\` exited ${String(run.status)} without JSON on stdout${streamNote(run)}`,
474
+ );
475
+ }
476
+
477
+ if (Array.isArray(parsed.verdicts)) {
478
+ return { kind: "replayed", verdicts: parseVerdicts(parsed.verdicts) };
479
+ }
480
+
481
+ const fatal = fatalFrom(parsed);
482
+ if (fatal) return fatal;
483
+
484
+ return unusable("`dogwood replay --format json` returned JSON in neither the verdict nor the error shape");
485
+ }
486
+
487
+ function parseVerdicts(value: unknown[]): DogwoodVerdict[] {
488
+ const out: DogwoodVerdict[] = [];
489
+ value.forEach((raw, position) => {
490
+ if (!isRecord(raw)) return;
491
+ // `allow`/`deny` lowercase, as upstream serializes the enum. Anything else
492
+ // is read as a deny rather than dropped: an unrecognised verdict is not a
493
+ // permission, and dropping the entry would shift every later index.
494
+ const verdict = raw.verdict === "allow" ? "allow" : "deny";
495
+ out.push({
496
+ index: typeof raw.index === "number" ? raw.index : position,
497
+ timestamp: typeof raw.timestamp === "number" ? raw.timestamp : 0,
498
+ verdict,
499
+ determiningRules: Array.isArray(raw.determining_rules)
500
+ ? raw.determining_rules.filter((r): r is number => typeof r === "number")
501
+ : [],
502
+ errors: errorList(raw.errors),
503
+ });
504
+ });
505
+ return out;
506
+ }
507
+
508
+ /** Per-evaluation errors, tolerating both a string list and a diagnostic list. */
509
+ function errorList(value: unknown): string[] {
510
+ if (!Array.isArray(value)) return [];
511
+ const out: string[] = [];
512
+ for (const entry of value) {
513
+ if (typeof entry === "string") out.push(entry);
514
+ else if (isRecord(entry) && typeof entry.message === "string") out.push(scrubPosition(entry.message));
515
+ }
516
+ return out;
517
+ }
518
+
433
519
  function stringList(value: unknown): string[] {
434
520
  return Array.isArray(value) ? value.filter((v): v is string => typeof v === "string") : [];
435
521
  }
@@ -481,6 +567,13 @@ const defaultRunner: DogwoodRunner = (binary, args) => {
481
567
  };
482
568
  };
483
569
 
570
+ /** An extra file+flag pair a subcommand needs — `replay`'s `--trace`, today. */
571
+ interface ExtraInput {
572
+ flag: string;
573
+ filename: string;
574
+ content: string;
575
+ }
576
+
484
577
  /**
485
578
  * Materialize a bundle into a scratch directory and run one subcommand.
486
579
  *
@@ -488,7 +581,12 @@ const defaultRunner: DogwoodRunner = (binary, args) => {
488
581
  * schema flags all take paths. The directory is removed in a `finally`, so a
489
582
  * throwing runner does not leave one behind.
490
583
  */
491
- function runBundle(binary: string, subcommand: string, bundle: DogwoodBundle): DogwoodRun {
584
+ function runBundle(
585
+ binary: string,
586
+ subcommand: string,
587
+ bundle: DogwoodBundle,
588
+ extras: ExtraInput[] = [],
589
+ ): DogwoodRun {
492
590
  const runner = defaults.runner ?? defaultRunner;
493
591
  const dir = mkdtempSync(join(tmpdir(), "chant-dogwood-"));
494
592
  try {
@@ -515,6 +613,12 @@ function runBundle(binary: string, subcommand: string, bundle: DogwoodBundle): D
515
613
  args.push("--providers", path);
516
614
  }
517
615
 
616
+ for (const extra of extras) {
617
+ const path = join(dir, extra.filename);
618
+ writeFileSync(path, extra.content, "utf-8");
619
+ args.push(extra.flag, path);
620
+ }
621
+
518
622
  // No `--emit`: it is ignored under `--format json`, which returns all three
519
623
  // lowered artifacts regardless. Passing it would imply a choice that the
520
624
  // CLI does not honour.
@@ -543,3 +647,20 @@ export function runDogwoodLower(binary: string, bundle: DogwoodBundle): DogwoodL
543
647
  return unusable(`the dogwood lower run failed: ${err instanceof Error ? err.message : String(err)}`);
544
648
  }
545
649
  }
650
+
651
+ /**
652
+ * Run `dogwood replay` over a bundle and a trace. Never throws.
653
+ *
654
+ * The trace is materialized beside the bundle's own files and passed as
655
+ * `--trace`; the same scratch directory is removed in the same `finally`, so a
656
+ * trace carrying a session's request payloads does not outlive the run.
657
+ */
658
+ export function runDogwoodReplay(binary: string, bundle: DogwoodBundle, trace: string): DogwoodReplayResult {
659
+ try {
660
+ return parseReplayOutput(
661
+ runBundle(binary, "replay", bundle, [{ flag: "--trace", filename: "trace.log", content: trace }]),
662
+ );
663
+ } catch (err) {
664
+ return unusable(`the dogwood replay run failed: ${err instanceof Error ? err.message : String(err)}`);
665
+ }
666
+ }
@@ -149,10 +149,11 @@ export type { EventSchemaProps, MacroLibraryProps, TemporalPolicyProps } from ".
149
149
  export {
150
150
  DOGWOOD_EVENT_SCHEMA_SUFFIX,
151
151
  DOGWOOD_POLICY_SUFFIX,
152
+ dogwoodPolicyRecords,
152
153
  renderTemporalPolicyText,
153
154
  serializeDogwood,
154
155
  } from "./serialize";
155
- export type { DogwoodSerializeResult } from "./serialize";
156
+ export type { DogwoodPolicyRecord, DogwoodSerializeResult } from "./serialize";
156
157
 
157
158
  export {
158
159
  blankComments,
@@ -177,9 +178,11 @@ export {
177
178
  findDogwoodBinary,
178
179
  formatDogwoodDiagnostic,
179
180
  parseLowerOutput,
181
+ parseReplayOutput,
180
182
  parseValidateOutput,
181
183
  resetDogwoodCli,
182
184
  runDogwoodLower,
185
+ runDogwoodReplay,
183
186
  runDogwoodValidate,
184
187
  } from "./cli";
185
188
  export type {
@@ -191,8 +194,78 @@ export type {
191
194
  DogwoodLabel,
192
195
  DogwoodLowerResult,
193
196
  DogwoodLowered,
197
+ DogwoodReplayResult,
194
198
  DogwoodRun,
195
199
  DogwoodRunner,
196
200
  DogwoodUnusable,
197
201
  DogwoodValidateResult,
202
+ DogwoodVerdict,
198
203
  } from "./cli";
204
+
205
+ // Replay traces (#1661) — typed construction of the §6 line grammar, with
206
+ // both-bag population as the default and the weakening as an opt-out.
207
+ export {
208
+ auditTrace,
209
+ decimalValue,
210
+ entityRef,
211
+ rawValue,
212
+ renderTrace,
213
+ renderTraceFields,
214
+ renderTraceLine,
215
+ renderTraceValue,
216
+ traceEntity,
217
+ traceEvent,
218
+ traceFixture,
219
+ } from "./trace";
220
+ export type {
221
+ TraceAuditOptions,
222
+ TraceBags,
223
+ TraceDecimal,
224
+ TraceEntityDecl,
225
+ TraceEntityRef,
226
+ TraceEvent,
227
+ TraceEventInput,
228
+ TraceFields,
229
+ TraceFixture,
230
+ TraceFixtureOptions,
231
+ TraceIssue,
232
+ TraceIssueKind,
233
+ TraceRaw,
234
+ TraceScope,
235
+ TraceTagged,
236
+ TraceValue,
237
+ } from "./trace";
238
+
239
+ // The replay activities (#1661). Contributed by name through
240
+ // `src/op/activities/index.ts`; the helpers are here for direct use.
241
+ export {
242
+ compareVerdicts,
243
+ dogwoodReplay,
244
+ dogwoodReplayReport,
245
+ renderReplaySummary,
246
+ resolveReplayInputs,
247
+ } from "./replay-activity";
248
+ export type {
249
+ DogwoodReplayArgs,
250
+ DogwoodReplayReportArgs,
251
+ ExpectedVerdict,
252
+ PolicyReplayDispatch,
253
+ PolicyReplayMode,
254
+ PolicyReplayReport,
255
+ ReplayDivergence,
256
+ ReplayExpectation,
257
+ } from "./replay-activity";
258
+
259
+ // The PolicyReplayOp composite and its typed step builders (#1661).
260
+ export {
261
+ DEFAULT_REPLAY_REPORT_PATH,
262
+ PolicyReplayOp,
263
+ dogwoodReplayReportStep,
264
+ dogwoodReplayStep,
265
+ } from "./replay-op";
266
+ export type {
267
+ DogwoodReplayReportStepOpts,
268
+ DogwoodReplayStepOpts,
269
+ PolicyReplayOpConfig,
270
+ PolicyReplayOpResources,
271
+ } from "./replay-op";