wowbagger 0.1.0-alpha.9 → 0.5.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/CHANGELOG.md +509 -0
- package/README.md +272 -136
- package/docs/adapter-contract.md +1 -1
- package/docs/host-contract.md +7 -1
- package/docs/mutation-contract.md +354 -82
- package/docs/work-claim-contract.md +466 -88
- package/package.json +2 -2
- package/schemas/core-capabilities-response.json +1 -1
- package/schemas/core-envelope.json +4 -3
- package/schemas/index.json +18 -0
- package/schemas/ledger-repair-proposal.json +170 -0
- package/schemas/ledger-repair-request.json +61 -0
- package/schemas/ledger-repair-response.json +90 -0
- package/schemas/report-config-v1.json +4 -0
- package/schemas/report-config-v2.json +5 -0
- package/skills/wowbagger/SKILL.md +242 -59
- package/src/adapter/core-probe.js +3 -4
- package/src/adapter/process-outcome.js +8 -1
- package/src/claim-capabilities.js +3 -3
- package/src/claim-coordinator.js +61 -12
- package/src/claim-journal.js +212 -7
- package/src/claim-prospective.js +1 -28
- package/src/claim-publication.js +412 -78
- package/src/claim-request.js +9 -0
- package/src/claim-store.js +9 -4
- package/src/cli.js +302 -56
- package/src/extensions.js +1 -0
- package/src/git-autocommit.js +106 -43
- package/src/git-reconciliation.js +74 -19
- package/src/git-worktrees.js +73 -0
- package/src/instrumentation.js +1 -0
- package/src/launch.js +2 -2
- package/src/ledger-repair.js +1170 -0
- package/src/mutation.js +73 -15
- package/src/reconciliation-classifier.js +117 -0
- package/src/report-evidence.js +158 -41
- package/src/report-graph.js +201 -73
- package/src/report-html.js +358 -155
- package/src/report-impact.js +106 -0
- package/src/report-selection.js +97 -0
- package/src/report-sequencing.js +4 -4
- package/src/report-svg.js +74 -20
- package/src/report-view.js +14 -1
- package/src/report.js +109 -23
- package/src/version-drift.js +98 -0
- package/src/worktree-identity.js +165 -0
|
@@ -81,8 +81,9 @@ complete difference against published version 2 (`0.1.0-alpha.4`):
|
|
|
81
81
|
- **the patchable title.** `title` joins the patchable set as a non-empty
|
|
82
82
|
schema string that replaces the current title whole (section 9), and section
|
|
83
83
|
9 gains the frontmatter ownership table that states, member by member, which
|
|
84
|
-
members are core-owned, which are consumer-editable through `patch`,
|
|
85
|
-
which are create-once. The version
|
|
84
|
+
members are core-owned, which are consumer-editable through `patch`, which
|
|
85
|
+
move through a dedicated command, and which are create-once. The version
|
|
86
|
+
stays 3 by the same argument the relations
|
|
86
87
|
and body deltas used: this widens the patch request schema, and adds, removes,
|
|
87
88
|
and renames no response envelope member. **Version 3 is published, so state
|
|
88
89
|
the consequence plainly: a consumer probing for title-patch support cannot
|
|
@@ -190,11 +191,11 @@ and stops.
|
|
|
190
191
|
|
|
191
192
|
The bootstrap wire, adapter approval, instruction, handoff, and fixture-format
|
|
192
193
|
versions are separate version domains and remain version 1. The adapter
|
|
193
|
-
contract remains version 2. The work-claim API
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
194
|
+
contract remains version 2. The work-claim API moved to 2 with this core
|
|
195
|
+
release because the item-source refusal replaced the version 1 error that an
|
|
196
|
+
oversized publication candidate used to receive. It later moved to 3 for
|
|
197
|
+
target-scoped `claim-verify`; the current value is always negotiated from
|
|
198
|
+
capabilities, never inferred from the core version.
|
|
198
199
|
|
|
199
200
|
Version negotiation uses distinct existing fields. A core consumer MUST read
|
|
200
201
|
the top-level `contract_version` from `capabilities --json`. A work-claim
|
|
@@ -258,7 +259,7 @@ and stops.
|
|
|
258
259
|
|
|
259
260
|
The bootstrap wire, adapter approval, instruction, handoff, and fixture-format
|
|
260
261
|
versions are separate version domains and remain version 1. The adapter
|
|
261
|
-
contract remains version 2 and the work-claim API remains version
|
|
262
|
+
contract remains version 2 and the work-claim API remains version 3. The list
|
|
262
263
|
query and the workbench projection each have their own version domain,
|
|
263
264
|
`query_version` and `projection_version`, both `1`: a consumer negotiates them
|
|
264
265
|
through `result.operations.list.query_version` and
|
|
@@ -321,16 +322,18 @@ wowbagger inspect --ledger <dir> --id <id> --workbench --as-of YYYY-MM-DD --json
|
|
|
321
322
|
wowbagger list --ledger <dir> --input <json-file|-> --json
|
|
322
323
|
wowbagger create --ledger <dir> --input <json-file|-> --json [--auto-commit]
|
|
323
324
|
wowbagger transition --ledger <dir> --input <json-file|-> --json [--auto-commit]
|
|
325
|
+
wowbagger parent-migrate --ledger <dir> --input <json-file|-> --json [--auto-commit]
|
|
326
|
+
wowbagger snooze --ledger <dir> --input <json-file|-> --json [--auto-commit]
|
|
324
327
|
wowbagger patch --ledger <dir> --input <json-file|-> --json [--auto-commit]
|
|
325
328
|
wowbagger mint-id [--date YYYY-MM-DD] --json
|
|
326
329
|
wowbagger mutation-finalize --ledger <dir> --recovery-token <token> --json
|
|
327
330
|
~~~
|
|
328
331
|
|
|
329
332
|
`--auto-commit` is a bare opt-in flag. It is accepted once on `create`,
|
|
330
|
-
`transition`, `patch`, and `publish-claimed`, and it
|
|
331
|
-
everywhere else. Repeating it is `invalid-request`.
|
|
332
|
-
does. Without it, every existing invocation keeps
|
|
333
|
-
files, index, and Git `HEAD`.
|
|
333
|
+
`transition`, `parent-migrate`, `snooze`, `patch`, and `publish-claimed`, and it
|
|
334
|
+
is an unknown argument everywhere else. Repeating it is `invalid-request`.
|
|
335
|
+
Section 13 defines what it does. Without it, every existing invocation keeps
|
|
336
|
+
its exact stdout, exit, files, index, and Git `HEAD`.
|
|
334
337
|
|
|
335
338
|
A dash for --input means standard input. File and standard-input requests have
|
|
336
339
|
identical semantics. Request bytes must be valid UTF-8 JSON with one top-level
|
|
@@ -338,7 +341,8 @@ object and no duplicate member names at any depth. Duplicate members are
|
|
|
338
341
|
invalid; a parser must not apply last-member-wins behaviour.
|
|
339
342
|
|
|
340
343
|
Unknown, missing, and repeated command arguments are invalid-request. Create,
|
|
341
|
-
transition, and patch use JSON input rather than
|
|
344
|
+
transition, parent migration, snooze, and patch use JSON input rather than
|
|
345
|
+
parallel field flags.
|
|
342
346
|
|
|
343
347
|
### Standard output and standard error
|
|
344
348
|
|
|
@@ -372,6 +376,7 @@ answer in two domains.
|
|
|
372
376
|
| work-claim | `work-claim` | 1, the legacy envelope marker | `result.operations.work_claim.api_version` of `claim capabilities --json` |
|
|
373
377
|
| ledger-publication | `ledger-publication` | 1, the legacy envelope marker | the same work-claim `api_version` |
|
|
374
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` |
|
|
375
380
|
| bare result | absent, and no `ok` member either | none | none |
|
|
376
381
|
|
|
377
382
|
The rule has three steps:
|
|
@@ -397,6 +402,7 @@ legacy claim-envelope marker, and a consumer must never compare it with the core
|
|
|
397
402
|
| `inspect` | core | core |
|
|
398
403
|
| `list` | core | core |
|
|
399
404
|
| `mint-id` | core | core |
|
|
405
|
+
| `version-drift` | core | core |
|
|
400
406
|
| `report` | core | core |
|
|
401
407
|
| `create` | core | core, or ledger-mutation when the claim fence refuses |
|
|
402
408
|
| `transition` | core | core, or ledger-mutation when the claim fence refuses |
|
|
@@ -411,13 +417,15 @@ legacy claim-envelope marker, and a consumer must never compare it with the core
|
|
|
411
417
|
| `claim-sync` | work-claim | work-claim |
|
|
412
418
|
| `claim-adopt` | work-claim | work-claim |
|
|
413
419
|
| `mutation-finalize` | work-claim | work-claim |
|
|
414
|
-
| `
|
|
420
|
+
| `number-repair-proposal` | ledger-repair | ledger-repair |
|
|
421
|
+
| `number-repair` | ledger-repair | ledger-repair |
|
|
415
422
|
| `publish-claimed` | ledger-publication | ledger-publication |
|
|
416
423
|
|
|
417
424
|
**Exact root members**
|
|
418
425
|
|
|
419
426
|
A core response has exactly `ok`, `command`, `contract_version`, and one of
|
|
420
|
-
`result` or `error`; `create`, `transition`,
|
|
427
|
+
`result` or `error`; `create`, `transition`, `parent-migrate`, `snooze`, and
|
|
428
|
+
`patch` add `state`. A
|
|
421
429
|
claim-domain response has exactly `ok`, `namespace`, `command`,
|
|
422
430
|
`contract_version`, `state`, and one of `result` or `error`; a `claim
|
|
423
431
|
capabilities` response omits `state`, and a claimed-publication response adds
|
|
@@ -425,8 +433,9 @@ capabilities` response omits `state`, and a claimed-publication response adds
|
|
|
425
433
|
Successful mutation responses may carry `result.changed_paths`. It is the
|
|
426
434
|
complete deterministic ledger-relative set whose bytes this invocation changed
|
|
427
435
|
in the working tree. It does not mean Git committed those paths. `create`
|
|
428
|
-
returns only its item path; `transition`, `
|
|
429
|
-
their item path plus the tracked reconciliation
|
|
436
|
+
returns only its item path; `transition`, `parent-migrate`, `snooze`, `patch`,
|
|
437
|
+
and `publish-claimed` return their item path plus the tracked reconciliation
|
|
438
|
+
log when that log changed.
|
|
430
439
|
`--auto-commit` additionally returns `commit_paths` and `git_commit`; its
|
|
431
440
|
`changed_paths` equals the committed set.
|
|
432
441
|
`operation_id` once schema validation has accepted it. No expected envelope has
|
|
@@ -442,7 +451,8 @@ them would break every existing reader for no gain a consumer can use, because
|
|
|
442
451
|
neither command mutates and neither participates in version negotiation. They
|
|
443
452
|
stay bare, and step 3 of the rule is how a consumer recognizes them.
|
|
444
453
|
|
|
445
|
-
A claim-fenced refusal to `create`, `transition`,
|
|
454
|
+
A claim-fenced refusal to `create`, `transition`, `parent-migrate`, `snooze`,
|
|
455
|
+
or `patch` answers in the
|
|
446
456
|
ledger-mutation domain with `command: "<command>-v1"` and
|
|
447
457
|
`contract_version: 1`. This is not envelope drift: it is the work-claim
|
|
448
458
|
contract answering, because a merge-coordinated backend refused the write
|
|
@@ -477,7 +487,7 @@ A successful read-only command has exactly:
|
|
|
477
487
|
}
|
|
478
488
|
~~~
|
|
479
489
|
|
|
480
|
-
A successful create, transition, or patch adds state:
|
|
490
|
+
A successful create, transition, parent migration, snooze, or patch adds state:
|
|
481
491
|
|
|
482
492
|
~~~json
|
|
483
493
|
{
|
|
@@ -504,7 +514,8 @@ A read-only error has exactly:
|
|
|
504
514
|
}
|
|
505
515
|
~~~
|
|
506
516
|
|
|
507
|
-
Every create, transition, or patch error has a state
|
|
517
|
+
Every create, transition, parent-migrate, snooze, or patch error has a state
|
|
518
|
+
member:
|
|
508
519
|
|
|
509
520
|
~~~json
|
|
510
521
|
{
|
|
@@ -546,7 +557,7 @@ presence is reported separately as bounded recovery_artifacts.
|
|
|
546
557
|
| 6 | An unexpected operating or post-publication recovery condition. | operation-failed, post-commit-recovery-required, write-outcome-unknown, git-commit-failed, git-commit-outcome-unknown, post-commit-reconciliation-failed |
|
|
547
558
|
|
|
548
559
|
Only exit 0 is normal completion. A client must inspect mutation state on every
|
|
549
|
-
nonzero create, transition, or patch result.
|
|
560
|
+
nonzero create, transition, parent-migrate, snooze, or patch result.
|
|
550
561
|
|
|
551
562
|
## 3. Deterministic invalid-request issues
|
|
552
563
|
|
|
@@ -681,7 +692,7 @@ capability paths; all omitted paths retain their version 1 values:
|
|
|
681
692
|
| `result.operations.list` | `{"supported":true,"write_scope":"none","cas_scope":"none","query_version":1}` |
|
|
682
693
|
| `result.operations.patch` | `{"supported":true,"write_scope":"single-item","cas_scope":"exact-byte-sha256"}` |
|
|
683
694
|
| `result.operations.report` | `{"supported":true,"write_scope":"derived-output","config_versions":[1,2],"named_views":true}` |
|
|
684
|
-
| `result.operations.work_claim.api_version` | `
|
|
695
|
+
| `result.operations.work_claim.api_version` | `3` |
|
|
685
696
|
| `result.limits.max_item_source_bytes` | `8388608` |
|
|
686
697
|
| `result.limits.default_list_page_size` | `50` |
|
|
687
698
|
| `result.limits.max_list_page_size` | `200` |
|
|
@@ -759,7 +770,8 @@ defines the advertisement.
|
|
|
759
770
|
`result.limits.max_item_source_bytes` is the first member of `result.limits`,
|
|
760
771
|
before `multi_item_atomicity`. It is the exact number of bytes the complete
|
|
761
772
|
serialized item source may occupy, and it applies to successor bytes accepted
|
|
762
|
-
by `create`, `transition`, `
|
|
773
|
+
by `create`, `transition`, `parent-migrate`, `snooze`, `patch`, and
|
|
774
|
+
`publish-claimed`. It does not claim a
|
|
763
775
|
raw request limit and it does not claim an `inspect` output limit; the
|
|
764
776
|
serialized `publish-claimed` request keeps its own separate transport bound.
|
|
765
777
|
|
|
@@ -783,10 +795,18 @@ another. It is **not** a statement that worktrees write independently.
|
|
|
783
795
|
|
|
784
796
|
On a provisioned Git-backed ledger they do not. One claim journal lives in the
|
|
785
797
|
shared Git common directory, so it serializes every worktree of that
|
|
786
|
-
repository: a recorded `transition` or
|
|
787
|
-
mutation in the others
|
|
798
|
+
repository. The serialization is scoped to the item: a recorded `transition` or
|
|
799
|
+
`patch` in one worktree refuses a mutation in the others that targets *that
|
|
800
|
+
item* with exit 6 `claim-store-unavailable`, reason
|
|
788
801
|
`publication-reconciliation-required`, until the writing commit is visible in
|
|
789
|
-
the blocked checkout.
|
|
802
|
+
the blocked checkout. A mutation targeting an unrelated item still runs, and
|
|
803
|
+
the sibling's finding remains visible. Own uncommitted work and out-of-protocol
|
|
804
|
+
revisions are global barriers and refuse every mutation. Bare `claim-verify`
|
|
805
|
+
reports exit 6 while any item carries a blocking finding.
|
|
806
|
+
`claim-verify --id <item>` keeps every finding visible but returns success when
|
|
807
|
+
only unrelated target-scoped findings remain; global findings still block.
|
|
808
|
+
See [the work-claim contract](work-claim-contract.md), section 3.2, for the
|
|
809
|
+
scope rules. Clones do not share the common directory, so
|
|
790
810
|
`limits.cross_clone_coordination: false` carries no such consequence.
|
|
791
811
|
|
|
792
812
|
That serialization is discoverable, per ledger, at
|
|
@@ -889,8 +909,8 @@ snapshot the successful item shape above defines, for the item the request
|
|
|
889
909
|
selected. It is present when the request resolves an item and no validation
|
|
890
910
|
error names that item's path. It is absent when nothing resolves, and absent
|
|
891
911
|
when the resolved item is itself faulted, because that item's own frontmatter
|
|
892
|
-
or placement is what validation rejects. A create, transition,
|
|
893
|
-
ledger-invalid refusal never carries it.
|
|
912
|
+
or placement is what validation rejects. A create, transition, parent-migrate,
|
|
913
|
+
snooze, or patch ledger-invalid refusal never carries it.
|
|
894
914
|
|
|
895
915
|
This keeps the section 5 rule intact — inspect loads and validates the complete
|
|
896
916
|
ledger, and every member of the attached snapshot comes from the one raw byte
|
|
@@ -1291,11 +1311,11 @@ A writer creates the lock file exclusively as valid UTF-8 JSON no larger than
|
|
|
1291
1311
|
~~~
|
|
1292
1312
|
|
|
1293
1313
|
writer_id is an opaque ASCII string of 1 through 128 characters. operation is
|
|
1294
|
-
create, transition, or patch — the
|
|
1295
|
-
`publish-claimed` writes no lock file, so no lock file
|
|
1296
|
-
never has to classify one. The remaining values must
|
|
1297
|
-
lock path. Metadata contains no credentials, user name,
|
|
1298
|
-
arguments.
|
|
1314
|
+
create, transition, parent-migrate, snooze, or patch — the operations that
|
|
1315
|
+
take per-ID locks. `publish-claimed` writes no lock file, so no lock file
|
|
1316
|
+
names it and a reader never has to classify one. The remaining values must
|
|
1317
|
+
match their schema and lock path. Metadata contains no credentials, user name,
|
|
1318
|
+
host name, or command arguments.
|
|
1299
1319
|
|
|
1300
1320
|
A reader reads at most 4097 bytes. A lock larger than 4096 bytes, invalid UTF-8,
|
|
1301
1321
|
duplicate-key JSON, invalid JSON, unknown members, or invalid field values is
|
|
@@ -1304,6 +1324,7 @@ one of too-large, invalid-utf8, duplicate-key, invalid-json, or invalid-shape.
|
|
|
1304
1324
|
Valid metadata returns owner and owner_diagnostic null. Raw invalid bytes are
|
|
1305
1325
|
never returned.
|
|
1306
1326
|
|
|
1327
|
+
|
|
1307
1328
|
Locks are never removed automatically merely because started_at is old. Manual
|
|
1308
1329
|
recovery follows ADR 0003.
|
|
1309
1330
|
|
|
@@ -1346,6 +1367,12 @@ Create accepts exactly:
|
|
|
1346
1367
|
| item extension members | No | Permitted schema extensions. |
|
|
1347
1368
|
| body | Yes | JSON string; empty and LF-leading strings are distinct and valid. |
|
|
1348
1369
|
|
|
1370
|
+
The member name `extensions` is reserved for the `patch` request container.
|
|
1371
|
+
Create refuses `item.extensions`; extension members must be named directly on
|
|
1372
|
+
the item, such as `item.tags` or `item.tier`. This prevents a nested mapping
|
|
1373
|
+
from becoming an extension value that `patch` and the declaration workflow
|
|
1374
|
+
cannot address.
|
|
1375
|
+
|
|
1349
1376
|
If a file named by `--input` cannot be read before a request ID is known,
|
|
1350
1377
|
create or transition returns `invalid-request` with one `invalid-value` issue at
|
|
1351
1378
|
`/input`, the stable message `Request input could not be read.`, and mutation
|
|
@@ -1536,6 +1563,68 @@ no-clobber publication still protects an intervening creator.
|
|
|
1536
1563
|
Successful create returns state committed and the inspect item shape from
|
|
1537
1564
|
section 5.
|
|
1538
1565
|
|
|
1566
|
+
### Journal-fenced allocation on a provisioned ledger
|
|
1567
|
+
|
|
1568
|
+
On a provisioned merge-coordinated ledger, a schema-version-2 create is a
|
|
1569
|
+
journaled legacy mutation. Under the shared namespace lock it reconciles,
|
|
1570
|
+
applies the allocation fence below, loads and validates the ledger, derives
|
|
1571
|
+
`1 + max(existing numbers)`, serializes the candidate, validates the complete
|
|
1572
|
+
candidate ledger, reserves journal capacity, and only then appends its
|
|
1573
|
+
`legacy-mutation-intent` with `command: "create-v1"` before any byte reaches
|
|
1574
|
+
the item path. Publication, exact-byte verification, and the terminal append
|
|
1575
|
+
all happen under that same lock. The intent carries
|
|
1576
|
+
`expected_revision: null`, which is valid only for `create-v1`. The committed
|
|
1577
|
+
terminal is `legacy-mutation` with `command: "create-v1"`; the create abort
|
|
1578
|
+
carries `command: "create-v1"` and `observed_revision: null`. No entry records
|
|
1579
|
+
the assigned number, because the candidate revision binds the complete item
|
|
1580
|
+
bytes and the ledger remains the one number authority.
|
|
1581
|
+
|
|
1582
|
+
The allocation fence reads reconciliation with one extra barrier. Every global
|
|
1583
|
+
finding blocks create as it blocks every write. On top of those, any
|
|
1584
|
+
coordinated item this checkout does not hold blocks `create`, because the
|
|
1585
|
+
journal records a committed terminal for an item whose number this working
|
|
1586
|
+
ledger cannot read. A stale revision of an item this checkout holds does not
|
|
1587
|
+
block `create`, because a number is immutable and the local maximum is already
|
|
1588
|
+
correct. A fenced create refuses with exit 6, `state: "unchanged"`,
|
|
1589
|
+
`error.code: "claim-store-unavailable"`, and
|
|
1590
|
+
`error.details.reason: "publication-reconciliation-required"` in the
|
|
1591
|
+
`ledger-mutation` domain as `create-v1`, having written no item byte. Resolve
|
|
1592
|
+
each finding by its own `remediation`, run `claim-verify` until it exits 0, and
|
|
1593
|
+
retry the same request ID; the retry takes the next number.
|
|
1594
|
+
|
|
1595
|
+
A create has no authorized predecessor, so Git `HEAD` is the only surface that
|
|
1596
|
+
can carry its authorized bytes, and an uncommitted create raises the global
|
|
1597
|
+
`git-finalization-required` barrier for every later mutation. Commit each
|
|
1598
|
+
created item before the next mutating command. This release adds no batch
|
|
1599
|
+
mutation; the supported bulk pattern remains the create-then-commit loop.
|
|
1600
|
+
A ledger that already carries duplicate numbers is item #182 recovery work and
|
|
1601
|
+
is repaired through the separate `ledger-repair` contract, not through core
|
|
1602
|
+
version 5 mutation. Run
|
|
1603
|
+
`number-repair-proposal --ledger <dir> --json`, review the complete mapping, then
|
|
1604
|
+
run `number-repair --ledger <dir> --input <repair.json> --json`. The repair
|
|
1605
|
+
command operates only when duplicate-number errors are the complete validation
|
|
1606
|
+
failure, preserves ULID identities and relation values, and publishes all
|
|
1607
|
+
affected items under the shared namespace fence. Arbitrary hand edits remain
|
|
1608
|
+
unsupported because they can damage IDs, paths, or references.
|
|
1609
|
+
|
|
1610
|
+
**What this guarantees, and what it does not.** The fence closes the reported
|
|
1611
|
+
PropertyCompass2 collision: cooperating alpha.14 worktrees of one clone that
|
|
1612
|
+
share one Git common directory can no longer commit two items carrying the same
|
|
1613
|
+
number, because every such create is visible through the shared journal before
|
|
1614
|
+
publication even without branch integration. Separate clones, separate
|
|
1615
|
+
machines, alpha.13 writers before the hard cutover, and noncooperating writes
|
|
1616
|
+
stay outside the fence and still rely on branch integration plus `validate`.
|
|
1617
|
+
|
|
1618
|
+
The widened journal grammar forces a hard cutover, so upgrade every writer in
|
|
1619
|
+
one Git coordination domain before the first alpha.14 create. An alpha.13
|
|
1620
|
+
binary cannot read a `create-v1` intent: it refuses with exit 6,
|
|
1621
|
+
`error.code` `claim-store-unavailable`, message
|
|
1622
|
+
`The durable claim store is unavailable.`, and `error.details.reason`
|
|
1623
|
+
`claim-store-unreadable`, leaving state unchanged and writing no item. That
|
|
1624
|
+
refusal means **this repository was written by a newer Wowbagger; upgrade this
|
|
1625
|
+
worktree to continue.** There is no automatic migration and no mixed-version
|
|
1626
|
+
grace period.
|
|
1627
|
+
|
|
1539
1628
|
## 8. Transition
|
|
1540
1629
|
|
|
1541
1630
|
### Request
|
|
@@ -1856,6 +1945,84 @@ temporary file followed by the platform's existing-file atomic replacement
|
|
|
1856
1945
|
primitive. It then re-reads exact final bytes. This remains a local filesystem
|
|
1857
1946
|
operation without universal crash durability or hostile-writer protection.
|
|
1858
1947
|
|
|
1948
|
+
## 8.1 Parent migration
|
|
1949
|
+
|
|
1950
|
+
`parent-migrate` moves one item to an epic or detaches it without changing item
|
|
1951
|
+
identity or lifecycle. Parent-migrate accepts exactly:
|
|
1952
|
+
|
|
1953
|
+
~~~json
|
|
1954
|
+
{
|
|
1955
|
+
"id": "wb_...",
|
|
1956
|
+
"expected_revision": "sha256:<64 lowercase hexadecimal characters>",
|
|
1957
|
+
"expected_parent": "wb_...",
|
|
1958
|
+
"parent": null,
|
|
1959
|
+
"date": "2030-01-11"
|
|
1960
|
+
}
|
|
1961
|
+
~~~
|
|
1962
|
+
|
|
1963
|
+
`id`, `expected_revision`, `expected_parent`, `parent`, and `date` are required.
|
|
1964
|
+
`expected_parent` and `parent` are each a canonical item ID or `null`.
|
|
1965
|
+
`expected_parent` is a second compare-and-swap witness: it must equal the
|
|
1966
|
+
current parent after the locked re-read. A mismatch returns exit 4
|
|
1967
|
+
`parent-migration-precondition-failed` with a `parent-revision-conflict` issue
|
|
1968
|
+
and both `expected_parent` and `actual_parent`. An unknown parent, a non-epic
|
|
1969
|
+
parent, self-parenting, or a date before `created` or `updated` returns exit 2
|
|
1970
|
+
with the same error code and deterministic issues. Revision and lock conflicts
|
|
1971
|
+
retain their ordinary exit 4 precedence.
|
|
1972
|
+
|
|
1973
|
+
The command sets `updated` to request `date` and changes only `parent`. For an
|
|
1974
|
+
item whose status is `done`, `killed`, `archived`, or `deferred`, the request
|
|
1975
|
+
date must equal the existing `updated` date. No status or liveness precondition
|
|
1976
|
+
exists; the complete candidate ledger still validates every parent and rollup
|
|
1977
|
+
invariant before publication.
|
|
1978
|
+
|
|
1979
|
+
A core success answers as command `parent-migrate`, contract version 5, state
|
|
1980
|
+
`committed`, and returns the lossless item. On a provisioned ledger, a claim
|
|
1981
|
+
fence refusal answers in the `ledger-mutation` domain as command
|
|
1982
|
+
`parent-migrate-v1`. `--auto-commit` commits the changed item, when its bytes
|
|
1983
|
+
move, plus the reconciliation log under the fixed parent-migrate subject.
|
|
1984
|
+
|
|
1985
|
+
Parent migration reuses the legacy `patch-v1` fence family in the durable claim
|
|
1986
|
+
journal. That journal `command` is a fence-family and recovery classifier, not
|
|
1987
|
+
the public operation name. Internally, `responseCommand` identifies the
|
|
1988
|
+
response operation and keeps `parent-migrate-v1` distinct in envelopes. The
|
|
1989
|
+
journal's attempt ID and expected, candidate, and committed revisions remain
|
|
1990
|
+
the recovery evidence; Git history remains the reviewable operation audit.
|
|
1991
|
+
|
|
1992
|
+
## 8.2 Snooze
|
|
1993
|
+
|
|
1994
|
+
`snooze` sets or clears one item's snooze date without changing lifecycle.
|
|
1995
|
+
Snooze accepts exactly:
|
|
1996
|
+
|
|
1997
|
+
~~~json
|
|
1998
|
+
{
|
|
1999
|
+
"id": "wb_...",
|
|
2000
|
+
"expected_revision": "sha256:<64 lowercase hexadecimal characters>",
|
|
2001
|
+
"snoozed_until": "2030-02-01",
|
|
2002
|
+
"date": "2030-01-11"
|
|
2003
|
+
}
|
|
2004
|
+
~~~
|
|
2005
|
+
|
|
2006
|
+
`id`, `expected_revision`, `snoozed_until`, and `date` are required.
|
|
2007
|
+
`snoozed_until` is an ISO calendar date or `null`; `null` removes the member.
|
|
2008
|
+
`date` is an ISO calendar date not before `created` or `updated`. The command
|
|
2009
|
+
sets `updated` to request `date` and changes only `snoozed_until`. For an item
|
|
2010
|
+
whose status is `done`, `killed`, `archived`, or `deferred`, the request date
|
|
2011
|
+
must equal the existing `updated` date.
|
|
2012
|
+
|
|
2013
|
+
Invalid input returns exit 2 `invalid-request`; stale item revision and lock
|
|
2014
|
+
conflicts retain exit 4; date and candidate validation use the same bounded
|
|
2015
|
+
issue and error shapes as patch. A core success answers as command `snooze`,
|
|
2016
|
+
contract version 5, state `committed`, and returns the lossless item. On a
|
|
2017
|
+
provisioned ledger, a claim fence refusal answers in the `ledger-mutation`
|
|
2018
|
+
domain as command `snooze-v1`. `--auto-commit` commits the changed item, when
|
|
2019
|
+
its bytes move, plus the reconciliation log under the fixed snooze subject.
|
|
2020
|
+
|
|
2021
|
+
Snooze also reuses the legacy `patch-v1` fence family in the durable claim
|
|
2022
|
+
journal. The journal `command` identifies the fence and recovery family, while
|
|
2023
|
+
`responseCommand` identifies the response operation as `snooze-v1`. This split
|
|
2024
|
+
is intentional and does not change the journal format.
|
|
2025
|
+
|
|
1859
2026
|
## 9. Patch
|
|
1860
2027
|
|
|
1861
2028
|
Patch changes the mutable non-lifecycle content of one existing item — its
|
|
@@ -1905,6 +2072,14 @@ Patch accepts exactly:
|
|
|
1905
2072
|
| date | Yes | ISO calendar date not earlier than existing created or updated. |
|
|
1906
2073
|
| set | Yes | Mapping naming at least one patchable field. |
|
|
1907
2074
|
|
|
2075
|
+
For an item whose status is `done`, `killed`, `archived`, or `deferred`, the
|
|
2076
|
+
request date must equal the existing `updated` date for `patch`, `snooze`, and
|
|
2077
|
+
`parent-migrate`. The active lifecycle date must equal `updated`; these three
|
|
2078
|
+
verbs update `updated` without changing that lifecycle date. An earlier request
|
|
2079
|
+
fails the date floor, while a later request produces `candidate-invalid` with
|
|
2080
|
+
`terminal-date-must-match-updated`. Inspect immediately before the mutation and
|
|
2081
|
+
reuse the item's current `updated` date.
|
|
2082
|
+
|
|
1908
2083
|
The patchable field set is exactly `title`, `priority`, `depends_on`,
|
|
1909
2084
|
`related`, `body`, `body_append`, and `extensions`. A set member outside it is an invalid-request issue at
|
|
1910
2085
|
its /set pointer — the boundary is stated here, not discovered from the
|
|
@@ -2077,6 +2252,27 @@ before it can correct anything. `validate` is therefore unchanged by this file,
|
|
|
2077
2252
|
and an item whose extension member disagrees with the declaration is still a
|
|
2078
2253
|
valid item — it is simply an item a patch can correct.
|
|
2079
2254
|
|
|
2255
|
+
**Provisioning a declaration on an existing ledger.**
|
|
2256
|
+
|
|
2257
|
+
`extensions-provision --ledger <dir> --input <request> --json [--dry-run]`
|
|
2258
|
+
accepts an explicit non-empty `members` mapping in the same version-1 member
|
|
2259
|
+
and type vocabulary. It never infers a type from stored values. Before it
|
|
2260
|
+
proposes anything, it requires the complete ledger to validate. For each
|
|
2261
|
+
selected member, it validates every stored occurrence against the selected
|
|
2262
|
+
type, requires at least one occurrence, and reports that occurrence count.
|
|
2263
|
+
The member need not appear on every item. Empty `string-list` values are valid;
|
|
2264
|
+
scalars, null, maps, nested lists, and lists containing non-strings conflict
|
|
2265
|
+
with `string-list`.
|
|
2266
|
+
|
|
2267
|
+
Dry-run returns the canonical declaration bytes and writes nothing. Publication
|
|
2268
|
+
creates exactly `.wowbagger/extensions.json` with no-clobber semantics.
|
|
2269
|
+
Repeating the identical declaration is idempotent; a different existing
|
|
2270
|
+
declaration is `extension-declaration-conflict`, exit 4, `unchanged`.
|
|
2271
|
+
Neither form changes an item byte or revision, records a claim-journal entry,
|
|
2272
|
+
or creates an item revision. The generated declaration is committed before
|
|
2273
|
+
the first patch that uses it. Anchors and aliases remain item-specific patch
|
|
2274
|
+
preconditions and do not prevent declaration provisioning.
|
|
2275
|
+
|
|
2080
2276
|
Absence is fail-closed and total. A ledger with no `extensions.json` has **no**
|
|
2081
2277
|
patchable extension member, and a `set.extensions` request against it is
|
|
2082
2278
|
refused `patch-precondition-failed`, exit 2, `unchanged`, with one
|
|
@@ -2130,8 +2326,8 @@ that parses as something else is caught before publication, not after.
|
|
|
2130
2326
|
|
|
2131
2327
|
### Frontmatter ownership
|
|
2132
2328
|
|
|
2133
|
-
Every frontmatter member belongs to exactly one of
|
|
2134
|
-
|
|
2329
|
+
Every frontmatter member belongs to exactly one of four classes, and this table
|
|
2330
|
+
is the whole boundary. A consumer reads it instead of sending a patch and
|
|
2135
2331
|
interpreting the refusal.
|
|
2136
2332
|
|
|
2137
2333
|
| Member | Class | How it changes |
|
|
@@ -2141,7 +2337,7 @@ interpreting the refusal.
|
|
|
2141
2337
|
| `number` | Core-owned | Create assigns it on schema version 2. It is the item handle and never moves. |
|
|
2142
2338
|
| `status` | Core-owned | `transition` only, along an allowed lifecycle edge. |
|
|
2143
2339
|
| `created` | Core-owned | Create derives it from the UTC date the ID encodes. |
|
|
2144
|
-
| `updated` | Core-owned | Every `transition` and `patch` sets it to `request.date`. |
|
|
2340
|
+
| `updated` | Core-owned | Every `transition`, `parent-migrate`, `snooze`, and `patch` sets it to `request.date`. |
|
|
2145
2341
|
| `completed` | Core-owned | `transition` writes it on completion and clears it on any other edge. |
|
|
2146
2342
|
| `killed` | Core-owned | `transition` writes it on a kill and clears it on any other edge. |
|
|
2147
2343
|
| `archived` | Core-owned | `transition` writes it on an archive and clears it on any other edge. |
|
|
@@ -2154,8 +2350,8 @@ interpreting the refusal.
|
|
|
2154
2350
|
| `body` (the region after the frontmatter, not a member) | Consumer-editable through `patch` | `set.body` replaces the whole body; `""` empties it. `set.body_append` appends without a merge; the two are mutually exclusive in one request. |
|
|
2155
2351
|
| `kind` | Create-once | Create fixes it. `patch` refuses it. |
|
|
2156
2352
|
| `provenance` | Create-once | Create writes it. Every later verb preserves it byte for byte. |
|
|
2157
|
-
| `parent` |
|
|
2158
|
-
| `snoozed_until` |
|
|
2353
|
+
| `parent` | Dedicated mutation through `parent-migrate` | Create may set it; `parent-migrate` repoints the existing item to an epic or detaches it with compare-and-swap witnesses. |
|
|
2354
|
+
| `snoozed_until` | Dedicated mutation through `snooze` | Create may set it; `snooze` sets or clears it with a compare-and-swap witness. |
|
|
2159
2355
|
| declared extension members (`tags`, `tier`, a consumer's own identifier fields) | Consumer-owned, patchable through `set.extensions` | `set.extensions.<member>` replaces the member whole; `null` removes it. Patchable only where `<ledger>/.wowbagger/extensions.json` declares the member and its value type, and only where the item does not write it with a YAML anchor or alias. |
|
|
2160
2356
|
| undeclared extension members | Consumer-owned, not patchable | Supplied at create, preserved byte for byte by every verb, and otherwise a reviewable hand-edit. A ledger with no extension declaration has no patchable extension member at all. |
|
|
2161
2357
|
|
|
@@ -2304,9 +2500,9 @@ on code, mutation state, and documented details.
|
|
|
2304
2500
|
|
|
2305
2501
|
### The bounded item source
|
|
2306
2502
|
|
|
2307
|
-
`create`, `transition`, and `patch` each measure
|
|
2308
|
-
successor before validating it as a ledger candidate.
|
|
2309
|
-
`result.limits.max_item_source_bytes` returns:
|
|
2503
|
+
`create`, `transition`, `parent-migrate`, `snooze`, and `patch` each measure
|
|
2504
|
+
the complete serialized successor before validating it as a ledger candidate.
|
|
2505
|
+
A successor larger than `result.limits.max_item_source_bytes` returns:
|
|
2310
2506
|
|
|
2311
2507
|
- code `item-source-too-large`;
|
|
2312
2508
|
- message `The proposed item source exceeds the supported byte limit.`;
|
|
@@ -2497,8 +2693,8 @@ claim-fenced mutation refusals and the bare `validate` and `ready` results.
|
|
|
2497
2693
|
|
|
2498
2694
|
A ledger becomes provisioned when `provision` binds a namespace to the
|
|
2499
2695
|
repository and `claim capabilities` reports `mode: "merge-coordinated"`. On
|
|
2500
|
-
such a ledger, `create`, `transition`, and `patch`
|
|
2501
|
-
coordinator described by the [work-claim
|
|
2696
|
+
such a ledger, `create`, `transition`, `parent-migrate`, `snooze`, and `patch`
|
|
2697
|
+
run inside the claim coordinator described by the [work-claim
|
|
2502
2698
|
contract](work-claim-contract.md).
|
|
2503
2699
|
|
|
2504
2700
|
### The rule
|
|
@@ -2506,17 +2702,42 @@ contract](work-claim-contract.md).
|
|
|
2506
2702
|
**Commit each mutation to Git before running the next mutating command.**
|
|
2507
2703
|
|
|
2508
2704
|
The coordinator records every authorized mutation in the durable journal and
|
|
2509
|
-
|
|
2510
|
-
|
|
2511
|
-
|
|
2512
|
-
|
|
2705
|
+
reconciles those records with Git `HEAD` and working-tree bytes. It refuses the
|
|
2706
|
+
next mutation when reconciliation finds an `unauthorized-revision`, requires
|
|
2707
|
+
Git finalization, or requires synchronization for the target item. A
|
|
2708
|
+
`worktree-synchronization-required` finding on an unrelated item remains
|
|
2709
|
+
visible without blocking that mutation.
|
|
2710
|
+
|
|
2711
|
+
An existing item's latest authorized working-tree bytes and an earlier
|
|
2712
|
+
authorized revision at `HEAD` form an authorized predecessor/successor window.
|
|
2713
|
+
That window produces no finding, so another mutation can run before the first
|
|
2714
|
+
one is committed. The later command's acceptance does not prove durability;
|
|
2715
|
+
the operating rule remains write, commit, `claim-verify`, next write.
|
|
2716
|
+
|
|
2717
|
+
`create` never occupies that window. A created item has no earlier authorized
|
|
2718
|
+
revision, so Git `HEAD` is the only surface that can carry its authorized
|
|
2719
|
+
bytes, and an uncommitted create raises the global `git-finalization-required`
|
|
2720
|
+
barrier for every later mutation, including the next create. Filing ten items
|
|
2721
|
+
is therefore ten serial `create --auto-commit` cycles, not one commit at the
|
|
2722
|
+
end. The accepted batch-create decision permanently rejects a batch mutation
|
|
2723
|
+
for the direct-Markdown architecture and keeps
|
|
2724
|
+
`limits.multi_item_atomicity: false`; see
|
|
2725
|
+
[`docs/design/2026-08-30-batch-create.md`](design/2026-08-30-batch-create.md).
|
|
2726
|
+
|
|
2727
|
+
The journal is bounded at 65,536 entries and 8,388,608 bytes. If capacity is
|
|
2728
|
+
known before a legacy create, transition, parent migration, snooze, or patch
|
|
2729
|
+
intent is published, the command returns exit 6 `claim-store-unavailable`,
|
|
2730
|
+
reason `journal-capacity-exceeded`, and `unchanged`. Existing journal bytes
|
|
2731
|
+
remain an exact prefix and no item byte is written. A genuinely unreadable
|
|
2732
|
+
journal retains `claim-store-unreadable`; an indeterminate outcome after an
|
|
2733
|
+
intent retains its outcome-unknown classification.
|
|
2513
2734
|
|
|
2514
2735
|
The loop that works:
|
|
2515
2736
|
|
|
2516
2737
|
~~~sh
|
|
2517
2738
|
wowbagger create --ledger <dir> --input request.json --json
|
|
2518
2739
|
git add <dir> && git commit -m "Record the mutation"
|
|
2519
|
-
wowbagger claim-verify --ledger <dir> --json
|
|
2740
|
+
wowbagger claim-verify --ledger <dir> --id <item> --json
|
|
2520
2741
|
wowbagger transition --ledger <dir> --input next.json --json
|
|
2521
2742
|
~~~
|
|
2522
2743
|
|
|
@@ -2526,10 +2747,11 @@ refusals below name it by design.
|
|
|
2526
2747
|
|
|
2527
2748
|
### The refusal
|
|
2528
2749
|
|
|
2529
|
-
|
|
2530
|
-
The refusal answers in the ledger-mutation domain, not the core domain,
|
|
2531
|
-
the claim coordinator refused before the core mutation ran. Section 2
|
|
2532
|
-
that rule; `namespace` is what a consumer reads to recognize it.
|
|
2750
|
+
A blocking reconciliation finding makes the next mutating command return exit
|
|
2751
|
+
6. The refusal answers in the ledger-mutation domain, not the core domain,
|
|
2752
|
+
because the claim coordinator refused before the core mutation ran. Section 2
|
|
2753
|
+
states that rule; `namespace` is what a consumer reads to recognize it. The
|
|
2754
|
+
example below is an authorized new item that is still absent from `HEAD`.
|
|
2533
2755
|
|
|
2534
2756
|
~~~json
|
|
2535
2757
|
{
|
|
@@ -2564,8 +2786,11 @@ that rule; `namespace` is what a consumer reads to recognize it.
|
|
|
2564
2786
|
`details.findings`. Every finding that blocks a mutation carries a
|
|
2565
2787
|
`remediation` string, and every such string names both the path to act on and
|
|
2566
2788
|
`claim-verify`. `actual_revision: null` with `observed_surface: "git-head"`
|
|
2567
|
-
means the authorized
|
|
2568
|
-
uncommitted mutation
|
|
2789
|
+
means the authorized item is absent from `HEAD`, so Git finalization is
|
|
2790
|
+
required. Not every uncommitted mutation produces this refusal: an existing
|
|
2791
|
+
item whose working tree has the latest authorized bytes while `HEAD` has an
|
|
2792
|
+
earlier authorized revision is the nonblocking predecessor/successor window
|
|
2793
|
+
defined above.
|
|
2569
2794
|
|
|
2570
2795
|
`spec/fixtures/mutation-refusals/uncommitted-prior-mutation/manifest.json` is
|
|
2571
2796
|
the normative envelope for this refusal.
|
|
@@ -2578,10 +2803,19 @@ envelope, subject and commit set included.
|
|
|
2578
2803
|
For every blocking finding:
|
|
2579
2804
|
|
|
2580
2805
|
1. Do what `remediation` says, for each finding, using its `expected_path`.
|
|
2581
|
-
`git-finalization-required` means commit that path.
|
|
2582
|
-
|
|
2583
|
-
|
|
2584
|
-
|
|
2806
|
+
`git-finalization-required` means commit that path. A
|
|
2807
|
+
`worktree-synchronization-required` finding means wait only when its
|
|
2808
|
+
`remediation` names an owner to wait for or says the expected revision is not
|
|
2809
|
+
yet reachable. When it says the revision is reachable in Git while no active
|
|
2810
|
+
named worktree owner is established, there is no commit left to wait for:
|
|
2811
|
+
inspect that reachable history, then restore or explicitly adopt reviewed
|
|
2812
|
+
bytes.
|
|
2813
|
+
2. Run `wowbagger claim-verify --ledger <dir> --id <finding.item_id> --json`
|
|
2814
|
+
for each affected item. Use the bare command only for strict repository
|
|
2815
|
+
diagnosis.
|
|
2816
|
+
3. Exit 0 with `state: "committed"` means that item is reconciled and its next
|
|
2817
|
+
mutating command may run. Exit 6 means blocking findings remain; repeat from
|
|
2818
|
+
step 1.
|
|
2585
2819
|
|
|
2586
2820
|
The reasons a `stale-write-detected` finding can carry, and the other blocking
|
|
2587
2821
|
finding codes, are enumerated in the [work-claim
|
|
@@ -2628,22 +2862,30 @@ by sending the flag, not by reading a version.
|
|
|
2628
2862
|
|
|
2629
2863
|
Only the paths this invocation owns:
|
|
2630
2864
|
|
|
2631
|
-
|
|
|
2632
|
-
|---|---|
|
|
2633
|
-
| `create` | the created item |
|
|
2865
|
+
| `create` | the created item and one `<ledger>/.wowbagger/reconcile-<namespace>.md` |
|
|
2634
2866
|
| `transition` | the changed item and one `<ledger>/.wowbagger/reconcile-<namespace>.md` |
|
|
2635
|
-
| `
|
|
2636
|
-
| `
|
|
2637
|
-
|
|
2638
|
-
`
|
|
2639
|
-
|
|
2640
|
-
|
|
2641
|
-
|
|
2867
|
+
| `parent-migrate` | the changed item and one reconciliation log |
|
|
2868
|
+
| `snooze` | the changed item and one reconciliation log |
|
|
2869
|
+
| `patch` | the changed item and one reconciliation log |
|
|
2870
|
+
| `publish-claimed` | the published item and one reconciliation log |
|
|
2871
|
+
|
|
2872
|
+
The item path appears in the set only when the successor bytes differ from the
|
|
2873
|
+
item bytes at `HEAD`. A byte-identical `parent-migrate`, `snooze`, or `patch`
|
|
2874
|
+
still records its decision in the reconciliation log, so its auto-commit set
|
|
2875
|
+
contains the log alone.
|
|
2876
|
+
|
|
2877
|
+
`create` is journal-visible from the item's birth, so a successful `create`
|
|
2878
|
+
commits exactly the created item and its reconciliation log. For every command,
|
|
2879
|
+
the log must already carry this invocation's terminal entry before it may be
|
|
2880
|
+
staged; if it does not, the invocation reports `git-commit-failed` with
|
|
2881
|
+
`reason: "log-unavailable"`.
|
|
2642
2882
|
|
|
2643
2883
|
Commit subjects are fixed:
|
|
2644
2884
|
|
|
2645
2885
|
wowbagger: create item #N
|
|
2646
2886
|
wowbagger: transition item #N
|
|
2887
|
+
wowbagger: parent-migrate item #N
|
|
2888
|
+
wowbagger: snooze item #N
|
|
2647
2889
|
wowbagger: patch item #N
|
|
2648
2890
|
wowbagger: publish claimed item #N
|
|
2649
2891
|
|
|
@@ -2664,12 +2906,16 @@ Before the mutation runs, the invocation takes a per-working-tree mutex and
|
|
|
2664
2906
|
requires all of:
|
|
2665
2907
|
|
|
2666
2908
|
- No path staged anywhere in the repository.
|
|
2667
|
-
- No dirty path under the ledger
|
|
2909
|
+
- No dirty path under the ledger, with one exception: `transition`,
|
|
2910
|
+
`parent-migrate`, `snooze`, `patch`, and `publish-claimed` tolerate a dirty
|
|
2911
|
+
current-namespace reconciliation log, because each rebuilds that one derived
|
|
2912
|
+
file from the authoritative journal. `create` does not tolerate it.
|
|
2668
2913
|
- A Git identity Git can resolve without committing.
|
|
2669
2914
|
- A `HEAD` that exists. A detached `HEAD` is supported, because a commit works
|
|
2670
2915
|
from one; an unborn `HEAD` refuses.
|
|
2671
|
-
-
|
|
2672
|
-
prior mutation refuse before
|
|
2916
|
+
- An internal `claim-verify` with no findings blocking the target item, which
|
|
2917
|
+
is also what makes an unreconciled prior mutation refuse before
|
|
2918
|
+
`publish-claimed`.
|
|
2673
2919
|
|
|
2674
2920
|
Unstaged and untracked paths **outside** the ledger are allowed and stay
|
|
2675
2921
|
byte-identical; they are never staged. Any other failure returns exit 4
|
|
@@ -2678,11 +2924,27 @@ staging, or commit occurs. `details.reason` is one of `staged-paths-present`,
|
|
|
2678
2924
|
`ledger-not-clean`, `identity-unavailable`, `unborn-head`, `mutex-held`,
|
|
2679
2925
|
`claim-state-unreconciled`, or `git-unavailable`.
|
|
2680
2926
|
|
|
2681
|
-
|
|
2682
|
-
|
|
2683
|
-
|
|
2684
|
-
|
|
2685
|
-
|
|
2927
|
+
Every `auto-commit-preflight-failed` refusal also carries
|
|
2928
|
+
`details.retryable`. `mutex-held` is retryable inside one working tree.
|
|
2929
|
+
`claim-state-unreconciled` also carries optional `claim_verify_code`,
|
|
2930
|
+
`claim_verify_reason`, `identity_diagnostic`, and bounded `findings`;
|
|
2931
|
+
`claim-store-locked` is retryable, while persistent reconciliation is not
|
|
2932
|
+
retryable. An `identity_diagnostic` reports an ambiguous or unreadable
|
|
2933
|
+
worktree identity — `duplicate-worktree-identity` with `worktree_id` and
|
|
2934
|
+
`live_worktree_count`, or `worktree-enumeration-failed` with no further member
|
|
2935
|
+
— and is never retryable. Every other
|
|
2936
|
+
preflight reason is not retryable. Clients branch on this boolean and the
|
|
2937
|
+
underlying verification reason, never on the generic message.
|
|
2938
|
+
|
|
2939
|
+
The rule is deliberately strict rather than preserving foreign staged work in
|
|
2940
|
+
a temporary index. A journal-owning auto-commit validates and rebuilds the
|
|
2941
|
+
dirty derived reconciliation log from the authoritative journal, then commits
|
|
2942
|
+
it with the mutation. Owning the log is not absorbing what was already in it:
|
|
2943
|
+
`create` still refuses a dirty reconciliation log, because residue that
|
|
2944
|
+
predates the invocation is foreign to the entries create is about to write.
|
|
2945
|
+
Every other dirty ledger path refuses. Claim refusal evidence is never
|
|
2946
|
+
suppressed: both the authoritative journal and its projected log retain the
|
|
2947
|
+
decision before a later command rebuilds or commits the log.
|
|
2686
2948
|
|
|
2687
2949
|
A flagged invocation on an advisory or non-provisioned ledger returns exit 5
|
|
2688
2950
|
`capability-unavailable` with `state: "unchanged"` before the mutation. It does
|
|
@@ -2704,12 +2966,18 @@ not fall back to manual mode.
|
|
|
2704
2966
|
dirt: refusing on it would make an already-published item impossible to
|
|
2705
2967
|
commit.
|
|
2706
2968
|
|
|
2969
|
+
When a successful mutation produces item bytes identical to `HEAD`, the item
|
|
2970
|
+
path is omitted from `commit_paths`; the journal log remains the only changed
|
|
2971
|
+
path. This avoids reporting a staged-path mismatch for a valid audit-only
|
|
2972
|
+
mutation and keeps `mutation-finalize` idempotent after an advanced `HEAD`.
|
|
2973
|
+
|
|
2707
2974
|
On success the response keeps its original domain and adds three members to
|
|
2708
2975
|
`result`: `git_commit`, `commit_paths`, and `claim_verified: true`. A successful
|
|
2709
2976
|
invocation does not return until an internal `claim-verify` exits 0 with no
|
|
2710
|
-
findings and a valid ledger.
|
|
2711
|
-
|
|
2712
|
-
|
|
2977
|
+
findings blocking the target item and a valid ledger. Nonblocking findings
|
|
2978
|
+
remain available to `claim-verify`; the success envelope does not duplicate
|
|
2979
|
+
them. For `publish-claimed`, the same verification must also report
|
|
2980
|
+
`git_finalized: true` and the new commit in the publication's finalization row.
|
|
2713
2981
|
|
|
2714
2982
|
### The commit-failed contract
|
|
2715
2983
|
|
|
@@ -2718,8 +2986,9 @@ Exit 6, `state: "committed"`, code `git-commit-failed`, message
|
|
|
2718
2986
|
still describes item publication as section 2 defines it. It does not claim Git
|
|
2719
2987
|
finalization.
|
|
2720
2988
|
|
|
2721
|
-
`create`, `transition`, and `patch` keep the core
|
|
2722
|
-
original command name, and the core
|
|
2989
|
+
`create`, `transition`, `parent-migrate`, `snooze`, and `patch` keep the core
|
|
2990
|
+
domain: no `namespace`, the original command name, and the core
|
|
2991
|
+
`contract_version`. `ledger-mutation` is
|
|
2723
2992
|
not used, because that domain means the fence refused before the core mutation
|
|
2724
2993
|
ran. `publish-claimed` keeps `namespace: "ledger-publication"`,
|
|
2725
2994
|
`command: "publish-claimed"`, its legacy envelope marker, and its top-level
|
|
@@ -2743,7 +3012,10 @@ it match.
|
|
|
2743
3012
|
|
|
2744
3013
|
A commit that is established while reconciliation then refuses is exit 6
|
|
2745
3014
|
`post-commit-reconciliation-failed` with `state: "committed"`. It carries
|
|
2746
|
-
`git_commit`, `commit_paths`, and
|
|
3015
|
+
`git_commit`, `commit_paths`, and optional `claim_verify_code`,
|
|
3016
|
+
`claim_verify_reason`, and bounded `findings` from the failed verification. The
|
|
3017
|
+
commit stands; callers inspect the preserved cause and never replay the
|
|
3018
|
+
mutation.
|
|
2747
3019
|
|
|
2748
3020
|
No failure envelope contains raw hook output, signing output, an absolute path,
|
|
2749
3021
|
an environment value, or platform exception text. A bounded human diagnostic may
|