ushman-ledger 1.2.2 → 1.3.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 (56) hide show
  1. package/AGENTS.md +7 -5
  2. package/ARCHITECTURE.md +8 -2
  3. package/CHANGELOG.md +11 -0
  4. package/README.md +27 -5
  5. package/TROUBLESHOOTING.md +17 -3
  6. package/dist/blobs.d.ts.map +1 -1
  7. package/dist/blobs.js +1 -1
  8. package/dist/builders.d.ts +33 -0
  9. package/dist/builders.d.ts.map +1 -1
  10. package/dist/builders.js +10 -1
  11. package/dist/cli.d.ts.map +1 -1
  12. package/dist/cli.js +91 -32
  13. package/dist/doctor.d.ts +1 -1
  14. package/dist/doctor.d.ts.map +1 -1
  15. package/dist/doctor.js +45 -11
  16. package/dist/handle.d.ts.map +1 -1
  17. package/dist/handle.js +67 -30
  18. package/dist/index.d.ts +3 -3
  19. package/dist/index.d.ts.map +1 -1
  20. package/dist/index.js +3 -3
  21. package/dist/list.d.ts +32 -0
  22. package/dist/list.d.ts.map +1 -1
  23. package/dist/list.js +1 -1
  24. package/dist/patch-resolver.d.ts.map +1 -1
  25. package/dist/patch-resolver.js +1 -1
  26. package/dist/process.d.ts +2 -0
  27. package/dist/process.d.ts.map +1 -0
  28. package/dist/process.js +16 -0
  29. package/dist/read-index.d.ts +7 -7
  30. package/dist/read-index.d.ts.map +1 -1
  31. package/dist/read-index.js +13 -9
  32. package/dist/record.d.ts.map +1 -1
  33. package/dist/record.js +1 -2
  34. package/dist/recovery.d.ts +8 -0
  35. package/dist/recovery.d.ts.map +1 -1
  36. package/dist/recovery.js +142 -30
  37. package/dist/render/retro.d.ts.map +1 -1
  38. package/dist/render/retro.js +4 -1
  39. package/dist/runtime-config.d.ts +2 -0
  40. package/dist/runtime-config.d.ts.map +1 -1
  41. package/dist/runtime-config.js +14 -0
  42. package/dist/schema/entry-core.d.ts +5 -2
  43. package/dist/schema/entry-core.d.ts.map +1 -1
  44. package/dist/schema/entry-core.js +3 -0
  45. package/dist/schema/entry-read.d.ts +57 -0
  46. package/dist/schema/entry-read.d.ts.map +1 -1
  47. package/dist/schema/entry-read.js +9 -1
  48. package/dist/schema/entry-write.d.ts +51 -0
  49. package/dist/schema/entry-write.d.ts.map +1 -1
  50. package/dist/schema/entry-write.js +9 -1
  51. package/dist/storage/filesystem.d.ts +14 -2
  52. package/dist/storage/filesystem.d.ts.map +1 -1
  53. package/dist/storage/filesystem.js +206 -39
  54. package/dist/storage/lock.d.ts.map +1 -1
  55. package/dist/storage/lock.js +38 -16
  56. package/package.json +1 -1
package/AGENTS.md CHANGED
@@ -29,11 +29,13 @@ An append-only ledger library and CLI for ushman v4 workspaces. It owns ledger s
29
29
  5. `src/schema/entry-migrations.ts`
30
30
  6. `src/schema/entry.ts`
31
31
  7. `src/storage/filesystem.ts`
32
- 8. `src/record.ts`
33
- 9. `src/handle.ts`
34
- 10. `src/coverage.ts`
35
- 11. `src/doctor.ts`
36
- 12. `src/cli.ts`
32
+ 8. `src/recovery.ts`
33
+ 9. `src/record.ts`
34
+ 10. `src/handle.ts`
35
+ 11. `src/runtime-config.ts`
36
+ 12. `src/coverage.ts`
37
+ 13. `src/doctor.ts`
38
+ 14. `src/cli.ts`
37
39
 
38
40
  ## Commands
39
41
 
package/ARCHITECTURE.md CHANGED
@@ -20,7 +20,9 @@ The same reconciliation path is used by reads, writes, coverage, doctor, render,
20
20
 
21
21
  - `manifest.json`: append-order metadata, per-phase pointers, idempotency index, and archive metadata.
22
22
  - `read-index.json`: durable lightweight scan index used by list/render/coverage/doctor.
23
+ - `external-temp-files/`: journals for custom render temp files created outside `.lab/ledger`.
23
24
  - `pending/`: append journals used to replay incomplete commits.
25
+ - `pending-quarantine/`: unreplayable pending commit journals plus quarantine metadata.
24
26
  - `pending-archives/`: archive journals used to adopt or discard incomplete archive writes.
25
27
  - `blobs/`: content-addressed patch payloads keyed by SHA-256.
26
28
  - `<phase>/`: append-only entry files per ledger phase.
@@ -30,6 +32,7 @@ The same reconciliation path is used by reads, writes, coverage, doctor, render,
30
32
  - Entries are immutable once written. Corrections use `correction` records linked to the original entry.
31
33
  - Each phase maintains its own `prevEntryId` chain so local append history is explicit and auditable.
32
34
  - Idempotency is logical-content based by default and can be overridden with an explicit `idempotencyKey`.
35
+ - `stage-write` records treat `filePath` as the required primary covered artifact and may extend coverage with extra normalized `links.affectedFiles`.
33
36
  - Patch payloads are de-duplicated by SHA-256 and stored once under `blobs/`.
34
37
 
35
38
  ## Read path
@@ -43,8 +46,8 @@ The same reconciliation path is used by reads, writes, coverage, doctor, render,
43
46
 
44
47
  - Atomic writes use temp files and rename.
45
48
  - Pending commit journals record the target sequence before the entry file and manifest can drift.
46
- - Startup reconciliation replays pending commits in manifest order, rebuilds missing or stale read indexes, adopts verified archives, and cleans stale temp files.
47
- - Manifest locks are reclaimed only after stale-owner checks, so a newer owner is not deleted during handoff.
49
+ - Startup reconciliation replays pending commits in manifest order, quarantines unreplayable pending commits, rebuilds missing or stale read indexes, adopts verified archives, and cleans stale temp files.
50
+ - Manifest locks are reclaimed after stale-owner or dead-owner checks, so a newer owner is not deleted during handoff.
48
51
  - Re-opening the ledger or rerunning any CLI command triggers the same recovery path; there is no separate manual recovery subcommand.
49
52
 
50
53
  ## Scale and tuning
@@ -57,6 +60,8 @@ The default scan contract is intentionally conservative and can be tuned with en
57
60
  - `USHMAN_LEDGER_READ_INDEX_REBUILD_CONCURRENCY`
58
61
  - `USHMAN_LEDGER_COVERAGE_FILE_STAT_CONCURRENCY`
59
62
  - `USHMAN_LEDGER_BLOB_HASH_CONCURRENCY`
63
+ - `USHMAN_LEDGER_DOCTOR_CHECKPOINT_MAX_AGE_MS`
64
+ - `USHMAN_LEDGER_DOCTOR_OPEN_ISSUE_MAX_AGE_MS`
60
65
  - `USHMAN_LEDGER_MAX_PATCH_BYTES`
61
66
 
62
67
  The benchmark entrypoint, `bun run bench:scale`, prints the active runtime config so measurements can be compared across different knob settings.
@@ -70,6 +75,7 @@ The benchmark entrypoint, `bun run bench:scale`, prints the active runtime confi
70
75
  ## Contributor map
71
76
 
72
77
  - `src/blobs.ts`: patch blob storage, size limits, and digest/path validation.
78
+ - `src/storage/lock.ts`: manifest lock acquisition, stale-owner reclaim, and reclaim-marker turnover.
73
79
  - `src/record.ts`: append pipeline and idempotency behavior.
74
80
  - `src/recovery.ts`: pending journal replay, read-index rebuild, and temp cleanup.
75
81
  - `src/read-index.ts`: durable scan index construction and maintenance.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,16 @@
1
1
  # Changelog
2
2
 
3
+ ## [1.2.0] - 2026-05-28
4
+
5
+ - Added `stage-write` ledger records for deterministic pipeline-owned candidate writes.
6
+ - `stage-write` now accepts `intake` alongside the later candidate-mutating stage ids so intake-owned writes such as auto-stubs and workspace runbooks can be recorded without falling back to patch semantics.
7
+ - Read-index coverage now treats `stage-write.filePath` the same as patch `affectedFiles`, so downstream coverage checks can distinguish stage output from operator edits without losing coverage accounting.
8
+ - Retro rendering now includes `stage-write` entries in the tool/action stream.
9
+ - Custom render outputs now journal their external temp files so startup recovery can clean stale crash leftovers outside `.lab/ledger`.
10
+ - Lock recovery now reclaims locks immediately when the recorded owner PID is no longer alive.
11
+ - Pending commit recovery now quarantines unreplayable journals and reports them through `doctor` instead of failing the whole reconciliation pass.
12
+ - Doctor stale-age windows for pre-change checkpoints and open issues are configurable through runtime environment variables.
13
+
3
14
  ## [1.1.0] - 2026-05-23
4
15
 
5
16
  - Added `change-log` records, narrative note subkinds, and `migration-log-md` / `workspace-narrative-md` render targets.
package/README.md CHANGED
@@ -33,6 +33,7 @@ import {
33
33
  appendSemanticCleanupSummaryNote,
34
34
  type BuildRecordInput,
35
35
  buildChangeLogRecord,
36
+ buildStageWriteRecord,
36
37
  buildValidatorResultRecord,
37
38
  deriveFilesChangedFromPatch,
38
39
  getLedgerRuntimeConfig,
@@ -75,6 +76,17 @@ await ledger.record(
75
76
  }),
76
77
  );
77
78
 
79
+ await ledger.record(
80
+ buildStageWriteRecord({
81
+ emitter: { tool: 'ushman-seed', version: '1.0.0' },
82
+ filePath: 'src/generated/candidate.ts',
83
+ phase: 'seed',
84
+ rationale: 'Seed stage wrote the initial candidate artifact.',
85
+ stage: 'seed',
86
+ summary: 'seed candidate output',
87
+ }),
88
+ );
89
+
78
90
  await ledger.record(
79
91
  buildValidatorResultRecord({
80
92
  emitter: { tool: 'ushman-doctor', version: '1.0.0' },
@@ -126,6 +138,7 @@ const buildRuntimeEventRecord = (input: RuntimeEventInput) => ({
126
138
  ```bash
127
139
  ushman-ledger record --workspace=<ws> --kind=tool-invocation --phase=capture --summary="capture started"
128
140
  ushman-ledger record --workspace=<ws> --kind=agent-patch --phase=cleanup --summary="capture git diff" --rationale="track working tree change" --diff-from-git=HEAD
141
+ ushman-ledger record --workspace=<ws> --kind=stage-write --phase=seed --summary="seed output" --rationale="pipeline wrote candidate" --file-path=src/generated/candidate.ts --stage=seed
129
142
  ushman-ledger record --workspace=<ws> --kind=change-log --subkind=smoke --phase=cleanup --summary="scope git diff" --diff-from-git=HEAD --git-paths=src/main.ts,src/cli.ts --git-diff-timeout-ms=10000 --git-diff-max-buffer-bytes=20971520
130
143
  ushman-ledger record --workspace=<ws> --kind=operator-decision --phase=cleanup --summary="manual override" --action=ledger-hand-edit --check-id=manual-review --rationale="operator edited the ledger after audit"
131
144
  ushman-ledger record --workspace=<ws> --kind=change-log --subkind=semantic-cleanup --phase=cleanup --summary="split schema modules" --diff=/tmp/change.patch --hypothesis="smaller schema modules keep the public API stable" --commands=$'bun test\nbun run typecheck' --smoke-result=pass --parity-status=green --rollback-plan="revert the schema split"
@@ -142,10 +155,12 @@ ushman-ledger doctor --workspace=<ws>
142
155
  ushman-ledger doctor --workspace=<ws> --json
143
156
  ```
144
157
 
145
- Valid record kinds: `tool-invocation`, `agent-patch`, `operator-patch`, `operator-decision`, `validator-result`, `runtime-event`, `note`, `correction`, `strip-decision-reverted`, `change-log`
158
+ Valid record kinds: `tool-invocation`, `stage-write`, `agent-patch`, `operator-patch`, `operator-decision`, `validator-result`, `runtime-event`, `note`, `correction`, `strip-decision-reverted`, `change-log`
146
159
 
147
160
  Valid phases: `capture`, `intake`, `seed`, `vendor-extract`, `cleanup`, `parity`, `characterize`, `equiv`, `analyze`, `recover`, `ship`, `migration`
148
161
 
162
+ Valid `stage-write` stages: `seed`, `vendor-extract`, `cleanup`, `candidate-promotion`
163
+
149
164
  Valid note subkinds: `regression`, `automation`, `retro`, `operator`, `tooling-gap`, `cleanup-wave`, `verified-flow`, `open-issue`, `decomposition-wave`, `semantic-cleanup-summary`
150
165
 
151
166
  Valid render targets: `retro`, `jsonl`, `timeline-html`, `dependency-graph`, `migration-log-md`, `workspace-narrative-md`
@@ -184,14 +199,16 @@ Valid render targets: `retro`, `jsonl`, `timeline-html`, `dependency-graph`, `mi
184
199
  - `operator-decision` entries capture `{ action, checkId?, rationale }` in `payload`. `action` is one of `bypass-doctor`, `skip-check`, `override-strip-decision`, `override-ship-state`, `manual-parity-assertion`, `ledger-hand-edit`, `escalation`.
185
200
  - `strip-decision-reverted` entries capture `{ stripDecisionId, rationale, invalidatedStages? }`.
186
201
  - `correction` entries require `links.correctsLedgerId` pointing at the entry they correct.
202
+ - `stage-write` entries capture `{ filePath, rationale, stage }` for deterministic pipeline-owned writes. `phase` records where the ledger event happened; `stage` records the pipeline stage that produced the artifact.
187
203
  - Patch entries (`agent-patch`, `operator-patch`) store a `diff` blob reference and a `rationale`. Patch text is stored once under `.lab/ledger/blobs/` and shared by hash.
188
204
 
189
205
  ## Links and coverage
190
206
 
191
207
  - `links.affectedFiles` should contain normalized workspace-relative paths for files changed by an `agent-patch` or `operator-patch`.
208
+ - `stage-write.filePath` is always treated as covered output. If one stage write should cover additional normalized paths, include them in `links.affectedFiles`; coverage merges both sources.
192
209
  - Use forward slashes, do not prefix paths with `./`, and do not include trailing slashes or `..` segments.
193
210
  - Coverage only considers candidate workspace files modified after workspace initialization.
194
- - A modified file is considered covered when any patch entry lists it in `links.affectedFiles`.
211
+ - A modified file is considered covered when a patch entry lists it in `links.affectedFiles` or a `stage-write` entry names it through `filePath`/`links.affectedFiles`.
195
212
  - Coverage is backed by a durable read index so repeated coverage runs do not rescan every patch entry.
196
213
 
197
214
  ## Append chain and concurrency
@@ -200,21 +217,22 @@ Valid render targets: `retro`, `jsonl`, `timeline-html`, `dependency-graph`, `mi
200
217
  - Manifest updates are serialized through a global ledger lock.
201
218
  - Appends use a pending-commit journal so entry files, the manifest, and the durable read index can be replayed after crashes.
202
219
  - Open, read, and append paths reconcile unfinished commits before serving ledger data.
203
- - Corrupt or stale manifest locks are reclaimed automatically with compare-and-swap style quarantine semantics.
220
+ - Corrupt, stale, or dead-owner manifest locks are reclaimed automatically with compare-and-swap style quarantine semantics.
204
221
 
205
222
  ## Crash recovery
206
223
 
207
224
  - Pending commit journals live under `.lab/ledger/pending/`.
225
+ - Pending commit journals that cannot be replayed are moved to `.lab/ledger/pending-quarantine/` and surfaced by `doctor`.
208
226
  - Pending archive journals live under `.lab/ledger/pending-archives/`.
209
227
  - Startup reconciliation replays journaled appends in manifest sequence order.
210
228
  - Startup reconciliation also rebuilds a missing or stale `read-index.json` from manifest sequence order.
211
229
  - Verified pending archives are adopted into the manifest on startup; corrupt or partial pending archives are deleted.
212
- - Stale temp files are cleaned for phase entries, the manifest, blobs, the read index, and render outputs.
230
+ - Stale temp files are cleaned for phase entries, the manifest, blobs, the read index, canonical render outputs, and tracked custom render outputs.
213
231
 
214
232
  ## Recovery & Troubleshooting
215
233
 
216
234
  - `.lab/ledger/pending/` contains append journals that let the ledger recover incomplete writes after crashes. Do not edit these files by hand.
217
- - If startup or `doctor` reports a pending commit mismatch, re-open the ledger or rerun the command first so reconciliation can replay or discard the journal safely.
235
+ - If startup moves a pending commit to `.lab/ledger/pending-quarantine/`, inspect the `doctor` finding and restore the journal only when its entry, sequence, and manifest base are known to be safe.
218
236
  - If `doctor` reports manifest or blob corruption, fix the underlying entry/blob mismatch first and rerun `doctor` before attempting `archive`.
219
237
 
220
238
  ## Scan behavior
@@ -249,7 +267,9 @@ Valid render targets: `retro`, `jsonl`, `timeline-html`, `dependency-graph`, `mi
249
267
  .manifest.lock
250
268
  manifest.json
251
269
  read-index.json
270
+ external-temp-files/
252
271
  pending/
272
+ pending-quarantine/
253
273
  pending-archives/
254
274
  blobs/
255
275
  render.md
@@ -290,6 +310,8 @@ bun run bench:scale
290
310
  - `USHMAN_LEDGER_READ_INDEX_REBUILD_CONCURRENCY`: concurrent entry reads used while rebuilding `read-index.json`. Defaults to `USHMAN_LEDGER_SCAN_CONCURRENCY`.
291
311
  - `USHMAN_LEDGER_COVERAGE_FILE_STAT_CONCURRENCY`: concurrent `stat()` calls during coverage scans. Defaults to `USHMAN_LEDGER_SCAN_CONCURRENCY`.
292
312
  - `USHMAN_LEDGER_BLOB_HASH_CONCURRENCY`: concurrent blob integrity hashes during `doctor`. Defaults to `USHMAN_LEDGER_SCAN_CONCURRENCY`.
313
+ - `USHMAN_LEDGER_DOCTOR_CHECKPOINT_MAX_AGE_MS`: stale window for `pre-change-checkpoint` follow-up findings. Default `86400000`.
314
+ - `USHMAN_LEDGER_DOCTOR_OPEN_ISSUE_MAX_AGE_MS`: stale window for unresolved `open-issue` note findings. Default `2592000000`.
293
315
  - `USHMAN_LEDGER_MAX_PATCH_BYTES`: maximum accepted patch/blob input size in bytes. Default `10485760`.
294
316
 
295
317
  All runtime tuning values must be positive integers. Invalid values fail fast with an explicit error so automation does not silently run with an unexpected fallback.
@@ -127,18 +127,28 @@ Action:
127
127
 
128
128
  ### `pre-change-checkpoint-stale`
129
129
 
130
- Meaning: a pre-change checkpoint aged past 24 hours without a follow-up entry using the same `idempotencyKey`.
130
+ Meaning: a pre-change checkpoint aged past the configured stale window without a follow-up entry using the same `idempotencyKey`. The default window is 24 hours.
131
131
 
132
132
  Action:
133
133
  - Append the follow-up change-log entry, or close the stale checkpoint with a correction entry explaining the abandoned work.
134
134
 
135
135
  ### `open-issue-stale`
136
136
 
137
- Meaning: an `open-issue` note is older than 30 days and has no correction/supersession link.
137
+ Meaning: an `open-issue` note is older than the configured stale window and has no correction/supersession link. The default window is 30 days.
138
138
 
139
139
  Action:
140
140
  - Append a correction or superseding note linking back to the old issue once the follow-up is complete.
141
141
 
142
+ ### `pending-commit-quarantined`
143
+
144
+ Meaning: startup recovery found a pending commit journal that could not be parsed, replayed, or reconciled with the current manifest, so it moved the journal to `.lab/ledger/pending-quarantine/` and continued reconciling the rest of the ledger.
145
+
146
+ Action:
147
+ - Inspect the finding metadata and matching quarantine files.
148
+ - Start with `ushman-ledger doctor --workspace="$WS" --json` so the finding metadata shows the quarantined file path and recorded reason.
149
+ - Restore the journal to `.lab/ledger/pending/` only if its entry, sequence, and manifest base are known to be safe.
150
+ - Otherwise keep or remove the quarantined file after recording an operator decision for the recovery outcome.
151
+
142
152
  ### `read-failure`
143
153
 
144
154
  Meaning: the ledger could not be parsed or reconciled cleanly before checks started.
@@ -159,12 +169,16 @@ Action:
159
169
 
160
170
  ### Ledger lock held by a dead process
161
171
 
162
- Rerun the original ledger command first. Lock reclamation happens during normal startup and append flows, so you usually do not need to delete lock files by hand.
172
+ Rerun the original ledger command first. Lock reclamation checks the recorded owner PID and stale age during normal startup and append flows, so you usually do not need to delete lock files by hand.
163
173
 
164
174
  ### Manifest and disk disagree after a crash
165
175
 
166
176
  Re-open the ledger first so pending commits can be replayed. If `doctor` still reports `manifest-entry-missing-on-disk` or `manifest-entry-location-missing`, repair the missing entry file or manifest location before archiving.
167
177
 
178
+ ### Custom doctor stale windows
179
+
180
+ Use `USHMAN_LEDGER_DOCTOR_CHECKPOINT_MAX_AGE_MS` to tune `pre-change-checkpoint-stale` and `USHMAN_LEDGER_DOCTOR_OPEN_ISSUE_MAX_AGE_MS` to tune `open-issue-stale`. Both values are positive integer millisecond windows and keep the default behavior when unset.
181
+
168
182
  ### Manual ledger edits
169
183
 
170
184
  Prefer appending `correction` or `operator-decision` records instead of editing historical entry files directly. If historical files were edited already, use `doctor` to identify the damaged chain or manifest pointers before appending new records.
@@ -1 +1 @@
1
- {"version":3,"file":"blobs.d.ts","sourceRoot":"","sources":["../src/blobs.ts"],"names":[],"mappings":"AA8CA,MAAM,MAAM,eAAe,GAAG;IAC1B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;CACjC,CAAC;AAEF,eAAO,MAAM,qBAAqB,GAAI,QAAQ,MAAM,WAKnD,CAAC;AAEF,eAAO,MAAM,0BAA0B,GAAI,WAAW,MAAM,EAAE,aAAa,MAAM,WAOhF,CAAC;AAEF,eAAO,MAAM,qBAAqB,GAAU,WAAW,MAAM,oBAO5D,CAAC;AAEF,eAAO,MAAM,cAAc,GAAU,eAAe,MAAM,EAAE,WAAW,MAAM,KAAG,OAAO,CAAC,eAAe,CAmBtG,CAAC;AAEF,eAAO,MAAM,sBAAsB,GAAU,eAAe,MAAM,EAAE,WAAW,MAAM,KAAG,OAAO,CAAC,eAAe,CAE9G,CAAC;AAEF,eAAO,MAAM,eAAe,GAAI,eAAe,MAAM,EAAE,QAAQ,MAAM,WACN,CAAC"}
1
+ {"version":3,"file":"blobs.d.ts","sourceRoot":"","sources":["../src/blobs.ts"],"names":[],"mappings":"AAsDA,MAAM,MAAM,eAAe,GAAG;IAC1B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;CACjC,CAAC;AAEF,eAAO,MAAM,qBAAqB,GAAI,QAAQ,MAAM,WAKnD,CAAC;AAEF,eAAO,MAAM,0BAA0B,GAAI,WAAW,MAAM,EAAE,aAAa,MAAM,WAOhF,CAAC;AAEF,eAAO,MAAM,qBAAqB,GAAU,WAAW,MAAM,oBAO5D,CAAC;AAEF,eAAO,MAAM,cAAc,GAAU,eAAe,MAAM,EAAE,WAAW,MAAM,KAAG,OAAO,CAAC,eAAe,CAmBtG,CAAC;AAEF,eAAO,MAAM,sBAAsB,GAAU,eAAe,MAAM,EAAE,WAAW,MAAM,KAAG,OAAO,CAAC,eAAe,CAE9G,CAAC;AAEF,eAAO,MAAM,eAAe,GAAI,eAAe,MAAM,EAAE,QAAQ,MAAM,WACN,CAAC"}
package/dist/blobs.js CHANGED
@@ -31,7 +31,7 @@ const countPatchLines = (patchText) => {
31
31
  });
32
32
  return { addedLines, removedLines };
33
33
  };
34
- const formatPatchLimitError = ({ bytes, limitBytes, sourceLabel }) => `Patch input from ${sourceLabel} is ${bytes} bytes, exceeding the configured limit of ${limitBytes} bytes. Reduce the diff size or increase USHMAN_LEDGER_MAX_PATCH_BYTES.`;
34
+ const formatPatchLimitError = ({ bytes, limitBytes, sourceLabel, }) => `Patch input from ${sourceLabel} is ${bytes} bytes, exceeding the configured limit of ${limitBytes} bytes. Reduce the diff size or increase USHMAN_LEDGER_MAX_PATCH_BYTES.`;
35
35
  const buildBlobPath = (workspaceRoot, sha256) => {
36
36
  const paths = resolveLedgerPaths(workspaceRoot);
37
37
  return path.join(paths.blobsDir, sha256.slice(0, 2), `${sha256}.patch`);
@@ -147,6 +147,39 @@ export declare const buildChangeLogRecord: (input: BuildRecordInput<Extract<Ledg
147
147
  phase: "capture" | "intake" | "seed" | "vendor-extract" | "cleanup" | "parity" | "characterize" | "equiv" | "analyze" | "recover" | "ship" | "migration";
148
148
  summary: string;
149
149
  };
150
+ /** Build a `stage-write` record. */
151
+ export declare const buildStageWriteRecord: (input: BuildRecordInput<Extract<LedgerRecord, {
152
+ kind: "stage-write";
153
+ }>>) => {
154
+ filePath: string;
155
+ kind: "stage-write";
156
+ rationale: string;
157
+ stage: "intake" | "seed" | "vendor-extract" | "cleanup" | "candidate-promotion";
158
+ details?: {
159
+ [x: string]: unknown;
160
+ } | undefined;
161
+ emitter: {
162
+ tool: string;
163
+ user?: string | undefined;
164
+ version: string;
165
+ };
166
+ idempotencyKey?: string | undefined;
167
+ links?: ({
168
+ affectedFiles?: string[] | undefined;
169
+ blobs?: string[] | undefined;
170
+ briefId?: string | undefined;
171
+ correctsLedgerId?: string | undefined;
172
+ gitRef?: string | undefined;
173
+ idempotencyKey?: string | undefined;
174
+ stripDecisionId?: string | undefined;
175
+ supersedesLedgerId?: string | undefined;
176
+ validatorVerdictId?: string | undefined;
177
+ } & {
178
+ [key: string]: unknown;
179
+ }) | undefined;
180
+ phase: "capture" | "intake" | "seed" | "vendor-extract" | "cleanup" | "parity" | "characterize" | "equiv" | "analyze" | "recover" | "ship" | "migration";
181
+ summary: string;
182
+ };
150
183
  /** Build a `strip-decision-reverted` record. */
151
184
  export declare const buildStripDecisionRevertedRecord: (input: BuildRecordInput<Extract<LedgerRecord, {
152
185
  kind: "strip-decision-reverted";
@@ -1 +1 @@
1
- {"version":3,"file":"builders.d.ts","sourceRoot":"","sources":["../src/builders.ts"],"names":[],"mappings":"AACA,OAAO,EAGH,KAAK,YAAY,EAIpB,MAAM,mBAAmB,CAAC;AAE3B,MAAM,MAAM,gBAAgB,CAAC,OAAO,SAAS,YAAY,IAAI,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,GAAG;IACjF,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;CACnC,CAAC;AAEF,+EAA+E;AAC/E,eAAO,MAAM,2BAA2B,GACpC,OAAO,gBAAgB,CAAC,OAAO,CAAC,YAAY,EAAE;IAAE,IAAI,EAAE,mBAAmB,CAAA;CAAE,CAAC,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAM3E,CAAC;AAEP,yCAAyC;AACzC,eAAO,MAAM,0BAA0B,GACnC,OAAO,gBAAgB,CAAC,OAAO,CAAC,YAAY,EAAE;IAAE,IAAI,EAAE,kBAAkB,CAAA;CAAE,CAAC,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAK1E,CAAC;AAEP,sEAAsE;AACtE,eAAO,MAAM,qBAAqB,GAAI,OAAO,gBAAgB,CAAC,OAAO,CAAC,YAAY,EAAE;IAAE,IAAI,EAAE,YAAY,CAAA;CAAE,CAAC,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;CAItG,CAAC;AAEP,mCAAmC;AACnC,eAAO,MAAM,oBAAoB,GAAI,OAAO,gBAAgB,CAAC,OAAO,CAAC,YAAY,EAAE;IAAE,IAAI,EAAE,YAAY,CAAA;CAAE,CAAC,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAIrG,CAAC;AAEP,gDAAgD;AAChD,eAAO,MAAM,gCAAgC,GACzC,OAAO,gBAAgB,CAAC,OAAO,CAAC,YAAY,EAAE;IAAE,IAAI,EAAE,yBAAyB,CAAA;CAAE,CAAC,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAKjF,CAAC"}
1
+ {"version":3,"file":"builders.d.ts","sourceRoot":"","sources":["../src/builders.ts"],"names":[],"mappings":"AACA,OAAO,EAGH,KAAK,YAAY,EAKpB,MAAM,mBAAmB,CAAC;AAE3B,MAAM,MAAM,gBAAgB,CAAC,OAAO,SAAS,YAAY,IAAI,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,GAAG;IACjF,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;CACnC,CAAC;AAEF,+EAA+E;AAC/E,eAAO,MAAM,2BAA2B,GACpC,OAAO,gBAAgB,CAAC,OAAO,CAAC,YAAY,EAAE;IAAE,IAAI,EAAE,mBAAmB,CAAA;CAAE,CAAC,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAM3E,CAAC;AAEP,yCAAyC;AACzC,eAAO,MAAM,0BAA0B,GACnC,OAAO,gBAAgB,CAAC,OAAO,CAAC,YAAY,EAAE;IAAE,IAAI,EAAE,kBAAkB,CAAA;CAAE,CAAC,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAK1E,CAAC;AAEP,sEAAsE;AACtE,eAAO,MAAM,qBAAqB,GAAI,OAAO,gBAAgB,CAAC,OAAO,CAAC,YAAY,EAAE;IAAE,IAAI,EAAE,YAAY,CAAA;CAAE,CAAC,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;CAItG,CAAC;AAEP,mCAAmC;AACnC,eAAO,MAAM,oBAAoB,GAAI,OAAO,gBAAgB,CAAC,OAAO,CAAC,YAAY,EAAE;IAAE,IAAI,EAAE,YAAY,CAAA;CAAE,CAAC,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAIrG,CAAC;AAEP,oCAAoC;AACpC,eAAO,MAAM,qBAAqB,GAAI,OAAO,gBAAgB,CAAC,OAAO,CAAC,YAAY,EAAE;IAAE,IAAI,EAAE,aAAa,CAAA;CAAE,CAAC,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAQvG,CAAC;AAEP,gDAAgD;AAChD,eAAO,MAAM,gCAAgC,GACzC,OAAO,gBAAgB,CAAC,OAAO,CAAC,YAAY,EAAE;IAAE,IAAI,EAAE,yBAAyB,CAAA;CAAE,CAAC,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAKjF,CAAC"}
package/dist/builders.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as v from 'valibot';
2
- import { ChangeLogRecordSchema, CorrectionRecordSchema, OperatorDecisionRecordSchema, StripDecisionRevertedRecordSchema, ValidatorResultRecordSchema, } from "./schema/entry.js";
2
+ import { ChangeLogRecordSchema, CorrectionRecordSchema, OperatorDecisionRecordSchema, StageWriteRecordSchema, StripDecisionRevertedRecordSchema, ValidatorResultRecordSchema, } from "./schema/entry.js";
3
3
  /** Build an `operator-decision` record with a validated structured payload. */
4
4
  export const buildOperatorDecisionRecord = (input) => v.parse(OperatorDecisionRecordSchema, {
5
5
  ...input,
@@ -21,6 +21,15 @@ export const buildChangeLogRecord = (input) => v.parse(ChangeLogRecordSchema, {
21
21
  ...input,
22
22
  kind: 'change-log',
23
23
  });
24
+ /** Build a `stage-write` record. */
25
+ export const buildStageWriteRecord = (input) => v.parse(StageWriteRecordSchema, {
26
+ ...input,
27
+ kind: 'stage-write',
28
+ links: {
29
+ ...(input.links ?? {}),
30
+ affectedFiles: [...new Set([...(input.links?.affectedFiles ?? []), input.filePath])],
31
+ },
32
+ });
24
33
  /** Build a `strip-decision-reverted` record. */
25
34
  export const buildStripDecisionRevertedRecord = (input) => v.parse(StripDecisionRevertedRecordSchema, {
26
35
  ...input,
package/dist/cli.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AA2DA,KAAK,UAAU,GAAG;IACd,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,cAAc,EAAE;QACrB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;KAC5B,CAAC;IACF,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC,cAAc,GAAG,aAAa,CAAC,UAAU,GAAG,MAAM,CAAC,CAAC;IAC3E,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,cAAc,CAAC;IACvC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,cAAc,CAAC;CAC1C,CAAC;AA29BF,eAAO,MAAM,YAAY,GAAU,MAAM,SAAS,MAAM,EAAE,EAAE,UAAS,OAAO,CAAC,UAAU,CAAM,KAAG,OAAO,CAAC,MAAM,CAqC7G,CAAC;AAEF,eAAO,MAAM,IAAI,GAAU,OAAM,SAAS,MAAM,EAA0B,KAAG,OAAO,CAAC,MAAM,CAE1F,CAAC"}
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AA6DA,KAAK,UAAU,GAAG;IACd,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,cAAc,EAAE;QACrB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;KAC5B,CAAC;IACF,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC,cAAc,GAAG,aAAa,CAAC,UAAU,GAAG,MAAM,CAAC,CAAC;IAC3E,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,cAAc,CAAC;IACvC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,cAAc,CAAC;CAC1C,CAAC;AAsjCF,eAAO,MAAM,YAAY,GAAU,MAAM,SAAS,MAAM,EAAE,EAAE,UAAS,OAAO,CAAC,UAAU,CAAM,KAAG,OAAO,CAAC,MAAM,CAqC7G,CAAC;AAEF,eAAO,MAAM,IAAI,GAAU,OAAM,SAAS,MAAM,EAA0B,KAAG,OAAO,CAAC,MAAM,CAE1F,CAAC"}
package/dist/cli.js CHANGED
@@ -9,7 +9,7 @@ import * as v from 'valibot';
9
9
  import { readPatchTextFromFile } from "./blobs.js";
10
10
  import { openLedger } from "./handle.js";
11
11
  import { deriveFilesChangedFromPatch } from "./patch-resolver.js";
12
- import { ChangeLogParityStatusSchema, ChangeLogSmokeResultSchema, ChangeLogSubkindSchema, LEDGER_KINDS, LEDGER_PHASES, parseLedgerRecord, WorkspaceRelativePathSchema, } from "./schema/entry.js";
12
+ import { ChangeLogParityStatusSchema, ChangeLogSmokeResultSchema, ChangeLogSubkindSchema, LEDGER_KINDS, LEDGER_PHASES, STAGE_WRITE_STAGES, parseLedgerRecord, WorkspaceRelativePathSchema, } from "./schema/entry.js";
13
13
  import { NoteSubkindSchema } from "./schema/note.js";
14
14
  import { LEDGER_LIBRARY_VERSION } from "./version.js";
15
15
  const execFileAsync = promisify(execFile);
@@ -38,7 +38,8 @@ const CHANGE_LOG_RECORD_ONLY_FLAGS = [
38
38
  'smoke-result',
39
39
  'subkind',
40
40
  ];
41
- const renderRecordUsage = (commandName) => `${commandName} record [--workspace=<ws>] --kind=<kind> --phase=<phase> --summary="..." [--rationale="..."] [--action=<operator-action>] [--check-id=<check-id>] [--diff=<patch-file>] [--diff-from-git=<ref>] [--git-paths=<csv>] [--git-diff-timeout-ms=<ms>] [--git-diff-max-buffer-bytes=<bytes>] [--idempotency-key=<key>] [--subkind=<change-log-subkind>] [--files-changed=<csv>] [--hypothesis="..."] [--commands="cmd1\ncmd2" | --commands-from=<file>] [--smoke-result=<result>] [--smoke-notes="..."] [--parity-status=<status>] [--rollback-plan="..."] [--rolls-back=<entry-id>] [--from-stdin]`;
41
+ const STAGE_WRITE_ONLY_FLAGS = ['file-path', 'stage'];
42
+ const renderRecordUsage = (commandName) => `${commandName} record [--workspace=<ws>] --kind=<kind> --phase=<phase> --summary="..." [--rationale="..."] [--file-path=<path>] [--stage=<stage>] [--action=<operator-action>] [--check-id=<check-id>] [--diff=<patch-file>] [--diff-from-git=<ref>] [--git-paths=<csv>] [--git-diff-timeout-ms=<ms>] [--git-diff-max-buffer-bytes=<bytes>] [--idempotency-key=<key>] [--subkind=<change-log-subkind>] [--files-changed=<csv>] [--hypothesis="..."] [--commands="cmd1\ncmd2" | --commands-from=<file>] [--smoke-result=<result>] [--smoke-notes="..."] [--parity-status=<status>] [--rollback-plan="..."] [--rolls-back=<entry-id>] [--from-stdin]`;
42
43
  class CliUsageError extends Error {
43
44
  }
44
45
  const DEFAULT_CONTEXT = {
@@ -54,6 +55,7 @@ const DEFAULT_CONTEXT = {
54
55
  const renderValidValues = () => `Valid values:
55
56
  kinds: ${LEDGER_KINDS.join(', ')}
56
57
  phases: ${LEDGER_PHASES.join(', ')}
58
+ stage-write stages: ${STAGE_WRITE_STAGES.join(', ')}
57
59
  note subkinds: ${NoteSubkindSchema.options.join(', ')}
58
60
  render targets: ${RENDER_TARGETS.join(', ')}
59
61
  `;
@@ -64,6 +66,8 @@ const renderRuntimeTuningHelp = () => `Runtime tuning env vars:
64
66
  USHMAN_LEDGER_READ_INDEX_REBUILD_CONCURRENCY (default: USHMAN_LEDGER_SCAN_CONCURRENCY)
65
67
  USHMAN_LEDGER_COVERAGE_FILE_STAT_CONCURRENCY (default: USHMAN_LEDGER_SCAN_CONCURRENCY)
66
68
  USHMAN_LEDGER_BLOB_HASH_CONCURRENCY (default: USHMAN_LEDGER_SCAN_CONCURRENCY)
69
+ USHMAN_LEDGER_DOCTOR_CHECKPOINT_MAX_AGE_MS (default: 86400000)
70
+ USHMAN_LEDGER_DOCTOR_OPEN_ISSUE_MAX_AGE_MS (default: 2592000000)
67
71
  USHMAN_LEDGER_MAX_PATCH_BYTES (default: 10485760)
68
72
  `;
69
73
  const renderHelp = (commandName) => `${commandName}
@@ -213,6 +217,18 @@ const parseWorkspaceRelativePathCsv = ({ flagName, raw }) => {
213
217
  }
214
218
  return uniquePaths;
215
219
  };
220
+ const parseWorkspaceRelativePathFlag = ({ flagName, flags, required = false, }) => {
221
+ const raw = required ? getRequiredString(flags, flagName) : getFlag(flags, flagName);
222
+ if (!raw) {
223
+ return undefined;
224
+ }
225
+ try {
226
+ return v.parse(WorkspaceRelativePathSchema, raw);
227
+ }
228
+ catch {
229
+ throw new CliUsageError(`--${flagName} path is not a normalized workspace-relative path: ${raw}`);
230
+ }
231
+ };
216
232
  const isGitDiffMaxBufferError = (error) => {
217
233
  const code = getErrorCode(error);
218
234
  if (code === 'ERR_CHILD_PROCESS_STDIO_MAXBUFFER') {
@@ -350,6 +366,13 @@ const parseRenderTarget = (flags) => {
350
366
  }
351
367
  return target;
352
368
  };
369
+ const parseRequiredStageWriteStage = (flags) => {
370
+ const stage = getRequiredString(flags, 'stage');
371
+ if (!STAGE_WRITE_STAGES.includes(stage)) {
372
+ throw new CliUsageError(`Invalid --stage value: ${stage}. Expected one of: ${STAGE_WRITE_STAGES.join(', ')}.`);
373
+ }
374
+ return stage;
375
+ };
353
376
  const splitCommandLines = (value) => value
354
377
  .split(/\r?\n/u)
355
378
  .map((command) => command.trim())
@@ -500,11 +523,13 @@ const validateRecordStdinFlags = (flags) => {
500
523
  'operator',
501
524
  'parity-status',
502
525
  'phase',
526
+ 'file-path',
503
527
  'rationale',
504
528
  'rollback-plan',
505
529
  'rolls-back',
506
530
  'smoke-notes',
507
531
  'smoke-result',
532
+ 'stage',
508
533
  'subkind',
509
534
  'summary',
510
535
  ].filter((flagName) => hasFlag(flags, flagName));
@@ -515,53 +540,87 @@ const validateRecordStdinFlags = (flags) => {
515
540
  .map((flagName) => `--${flagName}`)
516
541
  .join(', ')}. When using --from-stdin, provide all record fields in the JSON input.`);
517
542
  };
518
- const buildBaseRecordFromFlags = (parsed, context) => {
519
- const kind = getRequiredKind(parsed.flags);
520
- if (kind !== 'change-log') {
521
- rejectUnsupportedFlags('change-log', parsed.flags, CHANGE_LOG_RECORD_ONLY_FLAGS);
543
+ const applyRationaleFlag = ({ flags, kind, record, }) => {
544
+ const rationale = getFlag(flags, 'rationale');
545
+ if (!rationale) {
546
+ return rationale;
522
547
  }
523
- const record = {
524
- emitter: {
525
- tool: context.defaultEmitter.tool,
526
- version: context.defaultEmitter.version,
527
- },
528
- kind,
529
- phase: getRequiredPhase(parsed.flags),
530
- summary: getRequiredString(parsed.flags, 'summary'),
531
- };
532
- const rationale = getFlag(parsed.flags, 'rationale');
533
- if (rationale) {
534
- if (kind !== 'agent-patch' &&
535
- kind !== 'operator-patch' &&
536
- kind !== 'operator-decision' &&
537
- kind !== 'correction') {
538
- throw new CliUsageError('--rationale is only supported for patch, operator-decision, and correction records.');
539
- }
540
- if (kind !== 'operator-decision') {
541
- record.rationale = rationale;
542
- }
548
+ if (kind !== 'agent-patch' &&
549
+ kind !== 'operator-patch' &&
550
+ kind !== 'operator-decision' &&
551
+ kind !== 'correction' &&
552
+ kind !== 'stage-write') {
553
+ throw new CliUsageError('--rationale is only supported for patch, stage-write, operator-decision, and correction records.');
543
554
  }
555
+ if (kind !== 'operator-decision') {
556
+ record.rationale = rationale;
557
+ }
558
+ return rationale;
559
+ };
560
+ const applyKindSpecificRecordFields = ({ defaultTool, flags, kind, rationale, record, }) => {
544
561
  if (kind === 'agent-patch') {
545
562
  record.agent = {
546
- name: getFlag(parsed.flags, 'agent') ?? context.defaultEmitter.tool,
563
+ name: getFlag(flags, 'agent') ?? defaultTool,
547
564
  };
565
+ return;
548
566
  }
549
567
  if (kind === 'operator-patch') {
550
568
  record.operator = {
551
- name: getFlag(parsed.flags, 'operator') ?? context.defaultEmitter.tool,
569
+ name: getFlag(flags, 'operator') ?? defaultTool,
552
570
  };
571
+ return;
553
572
  }
554
573
  if (kind === 'operator-decision') {
555
- const action = getRequiredString(parsed.flags, 'action');
556
574
  record.payload = {
557
- action,
558
- checkId: getFlag(parsed.flags, 'check-id'),
575
+ action: getRequiredString(flags, 'action'),
576
+ checkId: getFlag(flags, 'check-id'),
559
577
  rationale: rationale ?? '',
560
578
  };
579
+ return;
561
580
  }
562
581
  if (kind === 'change-log') {
563
- record.subkind = parseRequiredChangeLogSubkind(parsed.flags);
582
+ record.subkind = parseRequiredChangeLogSubkind(flags);
583
+ return;
584
+ }
585
+ if (kind === 'stage-write') {
586
+ record.filePath = parseWorkspaceRelativePathFlag({
587
+ flagName: 'file-path',
588
+ flags,
589
+ required: true,
590
+ });
591
+ record.rationale = getRequiredString(flags, 'rationale');
592
+ record.stage = parseRequiredStageWriteStage(flags);
593
+ }
594
+ };
595
+ const buildBaseRecordFromFlags = (parsed, context) => {
596
+ const kind = getRequiredKind(parsed.flags);
597
+ if (kind !== 'change-log') {
598
+ rejectUnsupportedFlags('change-log', parsed.flags, CHANGE_LOG_RECORD_ONLY_FLAGS);
599
+ }
600
+ if (kind !== 'stage-write') {
601
+ rejectUnsupportedFlags('stage-write', parsed.flags, STAGE_WRITE_ONLY_FLAGS);
564
602
  }
603
+ const record = {
604
+ emitter: {
605
+ tool: context.defaultEmitter.tool,
606
+ version: context.defaultEmitter.version,
607
+ },
608
+ kind,
609
+ phase: getRequiredPhase(parsed.flags),
610
+ summary: getRequiredString(parsed.flags, 'summary'),
611
+ };
612
+ const rationale = applyRationaleFlag({
613
+ flags: parsed.flags,
614
+ kind,
615
+ record,
616
+ });
617
+ applyKindSpecificRecordFields({
618
+ defaultTool: context.defaultEmitter.tool,
619
+ flags: parsed.flags,
620
+ kind,
621
+ rationale,
622
+ record,
623
+ });
565
624
  const idempotencyKey = getFlag(parsed.flags, 'idempotency-key');
566
625
  if (idempotencyKey) {
567
626
  record.idempotencyKey = idempotencyKey;
package/dist/doctor.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { type PreparedLedgerState } from './recovery.ts';
2
- export declare const DOCTOR_FINDING_CODES: readonly ["blob-corrupt", "blob-missing", "blob-unreadable", "change-log-rollback-missing-target", "change-log-smoke-failure-missing-rollback-plan", "manifest-entry-count-mismatch", "manifest-entry-location-missing", "manifest-entry-missing-on-disk", "manifest-last-sequence-mismatch", "manifest-per-phase-latest-mismatch", "manifest-phase-mismatch", "manifest-sequence-mismatch", "open-issue-stale", "phase-prev-entry-mismatch", "pre-change-checkpoint-stale", "read-failure"];
2
+ export declare const DOCTOR_FINDING_CODES: readonly ["blob-corrupt", "blob-missing", "blob-unreadable", "change-log-rollback-missing-target", "change-log-smoke-failure-missing-rollback-plan", "manifest-entry-count-mismatch", "manifest-entry-location-missing", "manifest-entry-missing-on-disk", "manifest-last-sequence-mismatch", "manifest-per-phase-latest-mismatch", "manifest-phase-mismatch", "manifest-sequence-mismatch", "open-issue-stale", "pending-commit-quarantined", "phase-prev-entry-mismatch", "pre-change-checkpoint-stale", "read-failure"];
3
3
  export type DoctorFindingCode = (typeof DOCTOR_FINDING_CODES)[number];
4
4
  export type DoctorFindingMetadataValue = boolean | null | number | string;
5
5
  export type DoctorFinding = {
@@ -1 +1 @@
1
- {"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../src/doctor.ts"],"names":[],"mappings":"AAMA,OAAO,EAAmB,KAAK,mBAAmB,EAAE,MAAM,eAAe,CAAC;AAS1E,eAAO,MAAM,oBAAoB,8dAiBvB,CAAC;AAEX,MAAM,MAAM,iBAAiB,GAAG,CAAC,OAAO,oBAAoB,CAAC,CAAC,MAAM,CAAC,CAAC;AACtE,MAAM,MAAM,0BAA0B,GAAG,OAAO,GAAG,IAAI,GAAG,MAAM,GAAG,MAAM,CAAC;AAE1E,MAAM,MAAM,aAAa,GAAG;IACxB,QAAQ,CAAC,IAAI,EAAE,iBAAiB,CAAC;IACjC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,0BAA0B,CAAC,CAAC;IAC/D,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;CAChC,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IACvB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,QAAQ,EAAE,aAAa,EAAE,CAAC;IACnC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC;IAC1B,QAAQ,CAAC,EAAE,EAAE,OAAO,CAAC;CACxB,CAAC;AAqjBF,eAAO,MAAM,eAAe,GACxB,eAAe,MAAM,EACrB,UAAS;IAAE,QAAQ,CAAC,WAAW,CAAC,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,mBAAmB,CAAA;CAAO,KACvF,OAAO,CAAC,YAAY,CAqCtB,CAAC"}
1
+ {"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../src/doctor.ts"],"names":[],"mappings":"AAMA,OAAO,EAAiD,KAAK,mBAAmB,EAAE,MAAM,eAAe,CAAC;AAUxG,eAAO,MAAM,oBAAoB,4fAkBvB,CAAC;AAEX,MAAM,MAAM,iBAAiB,GAAG,CAAC,OAAO,oBAAoB,CAAC,CAAC,MAAM,CAAC,CAAC;AACtE,MAAM,MAAM,0BAA0B,GAAG,OAAO,GAAG,IAAI,GAAG,MAAM,GAAG,MAAM,CAAC;AAE1E,MAAM,MAAM,aAAa,GAAG;IACxB,QAAQ,CAAC,IAAI,EAAE,iBAAiB,CAAC;IACjC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,0BAA0B,CAAC,CAAC;IAC/D,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;CAChC,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IACvB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,QAAQ,EAAE,aAAa,EAAE,CAAC;IACnC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC;IAC1B,QAAQ,CAAC,EAAE,EAAE,OAAO,CAAC;CACxB,CAAC;AAwlBF,eAAO,MAAM,eAAe,GACxB,eAAe,MAAM,EACrB,UAAS;IAAE,QAAQ,CAAC,WAAW,CAAC,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,mBAAmB,CAAA;CAAO,KACvF,OAAO,CAAC,YAAY,CAsCtB,CAAC"}