ushman-ledger 0.3.0 → 1.1.0

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 (44) hide show
  1. package/CHANGELOG.md +4 -14
  2. package/README.md +8 -56
  3. package/dist/archive-journal.d.ts +29 -18
  4. package/dist/archive-journal.d.ts.map +1 -1
  5. package/dist/archive-journal.js +17 -17
  6. package/dist/builders.d.ts +52 -374
  7. package/dist/builders.d.ts.map +1 -1
  8. package/dist/builders.js +10 -60
  9. package/dist/cli.d.ts.map +1 -1
  10. package/dist/cli.js +8 -14
  11. package/dist/handle.d.ts +2 -2
  12. package/dist/handle.d.ts.map +1 -1
  13. package/dist/handle.js +1 -14
  14. package/dist/index.d.ts +3 -5
  15. package/dist/index.d.ts.map +1 -1
  16. package/dist/index.js +2 -4
  17. package/dist/lab-min.d.ts +7 -7
  18. package/dist/lab-min.d.ts.map +1 -1
  19. package/dist/lab-min.js +7 -9
  20. package/dist/list.d.ts +84 -325
  21. package/dist/list.d.ts.map +1 -1
  22. package/dist/read-index.d.ts +45 -57
  23. package/dist/read-index.d.ts.map +1 -1
  24. package/dist/read-index.js +16 -34
  25. package/dist/record.d.ts.map +1 -1
  26. package/dist/record.js +27 -114
  27. package/dist/recovery.d.ts +19 -8
  28. package/dist/recovery.d.ts.map +1 -1
  29. package/dist/recovery.js +13 -13
  30. package/dist/render/retro.d.ts.map +1 -1
  31. package/dist/render/retro.js +1 -4
  32. package/dist/schema/entry.d.ts +1365 -3291
  33. package/dist/schema/entry.d.ts.map +1 -1
  34. package/dist/schema/entry.js +184 -516
  35. package/dist/schema/manifest.d.ts +28 -41
  36. package/dist/schema/manifest.d.ts.map +1 -1
  37. package/dist/schema/manifest.js +20 -24
  38. package/dist/schema/note.d.ts +3 -9
  39. package/dist/schema/note.d.ts.map +1 -1
  40. package/dist/schema/note.js +2 -2
  41. package/dist/storage/filesystem.d.ts +0 -1
  42. package/dist/storage/filesystem.d.ts.map +1 -1
  43. package/dist/storage/filesystem.js +4 -4
  44. package/package.json +3 -4
@@ -1,59 +1,47 @@
1
- import { z } from 'zod';
1
+ import * as v from 'valibot';
2
2
  import { type LedgerEntry, type LedgerKind, type LedgerPhase } from './schema/entry.ts';
3
3
  import type { LedgerManifest } from './schema/manifest.ts';
4
- declare const ReadIndexEntrySchema: z.ZodObject<{
5
- id: z.ZodString;
6
- kind: z.ZodEnum<{
7
- "tool-invocation": "tool-invocation";
8
- "agent-patch": "agent-patch";
9
- "operator-patch": "operator-patch";
10
- "stage-transition": "stage-transition";
11
- "operator-decision": "operator-decision";
12
- "validator-result": "validator-result";
13
- "runtime-event": "runtime-event";
14
- note: "note";
15
- correction: "correction";
16
- "strip-decision-reverted": "strip-decision-reverted";
17
- "descope-brief": "descope-brief";
18
- "merge-return": "merge-return";
19
- "merge-return-rejected": "merge-return-rejected";
20
- revert: "revert";
21
- rollback: "rollback";
22
- "rework.test_retired": "rework.test_retired";
23
- }>;
24
- ts: z.ZodString;
25
- }, z.core.$strip>;
26
- declare const LedgerReadIndexSchema: z.ZodObject<{
27
- coveredFiles: z.ZodDefault<z.ZodArray<z.ZodString>>;
28
- entries: z.ZodDefault<z.ZodArray<z.ZodObject<{
29
- id: z.ZodString;
30
- kind: z.ZodEnum<{
31
- "tool-invocation": "tool-invocation";
32
- "agent-patch": "agent-patch";
33
- "operator-patch": "operator-patch";
34
- "stage-transition": "stage-transition";
35
- "operator-decision": "operator-decision";
36
- "validator-result": "validator-result";
37
- "runtime-event": "runtime-event";
38
- note: "note";
39
- correction: "correction";
40
- "strip-decision-reverted": "strip-decision-reverted";
41
- "descope-brief": "descope-brief";
42
- "merge-return": "merge-return";
43
- "merge-return-rejected": "merge-return-rejected";
44
- revert: "revert";
45
- rollback: "rollback";
46
- "rework.test_retired": "rework.test_retired";
47
- }>;
48
- ts: z.ZodString;
49
- }, z.core.$strip>>>;
50
- entryCount: z.ZodNumber;
51
- lastEntryId: z.ZodNullable<z.ZodString>;
52
- lastSequence: z.ZodNumber;
53
- schemaVersion: z.ZodLiteral<"ushman-ledger-read-index/v1">;
54
- }, z.core.$strip>;
55
- export type LedgerReadIndex = z.infer<typeof LedgerReadIndexSchema>;
56
- export type ReadIndexEntry = z.infer<typeof ReadIndexEntrySchema>;
4
+ declare const ReadIndexEntrySchema: v.ObjectSchema<{
5
+ readonly id: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, undefined>]>;
6
+ readonly kind: v.PicklistSchema<readonly ["tool-invocation", "agent-patch", "operator-patch", "operator-decision", "validator-result", "runtime-event", "note", "correction", "strip-decision-reverted"], undefined>;
7
+ readonly ts: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.IsoTimestampAction<string, undefined>]>;
8
+ }, undefined>;
9
+ declare const LedgerReadIndexSchema: v.SchemaWithPipe<readonly [v.ObjectSchema<{
10
+ readonly coveredFiles: v.OptionalSchema<v.ArraySchema<v.StringSchema<undefined>, undefined>, readonly []>;
11
+ readonly entries: v.OptionalSchema<v.ArraySchema<v.ObjectSchema<{
12
+ readonly id: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, undefined>]>;
13
+ readonly kind: v.PicklistSchema<readonly ["tool-invocation", "agent-patch", "operator-patch", "operator-decision", "validator-result", "runtime-event", "note", "correction", "strip-decision-reverted"], undefined>;
14
+ readonly ts: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.IsoTimestampAction<string, undefined>]>;
15
+ }, undefined>, undefined>, readonly []>;
16
+ readonly entryCount: v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 0, undefined>]>;
17
+ readonly lastEntryId: v.NullableSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, undefined>]>, undefined>;
18
+ readonly lastSequence: v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>, v.MinValueAction<number, 0, undefined>]>;
19
+ readonly schemaVersion: v.LiteralSchema<"ushman-ledger-read-index/v1", undefined>;
20
+ }, undefined>, v.CheckAction<{
21
+ coveredFiles: string[];
22
+ entries: {
23
+ id: string;
24
+ kind: "tool-invocation" | "agent-patch" | "operator-patch" | "operator-decision" | "validator-result" | "runtime-event" | "note" | "correction" | "strip-decision-reverted";
25
+ ts: string;
26
+ }[];
27
+ entryCount: number;
28
+ lastEntryId: string | null;
29
+ lastSequence: number;
30
+ schemaVersion: "ushman-ledger-read-index/v1";
31
+ }, "entryCount must match entries.length">, v.CheckAction<{
32
+ coveredFiles: string[];
33
+ entries: {
34
+ id: string;
35
+ kind: "tool-invocation" | "agent-patch" | "operator-patch" | "operator-decision" | "validator-result" | "runtime-event" | "note" | "correction" | "strip-decision-reverted";
36
+ ts: string;
37
+ }[];
38
+ entryCount: number;
39
+ lastEntryId: string | null;
40
+ lastSequence: number;
41
+ schemaVersion: "ushman-ledger-read-index/v1";
42
+ }, "lastEntryId must match the final indexed entry">]>;
43
+ export type LedgerReadIndex = v.InferOutput<typeof LedgerReadIndexSchema>;
44
+ export type ReadIndexEntry = v.InferOutput<typeof ReadIndexEntrySchema>;
57
45
  export type ManifestEntryLocation = readonly [string, {
58
46
  phase: LedgerPhase;
59
47
  sequence: number;
@@ -62,7 +50,7 @@ export declare const buildReadIndexFromManifest: (workspaceRoot: string, manifes
62
50
  coveredFiles: string[];
63
51
  entries: {
64
52
  id: string;
65
- kind: "tool-invocation" | "agent-patch" | "operator-patch" | "stage-transition" | "operator-decision" | "validator-result" | "runtime-event" | "note" | "correction" | "strip-decision-reverted" | "descope-brief" | "merge-return" | "merge-return-rejected" | "revert" | "rollback" | "rework.test_retired";
53
+ kind: "tool-invocation" | "agent-patch" | "operator-patch" | "operator-decision" | "validator-result" | "runtime-event" | "note" | "correction" | "strip-decision-reverted";
66
54
  ts: string;
67
55
  }[];
68
56
  entryCount: number;
@@ -77,7 +65,7 @@ export declare const ensureReadIndexUnderLock: (workspaceRoot: string, manifest:
77
65
  coveredFiles: string[];
78
66
  entries: {
79
67
  id: string;
80
- kind: "tool-invocation" | "agent-patch" | "operator-patch" | "stage-transition" | "operator-decision" | "validator-result" | "runtime-event" | "note" | "correction" | "strip-decision-reverted" | "descope-brief" | "merge-return" | "merge-return-rejected" | "revert" | "rollback" | "rework.test_retired";
68
+ kind: "tool-invocation" | "agent-patch" | "operator-patch" | "operator-decision" | "validator-result" | "runtime-event" | "note" | "correction" | "strip-decision-reverted";
81
69
  ts: string;
82
70
  }[];
83
71
  entryCount: number;
@@ -93,7 +81,7 @@ export declare const appendEntryToReadIndex: ({ entry, readIndex, sequence, }: {
93
81
  coveredFiles: string[];
94
82
  entries: {
95
83
  id: string;
96
- kind: "tool-invocation" | "agent-patch" | "operator-patch" | "stage-transition" | "operator-decision" | "validator-result" | "runtime-event" | "note" | "correction" | "strip-decision-reverted" | "descope-brief" | "merge-return" | "merge-return-rejected" | "revert" | "rollback" | "rework.test_retired";
84
+ kind: "tool-invocation" | "agent-patch" | "operator-patch" | "operator-decision" | "validator-result" | "runtime-event" | "note" | "correction" | "strip-decision-reverted";
97
85
  ts: string;
98
86
  }[];
99
87
  entryCount: number;
@@ -1 +1 @@
1
- {"version":3,"file":"read-index.d.ts","sourceRoot":"","sources":["../src/read-index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,EAAgB,KAAK,WAAW,EAAE,KAAK,UAAU,EAAE,KAAK,WAAW,EAAoB,MAAM,mBAAmB,CAAC;AACxH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAO3D,QAAA,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;iBAIxB,CAAC;AAEH,QAAA,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAyBrB,CAAC;AAEP,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AACpE,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAClE,MAAM,MAAM,qBAAqB,GAAG,SAAS,CAAC,MAAM,EAAE;IAAE,KAAK,EAAE,WAAW,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AA0HhG,eAAO,MAAM,0BAA0B,GAAU,eAAe,MAAM,EAAE,UAAU,cAAc;;;;;;;;;;;EAuB/F,CAAC;AAYF,eAAO,MAAM,kBAAkB,GAAI,OAAO,eAAe,EAAE,UAAU,cAAc,YAG1C,CAAC;AAE1C,eAAO,MAAM,aAAa,GAAU,eAAe,MAAM,KAAG,OAAO,CAAC,eAAe,GAAG,IAAI,CAWzF,CAAC;AAEF,eAAO,MAAM,aAAa,GAAU,eAAe,MAAM,EAAE,WAAW,eAAe,kBAGpF,CAAC;AAEF,eAAO,MAAM,wBAAwB,GAAU,eAAe,MAAM,EAAE,UAAU,cAAc;;;;;;;;;;;EAiB7F,CAAC;AAEF,eAAO,MAAM,sBAAsB,GAAI,iCAIpC;IACC,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC;IAC5B,QAAQ,CAAC,SAAS,EAAE,eAAe,CAAC;IACpC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC7B;;;;;;;;;;;CAYA,CAAC;AAEF,eAAO,MAAM,sBAAsB,GAAI,uCAIpC;IACC,QAAQ,CAAC,MAAM,EAAE;QACb,QAAQ,CAAC,IAAI,CAAC,EAAE,UAAU,CAAC;QAC3B,QAAQ,CAAC,KAAK,CAAC,EAAE,WAAW,CAAC;QAC7B,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;KAC3B,CAAC;IACF,QAAQ,CAAC,QAAQ,EAAE,cAAc,CAAC;IAClC,QAAQ,CAAC,cAAc,EAAE,cAAc,CAAC;CAC3C,YAeA,CAAC"}
1
+ {"version":3,"file":"read-index.d.ts","sourceRoot":"","sources":["../src/read-index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,CAAC,MAAM,SAAS,CAAC;AAG7B,OAAO,EAAgB,KAAK,WAAW,EAAE,KAAK,UAAU,EAAE,KAAK,WAAW,EAAoB,MAAM,mBAAmB,CAAC;AACxH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAO3D,QAAA,MAAM,oBAAoB;;;;aAIxB,CAAC;AAEH,QAAA,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;sDAiB1B,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,WAAW,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAC1E,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,WAAW,CAAC,OAAO,oBAAoB,CAAC,CAAC;AACxE,MAAM,MAAM,qBAAqB,GAAG,SAAS,CAAC,MAAM,EAAE;IAAE,KAAK,EAAE,WAAW,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AA0HhG,eAAO,MAAM,0BAA0B,GAAU,eAAe,MAAM,EAAE,UAAU,cAAc;;;;;;;;;;;EAuB/F,CAAC;AAYF,eAAO,MAAM,kBAAkB,GAAI,OAAO,eAAe,EAAE,UAAU,cAAc,YAG1C,CAAC;AAE1C,eAAO,MAAM,aAAa,GAAU,eAAe,MAAM,KAAG,OAAO,CAAC,eAAe,GAAG,IAAI,CAWzF,CAAC;AAEF,eAAO,MAAM,aAAa,GAAU,eAAe,MAAM,EAAE,WAAW,eAAe,kBAGpF,CAAC;AAEF,eAAO,MAAM,wBAAwB,GAAU,eAAe,MAAM,EAAE,UAAU,cAAc;;;;;;;;;;;EAiB7F,CAAC;AAEF,eAAO,MAAM,sBAAsB,GAAI,iCAIpC;IACC,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC;IAC5B,QAAQ,CAAC,SAAS,EAAE,eAAe,CAAC;IACpC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC7B;;;;;;;;;;;CAYA,CAAC;AAEF,eAAO,MAAM,sBAAsB,GAAI,uCAIpC;IACC,QAAQ,CAAC,MAAM,EAAE;QACb,QAAQ,CAAC,IAAI,CAAC,EAAE,UAAU,CAAC;QAC3B,QAAQ,CAAC,KAAK,CAAC,EAAE,WAAW,CAAC;QAC7B,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;KAC3B,CAAC;IACF,QAAQ,CAAC,QAAQ,EAAE,cAAc,CAAC;IAClC,QAAQ,CAAC,cAAc,EAAE,cAAc,CAAC;CAC3C,YAeA,CAAC"}
@@ -1,5 +1,5 @@
1
1
  import { readFile } from 'node:fs/promises';
2
- import { z } from 'zod';
2
+ import * as v from 'valibot';
3
3
  import { mapWithConcurrencyLimit } from "./async.js";
4
4
  import { stableStringify } from "./json.js";
5
5
  import { LEDGER_KINDS, parseLedgerEntry } from "./schema/entry.js";
@@ -7,40 +7,22 @@ import { readPhaseEntryText, resolveLedgerPaths, writeAtomicTextFile } from "./s
7
7
  const READ_INDEX_SCHEMA_VERSION = 'ushman-ledger-read-index/v1';
8
8
  const ENTRY_READ_BATCH_SIZE = 32;
9
9
  const ENTRY_READ_CONCURRENCY = 16;
10
- const ReadIndexEntrySchema = z.object({
11
- id: z.string().min(1),
12
- kind: z.enum(LEDGER_KINDS),
13
- ts: z.string().datetime({ offset: true }),
14
- });
15
- const LedgerReadIndexSchema = z
16
- .object({
17
- coveredFiles: z.array(z.string()).default([]),
18
- entries: z.array(ReadIndexEntrySchema).default([]),
19
- entryCount: z.number().int().nonnegative(),
20
- lastEntryId: z.string().min(1).nullable(),
21
- lastSequence: z.number().int().nonnegative(),
22
- schemaVersion: z.literal(READ_INDEX_SCHEMA_VERSION),
23
- })
24
- .superRefine((value, ctx) => {
25
- if (value.entryCount !== value.entries.length) {
26
- ctx.addIssue({
27
- code: 'custom',
28
- message: 'entryCount must match entries.length',
29
- path: ['entryCount'],
30
- });
31
- }
32
- const expectedLastEntryId = value.entries.at(-1)?.id ?? null;
33
- if (value.lastEntryId !== expectedLastEntryId) {
34
- ctx.addIssue({
35
- code: 'custom',
36
- message: 'lastEntryId must match the final indexed entry',
37
- path: ['lastEntryId'],
38
- });
39
- }
10
+ const ReadIndexEntrySchema = v.object({
11
+ id: v.pipe(v.string(), v.minLength(1)),
12
+ kind: v.picklist(LEDGER_KINDS),
13
+ ts: v.pipe(v.string(), v.isoTimestamp()),
40
14
  });
15
+ const LedgerReadIndexSchema = v.pipe(v.object({
16
+ coveredFiles: v.optional(v.array(v.string()), []),
17
+ entries: v.optional(v.array(ReadIndexEntrySchema), []),
18
+ entryCount: v.pipe(v.number(), v.integer(), v.minValue(0)),
19
+ lastEntryId: v.nullable(v.pipe(v.string(), v.minLength(1))),
20
+ lastSequence: v.pipe(v.number(), v.integer(), v.minValue(0)),
21
+ schemaVersion: v.literal(READ_INDEX_SCHEMA_VERSION),
22
+ }), v.check((value) => value.entryCount === value.entries.length, 'entryCount must match entries.length'), v.check((value) => value.lastEntryId === (value.entries.at(-1)?.id ?? null), 'lastEntryId must match the final indexed entry'));
41
23
  const parseReadIndexText = (filePath, text) => {
42
24
  try {
43
- return LedgerReadIndexSchema.parse(JSON.parse(text));
25
+ return v.parse(LedgerReadIndexSchema, JSON.parse(text));
44
26
  }
45
27
  catch (error) {
46
28
  throw new Error(`Invalid ledger read index at ${filePath}: ${error instanceof Error ? error.message : String(error)}`);
@@ -89,7 +71,7 @@ const mergeSortedUniquePaths = (existingPaths, additionalPaths) => {
89
71
  }
90
72
  return mergedPaths;
91
73
  };
92
- const buildReadIndex = ({ coveredFiles, entries, lastSequence, }) => LedgerReadIndexSchema.parse({
74
+ const buildReadIndex = ({ coveredFiles, entries, lastSequence, }) => v.parse(LedgerReadIndexSchema, {
93
75
  coveredFiles,
94
76
  entries,
95
77
  entryCount: entries.length,
@@ -162,7 +144,7 @@ export const readReadIndex = async (workspaceRoot) => {
162
144
  };
163
145
  export const saveReadIndex = async (workspaceRoot, readIndex) => {
164
146
  const filePath = resolveLedgerPaths(workspaceRoot).readIndexFile;
165
- await writeAtomicTextFile(filePath, `${stableStringify(LedgerReadIndexSchema.parse(readIndex), true)}\n`);
147
+ await writeAtomicTextFile(filePath, `${stableStringify(v.parse(LedgerReadIndexSchema, readIndex), true)}\n`);
166
148
  };
167
149
  export const ensureReadIndexUnderLock = async (workspaceRoot, manifest) => {
168
150
  let currentReadIndex = null;
@@ -1 +1 @@
1
- {"version":3,"file":"record.d.ts","sourceRoot":"","sources":["../src/record.ts"],"names":[],"mappings":"AAQA,OAAO,EAEH,KAAK,WAAW,EAQnB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAW3D,KAAK,qBAAqB,GAAG;IACzB,QAAQ,CAAC,eAAe,CAAC,EAAE,CAAC,OAAO,EAAE;QAAE,KAAK,EAAE,WAAW,CAAA;KAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9E,QAAQ,CAAC,iBAAiB,CAAC,EAAE,CAAC,OAAO,EAAE;QAAE,KAAK,EAAE,WAAW,CAAA;KAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAChF,QAAQ,CAAC,uBAAuB,CAAC,EAAE,CAAC,OAAO,EAAE;QAAE,KAAK,EAAE,WAAW,CAAC;QAAC,iBAAiB,EAAE,MAAM,CAAA;KAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACjH,QAAQ,CAAC,kBAAkB,CAAC,EAAE,CAAC,OAAO,EAAE;QAAE,KAAK,EAAE,WAAW,CAAA;KAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACpF,CAAC;AAuBF,eAAO,MAAM,wBAAwB,GAAI,eAAe,MAAM,EAAE,OAAO,qBAAqB,GAAG,IAAI,SAOlG,CAAC;AAgNF,eAAO,MAAM,YAAY,GACrB,eAAe,MAAM,EACrB,OAAO,OAAO,KACf,OAAO,CAAC;IAAE,KAAK,EAAE,WAAW,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,CAqF5C,CAAC;AAEF,eAAO,MAAM,aAAa,GACtB,eAAe,MAAM,EACrB,UAAU,cAAc,EACxB,SAAS,MAAM,KAChB,OAAO,CAAC,WAAW,CAUrB,CAAC"}
1
+ {"version":3,"file":"record.d.ts","sourceRoot":"","sources":["../src/record.ts"],"names":[],"mappings":"AAQA,OAAO,EAEH,KAAK,WAAW,EAKnB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAU3D,KAAK,qBAAqB,GAAG;IACzB,QAAQ,CAAC,eAAe,CAAC,EAAE,CAAC,OAAO,EAAE;QAAE,KAAK,EAAE,WAAW,CAAA;KAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9E,QAAQ,CAAC,iBAAiB,CAAC,EAAE,CAAC,OAAO,EAAE;QAAE,KAAK,EAAE,WAAW,CAAA;KAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAChF,QAAQ,CAAC,uBAAuB,CAAC,EAAE,CAAC,OAAO,EAAE;QAAE,KAAK,EAAE,WAAW,CAAC;QAAC,iBAAiB,EAAE,MAAM,CAAA;KAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACjH,QAAQ,CAAC,kBAAkB,CAAC,EAAE,CAAC,OAAO,EAAE;QAAE,KAAK,EAAE,WAAW,CAAA;KAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACpF,CAAC;AAUF,eAAO,MAAM,wBAAwB,GAAI,eAAe,MAAM,EAAE,OAAO,qBAAqB,GAAG,IAAI,SAOlG,CAAC;AAoHF,eAAO,MAAM,YAAY,GACrB,eAAe,MAAM,EACrB,OAAO,OAAO,KACf,OAAO,CAAC;IAAE,KAAK,EAAE,WAAW,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,CAqF5C,CAAC;AAEF,eAAO,MAAM,aAAa,GACtB,eAAe,MAAM,EACrB,UAAU,cAAc,EACxB,SAAS,MAAM,KAChB,OAAO,CAAC,WAAW,CAMrB,CAAC"}
package/dist/record.js CHANGED
@@ -1,29 +1,17 @@
1
1
  import { readFile } from 'node:fs/promises';
2
2
  import path from 'node:path';
3
+ import * as v from 'valibot';
3
4
  import { resolveBlobPath, storePatchBlob } from "./blobs.js";
4
5
  import { sha256Hex, stableStringify } from "./json.js";
5
6
  import { updateManifestForEntry } from "./manifest-update.js";
6
- import { derivePatchPayloadFromDiffText } from "./patch-metadata.js";
7
7
  import { appendEntryToReadIndex, saveReadIndex } from "./read-index.js";
8
8
  import { reconcileLedgerStateUnderLock, removePendingCommit, writePendingCommit } from "./recovery.js";
9
- import { LedgerEntrySchema, OperatorDecisionPayloadSchema, PatchPayloadWriteSchema, parseLedgerEntry, parseLedgerRecord, ValidatorResultPayloadSchema, } from "./schema/entry.js";
9
+ import { LedgerEntrySchema, parseLedgerEntry, parseLedgerRecord, } from "./schema/entry.js";
10
10
  import { ensureLedgerDirectories, readManifest, resolveLedgerPaths, saveManifest, writeEntryFile, } from "./storage/filesystem.js";
11
11
  import { acquireLock } from "./storage/lock.js";
12
- import { createDeterministicUuidV7 } from "./uuid.js";
13
12
  const appendRecordTestHooks = new Map();
14
13
  const resolveWorkspaceKey = (workspaceRoot) => path.resolve(workspaceRoot);
15
14
  const getAppendRecordTestHooks = (workspaceRoot) => appendRecordTestHooks.get(resolveWorkspaceKey(workspaceRoot));
16
- const warnedDeprecations = new Set();
17
- const warnOnce = (key, message) => {
18
- if (warnedDeprecations.has(key)) {
19
- return;
20
- }
21
- warnedDeprecations.add(key);
22
- process.emitWarning(message, {
23
- code: key,
24
- type: 'DeprecationWarning',
25
- });
26
- };
27
15
  export const setAppendRecordTestHooks = (workspaceRoot, hooks) => {
28
16
  const key = resolveWorkspaceKey(workspaceRoot);
29
17
  if (!hooks) {
@@ -64,118 +52,47 @@ const buildEntryId = (entryWithoutId, sequence) => {
64
52
  const bodyHash = sha256Hex(stableStringify(entryWithoutId));
65
53
  return `${toEntryIdTimestamp(entryWithoutId.ts)}-${sequence.toString().padStart(8, '0')}-${bodyHash.slice(0, 12)}`;
66
54
  };
67
- const normalizeValidatorResultRecord = (record) => {
68
- if (record.kind !== 'validator-result') {
69
- return record;
70
- }
71
- const payloadId = record.payload?.id;
72
- if (payloadId) {
73
- return {
74
- ...record,
75
- payload: ValidatorResultPayloadSchema.parse(record.payload),
76
- };
77
- }
78
- warnOnce('USHMAN_LEDGER_VALIDATOR_ID_COMPAT', 'validator-result records should provide payload.id. A compatibility UUIDv7 was synthesized for this append.');
79
- return {
80
- ...record,
81
- payload: {
82
- id: createDeterministicUuidV7({
83
- seed: stableStringify(record),
84
- timestamp: 0,
85
- }),
86
- },
87
- };
88
- };
89
- const resolvePatchTextAndBlob = async ({ record, workspaceRoot, }) => {
55
+ const loadPatchText = async ({ record, workspaceRoot, }) => {
90
56
  if (record.diffPath) {
91
- const patchText = await readFile(path.resolve(record.diffPath), 'utf8');
92
- return {
93
- patchText,
94
- storedDiff: await storePatchBlob(workspaceRoot, patchText),
95
- };
57
+ return readFile(path.resolve(record.diffPath), 'utf8');
96
58
  }
97
- if (record.payload?.diff) {
98
- const storedDiff = await storePatchBlob(workspaceRoot, record.payload.diff);
99
- if (record.diff && record.diff.blobSha256 !== storedDiff.blobSha256) {
100
- throw new Error(`Provided diff blob ${record.diff.blobSha256} does not match payload.diff hash ${storedDiff.blobSha256}.`);
101
- }
102
- return {
103
- patchText: record.payload.diff,
104
- storedDiff,
105
- };
59
+ if (record.diffText) {
60
+ return record.diffText;
106
61
  }
107
- if (!record.diff) {
108
- throw new Error(`${record.kind} records require payload.diff, diffPath, or diff metadata.`);
109
- }
110
- try {
111
- const patchText = await readBlobText(workspaceRoot, record.diff);
112
- return {
113
- patchText,
114
- storedDiff: record.diff,
115
- };
116
- }
117
- catch (error) {
118
- if (error.code === 'ENOENT') {
119
- throw new Error(`Patch blob ${record.diff.blobSha256} was not found. Store it first or use diffPath.`);
62
+ if (record.diff) {
63
+ try {
64
+ return await readBlobText(workspaceRoot, record.diff);
65
+ }
66
+ catch (error) {
67
+ if (error.code === 'ENOENT') {
68
+ throw new Error(`Patch blob ${record.diff.blobSha256} was not found. Store it first or use diffPath.`);
69
+ }
70
+ throw error;
120
71
  }
121
- throw error;
122
72
  }
123
- };
124
- const resolvePatchPayload = async ({ patchText, record, workspaceRoot, }) => {
125
- const derivedPayload = await derivePatchPayloadFromDiffText({
126
- patchText,
127
- workspaceRoot,
128
- });
129
- const mergedPayload = PatchPayloadWriteSchema.parse({
130
- ...derivedPayload,
131
- ...record.payload,
132
- diff: record.payload?.diff ?? patchText,
133
- diffSha256: record.payload?.diffSha256 ?? derivedPayload.diffSha256,
134
- fileSha256After: record.payload?.fileSha256After ?? derivedPayload.fileSha256After,
135
- fileSha256Before: record.payload?.fileSha256Before ?? derivedPayload.fileSha256Before,
136
- hunks: record.payload?.hunks ?? derivedPayload.hunks,
137
- touchedPaths: record.payload?.touchedPaths ?? derivedPayload.touchedPaths,
138
- });
139
- return mergedPayload;
73
+ throw new Error(`${record.kind} records require diff, diffPath, or diffText.`);
140
74
  };
141
75
  const resolvePatchRecord = async ({ record, workspaceRoot, }) => {
142
- const { patchText, storedDiff } = await resolvePatchTextAndBlob({
143
- record,
144
- workspaceRoot,
145
- });
146
- const payload = await resolvePatchPayload({
147
- patchText,
148
- record,
149
- workspaceRoot,
150
- });
151
- if (payload.diffSha256 !== storedDiff.blobSha256) {
152
- throw new Error(`Patch payload hash ${payload.diffSha256} does not match stored blob hash ${storedDiff.blobSha256}.`);
76
+ const patchText = await loadPatchText({ record, workspaceRoot });
77
+ const storedDiff = await storePatchBlob(workspaceRoot, patchText);
78
+ if (record.diff && record.diff.blobSha256 !== storedDiff.blobSha256) {
79
+ throw new Error(`Provided diff blob ${record.diff.blobSha256} does not match patch text hash ${storedDiff.blobSha256}.`);
153
80
  }
81
+ const { diffPath: _diffPath, diffText: _diffText, ...rest } = record;
154
82
  return {
155
- ...record,
83
+ ...rest,
156
84
  diff: storedDiff,
157
85
  links: {
158
86
  ...record.links,
159
- affectedFiles: [...new Set([...(record.links?.affectedFiles ?? []), ...payload.touchedPaths])],
160
87
  blobs: [...new Set([...(record.links?.blobs ?? []), storedDiff.blobSha256])],
161
88
  },
162
- payload,
163
89
  };
164
90
  };
165
91
  const normalizeRecord = async ({ record, workspaceRoot, }) => {
166
- const normalizedRecord = normalizeValidatorResultRecord(record);
167
- if (normalizedRecord.kind === 'agent-patch' || normalizedRecord.kind === 'operator-patch') {
168
- return resolvePatchRecord({
169
- record: normalizedRecord,
170
- workspaceRoot,
171
- });
92
+ if (record.kind === 'agent-patch' || record.kind === 'operator-patch') {
93
+ return resolvePatchRecord({ record, workspaceRoot });
172
94
  }
173
- return normalizedRecord.kind === 'operator-decision'
174
- ? {
175
- ...normalizedRecord,
176
- payload: OperatorDecisionPayloadSchema.parse(normalizedRecord.payload),
177
- }
178
- : normalizedRecord;
95
+ return record;
179
96
  };
180
97
  export const appendRecord = async (workspaceRoot, input) => {
181
98
  const parsed = parseLedgerRecord(input);
@@ -222,7 +139,7 @@ export const appendRecord = async (workspaceRoot, input) => {
222
139
  schemaVersion: 'ushman-ledger-entry/v1',
223
140
  ts: new Date().toISOString(),
224
141
  };
225
- const entry = LedgerEntrySchema.parse({
142
+ const entry = v.parse(LedgerEntrySchema, {
226
143
  ...entryWithoutId,
227
144
  id: buildEntryId(entryWithoutId, nextSequence),
228
145
  });
@@ -259,10 +176,6 @@ export const appendRecord = async (workspaceRoot, input) => {
259
176
  }
260
177
  };
261
178
  export const readEntryById = async (workspaceRoot, manifest, entryId) => {
262
- const location = manifest.entryLocations[entryId];
263
- if (!location) {
264
- throw new Error(`Ledger entry not found: ${entryId}`);
265
- }
266
- const text = await readFile(path.join(resolveLedgerPaths(workspaceRoot).phaseDir(location.phase), `${entryId}.json`), 'utf8');
179
+ const text = await readFile(path.join(resolveLedgerPaths(workspaceRoot).phaseDir(manifest.entryLocations[entryId].phase), `${entryId}.json`), 'utf8');
267
180
  return parseLedgerEntry(JSON.parse(text));
268
181
  };
@@ -13,7 +13,6 @@ export declare const writePendingCommit: ({ entry, logicalHash, manifest, worksp
13
13
  }) => Promise<string>;
14
14
  export declare const removePendingCommit: (filePath: string) => Promise<void>;
15
15
  export declare const reconcilePendingCommitsUnderLock: (workspaceRoot: string) => Promise<{
16
- [x: string]: unknown;
17
16
  archives: {
18
17
  createdAt: string;
19
18
  integrityHash: string;
@@ -21,17 +20,29 @@ export declare const reconcilePendingCommitsUnderLock: (workspaceRoot: string) =
21
20
  }[];
22
21
  createdAt: string;
23
22
  entryCount: number;
24
- entryLocations: Record<string, {
25
- phase: "seed" | "capture" | "intake" | "vendor-extract" | "cleanup" | "parity" | "characterize" | "equiv" | "analyze" | "recover" | "ship" | "migration";
26
- sequence: number;
27
- }>;
28
- idempotencyIndex: Record<string, Record<string, string>>;
23
+ entryLocations: {
24
+ [x: string]: {
25
+ phase: "capture" | "intake" | "seed" | "vendor-extract" | "cleanup" | "parity" | "characterize" | "equiv" | "analyze" | "recover" | "ship" | "migration";
26
+ sequence: number;
27
+ };
28
+ };
29
+ idempotencyIndex: {
30
+ [x: string]: {
31
+ [x: string]: string;
32
+ };
33
+ };
29
34
  lastSequence: number;
30
- perPhaseCounts: Record<string, number>;
31
- perPhaseLatest: Record<string, string>;
35
+ perPhaseCounts: {
36
+ [x: string]: number;
37
+ };
38
+ perPhaseLatest: {
39
+ [x: string]: string;
40
+ };
32
41
  schemaVersion: "ushman-ledger-manifest/v1";
33
42
  updatedAt: string;
34
43
  workspaceId: string;
44
+ } & {
45
+ [key: string]: unknown;
35
46
  }>;
36
47
  export declare const reconcileLedgerStateUnderLock: (workspaceRoot: string) => Promise<PreparedLedgerState>;
37
48
  export declare const loadLedgerState: (workspaceRoot: string) => Promise<PreparedLedgerState>;
@@ -1 +1 @@
1
- {"version":3,"file":"recovery.d.ts","sourceRoot":"","sources":["../src/recovery.ts"],"names":[],"mappings":"AAKA,OAAO,EAA4B,KAAK,eAAe,EAAE,MAAM,iBAAiB,CAAC;AACjF,OAAO,EAAE,KAAK,WAAW,EAAqB,MAAM,mBAAmB,CAAC;AACxE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AA0B3D,MAAM,MAAM,mBAAmB,GAAG;IAC9B,QAAQ,CAAC,QAAQ,EAAE,cAAc,CAAC;IAClC,QAAQ,CAAC,SAAS,EAAE,eAAe,CAAC;CACvC,CAAC;AA0JF,eAAO,MAAM,kBAAkB,GAAU,kDAKtC;IACC,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC;IAC5B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,QAAQ,EAAE,cAAc,CAAC;IAClC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;CAClC,oBAeA,CAAC;AAEF,eAAO,MAAM,mBAAmB,GAAU,UAAU,MAAM,kBAEzD,CAAC;AAEF,eAAO,MAAM,gCAAgC,GAAU,eAAe,MAAM;;;;;;;;;;;;;;;;;;;;EAyB3E,CAAC;AAEF,eAAO,MAAM,6BAA6B,GAAU,eAAe,MAAM,KAAG,OAAO,CAAC,mBAAmB,CAQtG,CAAC;AAEF,eAAO,MAAM,eAAe,GAAU,eAAe,MAAM,KAAG,OAAO,CAAC,mBAAmB,CAQxF,CAAC;AAEF,eAAO,MAAM,kBAAkB,GAAU,eAAe,MAAM,kBAE7D,CAAC"}
1
+ {"version":3,"file":"recovery.d.ts","sourceRoot":"","sources":["../src/recovery.ts"],"names":[],"mappings":"AAKA,OAAO,EAA4B,KAAK,eAAe,EAAE,MAAM,iBAAiB,CAAC;AACjF,OAAO,EAAE,KAAK,WAAW,EAAqB,MAAM,mBAAmB,CAAC;AACxE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AA0B3D,MAAM,MAAM,mBAAmB,GAAG;IAC9B,QAAQ,CAAC,QAAQ,EAAE,cAAc,CAAC;IAClC,QAAQ,CAAC,SAAS,EAAE,eAAe,CAAC;CACvC,CAAC;AA0JF,eAAO,MAAM,kBAAkB,GAAU,kDAKtC;IACC,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC;IAC5B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,QAAQ,EAAE,cAAc,CAAC;IAClC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;CAClC,oBAeA,CAAC;AAEF,eAAO,MAAM,mBAAmB,GAAU,UAAU,MAAM,kBAEzD,CAAC;AAEF,eAAO,MAAM,gCAAgC,GAAU,eAAe,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAyB3E,CAAC;AAEF,eAAO,MAAM,6BAA6B,GAAU,eAAe,MAAM,KAAG,OAAO,CAAC,mBAAmB,CAQtG,CAAC;AAEF,eAAO,MAAM,eAAe,GAAU,eAAe,MAAM,KAAG,OAAO,CAAC,mBAAmB,CAQxF,CAAC;AAEF,eAAO,MAAM,kBAAkB,GAAU,eAAe,MAAM,kBAE7D,CAAC"}
package/dist/recovery.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { readdir, readFile, rm, stat } from 'node:fs/promises';
2
2
  import path from 'node:path';
3
- import { z } from 'zod';
3
+ import * as v from 'valibot';
4
4
  import { reconcilePendingArchivesUnderLock } from "./archive-journal.js";
5
5
  import { getNextManifestSequence, updateManifestForEntry } from "./manifest-update.js";
6
6
  import { ensureReadIndexUnderLock } from "./read-index.js";
@@ -10,18 +10,18 @@ import { acquireLock } from "./storage/lock.js";
10
10
  const PendingCommitSchemaVersion = 'ushman-ledger-pending-commit/v1';
11
11
  // Pending commits capture the intended sequence and logical hash before the
12
12
  // entry file and manifest update diverge, so recovery can replay safely.
13
- const PendingCommitSchema = z.object({
14
- baseLastSequence: z.number().int().nonnegative(),
15
- createdAt: z.string().datetime({ offset: true }),
13
+ const PendingCommitSchema = v.object({
14
+ baseLastSequence: v.pipe(v.number(), v.integer(), v.minValue(0)),
15
+ createdAt: v.pipe(v.string(), v.isoTimestamp()),
16
16
  entry: LedgerEntrySchema,
17
- logicalHash: z.string().min(1),
18
- schemaVersion: z.literal(PendingCommitSchemaVersion),
19
- sequence: z.number().int().positive(),
17
+ logicalHash: v.pipe(v.string(), v.minLength(1)),
18
+ schemaVersion: v.literal(PendingCommitSchemaVersion),
19
+ sequence: v.pipe(v.number(), v.integer(), v.minValue(1)),
20
20
  });
21
21
  const formatSequence = (sequence) => sequence.toString().padStart(8, '0');
22
- const PendingCommitFileNameSchema = z.object({
23
- entryId: z.string().min(1),
24
- sequence: z.number().int().positive().max(Number.MAX_SAFE_INTEGER),
22
+ const PendingCommitFileNameSchema = v.object({
23
+ entryId: v.pipe(v.string(), v.minLength(1)),
24
+ sequence: v.pipe(v.number(), v.integer(), v.minValue(1), v.maxValue(Number.MAX_SAFE_INTEGER)),
25
25
  });
26
26
  const buildPendingCommitFilePath = (workspaceRoot, sequence, entryId) => path.join(resolveLedgerPaths(workspaceRoot).pendingCommitsDir, `${formatSequence(sequence)}-${entryId}.json`);
27
27
  const parsePendingCommitFileName = (name) => {
@@ -29,7 +29,7 @@ const parsePendingCommitFileName = (name) => {
29
29
  if (!match) {
30
30
  return null;
31
31
  }
32
- return PendingCommitFileNameSchema.parse({
32
+ return v.parse(PendingCommitFileNameSchema, {
33
33
  entryId: match[2],
34
34
  sequence: Number.parseInt(match[1], 10),
35
35
  });
@@ -37,7 +37,7 @@ const parsePendingCommitFileName = (name) => {
37
37
  const readPendingCommit = async (filePath) => {
38
38
  try {
39
39
  const text = await readFile(filePath, 'utf8');
40
- return PendingCommitSchema.parse(JSON.parse(text));
40
+ return v.parse(PendingCommitSchema, JSON.parse(text));
41
41
  }
42
42
  catch (error) {
43
43
  throw new Error(`Invalid pending commit at ${filePath}: ${error instanceof Error ? error.message : String(error)}`);
@@ -128,7 +128,7 @@ const applyPendingCommit = async ({ manifest, pending, workspaceRoot, }) => {
128
128
  export const writePendingCommit = async ({ entry, logicalHash, manifest, workspaceRoot, }) => {
129
129
  const nextSequence = getNextManifestSequence(manifest.lastSequence);
130
130
  const filePath = buildPendingCommitFilePath(workspaceRoot, nextSequence, entry.id);
131
- await writeAtomicJsonFile(filePath, PendingCommitSchema.parse({
131
+ await writeAtomicJsonFile(filePath, v.parse(PendingCommitSchema, {
132
132
  baseLastSequence: manifest.lastSequence,
133
133
  createdAt: new Date().toISOString(),
134
134
  entry,
@@ -1 +1 @@
1
- {"version":3,"file":"retro.d.ts","sourceRoot":"","sources":["../../src/render/retro.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAgHtD,eAAO,MAAM,mBAAmB,GAAU,wBAGvC;IACC,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC,WAAW,CAAC,CAAC;IAC7C,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;CAC9B,KAAG,OAAO,CAAC,MAAM,CA6CjB,CAAC"}
1
+ {"version":3,"file":"retro.d.ts","sourceRoot":"","sources":["../../src/render/retro.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AA6GtD,eAAO,MAAM,mBAAmB,GAAU,wBAGvC;IACC,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC,WAAW,CAAC,CAAC;IAC7C,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;CAC9B,KAAG,OAAO,CAAC,MAAM,CA6CjB,CAAC"}
@@ -13,10 +13,7 @@ const createRetroBuckets = () => ({
13
13
  });
14
14
  const isProblemEntry = (entry) => (entry.kind === 'note' && entry.subkind === 'regression') ||
15
15
  (entry.kind === 'runtime-event' && entry.level === 'error');
16
- const isToolEntry = (entry) => entry.kind === 'tool-invocation' ||
17
- entry.kind === 'agent-patch' ||
18
- entry.kind === 'operator-patch' ||
19
- entry.kind === 'stage-transition';
16
+ const isToolEntry = (entry) => entry.kind === 'tool-invocation' || entry.kind === 'agent-patch' || entry.kind === 'operator-patch';
20
17
  const isToolingEntry = (entry) => (entry.kind === 'note' && entry.subkind === 'automation') ||
21
18
  (entry.kind === 'note' && entry.subkind === 'tooling-gap');
22
19
  const isRetroNote = (entry) => entry.kind === 'note' && entry.subkind === 'retro';