wowbagger 0.1.0-alpha.9 → 0.5.0-beta.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.
package/README.md CHANGED
@@ -30,10 +30,10 @@ 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.9` is on npm under
34
- > the `next` tag and on this repository's `v0.1.0-alpha.9` tag. It is the
35
- > version this repository runs its own backlog on. The API is not frozen and the
36
- > version will move before a stable release.
33
+ > **Status: beta, published, and self-hosted.** `0.5.0-beta.0` is on npm under
34
+ > the `next` tag and on this repository's `v0.5.0-beta.0` tag. It is the
35
+ > version this repository runs its own backlog on. The API remains pre-stable
36
+ > and can change before the first stable release.
37
37
  >
38
38
  > **Install with `@next`.** Every published release is a prerelease. The
39
39
  > registry requires a `latest` dist-tag, so `latest` mirrors `next` — a bare
@@ -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.9
80
+ wowbagger --version # require 0.5.0-beta.0
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
@@ -86,10 +86,12 @@ wowbagger inspect --ledger ledger --number N --json
86
86
 
87
87
  For a write, inspect immediately before dispatch, send the returned exact-byte
88
88
  revision as the compare-and-swap witness, use the explicit core mutation, and
89
- validate again. Commit each provisioned-ledger mutation before the next one.
90
- Never replay a lost write: reconnect, re-read current state, and treat the
91
- outcome as unknown until the core or a human resolves it. Numbers are the
92
- human-facing item identity; `wb_...` ULIDs are internal identities.
89
+ validate again. On a provisioned ledger, commit each `create`, `transition`,
90
+ `parent-migrate`, `snooze`, `patch`, or `publish-claimed` mutation before the
91
+ next mutating command. Never replay a lost write: reconnect, re-read current
92
+ state, and treat the outcome as unknown until the core or a human resolves it.
93
+ Numbers are the human-facing item identity; `wb_...` ULIDs are internal
94
+ identities.
93
95
 
94
96
  The core owns validation, ready selection, projections, lifecycle, CAS,
95
97
  publication, claims, fencing, and reconciliation. The harness or host owns
@@ -98,13 +100,14 @@ cooperating writers; they are not exclusive locks.
98
100
 
99
101
  ## Start here
100
102
 
101
- Install the core CLI, then verify it. The core requires Node.js 20 or later:
103
+ Install the core CLI, then verify it. The supported runtime is Node.js 24; Node
104
+ 26 remains excluded because of the separate Vitest incompatibility:
102
105
 
103
106
  ```sh
104
- npm install -g wowbagger@0.1.0-alpha.9 # exact plugin-matched release
107
+ npm install -g wowbagger@0.5.0-beta.0 # exact plugin-matched release
105
108
  # or, from this release's Git tag:
106
- # npm install -g github:lstutzman/wowbagger#v0.1.0-alpha.9
107
- wowbagger --version # 0.1.0-alpha.9
109
+ # npm install -g github:lstutzman/wowbagger#v0.5.0-beta.0
110
+ wowbagger --version # 0.5.0-beta.0
108
111
  wowbagger capabilities --json # must report contract_version: 5
109
112
  ```
110
113
 
@@ -166,21 +169,45 @@ names — `create` publishes into an existing directory and does not make one.
166
169
  Nothing is renamed after a create. This repository dogfoods that binding: its
167
170
  own items live in [`ledger/items/`](ledger/items/).
168
171
 
169
- If your items mirror an external tracker and carry your own identifier fields,
170
- declare them now too. `<ledger>/.wowbagger/extensions.json` is what makes a
171
- consumer-owned extension member patchable:
172
+ If your items will mirror an external tracker and carry consumer-owned fields,
173
+ declare those fields **before the first item**. The declaration makes each
174
+ named extension member patchable:
172
175
 
173
176
  ```sh
174
177
  echo '{"extensions_version":1,"members":{"external_id":"string"}}' \
175
178
  > path/to/ledger/.wowbagger/extensions.json
176
179
  ```
177
180
 
178
- Each member declares one value type — `string`, `integer`, `boolean`, or
179
- `string-list`. **A ledger without that file has no patchable extension member at
180
- all**, and a `set.extensions` patch against it is refused by name. The
181
- declaration authorizes a write; it never describes the ledger, so `validate`
182
- does not read it. Both files are ledger setup, not runner configuration: commit
183
- them.
181
+ Each member declares one value type: `string`, `integer`, `boolean`, or
182
+ `string-list`. A ledger without the file has no patchable extension member,
183
+ and `set.extensions` refuses the missing declaration by name. The declaration
184
+ authorizes writes; it does not define item validity, so `validate` does not
185
+ read it. Commit the declaration with the other ledger setup.
186
+
187
+ If an existing ledger already carries extension values, do not create the
188
+ declaration by hand. Select every member and type explicitly in a request,
189
+ review a dry run, then publish the same proposal:
190
+
191
+ ```json
192
+ {"members":{"tags":"string-list"}}
193
+ ```
194
+
195
+ ```sh
196
+ wowbagger extensions-provision --ledger path/to/ledger \
197
+ --input declaration.json --json --dry-run
198
+ wowbagger extensions-provision --ledger path/to/ledger \
199
+ --input declaration.json --json
200
+ git add path/to/ledger/.wowbagger/extensions.json
201
+ git commit -m "Declare patchable ledger extensions"
202
+ ```
203
+
204
+ The command first requires a valid complete ledger. It validates every
205
+ occurrence of each selected member, reports occurrence counts, changes no item
206
+ bytes, and publishes one canonical declaration without overwriting a different
207
+ one. Commit that file before the first corresponding `patch`, inspect the
208
+ target for its current revision, then use `set.extensions.tags`. An item that
209
+ writes the selected member with a YAML anchor or alias remains
210
+ `extension-anchored` and requires a reviewed hand-edit.
184
211
 
185
212
  Cores at `0.1.0-alpha.4` and earlier ignore the layout file and publish every
186
213
  item at the ledger root.
@@ -269,8 +296,9 @@ skill exists because four things break when it does.
269
296
  - **Validation is whole-ledger and fail-closed.** One malformed item refuses
270
297
  every read and every guarded mutation on that ledger, including commands that
271
298
  never touch it. A hand-edit finds that out later, and usually in someone
272
- else's session. `create`, `transition`, and `patch` validate the complete
273
- candidate ledger *before* publishing anything, and refuse `unchanged`.
299
+ else's session. `create`, `transition`, `parent-migrate`, `snooze`, and
300
+ `patch` validate the complete candidate ledger *before* publishing anything,
301
+ and refuse `unchanged`.
274
302
  - **A hand-edit has no lost-update guard.** Every guarded write takes the exact
275
303
  SHA-256 revision `inspect` returned and refuses if the bytes moved. An editor
276
304
  writes over whatever is there.
@@ -322,7 +350,7 @@ two supported install routes:
322
350
  registry requires a `latest` tag), so a bare install resolves to the same
323
351
  bytes.
324
352
  - **git tag** —
325
- `npm install -g github:lstutzman/wowbagger#v0.1.0-alpha.9` installs this
353
+ `npm install -g github:lstutzman/wowbagger#v0.5.0-beta.0` installs this
326
354
  release. Installing at a ref installs the core and every adapter that ref
327
355
  carries.
328
356
 
@@ -358,10 +386,10 @@ version.
358
386
 
359
387
  ### Security
360
388
 
361
- - **Read-only by default.** `validate`, `ready`, `report`, `inspect`,
362
- `capabilities`, and `mint-id` never modify anything. Every mutation
363
- (`create`, `transition`, `patch`, and `publish-claimed`) is an explicit,
364
- reviewable write.
389
+ - **Read-only by default.** `validate`, `ready`, `report`, `inspect`, `list`,
390
+ `capabilities`, and `mint-id` never modify anything. Every item mutation
391
+ (`create`, `transition`, `parent-migrate`, `snooze`, `patch`, and
392
+ `publish-claimed`) is an explicit, reviewable write.
365
393
  - **Lock is not a claim.** A short mutation lock serializes writers during one
366
394
  operation. It does not grant a work claim.
367
395
  - **Claims are merge-coordinated, not exclusive.** `claim acquire` uses
@@ -394,7 +422,7 @@ Upgrade the pieces you installed:
394
422
 
395
423
  ```sh
396
424
  npm install -g wowbagger@next # public npm registry
397
- npm install -g github:lstutzman/wowbagger#v0.1.0-alpha.9 # immutable Git release
425
+ npm install -g github:lstutzman/wowbagger#v0.5.0-beta.0 # immutable Git release
398
426
  git pull && npm ci # or: a direct checkout
399
427
  ```
400
428
 
@@ -442,6 +470,16 @@ core, these are the changes most likely to touch you:
442
470
  `create` and refuses a caller-supplied one; `patch` refuses it because it is
443
471
  immutable identity. Keep a legacy identifier in a declared extension member or
444
472
  in the item body.
473
+
474
+ - **Repair duplicate numbers through `ledger-repair` version 1.** Generate a
475
+ read-only proposal with `number-repair-proposal`, review every
476
+ `expected_revision` and `replacement_number`, then apply the complete mapping
477
+ with `number-repair`. The command preserves ULID identities and relations and
478
+ does not change core contract version 5.
479
+
480
+ - **Run `version-drift --json` before mutation.** It compares the installed
481
+ skill pin, required core contract, and running core, and names the stale
482
+ package, plugin cache, or linked checkout with remediation.
445
483
  - **Delete your local ULID generator.** `wowbagger mint-id --json` prints a
446
484
  canonical ID; `--date YYYY-MM-DD` selects the creation date the ID must
447
485
  encode.
@@ -552,7 +590,8 @@ approval never rides the bootstrap request, which the model controls;
552
590
 
553
591
  ## Core commands
554
592
 
555
- The current core requires Node.js 20 or later. From a Wowbagger checkout,
593
+ The current core requires Node.js 24. Node 26 is not in the supported matrix.
594
+ From a Wowbagger checkout,
556
595
  `./bin/wowbagger.js --help` prints the full command inventory,
557
596
  `./bin/wowbagger.js <command> --help` prints that command's usage, and
558
597
  `./bin/wowbagger.js --version` prints the installed package version. The
@@ -565,21 +604,28 @@ npm ci
565
604
  ./bin/wowbagger.js ready --ledger path/to/ledger --as-of 2030-01-15
566
605
  ./bin/wowbagger.js report --ledger path/to/ledger --as-of 2030-01-15 --json
567
606
  ./bin/wowbagger.js capabilities --json
568
- ./bin/wowbagger.js mint-id --json
569
607
  ./bin/wowbagger.js inspect --ledger path/to/ledger --id wb_... --json
570
608
  ./bin/wowbagger.js inspect --ledger path/to/ledger --number 30 --json
609
+ ./bin/wowbagger.js list --ledger path/to/ledger --input query.json --json
571
610
  ./bin/wowbagger.js create --ledger path/to/ledger --input request.json --json
572
611
  ./bin/wowbagger.js transition --ledger path/to/ledger --input request.json --json
612
+ ./bin/wowbagger.js parent-migrate --ledger path/to/ledger --input request.json --json
613
+ ./bin/wowbagger.js snooze --ledger path/to/ledger --input request.json --json
573
614
  ./bin/wowbagger.js patch --ledger path/to/ledger --input request.json --json
615
+ ./bin/wowbagger.js extensions-provision --ledger path/to/ledger --input declaration.json --json
616
+ ./bin/wowbagger.js mint-id --json
617
+ ./bin/wowbagger.js publish-claimed --ledger path/to/ledger --input request.json --json
618
+ ./bin/wowbagger.js claim-merge-verify --ledger path/to/ledger --base main --head feature --json
619
+ ./bin/wowbagger.js claim-sync --ledger path/to/ledger --json
620
+ ./bin/wowbagger.js claim-adopt --ledger path/to/ledger --input request.json --json
621
+ ./bin/wowbagger.js mutation-finalize --ledger path/to/ledger --recovery-token token --json
574
622
  ./bin/wowbagger.js provision --ledger path/to/ledger --json
575
623
  ./bin/wowbagger.js claim capabilities --ledger path/to/ledger --json
576
624
  ./bin/wowbagger.js claim acquire --ledger path/to/ledger --input request.json --json
577
625
  ./bin/wowbagger.js claim read --ledger path/to/ledger --input request.json --json
578
626
  ./bin/wowbagger.js claim renew --ledger path/to/ledger --input request.json --json
579
627
  ./bin/wowbagger.js claim release --ledger path/to/ledger --input request.json --json
580
- ./bin/wowbagger.js publish-claimed --ledger path/to/ledger --input request.json --json
581
- ./bin/wowbagger.js claim-verify --ledger path/to/ledger --json
582
- ./bin/wowbagger.js claim-adopt --ledger path/to/ledger --input request.json --json
628
+ ./bin/wowbagger.js claim-verify --ledger path/to/ledger [--id wb_...] --json
583
629
  ```
584
630
 
585
631
  `validate` writes exactly one JSON result to standard output. A valid ledger
@@ -642,10 +688,12 @@ change is an addition. And **extension members are patchable only where the
642
688
  ledger declares them** — see [Set the ledger up before the first
643
689
  item](#set-the-ledger-up-before-the-first-item).
644
690
 
645
- Which members you own at all is a three-way split — core-owned,
646
- consumer-editable through `patch`, and create-once — stated member by member in
647
- the mutation contract's **frontmatter ownership** table. Read the table; do not
648
- send a patch and interpret the refusal.
691
+ Which members you own at all is a four-way split — core-owned,
692
+ consumer-editable through `patch`, mutable through a dedicated command, and
693
+ create-once — stated member by member in the mutation contract's
694
+ **frontmatter ownership** table. Use `parent-migrate` to repoint an existing
695
+ item to or from an epic, and `snooze` to set or clear `snoozed_until`. Read the
696
+ table; do not send a patch and interpret the refusal.
649
697
 
650
698
  ### An epic's progress is derived, never stored
651
699
 
@@ -670,9 +718,11 @@ command asks you to parse the Markdown by hand:
670
718
  refusal carries `error.details.item`, the complete snapshot of the item you
671
719
  asked for, whenever no validation error names that item's path. A faulted
672
720
  item is withheld; `validate` already names its repair.
673
- - `claim-verify --json` reports `result.ledger_validation`. Exit 0 with
674
- `findings: []` and `ledger_validation.valid: false` says the claim journal is
675
- consistent and validation alone is blocking every mutation.
721
+ - `claim-verify --json` reports `result.ledger_validation`. Bare verification
722
+ is strict repository-wide mode; `--id <item>` keeps all findings visible but
723
+ fails only for that item and global barriers. Exit 0 with an invalid
724
+ `ledger_validation` still means claim state is clean but validation blocks
725
+ mutation.
676
726
 
677
727
  ### Work claims
678
728
 
@@ -702,22 +752,29 @@ operating rule:
702
752
 
703
753
  **Commit each mutation to Git before running the next mutating command.**
704
754
 
705
- The durable claim store validates every recorded mutation against Git `HEAD`,
706
- not against working-tree bytes. That is what makes a recorded mutation durable
707
- rather than a local edit one `git checkout` away from vanishing. An uncommitted
708
- mutation is an unreconciled mutation, so the next `create`, `transition`, or
709
- `patch` refuses instead of writing on top of it.
755
+ The durable claim store reconciles every recorded mutation with Git `HEAD` and
756
+ the working tree. The next mutation refuses when that reconciliation finds an
757
+ `unauthorized-revision`, requires Git finalization, or requires synchronization
758
+ for the item the command targets. A synchronization finding on an unrelated
759
+ item remains visible to `claim-verify` but does not block the command.
760
+
761
+ An existing item's latest authorized working-tree bytes and an earlier
762
+ authorized revision at `HEAD` form an authorized predecessor/successor window.
763
+ That window produces no finding, so another mutation can run before the first
764
+ one is committed. Acceptance of the later mutation does not make either change
765
+ durable. Commit each mutation anyway, then run `claim-verify`.
710
766
 
711
767
  The loop that works:
712
768
 
713
769
  ```sh
714
770
  ./bin/wowbagger.js create --ledger path/to/ledger --input request.json --json
715
771
  git add path/to/ledger && git commit -m "Record the mutation"
716
- ./bin/wowbagger.js claim-verify --ledger path/to/ledger --json
772
+ ./bin/wowbagger.js claim-verify --ledger path/to/ledger --id wb_... --json
717
773
  ./bin/wowbagger.js transition --ledger path/to/ledger --input next.json --json
718
774
  ```
719
775
 
720
- Skip the commit and the next command returns exit 6:
776
+ For example, an authorized new item that is still absent from `HEAD` makes the
777
+ next command return exit 6:
721
778
 
722
779
  ```json
723
780
  {"ok":false,"namespace":"ledger-mutation","command":"create-v1","contract_version":1,
@@ -732,10 +789,16 @@ Skip the commit and the next command returns exit 6:
732
789
  `state: "unchanged"` is exact — nothing was written. **`claim-verify` is the
733
790
  reconciliation procedure.** Read `details.findings`, do what each
734
791
  `remediation` string says, run `claim-verify` until it returns exit 0, then
735
- repeat the refused command.
792
+ repeat the refused command. A `worktree-synchronization-required` finding on an
793
+ unrelated item does not block the requested mutation. The same finding on the
794
+ target item, and every `unauthorized-revision` finding, remains blocking.
736
795
 
737
- Batch work is where this bites. Filing ten items means ten commits, not one
738
- commit at the end.
796
+ Batch work is where this bites. Filing ten items means ten serial
797
+ `create --auto-commit` calls and ten commits, not one batch commit. Wowbagger
798
+ permanently rejects batch create for the direct-Markdown architecture:
799
+ `limits.multi_item_atomicity` remains `false`, request order is the supported
800
+ bulk order, and each create must finish or recover before the next begins. See
801
+ the [batch-create decision](docs/design/2026-08-30-batch-create.md).
739
802
 
740
803
  ### Or fold the commit into the mutation
741
804
 
@@ -748,16 +811,23 @@ ledger only:
748
811
 
749
812
  It is opt-in per invocation. There is no configuration setting or environment
750
813
  default, because a hidden default would make existing automation create Git
751
- commits unexpectedly. The flag is accepted on `create`, `transition`, `patch`,
752
- and `publish-claimed`.
814
+ commits unexpectedly. The flag is accepted on `create`, `transition`,
815
+ `parent-migrate`, `snooze`, `patch`, and `publish-claimed`.
753
816
 
754
817
  What one flagged invocation does: refuse if anything is staged anywhere or any
755
- path under the ledger is dirty; reconcile; run the mutation unchanged; commit
756
- exactly the changed item and at most one
818
+ foreign path under the ledger is dirty; reconcile; run the mutation unchanged;
819
+ commit exactly the changed item and at most one
757
820
  `.wowbagger/reconcile-<namespace>.md` with a fixed subject such as
758
821
  `wowbagger: transition item #7`; verify the commit; then run `claim-verify`
759
- before it answers. On success the result gains `git_commit`, `commit_paths`, and
760
- `claim_verified`.
822
+ before it answers. A command that owns the claim journal may rebuild only its
823
+ derived reconciliation log during preflight. `create` remains strict, and
824
+ every other dirty ledger path still refuses. On success the result gains
825
+ `git_commit`, `commit_paths`, and `claim_verified`.
826
+
827
+ If claim verification refuses, auto-commit preserves its code and reason in
828
+ `claim_verify_code` and `claim_verify_reason`. Only
829
+ `claim_verify_reason: "claim-store-locked"` is retryable; unresolved
830
+ reconciliation is not.
761
831
 
762
832
  Unstaged and untracked files **outside** the ledger are left alone. Hooks and
763
833
  signing are honoured; `--no-verify` is never passed. Nothing is pushed.
@@ -1143,18 +1213,20 @@ the finding as a ledger item rather than leaving it in a transcript.
1143
1213
 
1144
1214
  ### The verification gate
1145
1215
 
1146
- Four commands. All four must pass, and the test commands run on **both** the
1147
- current Node runtime and Node 20:
1216
+ Four commands. All four must pass, and the test commands run on **Node 24.20.0**:
1148
1217
 
1149
1218
  ```sh
1150
- TMPDIR=/tmp node --test test/*.test.js
1151
- TMPDIR=/tmp /opt/homebrew/opt/node@20/bin/node --test test/*.test.js
1152
- TMPDIR=/tmp node spec/run-adapter-implementation.js
1153
- node bin/wowbagger.js validate --ledger ledger --json
1219
+ TMPDIR=/tmp /opt/homebrew/opt/node@24/bin/node --test test/*.test.js
1220
+ TMPDIR=/tmp /opt/homebrew/opt/node@24/bin/node --pending-deprecation --throw-deprecation --test test/*.test.js
1221
+ TMPDIR=/tmp /opt/homebrew/opt/node@24/bin/node spec/run-adapter-implementation.js
1222
+ TMPDIR=/tmp /opt/homebrew/opt/node@24/bin/node bin/wowbagger.js validate --ledger ledger --json
1154
1223
  ```
1155
1224
 
1156
1225
  `TMPDIR=/tmp` is not optional: the default macOS temporary path makes the claim
1157
- lock socket path too long. Substitute your own Node 20 binary path.
1226
+ lock socket path too long. Use an explicit Node 24.20.0 binary path.
1227
+
1228
+ The supported runtime matrix is Node 24.20.0. Node 26 remains excluded until
1229
+ the separate Vitest incompatibility reported by Lee is resolved.
1158
1230
 
1159
1231
  `npm test`, `npm audit --omit=dev`, and `git diff --check` are useful alongside
1160
1232
  it; they are not a substitute for the four commands above.
@@ -1477,7 +1477,7 @@ error registry. It changes only this versioned surface:
1477
1477
  The core capability probe adapter contract version 2 requires is core
1478
1478
  contract version 5. It adds exactly
1479
1479
  `operations.patch: {"supported":true,"write_scope":"single-item","cas_scope":"exact-byte-sha256"}`,
1480
- `operations.work_claim.api_version: 2`, and
1480
+ `operations.work_claim.api_version: 3`, and
1481
1481
  `limits.max_item_source_bytes: 8388608` as the first member of
1482
1482
  `limits`.
1483
1483
  Its mutation backend scope is always
@@ -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