Skip to content

feat(#97): extend event vocabulary with ratify + supersede emit/replay (re-merge as rebase, supersedes #129)#132

Merged
jinhongkuan merged 4 commits into
devfrom
feat/event-vocabulary-extension
Apr 30, 2026
Merged

feat(#97): extend event vocabulary with ratify + supersede emit/replay (re-merge as rebase, supersedes #129)#132
jinhongkuan merged 4 commits into
devfrom
feat/event-vocabulary-extension

Conversation

@jinhongkuan

Copy link
Copy Markdown
Contributor

Summary

Re-opens the v0.18.0 event vocabulary extension work for rebase-and-merge so the 4 original atomic commits land on `dev` as individually-cherry-pickable SHAs (instead of one opaque squash blob).

This is the same code as the previous PR #129 — no diff changes. Only the merge mechanics are different.

Commits (in order)

  1. `1b24e2e` — feat(RFC: append-only event-sourced ledger with rebuildable projection #97): extend event vocabulary with ratify + supersede emit/replay
  2. `7a012d1` — fix(ruff): drop unused find_decision_by_canonical_id import from team_adapter
  3. `b2869e2` — fix(ruff): format pass on touched files
  4. `9473648` — docs: CHANGELOG entry for v0.18.0 (RFC: append-only event-sourced ledger with rebuildable projection #97 event vocabulary extension)

Why this re-merge

Original #129 squash-merged into `c233eb1`. Reverted in #131 (`b3d93d0`) so this replacement can land via rebase-and-merge. Net diff vs dev pre-revert is zero — same files, same content. Only the history shape changes from one opaque commit to four atomic ones.

Sequencing context

Linked issues

Refs #97 (already labeled `merged-to-dev`; staying open per RFC convention)

Test plan

  • CI green on dev-bound checks (ruff+mypy, MCP regression linux+windows, schema persistence, drift, preflight eval, TruffleHog).
  • After merge: `git log --oneline origin/dev | head -6` shows the 4 atomic commits in order on top of `b3d93d0`.
  • Cherry-pick smoke: `git checkout triage-from-dev && git cherry-pick -x 1b24e2e` no longer hits the previous 5-file conflict (or, if minimal conflicts remain on `handlers/ratify.py` etc., they reflect the intended per-commit slice rather than the squash blob).

Notes

  • All 4 commits are buildable individually (the two ruff fixes were applied to keep CI green at each step on the original feature branch).
  • `Triage-Cc:` trailer convention from upcoming §10.5 is not retroactively added to these commits — they predate the convention. The release manager will manually decide which subset triage-backports per §10.5.1 eligibility.

🤖 Generated with Claude Code

jinhongkuan and others added 4 commits April 29, 2026 20:16
Wires the missing decision-status events into the existing JSONL +
materializer pipeline so the shipped event vocabulary matches the v0
architecture description (decision_ratified, decision_superseded
alongside the existing ingest/bind/link_commit events).

Changes:

- ledger/adapter.py: add `apply_ratify(decision_id, signoff)` and
  `apply_supersede(new_id, old_id, ...)` to SurrealDBLedgerAdapter.
  Both methods are idempotent so the materializer can replay them
  safely. They wrap the existing inline UPDATE + project + supersedes
  helpers — no behavioral change for solo mode.
- events/team_adapter.py: add wrappers that emit
  `decision_ratified.completed` and `decision_superseded.completed`
  events before delegating to the inner adapter. Event payloads carry
  `canonical_id` (UUIDv5 from description + source_type + source_ref)
  so cross-author replay can resolve to the peer's local row even
  though SurrealDB-generated decision ids are per-DB.
- events/materializer.py: replay cases for the two new event types.
  Each looks up the local decision row by canonical_id; warns and
  skips if not found (out-of-order replay across authors).
- handlers/ratify.py: route through `ledger.apply_ratify` instead of
  inline UPDATE + project_decision_status + update_decision_status.
  Pre-write idempotency check (early return when state already matches)
  is unchanged.
- handlers/resolve_collision.py: route through `ledger.apply_supersede`
  for the supersede branch. Edge creation + frozen-signoff merge moves
  into the adapter so it's reachable from replay.
- ledger/queries.py: new `get_canonical_id(client, decision_id)` and
  `find_decision_by_canonical_id(client, canonical_id)` helpers.

Tests:

- tests/test_team_event_replay.py (new) — three round-trip tests:
  ratify, supersede (with edge replay), and ingest regression. Each
  ingests through team adapter A, then connects a fresh team adapter B
  pointing at the same JSONL log + a fresh memory:// inner DB and a
  fresh watermark. Asserts state in B matches what A wrote.
- tests/test_preflight_id_plumbing.py — updated the ratify mock to
  match the new `ledger.apply_ratify` shape.

Out of scope (deferred to future PRs): compliance_checked event (Phase
4 uses CHANGEFEED), CHANGEFEED extension to code_subject /
subject_identity / binds_to / code_region (schema migration), SHA256
chain (strictly v1).

Closes part of #97.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…_adapter

The materializer imports the helper inline at the call site. The
top-level import in team_adapter.py was leftover from an earlier
draft and never used.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Run ruff format on the three files modified in this PR. No semantic
change — purely whitespace/argument-split normalization to satisfy
`ruff format --check .` in CI.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Per DEV_CYCLE §7, every user-visible change gets a CHANGELOG entry.
This is an additive feature (new event types in the team-mode JSONL
log), so it bumps to MINOR per §6.2.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@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: 77a0e14d-a446-45a8-92f3-5b2a5a5fa06e

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 feat/event-vocabulary-extension

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.

@github-actions

Copy link
Copy Markdown

Bicameral drift report — skipped

No bicameral/decisions.yaml found in repo root. Drift report is skipped for this PR.

To enable: add a bicameral/decisions.yaml manifest. See setup guide (link to be added when manifest spec ships).

@jinhongkuan jinhongkuan merged commit 68108cd into dev Apr 30, 2026
17 checks passed
@jinhongkuan jinhongkuan deleted the feat/event-vocabulary-extension branch April 30, 2026 04:39
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.

1 participant