Skip to content

feat(#124): backport CLI link_commit registration to triage (cherry-pick of 431e202 with §10.5.3 adaptations)#134

Merged
jinhongkuan merged 1 commit into
triage-from-devfrom
triage/124-link-commit-cli
Apr 30, 2026
Merged

feat(#124): backport CLI link_commit registration to triage (cherry-pick of 431e202 with §10.5.3 adaptations)#134
jinhongkuan merged 1 commit into
triage-from-devfrom
triage/124-link-commit-cli

Conversation

@jinhongkuan

Copy link
Copy Markdown
Contributor

Summary

Backports #124's user-facing fix from `dev` (`431e202`) to `triage-from-dev`: registers `link_commit` as a CLI subcommand so the post-commit git hook installed by `bicameral-mcp setup` (Guided mode) actually syncs the ledger instead of silently no-op'ing.

Second cherry-pick onto `triage-from-dev` under the new DEV_CYCLE.md §10.5 protocol; first to exercise §10.5.3's "adaptable when surface diverged but dependencies satisfied" clause beyond the simple subtractive case.

Cherry-pick provenance

`(cherry picked from commit 431e2026...)` — recorded by `git cherry-pick -x`.

Adaptations (per §10.5.3)

Six annotated adaptations / skips, all driven by the same root cause: the dev commit bundled #124's fix with #48 prerequisites (pre-push drift hook, branch-scan subcommand) that triage doesn't carry.

  1. `server.py` — kept the helper extraction, omitted Pre-push git hook: surface drift warnings before git push #48 pieces. Dev's `_register_subparsers` / `_dispatch` shape is preserved (so the `test_hook_command_registration.py` smoke can introspect registered subcommands), but with branch-scan subparser registration and the setup `--with-push-hook` flag dropped.
  2. `server.py:_dispatch` — kept the setup → link_commit dispatch chain shape; dropped the branch-scan dispatch case (cli/branch_scan.py is a Pre-push git hook: surface drift warnings before git push #48 missing prereq); kept the link_commit dispatch case (the actual post-commit hook silently no-ops — bicameral-mcp link_commit HEAD is not a registered subcommand #124 fix).
  3. `tests/test_hook_command_registration.py` — dropped the `_GIT_PRE_PUSH_HOOK` import + the `test_pre_push_hook_command_is_registered` test (pre-push hook is Pre-push git hook: surface drift warnings before git push #48); scoped `test_all_hook_commands_have_dispatch_branches` to `_GIT_POST_COMMIT_HOOK` only. The canonical post-commit hook silently no-ops — bicameral-mcp link_commit HEAD is not a registered subcommand #124 regression test (`test_post_commit_hook_command_is_registered`) is preserved.
  4. `cli/branch_scan.py` — kept triage's prior absence (added by Pre-push git hook: surface drift warnings before git push #48 on dev); the cherry-pick wanted to refactor it.
  5. `docs/META_LEDGER.md` — kept triage's HEAD chain state. Dev's v0.4.14 — surface source_excerpt + meeting_date in read responses #21/Proposal: Ed25519 signed EventEnvelopes for tamper-evident decision history #23 chain entries are dev's chain.
  6. `CHANGELOG.md` — kept triage's HEAD. The triage release narrative for this batch lives in PR release: v0.13.5 (triage) — bug fixes + event vocabulary backport (#74, #95, #97, #98, #124) #128 per DEV_CYCLE §10.5.4.

What this lands on triage

  • New CLI subcommand `bicameral-mcp link_commit [HEAD]`: registers the missing subcommand the post-commit hook calls.
  • Hardened post-commit hook (auto-merged via `setup_wizard.py`): writes stderr to `${HOME}/.bicameral/hook-errors.log` (was `/dev/null`), surfaces a one-line summary on stderr, always exits 0. `>` truncation auto-clears stale errors on next successful run.
  • New helper module `cli/_link_commit_runner.py`: shared sync wrapper around `handle_link_commit` (lazy-imports SurrealDB modules; graceful skip if no ledger).
  • New CLI entry `cli/link_commit_cli.py`: JSON-to-stdout default, `--quiet` for hooks, always exits 0.
  • Two test files added: `test_link_commit_cli.py` (6 tests), `test_hook_command_registration.py` (2 tests after triage adaptation, 3 on dev).

Architectural caveat (worth knowing)

`link_commit` syncs the ledger but does not auto-resolve drift. Pending-compliance indicators that accumulate post-sync still need to be cleared via `resolve_compliance` (caller-driven via dashboard or MCP tool call). For users with an active Claude Code session, `server.py:874`'s tool-call auto-sync was already handling this pre-#124. The post-commit hook only matters for out-of-session committers (different terminals, non-MCP agents, dashboard-driven workflows). #124 restores documented hook behavior; it does not (by design) make the system more autonomous about acting on detected drift.

Test plan

  • Local: 8/8 pass (`test_link_commit_cli.py` 6/6, `test_hook_command_registration.py` 2/2 after adaptation)
  • Local: `_register_subparsers` introspection returns `['config', 'link_commit', 'reset', 'setup']` — exactly the triage-eligible set
  • Manual smoke: `python3 -m server link_commit --help` renders
  • CI green on `triage-from-dev`-bound checks

Risk assessment

L2 (touches user-facing CLI surface and the install path; introduces new module `cli/_link_commit_runner.py` + `cli/link_commit_cli.py` on triage).

DEV_CYCLE references

  • §10.5.1 eligibility — bug fix for documented behavior; small additive surface; isolated risk
  • §10.5.3 adaptation clause — six documented adaptations, 0 inventions (all subtractive: drop missing-prereq surface)
  • §10.5.4 release scrutiny — adapted commits should be a small fraction; this PR carries six adaptations but they're all "drop Pre-push git hook: surface drift warnings before git push #48 prereqs" — same root cause, six surfaces

Linked issues

Closes #124 on merge into `triage-from-dev` (per DEV_CYCLE §2.2 "PRs target triage-from-dev, so issues close at the triage-merge")

🤖 Generated with Claude Code

…hook

Phase 0a — Decompose server.py:cli_main (92 LOC → 15 LOC orchestrator
+ _register_subparsers (16 LOC) + _dispatch (29 LOC)). Razor-compliant.

Phase 0 — Promote cli/branch_scan.py:_invoke_link_commit to shared
cli/_link_commit_runner.py module. Pure refactor under existing
test_branch_scan_cli.py coverage.

Phase 1 — Register link_commit CLI subcommand:
- cli/link_commit_cli.py (29 LOC) — JSON-to-stdout default, --quiet
  flag, always exits 0 (graceful skip on no-ledger or handler error).
- server.py — subparser registration in _register_subparsers + dispatch
  branch in _dispatch.
- tests/test_link_commit_cli.py (6 tests) — argparse defaults, output
  shape, --quiet, no-ledger graceful skip, handler-exception graceful
  skip.

Phase 2 — Harden post-commit hook:
- setup_wizard.py:_GIT_POST_COMMIT_HOOK now writes stderr to
  ${HOME}/.bicameral/hook-errors.log (was /dev/null), surfaces a
  one-line summary on stderr, always exits 0. > truncates the file
  on each run so successful commits auto-clear stale errors. F-2
  remediation per audit v2.
- tests/test_hook_command_registration.py (3 tests) — smoke that
  walks every bicameral-mcp <cmd> in installed hooks and asserts
  CLI registration + dispatch coverage. Original #124 bug class is
  now caught at PR time.

Phase 3 — CHANGELOG [Unreleased] Fixed entry.

Validation: 20 passed, 1 skipped (Windows chmod). ruff check + format
+ mypy clean. Manual smoke: link_commit --help renders.

Plan v2 PASS at META_LEDGER #21 (chain 86225d49). Implementation
sealed at META_LEDGER #22 (chain e83d674c).

Closes #124.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
(cherry picked from commit 431e202)

Adaptation: server.py — kept dev's _register_subparsers / _dispatch helper extraction (#124 phase 0a refactor) so test_hook_command_registration.py introspection works; omitted dev's branch-scan subparser registration and the setup --with-push-hook flag (both are #48 prerequisites missing on triage)
Adaptation: server.py:_dispatch — kept dev's setup → branch-scan → link_commit dispatch chain shape; dropped branch-scan dispatch case (cli/branch_scan.py is a missing prerequisite from #48 on triage); kept link_commit dispatch case (the actual #124 fix)
Adaptation: tests/test_hook_command_registration.py — dropped _GIT_PRE_PUSH_HOOK import + the test_pre_push_hook_command_is_registered test (pre-push hook is from #48, not on triage); test_all_hook_commands_have_dispatch_branches scoped to _GIT_POST_COMMIT_HOOK only; test_post_commit_hook_command_is_registered (the canonical #124 regression test) is preserved
Skip: cli/branch_scan.py — kept triage's prior absence of this file (added by #48); the cherry-pick wanted to refactor it
Skip: docs/META_LEDGER.md — kept triage's HEAD chain state; e6d4b8f's META_LEDGER #21/#23 entries are dev's chain, not triage's
Skip: CHANGELOG.md — kept triage's HEAD; v0.X.Y triage release narrative goes in PR #128 per DEV_CYCLE §10.5.4
@coderabbitai

coderabbitai Bot commented Apr 30, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: ff3d41fa-8e4e-44bf-b950-7e1167dca4a2

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch triage/124-link-commit-cli

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants