feat(review): headless JSON verbs + guided assumption-review console - #162
Merged
Conversation
Expose the assumption-review lifecycle as headless `--json` verbs and add a packaged Claude Code skill that drives them, so clearing the review queue no longer requires a human at a bare terminal. Implements specs/053-assumption-review-console (all 27 tasks). US1 — headless JSON verbs: - `review --list [--status|--spec|--severity]...` (verb `review.list`), filtered and canonically ordered server-side. - `review <id> --answer/--waive --json`, `review --spec <s> --waive --json`. - `reconcile --json` / `reconcile --dry-run --json`. - `land --status --json` (new read-only frontier query) and `land --json`. - One shared envelope + error-kind registry (`cli/json_output.py`); one canonical entry-row projection (`assumptions/serialize.py`) shared verbatim by `review --list` and the land report so they can't drift. US2 — guided console: - `maverick-review` skill, installed by `maverick init`, removed by `maverick uninstall`. Sweeps the open queue one entry at a time, applies each decision immediately through the JSON verbs above, then runs reconcile once and reports the frontier. US3 — batched reconcile / frontier / landing flow, with landing offered only on explicit human confirmation. Human-mode output is unchanged throughout (FR-018). Also addresses a code review of the above: - `write_json_document` disables Rich emoji substitution — `:key:`-shaped runs in agent-authored questions and answers were being silently rewritten to unicode emoji on every JSON verb. - Post-write projection re-reads moved outside `json_error_handler`, so a transient read failure after a committed ledger write is reported as `degraded`, not as a failed verb. - bd-availability preconditions report `bd-unavailable` on every verb (was `validation` on two paths). - `land --status`/`land --json` gained a top-level `degraded` flag: an unreadable ledger made `frontier_clear` trivially true and therefore indistinguishable from a verified frontier. - `land.run`'s nothing-to-land early return emits the full result shape. - Heuristic curation reports `absorb_ran`/`squashed_count` so an absorb-only rewrite isn't indistinguishable from a no-op. - `WorkflowError.reason_code` replaces prose substring matching for precondition classification (markers kept as a fallback). - New `cli/commands/land_gate.py` holds the gate/report logic shared by `land` and `land --status`, removing a private-surface import cycle and taking land.py back under the module-size guardrail. - Skill install path shared via `maverick.skills`, written atomically; bd-readiness factored into one `bd_ready_reason()` predicate. Fixes a pre-existing bug found along the way: nothing ever set `ctx.obj["verbosity"]` (the root group sets `ctx.obj["verbose"]`), so verbose progress rendering was dead for every workflow. Now resolved via a shared `resolve_verbosity()`. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012av72R5SPCc84chsUNjhLC
Rich wraps at the terminal width by default, so `maverick uninstall --dry-run` split long file paths mid-segment and left them uncopyable. `soft_wrap=True` keeps each path on one line. Caught by CI, whose tmp directories are longer than a dev box's — the existing assertion passed locally and failed there. The replacement test constructs a path wider than Rich's default width so it fails regardless of environment. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012av72R5SPCc84chsUNjhLC
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Implements
specs/053-assumption-review-console(all 27 tasks).Expose the assumption-review lifecycle as headless
--jsonverbs, and add a packaged Claude Code skill that drives them — so clearing the review queue no longer requires a human sitting at a bare terminal.What's here
US1 — headless JSON verbs. Every review-lifecycle verb is invocable with
--json:review.listreview --list [--status|--spec|--severity]...review.answer/review.waivereview <id> --answer/--waivereview.bulk-waivereview --spec <s> --waive <reason>reconcile.run/reconcile.dry-runreconcile [--dry-run]land.statusland --status(new read-only frontier query)land.runlandThey share one envelope and error-kind registry (
cli/json_output.py), and one canonical entry-row projection (assumptions/serialize.py) used verbatim by bothreview --listand the land report, so the two surfaces can't drift.US2 — guided console. A packaged
maverick-reviewskill, installed bymaverick initand removed bymaverick uninstall. It sweeps the open queue one entry at a time viaAskUserQuestion, applies each decision immediately through the JSON verbs, and never touches jj/git/bd directly.US3 — batched flow. One reconcile after the sweep (not per answer), then a frontier report, then landing offered only on explicit human confirmation.
maverick reviewwithout--jsonis unchanged (FR-018) — it remains the fallback for humans without Claude Code.Review fixes folded in
A code review of the above surfaced 15 findings, all fixed here. The load-bearing ones:
write_json_documentwent through a RichConsolewith emoji substitution left on, so any:name:run inside a string value was rewritten to a unicode emoji. Agent-authored questions and answers hit this routinely, andreview --answer "<adopted_answer>"then wrote the mutated text back into the ledger.json_error_handler, so a transient bd hiccup after the ledger write turned intook: false, kind: bd-unavailable— telling the caller a recorded decision wasn't recorded. The re-read now fails soft (degraded: true).frontier_cleartriviallytrue. Added a top-leveldegradedflag; the skill and contracts now requirefrontier_clear && !degradedbefore offering to land.bd-unavailablewas reported asvalidationon two review paths, which the skill's preflight branches on.WorkflowError.reason_codereplaces prose substring-matching for precondition classification, so rewording a message can't silently reclassify it asinternal.Plus:
land.run's nothing-to-land return now emits the full result shape; heuristic curation reportsabsorb_ran/squashed_count(absorb rewrites history without squashing anything); a newcli/commands/land_gate.pyremoves a private-surface import cycle betweenlandandland --statusand takesland.pyback under the module-size guardrail; the skill install path is shared and written atomically; bd-readiness is one shared predicate.Pre-existing bug found along the way: nothing ever set
ctx.obj["verbosity"]— the root group setsctx.obj["verbose"]— so verbose progress rendering was dead for every workflow, not just this feature's paths. Fixed at the source.Verification
make cigreen: format, lint, mypy, and 4379 passed / 1 xfailed. Also smoke-tested end to end against realbd/jjin a scratch repo (seeded ledger entries; exercised list/answer/waive/already-resolved/reconcile/land-status), which is how thereconcile.statusdocumentation fix inland-report-schema.mdwas confirmed.Two caveats worth naming:
tests/integration/workflows/test_reconcile_jj.pyandtests/integration/test_assumption_ledger_flow.pyintermittently hit the 30s pytest timeout under parallel load with realjj/bdsubprocesses. They pass in isolation and are unaffected by this branch — pre-existing flakiness that deserves its own look./maverick-reviewsession (no interactive Claude Code UI in this environment). Worth one real run against a seeded project before fully trusting the UX.🤖 Generated with Claude Code
https://claude.ai/code/session_012av72R5SPCc84chsUNjhLC