wowbagger 0.1.0-alpha.7 → 0.1.0-alpha.8
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 +193 -1
- package/README.md +194 -16
- package/adapters/claude-code/wowbagger-adapter.json +1 -1
- package/adapters/codex/wowbagger-adapter.json +1 -1
- package/adapters/opencode/wowbagger-adapter.json +1 -1
- package/docs/adapter-contract.md +66 -6
- package/docs/host-contract.md +287 -0
- package/docs/mutation-contract.md +558 -17
- package/docs/work-claim-contract.md +56 -24
- package/package.json +14 -1
- package/schemas/bare-ready-result.json +27 -0
- package/schemas/bare-validation-result.json +23 -0
- package/schemas/common.json +470 -0
- package/schemas/core-capabilities-response.json +346 -0
- package/schemas/core-envelope.json +141 -0
- package/schemas/core-inspect-response.json +37 -0
- package/schemas/core-inspect-workbench-response.json +340 -0
- package/schemas/core-list-error-response.json +242 -0
- package/schemas/core-list-query.json +98 -0
- package/schemas/core-list-response.json +140 -0
- package/schemas/core-report-response.json +379 -0
- package/schemas/core-transition-error-response.json +852 -0
- package/schemas/core-transition-request.json +47 -0
- package/schemas/core-transition-response.json +49 -0
- package/schemas/index.json +108 -0
- package/schemas/ledger-mutation-refusal.json +288 -0
- package/schemas/report-config-v1.json +140 -0
- package/schemas/report-config-v2.json +242 -0
- package/skills/wowbagger/SKILL.md +151 -38
- package/src/adapter/core-probe.js +87 -7
- package/src/claim-capabilities.js +4 -5
- package/src/claim-coordinator.js +15 -2
- package/src/claim-prospective.js +151 -0
- package/src/claim-publication.js +49 -9
- package/src/claim-sync.js +66 -0
- package/src/cli.js +671 -49
- package/src/extension-provision.js +33 -0
- package/src/git-autocommit.js +36 -6
- package/src/git-reconciliation.js +53 -9
- package/src/launch.js +52 -0
- package/src/lifecycle.js +153 -0
- package/src/limits.js +39 -0
- package/src/list.js +365 -0
- package/src/mutation.js +145 -118
- package/src/projection.js +39 -0
- package/src/report-graph.js +122 -21
- package/src/report-html.js +219 -51
- package/src/report-view.js +189 -0
- package/src/report.js +145 -15
- package/src/validate.js +4 -1
- package/src/workbench.js +117 -0
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,160 @@ consolidation. The first tagged release inherits this file.
|
|
|
7
7
|
|
|
8
8
|
## Unreleased
|
|
9
9
|
|
|
10
|
+
## 0.1.0-alpha.8 - 2026-08-23
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- **A published launch seam for a host that cannot run a shell.** The package
|
|
15
|
+
now declares `exports`, and its main entry `wowbagger` exposes
|
|
16
|
+
`CORE_SCRIPT_PATH`, `MINIMUM_NODE_MAJOR`, and `resolveCoreLaunch(argv)`, which
|
|
17
|
+
returns the exact process tuple a direct-core host needs: an absolute Node
|
|
18
|
+
executable, an argument array whose first element is the absolute
|
|
19
|
+
`bin/wowbagger.js`, and `shell: false`. A host that resolves its own runtime
|
|
20
|
+
gets `resolveCoreLaunch(argv, { nodeExecutable })`, and a relative or bare
|
|
21
|
+
executable name is refused rather than left for PATH to answer. The script
|
|
22
|
+
path is also resolvable on its own as `wowbagger/wowbagger.js` for a host that
|
|
23
|
+
wants the path without importing anything. Deep imports that already worked —
|
|
24
|
+
`wowbagger/src/limits.js` and every other published path — keep resolving
|
|
25
|
+
through an explicit `"./*"` subpath. No command accepts, refuses, emits, or
|
|
26
|
+
writes anything different.
|
|
27
|
+
|
|
28
|
+
- **The machine contract ships as JSON Schema, not only as prose and fixtures.**
|
|
29
|
+
Seventeen JSON Schema 2020-12 documents under `schemas/` are published with
|
|
30
|
+
the package and resolvable as `wowbagger/schemas/<file>.json`, with
|
|
31
|
+
`schemas/index.json` naming each one's response domain and that domain's
|
|
32
|
+
version. They cover the core envelope and its four exact root shapes, the
|
|
33
|
+
capabilities envelope with every advertised limit as a constant, the two bare
|
|
34
|
+
results, the list query and its page and refusals, the default and workbench
|
|
35
|
+
inspect projections, the transition request, success, and every documented
|
|
36
|
+
refusal with its mutation state, the `ledger-mutation` fence refusals, report
|
|
37
|
+
configuration versions 1 and 2, and the report responses including a named
|
|
38
|
+
view. Every schema fixes its root members exactly and pins the version of its
|
|
39
|
+
own domain, so a core envelope refuses a namespaced refusal, a version 4
|
|
40
|
+
envelope, or an extra root member, and a version 1 report configuration
|
|
41
|
+
refuses a version 2 one. Exactness reaches the members too: an item core must
|
|
42
|
+
carry both relation lists, because the core view always emits them, and a
|
|
43
|
+
refusal raised before a commit is established pins its state to `unchanged`
|
|
44
|
+
rather than admitting the indeterminate state that only an interrupted write
|
|
45
|
+
can report. The validator is a test-only dependency; the runtime still has
|
|
46
|
+
exactly one dependency.
|
|
47
|
+
|
|
48
|
+
### Documentation
|
|
49
|
+
|
|
50
|
+
- **`docs/host-contract.md` publishes the direct-core host boundary.** One
|
|
51
|
+
document now states what a UI plugin or other non-agent consumer needs and
|
|
52
|
+
what it must supply itself: the package resolution seam and the four-part
|
|
53
|
+
launch — Node.js 20 or later, an absolute Node executable, the absolute
|
|
54
|
+
`wowbagger.js`, an argument array, and `shell: false`; bounded stdin or a
|
|
55
|
+
host-created request file, never shell source and never inline unbounded argv
|
|
56
|
+
JSON; captured stdout and stderr; the owning-host path rule for a worktree, a
|
|
57
|
+
plain folder, direct SSH, and WSL, with no cross-runtime path guessing;
|
|
58
|
+
namespace-first response dispatch and the exit table; every advertised limit
|
|
59
|
+
with its exact value; the once-only dispatch sequence for a lost response; and
|
|
60
|
+
the seventeen packaged JSON Schemas by domain. It states that a missing
|
|
61
|
+
executable is a host-level result rather than malformed Wowbagger JSON, that
|
|
62
|
+
the host owns executable discovery, working directory, timeout, cancellation,
|
|
63
|
+
process-tree containment, stream caps, and routing, and that Wowbagger will
|
|
64
|
+
not add automatic transitions, mirrored ledger state, operation identity,
|
|
65
|
+
remote routing, or a daemon. The full `inspect` read is documented as
|
|
66
|
+
deliberately unbounded, with the reason. The README, the installed skill, and
|
|
67
|
+
`SPEC.md` section 10 point at it, and it ships in the npm package.
|
|
68
|
+
- **The public version and lifecycle vocabulary agrees with the runtime.**
|
|
69
|
+
`SPEC.md` section 10 said core mutation contracts 1 and 2 were defined and
|
|
70
|
+
that the runtime emitted version 2; it now says 1 through 5 and version 5. The
|
|
71
|
+
mutation contract's status line said versions 1, 2, and 3 with the runtime on
|
|
72
|
+
3; it now says 1 through 5 and version 5. `deferred` has been a real status
|
|
73
|
+
since it shipped, but `SPEC.md` omitted it from the status field, the
|
|
74
|
+
lifecycle table, the transition table, the terminal-date invariants, the
|
|
75
|
+
decision-action list, and the terminal-decision table, and the mutation
|
|
76
|
+
contract omitted the `deferred` date from the lossless core view; all seven
|
|
77
|
+
now name it, along with the `resolve`, `defer`, and `undefer` decision actions
|
|
78
|
+
the validator has always accepted. No behaviour changed: these were prose
|
|
79
|
+
omissions, and the tests that guard them read the vocabularies from
|
|
80
|
+
`src/lifecycle.js` and `src/validate.js` rather than retyping them.
|
|
81
|
+
- **Response loss is a named contract instead of folklore.** The mutation
|
|
82
|
+
contract, the adapter contract, the README, and the installed skill now carry
|
|
83
|
+
the same sequence for a mutation whose response never arrived: dispatch once,
|
|
84
|
+
never replay, invalidate the inspected revision, reconnect, then re-read the
|
|
85
|
+
ledger. The mutation contract's new section 10 table separates the outcomes a
|
|
86
|
+
caller may act on — committed success, proven non-write, committed recovery,
|
|
87
|
+
unknown publication — from the two that establish nothing, a signalled or
|
|
88
|
+
timed-out transport and a missing envelope, and states that a later item state
|
|
89
|
+
never proves that the lost dispatch caused it. Adapter contract section 6.2
|
|
90
|
+
documents the `mutation_outcome: "unknown"` envelope and its per-command
|
|
91
|
+
`recovery` object exactly as the adapter emits them, and states that exit 4
|
|
92
|
+
`revision-conflict` is a proven non-write that is never relabelled response
|
|
93
|
+
loss. There is no operation ID, durable outcome store, or replay endpoint;
|
|
94
|
+
adding correlation requires a new contract decision. No command accepts,
|
|
95
|
+
refuses, emits, or writes anything different. Two conformance vectors now pin
|
|
96
|
+
the core's own exit-6 `write-outcome-unknown` and `post-commit-recovery-required`
|
|
97
|
+
envelopes at the adapter's process-outcome seam, taking the adapter vector set
|
|
98
|
+
to 212 assertions.
|
|
99
|
+
- **The exit tables state where `report` actually lands.** Both contracts filed
|
|
100
|
+
exit 1 as a bare-result-only condition and exit 3 as every invalid ledger,
|
|
101
|
+
while `report` answers an invalid ledger, an unreadable input, and a failed
|
|
102
|
+
publication at exit 1. The mutation contract now carries an exit 1 row naming
|
|
103
|
+
those codes, lists `report-config-invalid` and `report-view-not-found` in its
|
|
104
|
+
exit 2 row, and scopes exit 3 to every command except `report`; the host
|
|
105
|
+
contract's exit 1 and exit 3 conditions say the same. Two guards assert the
|
|
106
|
+
rows against the codes the runtime emits.
|
|
107
|
+
|
|
108
|
+
### Changed
|
|
109
|
+
|
|
110
|
+
- **The report filters by facet groups instead of one value at a time.** The
|
|
111
|
+
drill-down's single-value mapped-field selects and its All/Ready/Blocked/
|
|
112
|
+
Ineligible buttons are gone. In their place is one group of checkbox chips per
|
|
113
|
+
dimension of the open set — Readiness, Status, Kind, and every configured
|
|
114
|
+
mapped field, so a mapped `class: bug` is a chip rather than a value hidden in
|
|
115
|
+
a dropdown. Values inside a group are alternatives, groups narrow each other,
|
|
116
|
+
and the search box is one more condition; every chip states the count it would
|
|
117
|
+
leave, measured against the search and the other groups but never against its
|
|
118
|
+
own, so two selections in one group cannot make their siblings read zero. A
|
|
119
|
+
visible result count, per-chip selected state, and `Clear filters` are new, and
|
|
120
|
+
opening a Work next or Attention row still clears whatever detached its card,
|
|
121
|
+
facets included.
|
|
122
|
+
- **The ledger graph filters by lifecycle status.** One chip group above the
|
|
123
|
+
stage carries the statuses the ledger holds, all selected, with `Select all`
|
|
124
|
+
and `Clear`. Deselecting a status drops its nodes, every link incident to one,
|
|
125
|
+
and their labels, reheats the layout in place, and takes a hidden node off the
|
|
126
|
+
hover card; the roster and node count follow the same selection, and an empty
|
|
127
|
+
selection draws an empty graph that says so. The legend, the WebGL-less
|
|
128
|
+
roster, camera interaction, and the no-fetch contract are unchanged, and
|
|
129
|
+
nothing here reads or writes the ledger.
|
|
130
|
+
|
|
131
|
+
### Fixed
|
|
132
|
+
|
|
133
|
+
- **A report failure before publication says so, and never arrives causeless.**
|
|
134
|
+
An output path the filesystem cannot resolve — a `--out` under a regular
|
|
135
|
+
file, an unreadable directory on the way to it — was a raw runtime error
|
|
136
|
+
escaping into the command's catch-all, answered as `report-write-failed` with
|
|
137
|
+
empty `details` even though nothing had been rendered or replaced. It is now
|
|
138
|
+
`report-read-failed` with `details.operation` naming which resolution failed,
|
|
139
|
+
`details.path` naming the path the caller configured or passed, and
|
|
140
|
+
`details.cause` naming the filesystem's own code. An error no report path
|
|
141
|
+
throws on purpose still answers `report-write-failed`, because nothing
|
|
142
|
+
reached the output path, but it now carries `{operation, cause}` instead of
|
|
143
|
+
`{}`. Every `details.cause` is a bounded token — an error code, or the
|
|
144
|
+
error's kind when the runtime gave no code — so a publication failure no
|
|
145
|
+
longer republishes a runtime message, and the paths, credentials, and
|
|
146
|
+
run-specific values a message carries stay out of the envelope. Atomic
|
|
147
|
+
publication is unchanged: a report already at the selected path survives
|
|
148
|
+
every one of these refusals.
|
|
149
|
+
- **An empty named view stops blaming the reader.** A view whose criteria
|
|
150
|
+
matched nothing rendered the drill-down's `No items match these filters.` and
|
|
151
|
+
the graph's `No status is selected`, sending a reader to controls that could
|
|
152
|
+
not bring an item back. A named artifact with no items now states
|
|
153
|
+
`No ledger item matches this view's criteria.` and, in the graph, that it has
|
|
154
|
+
nothing to draw — visibly, without waiting for scripting. A report that holds
|
|
155
|
+
items keeps the filter and status copy, which is the honest answer when the
|
|
156
|
+
reader is the one who narrowed it, and the base report's bytes are unchanged.
|
|
157
|
+
- **`core-report-response.json` named a member the report never emitted.** The
|
|
158
|
+
published `ledger-invalid` refusal required `details.validation_errors`,
|
|
159
|
+
which is the mutation commands' member name; `report` has always emitted
|
|
160
|
+
`details.errors`. A consumer validating a real refusal against the shipped
|
|
161
|
+
schema failed on the runtime's own bytes. The schema now states `errors`, and
|
|
162
|
+
a live invalid-ledger report run is validated against it.
|
|
163
|
+
|
|
10
164
|
## 0.1.0-alpha.7 - 2026-08-18
|
|
11
165
|
|
|
12
166
|
### Changed
|
|
@@ -157,6 +311,44 @@ consolidation. The first tagged release inherits this file.
|
|
|
157
311
|
|
|
158
312
|
### Added
|
|
159
313
|
|
|
314
|
+
- **`inspect` answers a bounded per-item lifecycle affordance projection.**
|
|
315
|
+
`inspect --ledger <dir> (--id <id> | --number <n>) --workbench --as-of
|
|
316
|
+
YYYY-MM-DD --json` returns, from one complete validated ledger snapshot,
|
|
317
|
+
`result.workbench`: the projection version, the as-of date, the ledger
|
|
318
|
+
snapshot witness, an `observation` member, a bounded item summary, and one
|
|
319
|
+
`transition_options` entry for every lifecycle target the native edge table
|
|
320
|
+
allows out of that item's kind and status. Each option names its target
|
|
321
|
+
status, its generated decision action or `null`, whether a caller-supplied
|
|
322
|
+
summary and rationale are required, the minimum legal transition date
|
|
323
|
+
`max(created, updated)`, its observed enabled state, and the observed
|
|
324
|
+
precondition issues and multi-item blockers in the exact `transition`
|
|
325
|
+
vocabulary. A workbench can now show a person which transitions an item can
|
|
326
|
+
take without duplicating lifecycle logic and without submitting a mutating
|
|
327
|
+
probe.
|
|
328
|
+
|
|
329
|
+
The read is an observation, not a lease, and says so in the response:
|
|
330
|
+
`observation.authority` is `observed-snapshot` and `observation.rechecked_by`
|
|
331
|
+
names what a later `transition` rechecks under lock — revision, lock, claim
|
|
332
|
+
fence, reconciliation, and candidate validation. It writes no item, lock,
|
|
333
|
+
claim journal, reconciliation log, or Git state, and it takes no lock.
|
|
334
|
+
`transition` and the projection share one lifecycle definition
|
|
335
|
+
(`src/lifecycle.js`), and a differential guard dispatches every projected
|
|
336
|
+
option and every unadvertised target through the real mutation, so an
|
|
337
|
+
advertised affordance cannot drift from what the mutation does.
|
|
338
|
+
|
|
339
|
+
Every variable-size field is bounded and says what it left out: the projected
|
|
340
|
+
title, the relation lists, each option's issues and blockers, and the related
|
|
341
|
+
IDs inside an issue. `--workbench` requires `--as-of`, an unpaired `--as-of`
|
|
342
|
+
is refused rather than ignored, and an `inspect` invocation without
|
|
343
|
+
`--workbench` is byte-identical to before. `capabilities` advertises
|
|
344
|
+
`operations.inspect.workbench` and the three exact bounds
|
|
345
|
+
`max_workbench_title_characters`, `max_workbench_collection_entries`, and
|
|
346
|
+
`max_workbench_response_bytes`; the core contract version stays 5, and the
|
|
347
|
+
projection is negotiated by its own `projection_version`. An invalid ledger is
|
|
348
|
+
`ledger-invalid` at exit 3 with no projection attached, and a projection that
|
|
349
|
+
would exceed its response bound is refused whole with
|
|
350
|
+
`workbench-response-too-large` at exit 2.
|
|
351
|
+
|
|
160
352
|
- **The conformance suite now measures real core outcomes end to end.** A new
|
|
161
353
|
equivalence case, `16-core-outcome-e2e`, carries nine hand-authored scenarios
|
|
162
354
|
that each run the direct real core in one isolated temporary workspace and,
|
|
@@ -570,7 +762,7 @@ consolidation. The first tagged release inherits this file.
|
|
|
570
762
|
every read and every guarded mutation on that ledger, including ones that
|
|
571
763
|
never touch the misplaced item, so the refusal has to say where the item
|
|
572
764
|
belongs. The claim fence is not involved: `claim-verify` reports no finding
|
|
573
|
-
on such a ledger, refuting
|
|
765
|
+
on such a ledger, refuting an earlier consumer report that a
|
|
574
766
|
root-misplaced item makes the fence report `stale-write-detected` with
|
|
575
767
|
`actual_revision: null`. Fixtures pin both configuration orders — layout
|
|
576
768
|
bound first, and layout bound after the item was already committed at the
|
package/README.md
CHANGED
|
@@ -20,8 +20,8 @@ agent to use those guarantees instead of hand-editing your Markdown.
|
|
|
20
20
|
|
|
21
21
|
**Start here:** [install the core and set up a ledger](#start-here).
|
|
22
22
|
|
|
23
|
-
> **Status: alpha, published, and self-hosted.** `0.1.0-alpha.
|
|
24
|
-
> the `next` tag and on this repository's `v0.1.0-alpha.
|
|
23
|
+
> **Status: alpha, published, and self-hosted.** `0.1.0-alpha.8` is on npm under
|
|
24
|
+
> the `next` tag and on this repository's `v0.1.0-alpha.8` tag. It is the
|
|
25
25
|
> version this repository runs its own backlog on. The API is not frozen and the
|
|
26
26
|
> version will move before a stable release.
|
|
27
27
|
>
|
|
@@ -39,7 +39,7 @@ agent to use those guarantees instead of hand-editing your Markdown.
|
|
|
39
39
|
> version is **3**. Three adapter packages ship — Claude Code, Codex, and
|
|
40
40
|
> OpenCode — on one shared engine at adapter contract version 2. Only the Claude
|
|
41
41
|
> Code adapter declares a `supported` platform, Darwin, from a native run of all
|
|
42
|
-
>
|
|
42
|
+
> 212 conformance assertions across all 16 cases. Every other adapter and
|
|
43
43
|
> platform declaration is `unverified`; do not infer support because the CLI
|
|
44
44
|
> starts.
|
|
45
45
|
>
|
|
@@ -60,8 +60,8 @@ Install the core CLI, then verify it:
|
|
|
60
60
|
```sh
|
|
61
61
|
npm install -g wowbagger@next # public npm registry
|
|
62
62
|
# or, from this release's Git tag:
|
|
63
|
-
# npm install -g github:lstutzman/wowbagger#v0.1.0-alpha.
|
|
64
|
-
wowbagger --version # 0.1.0-alpha.
|
|
63
|
+
# npm install -g github:lstutzman/wowbagger#v0.1.0-alpha.8
|
|
64
|
+
wowbagger --version # 0.1.0-alpha.8
|
|
65
65
|
wowbagger capabilities --json
|
|
66
66
|
```
|
|
67
67
|
|
|
@@ -75,7 +75,7 @@ In Claude Code, add the plugin:
|
|
|
75
75
|
The plugin drives the installed core rather than bundling one, so a mismatch is
|
|
76
76
|
detectable instead of silent. Its skill reads `wowbagger --version` and
|
|
77
77
|
`capabilities`; it requires the same distribution version as the plugin and core
|
|
78
|
-
`contract_version:
|
|
78
|
+
`contract_version: 5`. It refuses an absent or incompatible core. It will not
|
|
79
79
|
fall back to editing ledger files by hand, because that would bypass validation
|
|
80
80
|
and atomic publication.
|
|
81
81
|
|
|
@@ -253,7 +253,7 @@ two supported install routes:
|
|
|
253
253
|
registry requires a `latest` tag), so a bare install resolves to the same
|
|
254
254
|
bytes.
|
|
255
255
|
- **git tag** —
|
|
256
|
-
`npm install -g github:lstutzman/wowbagger#v0.1.0-alpha.
|
|
256
|
+
`npm install -g github:lstutzman/wowbagger#v0.1.0-alpha.8` installs this
|
|
257
257
|
release. Installing at a ref installs the core and every adapter that ref
|
|
258
258
|
carries.
|
|
259
259
|
|
|
@@ -325,7 +325,7 @@ Upgrade the pieces you installed:
|
|
|
325
325
|
|
|
326
326
|
```sh
|
|
327
327
|
npm install -g wowbagger@next # public npm registry
|
|
328
|
-
npm install -g github:lstutzman/wowbagger#v0.1.0-alpha.
|
|
328
|
+
npm install -g github:lstutzman/wowbagger#v0.1.0-alpha.8 # immutable Git release
|
|
329
329
|
git pull && npm ci # or: a direct checkout
|
|
330
330
|
```
|
|
331
331
|
|
|
@@ -342,12 +342,12 @@ wowbagger capabilities --json
|
|
|
342
342
|
```
|
|
343
343
|
|
|
344
344
|
The plugin requires its exact core distribution version and top-level core
|
|
345
|
-
`contract_version:
|
|
345
|
+
`contract_version: 5`. Direct API consumers must check the contract version
|
|
346
346
|
they support; installed plugin users must also keep the plugin and core
|
|
347
347
|
distribution versions equal.
|
|
348
348
|
|
|
349
349
|
The shipped adapter selects only adapter contract version 2 and requires core
|
|
350
|
-
contract version
|
|
350
|
+
contract version 5. The adapter contract and the core contract are separate
|
|
351
351
|
version domains: the adapter stays at 2 while the core moves to 4. A v1-only
|
|
352
352
|
consumer receives `unsupported-adapter-contract-version`; it does not receive v2
|
|
353
353
|
behavior. The schema-2 transport is available. Ledger migration remains a
|
|
@@ -463,8 +463,8 @@ TMPDIR=/tmp node spec/run-adapter-implementation.js --target codex
|
|
|
463
463
|
TMPDIR=/tmp node spec/run-adapter-implementation.js --target opencode
|
|
464
464
|
```
|
|
465
465
|
|
|
466
|
-
The native Darwin and Linux Claude Code reports each pass all
|
|
467
|
-
cases and report `"status": "pass"`. Codex and OpenCode execute the same
|
|
466
|
+
The native Darwin and Linux Claude Code reports each pass all 212 assertions across all 16
|
|
467
|
+
cases and report `"status": "pass"`. Codex and OpenCode execute the same 212
|
|
468
468
|
assertions through the same engine, but both target reports remain `"fail"`
|
|
469
469
|
pending target-specific evidence, and every platform declaration on those two
|
|
470
470
|
manifests stays `unverified`. The Kimi and OpenAI-compatible harness adapters
|
|
@@ -705,6 +705,35 @@ Repeating it creates no second commit, so a lost response and a failed commit
|
|
|
705
705
|
recover the same way. [docs/mutation-contract.md](docs/mutation-contract.md)
|
|
706
706
|
section 13 is the full contract.
|
|
707
707
|
|
|
708
|
+
### When the response is lost
|
|
709
|
+
|
|
710
|
+
A mutation you dispatched can lose its response: the process is signalled or
|
|
711
|
+
times out, a stream arrives truncated, or the transport to the machine that owns
|
|
712
|
+
the ledger drops. None of that observes the ledger, so none of it says whether
|
|
713
|
+
the write applied.
|
|
714
|
+
|
|
715
|
+
Only a complete observed result establishes an outcome. Exit 0 with state
|
|
716
|
+
`committed` is a success; a complete refusal with state `unchanged` is a proven
|
|
717
|
+
non-write; exit 6 `post-commit-recovery-required` says the item is published and
|
|
718
|
+
cleanup remains; exit 6 `write-outcome-unknown` says publication was attempted
|
|
719
|
+
and the visible bytes are indeterminate. Anything else — signal, timeout,
|
|
720
|
+
truncated output, no envelope, no response at all — is unresolved.
|
|
721
|
+
|
|
722
|
+
Unresolved is answered by one sequence, never a retry: Dispatch once, never
|
|
723
|
+
replay, invalidate the inspected revision, reconnect, then re-read the ledger.
|
|
724
|
+
Re-reading is `validate` plus `inspect` of the ID you already know, compared
|
|
725
|
+
against what you observed before you dispatched. What you read back is current
|
|
726
|
+
ledger state; it never proves that the lost dispatch caused it. A person reviews
|
|
727
|
+
that comparison before any new mutation, and the new mutation is built on the
|
|
728
|
+
current revision, not resent.
|
|
729
|
+
|
|
730
|
+
Exit 4 is not response loss. A `revision-conflict` proves the write did not run;
|
|
731
|
+
re-inspect and decide again.
|
|
732
|
+
|
|
733
|
+
There is no operation ID and no replay endpoint, because nothing replays.
|
|
734
|
+
[docs/mutation-contract.md](docs/mutation-contract.md) section 10 is the full
|
|
735
|
+
contract.
|
|
736
|
+
|
|
708
737
|
### When the item was changed outside the protocol
|
|
709
738
|
|
|
710
739
|
An `unauthorized-revision` finding means someone edited the item without going
|
|
@@ -771,6 +800,18 @@ graph**. State counts, item cards, filters, grouping, detail levels, terminal
|
|
|
771
800
|
history, and area-diverse ready batches all remain, demoted below that decision
|
|
772
801
|
surface.
|
|
773
802
|
|
|
803
|
+
The drill-down filters are **facet groups**: Readiness, Status, Kind, and one
|
|
804
|
+
group for every configured mapped field, each a fieldset of checkbox chips.
|
|
805
|
+
Values inside a group are alternatives and groups narrow each other, so
|
|
806
|
+
`ready` or `blocked` in Readiness plus `bug` in Class means ready-or-blocked
|
|
807
|
+
bugs; the search box is one more condition on the same answer. Every chip
|
|
808
|
+
carries the count it would leave, measured against the search and the other
|
|
809
|
+
groups but never against its own, so two selections in one group cannot make
|
|
810
|
+
their siblings read zero. The result count states how much of the open set is
|
|
811
|
+
showing, and **Clear filters** gives every selection back. A Work next or
|
|
812
|
+
Attention row still reaches its card: opening one clears the facets and the
|
|
813
|
+
search first, because a row that names an item promises the item can be seen.
|
|
814
|
+
|
|
774
815
|
The evidence layer is inline SVG, drawn at generation time and embedded in the
|
|
775
816
|
file: an aging heatmap, weekly arrivals against completions, throughput with a
|
|
776
817
|
four-week mean, a cumulative flow area, accept-to-complete cycle time, and a
|
|
@@ -789,6 +830,14 @@ arrowed, a `parent` edge is curved and unarrowed. Hovering or clicking a node
|
|
|
789
830
|
opens a card with its number, title, status, age, leverage, and the same
|
|
790
831
|
reasons line the ranked list prints for it.
|
|
791
832
|
|
|
833
|
+
Above the stage sits one chip group of the lifecycle statuses the ledger holds,
|
|
834
|
+
all selected, with **Select all** and **Clear**. Deselecting a status drops its
|
|
835
|
+
nodes, every link that touched one of them, and their labels together, then
|
|
836
|
+
reheats the layout in place: nothing is reloaded and the ledger is never
|
|
837
|
+
touched. The roster and the node count follow the same selection, and clearing
|
|
838
|
+
every status draws an empty graph that says it is empty rather than quietly
|
|
839
|
+
showing the last one.
|
|
840
|
+
|
|
792
841
|
The renderer is [`3d-force-graph`](https://github.com/vasturiano/3d-force-graph)
|
|
793
842
|
over Three.js, vendored into `vendor/3d-force-graph/` at a pinned version
|
|
794
843
|
`1.80.0` with its upstream SHA-256 recorded in
|
|
@@ -827,6 +876,134 @@ validates them. `complexity` weighs `xs`/`s`/`small` as 1, `m`/`medium` as 2,
|
|
|
827
876
|
`l`/`large` as 3, and `xl`/`extra-large` as 5; any other value carries no
|
|
828
877
|
weight and is shown as written.
|
|
829
878
|
|
|
879
|
+
### Named custom report views
|
|
880
|
+
|
|
881
|
+
A named custom view is a second self-contained report generated from the same
|
|
882
|
+
complete ledger. Every section of it — statistics, **Work next**, **Attention**,
|
|
883
|
+
the evidence layer, the graph, the open-item drill-down, terminal history, and
|
|
884
|
+
the swarm batches — describes one configured subset, so the file is honest to
|
|
885
|
+
share as a scoped report. Excluded items are absent from the bytes rather than
|
|
886
|
+
hidden by a stylesheet. The base report stays available and unchanged.
|
|
887
|
+
|
|
888
|
+
Report configuration `report_version: 2` accepts every version 1 member and adds
|
|
889
|
+
one more, `views`. A version 1 configuration keeps generating its base report
|
|
890
|
+
unchanged, and a version 2 configuration with no view selected publishes the
|
|
891
|
+
same base report from its inherited base members:
|
|
892
|
+
|
|
893
|
+
```json
|
|
894
|
+
{
|
|
895
|
+
"report_version": 2,
|
|
896
|
+
"repository": { "name": "Example repository" },
|
|
897
|
+
"title": "Ledger report",
|
|
898
|
+
"output": "../../ledger-report.html",
|
|
899
|
+
"fields": {
|
|
900
|
+
"area": "/priority_area",
|
|
901
|
+
"complexity": "/complexity",
|
|
902
|
+
"class": "/class",
|
|
903
|
+
"security": "/security"
|
|
904
|
+
},
|
|
905
|
+
"views": {
|
|
906
|
+
"security-blockers": {
|
|
907
|
+
"title": "Security blockers",
|
|
908
|
+
"output": "../../reports/security-blockers.html",
|
|
909
|
+
"filters": {
|
|
910
|
+
"readiness": ["blocked"],
|
|
911
|
+
"status": ["backlog", "in-progress"],
|
|
912
|
+
"kind": ["task"],
|
|
913
|
+
"fields": {
|
|
914
|
+
"class": ["bug"],
|
|
915
|
+
"security": ["high", "critical"]
|
|
916
|
+
}
|
|
917
|
+
}
|
|
918
|
+
}
|
|
919
|
+
}
|
|
920
|
+
}
|
|
921
|
+
```
|
|
922
|
+
|
|
923
|
+
Generate one view by name:
|
|
924
|
+
|
|
925
|
+
```sh
|
|
926
|
+
wowbagger report --ledger <dir> --view <name> --as-of YYYY-MM-DD --json
|
|
927
|
+
```
|
|
928
|
+
|
|
929
|
+
One invocation generates one artifact; no flag generates them all. `--out <file>`
|
|
930
|
+
overrides the selected output for that invocation, view or base alike, and the
|
|
931
|
+
configured paths are still validated when it is present.
|
|
932
|
+
|
|
933
|
+
A view name is a portable identifier matching `^[a-z][a-z0-9-]{0,63}$`. Names are
|
|
934
|
+
case-sensitive and `views` holds at most 64 views. Each view takes exactly
|
|
935
|
+
`title`, `output`, and `filters`. Unknown members fail closed.
|
|
936
|
+
|
|
937
|
+
`filters` takes exactly `readiness`, `status`, `kind`, and `fields`, and at least
|
|
938
|
+
one of `readiness`, `status`, `kind`, or `fields` must be present. The semantics
|
|
939
|
+
are the drill-down's: **OR within one filter group; AND across groups**, so
|
|
940
|
+
`readiness: ["blocked"]` with `class: ["bug"]` means blocked bugs. `readiness`
|
|
941
|
+
takes `ready`, `blocked`, or `ineligible`; `status` takes `triage`, `backlog`,
|
|
942
|
+
`in-progress`, `done`, `killed`, `archived`, or `deferred`; `kind` takes `task`
|
|
943
|
+
or `epic`.
|
|
944
|
+
|
|
945
|
+
A `fields` key must also be a configured report field. Each field filter is a
|
|
946
|
+
non-empty array of unique JSON strings, finite numbers, or booleans, and matching
|
|
947
|
+
preserves JSON scalar type and value: stringification is not equality, so a
|
|
948
|
+
mapped `2` does not answer a filter for `"2"`. An item carrying no mapped value
|
|
949
|
+
for a field matches no value selected for that field. No title-text inference,
|
|
950
|
+
regular expression, arbitrary JSON pointer, or body search belongs in a view
|
|
951
|
+
filter.
|
|
952
|
+
|
|
953
|
+
Wowbagger validates the complete ledger and computes readiness against the
|
|
954
|
+
complete ledger before it filters, so excluding a blocker never makes blocked
|
|
955
|
+
work read as ready. What a view derives from its retained set does change:
|
|
956
|
+
statistics, ranking leverage, epic enablement, evidence, attention, graph
|
|
957
|
+
membership, and the swarm batches are all view-scoped, so the same item can
|
|
958
|
+
report smaller numbers here than in the base report. That is why the artifact
|
|
959
|
+
names its view and its fixed criteria at the top. A retained item that names an
|
|
960
|
+
excluded dependency, parent, blocker, or related item still prints that item's
|
|
961
|
+
number instead of a raw ULID, and the excluded item gets no row, no graph node,
|
|
962
|
+
no history entry, and no hidden payload.
|
|
963
|
+
|
|
964
|
+
Inside the file, the interactive facets and the graph status chips narrow the
|
|
965
|
+
retained subset further and can never reveal an excluded item. **Clear filters**
|
|
966
|
+
restores the complete custom-view subset, never the base ledger.
|
|
967
|
+
|
|
968
|
+
The base output and every view output must be pairwise distinct after path
|
|
969
|
+
resolution, and each must resolve outside the ledger under the same no-follow
|
|
970
|
+
containment rule the base output already obeys. A colliding or contained output
|
|
971
|
+
is `report-config-invalid` before anything is rendered, `--out` present or not.
|
|
972
|
+
|
|
973
|
+
A named success adds exactly one member to the existing report result,
|
|
974
|
+
`result.view`, and its `item_count` and `ready_count` describe the filtered
|
|
975
|
+
subset. A base report's result gains no `view` member:
|
|
976
|
+
|
|
977
|
+
```json
|
|
978
|
+
{
|
|
979
|
+
"ok": true,
|
|
980
|
+
"command": "report",
|
|
981
|
+
"contract_version": 5,
|
|
982
|
+
"result": {
|
|
983
|
+
"report_version": 2,
|
|
984
|
+
"as_of": "2026-08-21",
|
|
985
|
+
"output": "/absolute/reports/security-blockers.html",
|
|
986
|
+
"item_count": 12,
|
|
987
|
+
"ready_count": 0,
|
|
988
|
+
"view": "security-blockers"
|
|
989
|
+
}
|
|
990
|
+
}
|
|
991
|
+
```
|
|
992
|
+
|
|
993
|
+
`--view` requires `report_version: 2`. A missing or unknown name is
|
|
994
|
+
`report-view-not-found` at exit 2 and leaves every existing output untouched. An
|
|
995
|
+
invalid filter value, an unmapped `fields` key, and a colliding output are
|
|
996
|
+
`report-config-invalid` at exit 2. An empty matched subset is not a failure: it
|
|
997
|
+
publishes a valid report with zero items and explicit empty-state copy. Failed
|
|
998
|
+
publication preserves the prior artifact, so never read an existing output as
|
|
999
|
+
fresh. `wowbagger capabilities --json` advertises the whole surface at
|
|
1000
|
+
`result.operations.report`, so no consumer has to probe by generating a file.
|
|
1001
|
+
|
|
1002
|
+
A custom view is scoped output and **not a security boundary**: it applies no
|
|
1003
|
+
redaction and no access control, and the artifact states plainly that it is a
|
|
1004
|
+
filtered subset of the named repository ledger. Automation reads the JSON result,
|
|
1005
|
+
never the generated HTML and never human output.
|
|
1006
|
+
|
|
830
1007
|
This repository keeps its report configuration in
|
|
831
1008
|
`ledger/.wowbagger/report.json`. Generate the ignored local report with the
|
|
832
1009
|
current UTC date:
|
|
@@ -846,6 +1023,7 @@ they disagree with anything above:
|
|
|
846
1023
|
| [docs/mutation-contract.md](docs/mutation-contract.md) | Response domains and dispatch, capabilities, inspect, create, transition, patch, the extension declaration, the frontmatter ownership table, errors and recovery, and commit-per-mutation. |
|
|
847
1024
|
| [docs/work-claim-contract.md](docs/work-claim-contract.md) | Provisioning, claim CAS rules, claimed publication, reconciliation, revision adoption, and the difference between strict fenced and merge-coordinated backends. |
|
|
848
1025
|
| [docs/adapter-contract.md](docs/adapter-contract.md) | The harness adapter boundary: negotiation, forwarding, guards, approval, and honest outcome mapping. |
|
|
1026
|
+
| [docs/host-contract.md](docs/host-contract.md) | The direct-core host boundary: package resolution, the shell-free process tuple, bounded transport, owning-host paths, response dispatch, advertised limits, and the packaged JSON Schemas. |
|
|
849
1027
|
| [docs/openai-compatible-integration.md](docs/openai-compatible-integration.md) | What an OpenAI-compatible host can do today, and what a compatibility claim would require. |
|
|
850
1028
|
| [docs/schema-2-migration.md](docs/schema-2-migration.md) | The quiesced schema version 1 to 2 migration runbook. |
|
|
851
1029
|
| [skills/wowbagger/SKILL.md](skills/wowbagger/SKILL.md) | The shipped agent instructions. |
|
|
@@ -1011,10 +1189,10 @@ It is the durable work ledger beneath those systems.
|
|
|
1011
1189
|
**Shipped: the policy-input contract and the report's mapped fields keep
|
|
1012
1190
|
consumer vocabulary out of the schema.**
|
|
1013
1191
|
- Stabilize the machine-readable command contract and compatibility evidence.
|
|
1014
|
-
**In progress at core contract version
|
|
1192
|
+
**In progress at core contract version 5; the version is not frozen.**
|
|
1015
1193
|
- Ship Claude Code and Codex adapters. **Claude Code, Codex, and OpenCode
|
|
1016
1194
|
packages share the version 2 engine; the Claude Code manifest declares Darwin
|
|
1017
|
-
`supported` after passing all
|
|
1195
|
+
`supported` after passing all 212 native assertions. Other adapter targets and
|
|
1018
1196
|
platform declarations remain unverified.**
|
|
1019
1197
|
- Document the generic tool contract for other agent harnesses. **Shipped as the
|
|
1020
1198
|
adapter contract and the OpenAI-compatible integration guide.**
|
|
@@ -1023,8 +1201,8 @@ It is the durable work ledger beneath those systems.
|
|
|
1023
1201
|
publication, Git reconciliation, and explicit revision adoption. It
|
|
1024
1202
|
deliberately reports `safe_exclusive_dispatch: false`; direct writes and other
|
|
1025
1203
|
uncoordinated paths remain bypasses.**
|
|
1026
|
-
-
|
|
1027
|
-
project. **
|
|
1204
|
+
- Keep consumer-specific adoption and migration outside the core Wowbagger
|
|
1205
|
+
project. **They are not Wowbagger deliverables.**
|
|
1028
1206
|
|
|
1029
1207
|
## License
|
|
1030
1208
|
|