wowbagger 0.1.0-alpha.14 → 0.1.0-alpha.17

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.
package/CHANGELOG.md CHANGED
@@ -7,6 +7,55 @@ consolidation. The first tagged release inherits this file.
7
7
 
8
8
  ## Unreleased
9
9
 
10
+ ## 0.1.0-alpha.17 - 2026-08-30
11
+
12
+ - **Breaking:** raise the supported Node.js floor from 20 to 24. Node 20 and
13
+ Node 22 no longer satisfy `engines.node`; Node 26 remains outside the
14
+ supported matrix because of the separate Vitest incompatibility reported by
15
+ Lee.
16
+
17
+ The alpha.14 hard cutover remains the baseline: `claim-store-unavailable`
18
+ answers **The durable claim store is unavailable.** with
19
+ `claim-store-unreadable`; upgrade every writer before the first alpha.14 create.
20
+ There is no automatic migration or mixed-version grace period. There is no
21
+ batch mutation, the create-then-commit loop remains supported, item #186 owns
22
+ batch design, and item #182 owns existing duplicate numbers. The fence adds no
23
+ new Git roster or history traversal and costs two extra fsync'd journal appends
24
+ within the 65,536-entry limit.
25
+
26
+
27
+ ## 0.1.0-alpha.16 - 2026-08-30
28
+
29
+ - Added `version-drift --json` to detect stale installed skill pins, core
30
+ contract versions, and package provenance before ledger mutation.
31
+
32
+ The alpha.14 hard cutover remains the baseline: `claim-store-unavailable`
33
+ answers **The durable claim store is unavailable.** with
34
+ `claim-store-unreadable`; upgrade every writer before the first alpha.14
35
+ create. There is no automatic migration or mixed-version grace period. There is
36
+ no batch mutation, the create-then-commit loop remains supported, item #186 owns
37
+ batch design, and item #182 owns existing duplicate numbers. The fence adds no
38
+ new Git roster or history traversal and costs two extra fsync'd journal appends
39
+ within the 65,536-entry limit.
40
+
41
+ ## 0.1.0-alpha.15 - 2026-08-30
42
+
43
+ - **Duplicate-number recovery now has a separate `ledger-repair` contract
44
+ version 1.** Use the read-only `number-repair-proposal` command to review a
45
+ complete mapping, then apply it with `number-repair`. The repair path requires
46
+ duplicate-number errors to be the complete validation failure, preserves ULID
47
+ identities and relation values, uses the shared namespace fence, records
48
+ durable intent/final entries, and supports bounded auto-commit recovery.
49
+
50
+ The alpha.14 hard cutover remains the baseline: `claim-store-unavailable`
51
+ answers **The durable claim store is unavailable.** with
52
+ `claim-store-unreadable`; upgrade every writer before the first alpha.14
53
+ create. There is no automatic migration or mixed-version grace period. There is
54
+ no batch mutation, the create-then-commit loop remains supported, item #186 owns
55
+ batch design, and item #182 owns existing duplicate numbers.
56
+ The fence adds no new Git roster or history traversal and costs two extra
57
+ fsync'd journal appends within the 65,536-entry limit.
58
+
10
59
  ## 0.1.0-alpha.14 - 2026-08-29
11
60
 
12
61
  ### Changed
package/README.md CHANGED
@@ -30,8 +30,8 @@ agent to use those guarantees instead of hand-editing your Markdown.
30
30
 
31
31
  **Start here:** [install the core and set up a ledger](#start-here).
32
32
 
33
- > **Status: alpha, published, and self-hosted.** `0.1.0-alpha.14` is on npm under
34
- > the `next` tag and on this repository's `v0.1.0-alpha.14` tag. It is the
33
+ > **Status: alpha, published, and self-hosted.** `0.1.0-alpha.17` is on npm under
34
+ > the `next` tag and on this repository's `v0.1.0-alpha.17` tag. It is the
35
35
  > version this repository runs its own backlog on. The API is not frozen and the
36
36
  > version will move before a stable release.
37
37
  >
@@ -77,7 +77,7 @@ Wowbagger is the core authority for a Git-native work ledger. Use it instead
77
77
  of editing ledger Markdown by hand.
78
78
 
79
79
  ```sh
80
- wowbagger --version # require 0.1.0-alpha.14
80
+ wowbagger --version # require 0.1.0-alpha.17
81
81
  wowbagger capabilities --json # require contract_version: 5
82
82
  wowbagger validate --ledger ledger --json
83
83
  wowbagger ready --ledger ledger --as-of YYYY-MM-DD --json
@@ -103,10 +103,10 @@ cooperating writers; they are not exclusive locks.
103
103
  Install the core CLI, then verify it. The core requires Node.js 20 or later:
104
104
 
105
105
  ```sh
106
- npm install -g wowbagger@0.1.0-alpha.14 # exact plugin-matched release
106
+ npm install -g wowbagger@0.1.0-alpha.17 # exact plugin-matched release
107
107
  # or, from this release's Git tag:
108
- # npm install -g github:lstutzman/wowbagger#v0.1.0-alpha.14
109
- wowbagger --version # 0.1.0-alpha.14
108
+ # npm install -g github:lstutzman/wowbagger#v0.1.0-alpha.17
109
+ wowbagger --version # 0.1.0-alpha.17
110
110
  wowbagger capabilities --json # must report contract_version: 5
111
111
  ```
112
112
 
@@ -325,7 +325,7 @@ two supported install routes:
325
325
  registry requires a `latest` tag), so a bare install resolves to the same
326
326
  bytes.
327
327
  - **git tag** —
328
- `npm install -g github:lstutzman/wowbagger#v0.1.0-alpha.14` installs this
328
+ `npm install -g github:lstutzman/wowbagger#v0.1.0-alpha.17` installs this
329
329
  release. Installing at a ref installs the core and every adapter that ref
330
330
  carries.
331
331
 
@@ -397,7 +397,7 @@ Upgrade the pieces you installed:
397
397
 
398
398
  ```sh
399
399
  npm install -g wowbagger@next # public npm registry
400
- npm install -g github:lstutzman/wowbagger#v0.1.0-alpha.14 # immutable Git release
400
+ npm install -g github:lstutzman/wowbagger#v0.1.0-alpha.17 # immutable Git release
401
401
  git pull && npm ci # or: a direct checkout
402
402
  ```
403
403
 
@@ -445,6 +445,16 @@ core, these are the changes most likely to touch you:
445
445
  `create` and refuses a caller-supplied one; `patch` refuses it because it is
446
446
  immutable identity. Keep a legacy identifier in a declared extension member or
447
447
  in the item body.
448
+
449
+ - **Repair duplicate numbers through `ledger-repair` version 1.** Generate a
450
+ read-only proposal with `number-repair-proposal`, review every
451
+ `expected_revision` and `replacement_number`, then apply the complete mapping
452
+ with `number-repair`. The command preserves ULID identities and relations and
453
+ does not change core contract version 5.
454
+
455
+ - **Run `version-drift --json` before mutation.** It compares the installed
456
+ skill pin, required core contract, and running core, and names the stale
457
+ package, plugin cache, or linked checkout with remediation.
448
458
  - **Delete your local ULID generator.** `wowbagger mint-id --json` prints a
449
459
  canonical ID; `--date YYYY-MM-DD` selects the creation date the ID must
450
460
  encode.
@@ -1171,18 +1181,20 @@ the finding as a ledger item rather than leaving it in a transcript.
1171
1181
 
1172
1182
  ### The verification gate
1173
1183
 
1174
- Four commands. All four must pass, and the test commands run on **both** the
1175
- current Node runtime and Node 20:
1184
+ Four commands. All four must pass, and the test commands run on **Node 24.20.0**:
1176
1185
 
1177
1186
  ```sh
1178
- TMPDIR=/tmp node --test test/*.test.js
1179
- TMPDIR=/tmp /opt/homebrew/opt/node@20/bin/node --test test/*.test.js
1180
- TMPDIR=/tmp node spec/run-adapter-implementation.js
1181
- node bin/wowbagger.js validate --ledger ledger --json
1187
+ TMPDIR=/tmp /opt/homebrew/opt/node@24/bin/node --test test/*.test.js
1188
+ TMPDIR=/tmp /opt/homebrew/opt/node@24/bin/node --pending-deprecation --throw-deprecation --test test/*.test.js
1189
+ TMPDIR=/tmp /opt/homebrew/opt/node@24/bin/node spec/run-adapter-implementation.js
1190
+ TMPDIR=/tmp /opt/homebrew/opt/node@24/bin/node bin/wowbagger.js validate --ledger ledger --json
1182
1191
  ```
1183
1192
 
1184
1193
  `TMPDIR=/tmp` is not optional: the default macOS temporary path makes the claim
1185
- lock socket path too long. Substitute your own Node 20 binary path.
1194
+ lock socket path too long. Use an explicit Node 24.20.0 binary path.
1195
+
1196
+ The supported runtime matrix is Node 24.20.0. Node 26 remains excluded until
1197
+ the separate Vitest incompatibility reported by Lee is resolved.
1186
1198
 
1187
1199
  `npm test`, `npm audit --omit=dev`, and `git diff --check` are useful alongside
1188
1200
  it; they are not a substitute for the four commands above.
@@ -26,10 +26,13 @@ shell: an absolute Node executable, the absolute `wowbagger.js` the package
26
26
  installed, an argument array, and `shell: false`. Neither path is discovered by
27
27
  searching a global npm directory, and neither is a platform command shim.
28
28
 
29
- Wowbagger requires Node.js 20 or later. The package declares that floor in
29
+ Wowbagger requires Node.js 24 or later. The package declares that floor in
30
30
  `engines.node`, and the launch seam exports it as `MINIMUM_NODE_MAJOR` for a
31
31
  host that resolves its own runtime instead of reusing the one it is running on.
32
32
 
33
+ The supported release matrix is Node 24.20.0. Node 26 is excluded until the
34
+ separate Vitest incompatibility reported by Lee is resolved.
35
+
33
36
  ~~~js
34
37
  import { resolveCoreLaunch } from 'wowbagger';
35
38
 
@@ -258,6 +261,9 @@ not a fetch URL.
258
261
  | `bare-ready-result.json` | bare result | a `ready` success |
259
262
  | `ledger-mutation-refusal.json` | ledger-mutation 1 | the legacy-write fence refusals |
260
263
  | `report-config-v1.json` | report config 1 | `<ledger>/.wowbagger/report.json` at version 1 |
264
+ | `ledger-repair-request.json` | ledger-repair 1 | the strict `number-repair` request |
265
+ | `ledger-repair-proposal.json` | ledger-repair 1 | the read-only `number-repair-proposal` result |
266
+ | `ledger-repair-response.json` | ledger-repair 1 | every `number-repair-proposal` and `number-repair` response |
261
267
  | `report-config-v2.json` | report config 2 | the same file at version 2, which names views |
262
268
 
263
269
  Every schema fixes its root members exactly and pins the version of its own
@@ -376,6 +376,7 @@ answer in two domains.
376
376
  | work-claim | `work-claim` | 1, the legacy envelope marker | `result.operations.work_claim.api_version` of `claim capabilities --json` |
377
377
  | ledger-publication | `ledger-publication` | 1, the legacy envelope marker | the same work-claim `api_version` |
378
378
  | ledger-mutation | `ledger-mutation` | 1, the legacy envelope marker | the same work-claim `api_version` |
379
+ | ledger-repair | `ledger-repair` | 1 | `contract_version` of `number-repair-proposal` or `number-repair` |
379
380
  | bare result | absent, and no `ok` member either | none | none |
380
381
 
381
382
  The rule has three steps:
@@ -401,6 +402,7 @@ legacy claim-envelope marker, and a consumer must never compare it with the core
401
402
  | `inspect` | core | core |
402
403
  | `list` | core | core |
403
404
  | `mint-id` | core | core |
405
+ | `version-drift` | core | core |
404
406
  | `report` | core | core |
405
407
  | `create` | core | core, or ledger-mutation when the claim fence refuses |
406
408
  | `transition` | core | core, or ledger-mutation when the claim fence refuses |
@@ -415,7 +417,8 @@ legacy claim-envelope marker, and a consumer must never compare it with the core
415
417
  | `claim-sync` | work-claim | work-claim |
416
418
  | `claim-adopt` | work-claim | work-claim |
417
419
  | `mutation-finalize` | work-claim | work-claim |
418
- | `claim verify` | ledger-publication, `command: "read"` | ledger-publication |
420
+ | `number-repair-proposal` | ledger-repair | ledger-repair |
421
+ | `number-repair` | ledger-repair | ledger-repair |
419
422
  | `publish-claimed` | ledger-publication | ledger-publication |
420
423
 
421
424
  **Exact root members**
@@ -1600,10 +1603,16 @@ A create has no authorized predecessor, so Git `HEAD` is the only surface that
1600
1603
  can carry its authorized bytes, and an uncommitted create raises the global
1601
1604
  `git-finalization-required` barrier for every later mutation. Commit each
1602
1605
  created item before the next mutating command. This release adds no batch
1603
- mutation; the supported bulk pattern is the create-then-commit loop, and item
1604
- #186 owns safe batch design. A ledger that already carries duplicate numbers is
1605
- item #182's recovery work: it fails validation and refuses every mutation
1606
- before allocation, and nothing here renumbers it.
1606
+ mutation; the supported bulk pattern remains the create-then-commit loop.
1607
+ A ledger that already carries duplicate numbers is item #182 recovery work and
1608
+ is repaired through the separate `ledger-repair` contract, not through core
1609
+ version 5 mutation. Run
1610
+ `number-repair-proposal --ledger <dir> --json`, review the complete mapping, then
1611
+ run `number-repair --ledger <dir> --input <repair.json> --json`. The repair
1612
+ command operates only when duplicate-number errors are the complete validation
1613
+ failure, preserves ULID identities and relation values, and publishes all
1614
+ affected items under the shared namespace fence. Arbitrary hand edits remain
1615
+ unsupported because they can damage IDs, paths, or references.
1607
1616
 
1608
1617
  **What this guarantees, and what it does not.** The fence closes the reported
1609
1618
  PropertyCompass2 collision: cooperating alpha.14 worktrees of one clone that
@@ -477,16 +477,14 @@ intent and one committed terminal, so with no other activity the
477
477
  ceiling. Capacity is checked before publication and fails closed. Journal
478
478
  compaction is not part of this change.
479
479
 
480
- **A ledger that already carries duplicate numbers is item #182's recovery
481
- work, not this fix's.** Such a ledger fails validation and refuses every
482
- mutation before allocation, and item #182 owns the fenced repair. #181 prevents
483
- new collisions in every valid ledger; it neither renumbers damaged items nor
484
- makes an invalid ledger worse. Editing `number` in the item source by hand,
485
- committing it, and then running `claim-adopt` is **not a supported
486
- workaround**: one field deployment did exactly that as an emergency
487
- intervention during an outage, and it bypasses the number-collision and
488
- reference checks every mutation performs, so it can leave dangling
489
- `depends_on`, `related`, and parent references that nothing reports.
480
+ A ledger that already carries duplicate numbers is item #182 recovery work and
481
+ is repaired through the separate `ledger-repair` contract, not through claim
482
+ operations. Run `number-repair-proposal --ledger <dir> --json`, review the
483
+ complete mapping, then run `number-repair --ledger <dir> --input <repair.json>
484
+ --json`. The repair command runs only when duplicate-number errors are the
485
+ complete validation failure, preserves ULID identities and relation values, and
486
+ publishes all affected items under the shared namespace fence. Arbitrary hand
487
+ edits remain unsupported because they can damage IDs, paths, or references.
490
488
 
491
489
  **What alpha.14 guarantees, and what it does not.** Alpha.14 closes the
492
490
  reported PropertyCompass2 collision: cooperating alpha.14 worktrees of one
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wowbagger",
3
- "version": "0.1.0-alpha.14",
3
+ "version": "0.1.0-alpha.17",
4
4
  "description": "Git-native work ledger for coding agents: deterministic ready queues, guarded CAS mutations, claims and fencing, and self-contained HTML reports.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -30,7 +30,7 @@
30
30
  "cli"
31
31
  ],
32
32
  "engines": {
33
- "node": ">=20"
33
+ "node": ">=24"
34
34
  },
35
35
  "bin": {
36
36
  "wowbagger": "bin/wowbagger.js"
@@ -25,7 +25,8 @@
25
25
  "inspect",
26
26
  "list",
27
27
  "mint-id",
28
- "report"
28
+ "report",
29
+ "version-drift"
29
30
  ]
30
31
  },
31
32
  "contract_version": {
@@ -55,8 +56,8 @@
55
56
  "capabilities",
56
57
  "inspect",
57
58
  "list",
58
- "mint-id",
59
- "report"
59
+ "report",
60
+ "version-drift"
60
61
  ]
61
62
  },
62
63
  "contract_version": {
@@ -92,6 +92,24 @@
92
92
  "version": 1,
93
93
  "summary": "Legacy-write fence refusals in the ledger-mutation namespace."
94
94
  },
95
+ {
96
+ "file": "ledger-repair-proposal.json",
97
+ "domain": "ledger-repair",
98
+ "version": 1,
99
+ "summary": "The read-only duplicate-number repair proposal result."
100
+ },
101
+ {
102
+ "file": "ledger-repair-request.json",
103
+ "domain": "ledger-repair",
104
+ "version": 1,
105
+ "summary": "The strict number-repair request, covering the complete duplicate set."
106
+ },
107
+ {
108
+ "file": "ledger-repair-response.json",
109
+ "domain": "ledger-repair",
110
+ "version": 1,
111
+ "summary": "Every ledger-repair response: the proposal and apply envelopes at repair version 1."
112
+ },
95
113
  {
96
114
  "file": "report-config-v1.json",
97
115
  "domain": "report-config",
@@ -0,0 +1,170 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://github.com/lstutzman/wowbagger/schemas/ledger-repair-proposal.json",
4
+ "title": "number-repair-proposal result, ledger-repair version 1",
5
+ "description": "The `result` member of a successful `number-repair-proposal` response. The proposal is read-only: it reads the raw items of a ledger whose complete error set is duplicate numbers and computes the mapping that would repair it, writing nothing. The caller confirms or replaces `suggested_changes` and submits them as a `number-repair` request, which validates every witness again under the repair lock.",
6
+ "type": "object",
7
+ "additionalProperties": false,
8
+ "required": [
9
+ "ledger_snapshot_revision",
10
+ "duplicate_groups",
11
+ "items",
12
+ "suggested_changes",
13
+ "preserved_items",
14
+ "validation_errors"
15
+ ],
16
+ "properties": {
17
+ "ledger_snapshot_revision": {
18
+ "$ref": "https://github.com/lstutzman/wowbagger/schemas/common.json#/$defs/revision",
19
+ "description": "The digest over the complete relevant source bytes this proposal was computed from. A repair request replays it so a changed ledger is a conflict rather than a surprise."
20
+ },
21
+ "duplicate_groups": {
22
+ "type": "array",
23
+ "minItems": 1,
24
+ "description": "One entry per duplicated number, naming every item that carries it. A repair request must resolve every group.",
25
+ "items": {
26
+ "type": "object",
27
+ "additionalProperties": false,
28
+ "required": [
29
+ "number",
30
+ "item_ids"
31
+ ],
32
+ "properties": {
33
+ "number": {
34
+ "type": "integer",
35
+ "minimum": 1
36
+ },
37
+ "item_ids": {
38
+ "type": "array",
39
+ "minItems": 2,
40
+ "uniqueItems": true,
41
+ "items": {
42
+ "$ref": "https://github.com/lstutzman/wowbagger/schemas/common.json#/$defs/itemId"
43
+ }
44
+ }
45
+ }
46
+ }
47
+ },
48
+ "items": {
49
+ "type": "array",
50
+ "minItems": 1,
51
+ "description": "Every item in a duplicate group, with the configured path and exact source revision a repair request witnesses.",
52
+ "items": {
53
+ "type": "object",
54
+ "additionalProperties": false,
55
+ "required": [
56
+ "item_id",
57
+ "path",
58
+ "revision",
59
+ "number"
60
+ ],
61
+ "properties": {
62
+ "item_id": {
63
+ "$ref": "https://github.com/lstutzman/wowbagger/schemas/common.json#/$defs/itemId"
64
+ },
65
+ "path": {
66
+ "type": "string",
67
+ "minLength": 1,
68
+ "description": "The item's configured path, relative to the ledger directory."
69
+ },
70
+ "revision": {
71
+ "$ref": "https://github.com/lstutzman/wowbagger/schemas/common.json#/$defs/revision"
72
+ },
73
+ "number": {
74
+ "type": "integer",
75
+ "minimum": 1
76
+ }
77
+ }
78
+ }
79
+ },
80
+ "suggested_changes": {
81
+ "type": "array",
82
+ "minItems": 1,
83
+ "description": "The computed mapping, in the exact shape of the `changes` member of a number-repair request. Each group keeps the number on its lexicographically smallest ULID and moves the rest above the current maximum number.",
84
+ "items": {
85
+ "type": "object",
86
+ "additionalProperties": false,
87
+ "required": [
88
+ "item_id",
89
+ "expected_revision",
90
+ "expected_number",
91
+ "replacement_number"
92
+ ],
93
+ "properties": {
94
+ "item_id": {
95
+ "$ref": "https://github.com/lstutzman/wowbagger/schemas/common.json#/$defs/itemId"
96
+ },
97
+ "expected_revision": {
98
+ "$ref": "https://github.com/lstutzman/wowbagger/schemas/common.json#/$defs/revision"
99
+ },
100
+ "expected_number": {
101
+ "type": "integer",
102
+ "minimum": 1
103
+ },
104
+ "replacement_number": {
105
+ "type": "integer",
106
+ "minimum": 1
107
+ }
108
+ }
109
+ }
110
+ },
111
+ "preserved_items": {
112
+ "type": "array",
113
+ "minItems": 1,
114
+ "description": "Item IDs the proposal keeps at their current number.",
115
+ "uniqueItems": true,
116
+ "items": {
117
+ "$ref": "https://github.com/lstutzman/wowbagger/schemas/common.json#/$defs/itemId"
118
+ }
119
+ },
120
+ "references": {
121
+ "type": "array",
122
+ "description": "The affected items' relations, exactly as the source carries them. Relations are ULIDs, so a number repair preserves them; they are reported so a caller can confirm that nothing identity-bearing is being rewritten.",
123
+ "items": {
124
+ "type": "object",
125
+ "additionalProperties": false,
126
+ "required": [
127
+ "item_id",
128
+ "depends_on",
129
+ "related",
130
+ "parent"
131
+ ],
132
+ "properties": {
133
+ "item_id": {
134
+ "$ref": "https://github.com/lstutzman/wowbagger/schemas/common.json#/$defs/itemId"
135
+ },
136
+ "depends_on": {
137
+ "type": "array",
138
+ "items": {
139
+ "$ref": "https://github.com/lstutzman/wowbagger/schemas/common.json#/$defs/itemId"
140
+ }
141
+ },
142
+ "related": {
143
+ "type": "array",
144
+ "items": {
145
+ "$ref": "https://github.com/lstutzman/wowbagger/schemas/common.json#/$defs/itemId"
146
+ }
147
+ },
148
+ "parent": {
149
+ "oneOf": [
150
+ {
151
+ "$ref": "https://github.com/lstutzman/wowbagger/schemas/common.json#/$defs/itemId"
152
+ },
153
+ {
154
+ "type": "null"
155
+ }
156
+ ]
157
+ }
158
+ }
159
+ }
160
+ },
161
+ "validation_errors": {
162
+ "type": "array",
163
+ "minItems": 1,
164
+ "description": "The complete current validation errors. A proposal is produced only when every one of them is a duplicate-number error; any other error returns ledger-repair-not-applicable instead.",
165
+ "items": {
166
+ "$ref": "https://github.com/lstutzman/wowbagger/schemas/common.json#/$defs/validationError"
167
+ }
168
+ }
169
+ }
170
+ }
@@ -0,0 +1,61 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://github.com/lstutzman/wowbagger/schemas/ledger-repair-request.json",
4
+ "title": "number-repair request, ledger-repair version 1",
5
+ "description": "The strict JSON request `number-repair` reads from stdin or a host-created request file. One request covers the complete duplicate set: a partial mapping is refused, because moving one group cannot produce a valid complete ledger while another group remains. Each change carries the witnesses the apply path compares under the repair lock. `ledger-repair` is its own contract version, separate from the core contract version and the work-claim contract version.",
6
+ "type": "object",
7
+ "additionalProperties": false,
8
+ "required": [
9
+ "repair_id",
10
+ "ledger_snapshot_revision",
11
+ "date",
12
+ "changes"
13
+ ],
14
+ "properties": {
15
+ "repair_id": {
16
+ "type": "string",
17
+ "pattern": "^nr_[0-9]{8}_[0-9]{4}$",
18
+ "description": "The bounded recovery key: `nr_`, the repair date, and a four-digit sequence within that date. An interrupted apply is resumed by this ID rather than retried blindly."
19
+ },
20
+ "ledger_snapshot_revision": {
21
+ "$ref": "https://github.com/lstutzman/wowbagger/schemas/common.json#/$defs/revision",
22
+ "description": "The complete-snapshot witness the proposal was computed against. A changed snapshot is a conflict, never a repair applied to bytes the caller never read."
23
+ },
24
+ "date": {
25
+ "$ref": "https://github.com/lstutzman/wowbagger/schemas/common.json#/$defs/isoDate"
26
+ },
27
+ "changes": {
28
+ "type": "array",
29
+ "minItems": 1,
30
+ "description": "One entry per moved item. No `item_id` repeats, because an item moves once, and no `replacement_number` repeats, because two items cannot land on one number. An empty list is an invalid request rather than a no-op.",
31
+ "items": {
32
+ "type": "object",
33
+ "additionalProperties": false,
34
+ "required": [
35
+ "item_id",
36
+ "expected_revision",
37
+ "expected_number",
38
+ "replacement_number"
39
+ ],
40
+ "properties": {
41
+ "item_id": {
42
+ "$ref": "https://github.com/lstutzman/wowbagger/schemas/common.json#/$defs/itemId"
43
+ },
44
+ "expected_revision": {
45
+ "$ref": "https://github.com/lstutzman/wowbagger/schemas/common.json#/$defs/revision"
46
+ },
47
+ "expected_number": {
48
+ "type": "integer",
49
+ "minimum": 1,
50
+ "description": "The number the item carries now, compared as an integer. It is a witness, not a label."
51
+ },
52
+ "replacement_number": {
53
+ "type": "integer",
54
+ "minimum": 1,
55
+ "description": "The number the item is moved to. The apply path refuses a collision with any item that is not being moved."
56
+ }
57
+ }
58
+ }
59
+ }
60
+ }
61
+ }
@@ -0,0 +1,90 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://github.com/lstutzman/wowbagger/schemas/ledger-repair-response.json",
4
+ "title": "ledger-repair responses, contract version 1",
5
+ "description": "Every `number-repair-proposal` and `number-repair` --json response. The root carries a `namespace` member: dispatch on `namespace` before reading any version field. `contract_version` is the repair domain's own version 1 — the core contract version and the work-claim contract version are separate and unchanged by it. A future change to the request or the repaired source shape requires a new repair contract version rather than a silent reinterpretation of version 1.",
6
+ "type": "object",
7
+ "oneOf": [
8
+ {
9
+ "title": "repair success",
10
+ "type": "object",
11
+ "additionalProperties": false,
12
+ "required": [
13
+ "ok",
14
+ "namespace",
15
+ "command",
16
+ "contract_version",
17
+ "state",
18
+ "result"
19
+ ],
20
+ "properties": {
21
+ "ok": {
22
+ "const": true
23
+ },
24
+ "namespace": {
25
+ "const": "ledger-repair"
26
+ },
27
+ "command": {
28
+ "enum": [
29
+ "number-repair-proposal",
30
+ "number-repair"
31
+ ]
32
+ },
33
+ "contract_version": {
34
+ "const": 1
35
+ },
36
+ "state": {
37
+ "enum": [
38
+ "unchanged",
39
+ "committed"
40
+ ],
41
+ "description": "A proposal changes nothing, so it is always `unchanged`. An applied repair is `committed`."
42
+ },
43
+ "result": {
44
+ "type": "object",
45
+ "description": "The proposal result is the ledger-repair-proposal schema. The apply result names the repair ID, the snapshot it was applied against, the changed items, and the Git commit when one was established."
46
+ }
47
+ }
48
+ },
49
+ {
50
+ "title": "repair refusal",
51
+ "type": "object",
52
+ "additionalProperties": false,
53
+ "required": [
54
+ "ok",
55
+ "namespace",
56
+ "command",
57
+ "contract_version",
58
+ "state",
59
+ "error"
60
+ ],
61
+ "properties": {
62
+ "ok": {
63
+ "const": false
64
+ },
65
+ "namespace": {
66
+ "const": "ledger-repair"
67
+ },
68
+ "command": {
69
+ "enum": [
70
+ "number-repair-proposal",
71
+ "number-repair"
72
+ ]
73
+ },
74
+ "contract_version": {
75
+ "const": 1
76
+ },
77
+ "state": {
78
+ "enum": [
79
+ "unchanged",
80
+ "unknown"
81
+ ],
82
+ "description": "`unchanged` states that no ledger byte was written. `unknown` is reserved for an outcome this core could not resolve; it never accompanies a refusal raised before any write was attempted."
83
+ },
84
+ "error": {
85
+ "$ref": "https://github.com/lstutzman/wowbagger/schemas/common.json#/$defs/error"
86
+ }
87
+ }
88
+ }
89
+ ]
90
+ }