Skip to content

feat(#97): backport event vocabulary extension to triage (cherry-pick of e6d4b8f with §10.5.3 adaptations)#133

Merged
jinhongkuan merged 1 commit into
triage-from-devfrom
triage/97-event-vocab-backport
Apr 30, 2026
Merged

feat(#97): backport event vocabulary extension to triage (cherry-pick of e6d4b8f with §10.5.3 adaptations)#133
jinhongkuan merged 1 commit into
triage-from-devfrom
triage/97-event-vocab-backport

Conversation

@jinhongkuan

Copy link
Copy Markdown
Contributor

Summary

Backports the v0.18.0 event vocabulary extension (`decision_ratified` + `decision_superseded` emit/replay) from `dev` (`e6d4b8f`) to `triage-from-dev`.

This is the first cherry-pick onto `triage-from-dev` under the new DEV_CYCLE.md §10.5 protocol. It exercises §10.5.3's adaptation clause that landed alongside it.

Cherry-pick provenance

`(cherry picked from commit e6d4b8f)` — recorded by `git cherry-pick -x` per §10.5.3.

Adaptations (per §10.5.3)

Three hunks required adaptation. All annotated in the commit message and (where load-bearing) in the code itself with `# triage-adapt:` comments:

  1. `ledger/queries.py` — auto-merge had bundled the Tooling: bulk-classify utility for legacy decision_level = NULL rows #77 `update_decision_level` block (PR feat: decision_level classifier + MCP primitives + CLI (#77) #107, decision_level classifier, v0.16.0) into the resolution at the same insertion point as RFC: append-only event-sourced ledger with rebuildable projection #97's two new helpers. Dropped the Tooling: bulk-classify utility for legacy decision_level = NULL rows #77 block (missing prerequisite on triage; not part of e6d4b8f's actual diff). Kept only RFC: append-only event-sourced ledger with rebuildable projection #97's intended additions: `get_canonical_id` and `find_decision_by_canonical_id`.

  2. `handlers/ratify.py` — auto-merge had bundled an import of `preflight_telemetry` (Preflight: telemetry capture loop for real-world failure feedback #65 preflight telemetry capture loop) into the resolution. Dropped the import (missing prerequisite; not referenced by the cherry-picked body). Kept the intended import-list change (drop `update_decision_status`).

  3. `tests/test_preflight_id_plumbing.py` — file is deleted on triage. e6d4b8f updates the ratify mock in this file; that update is moot here. Kept triage's prior deletion via `git rm`.

`handlers/resolve_collision.py`'s body conflict was resolved by taking e6d4b8f's content verbatim — not an adaptation, just selecting the cherry-picked side. The HEAD inline block differed from dev's pre-#97 inline block by formatting only.

What this lands on triage

  • Pure additive (auto-merge applied cleanly):
    • `events/materializer.py` (+50): replay cases for `decision_ratified.completed` and `decision_superseded.completed` events
    • `events/team_adapter.py` (+59): emit wrappers for the new event types
    • `ledger/adapter.py` (+64): `apply_ratify` and `apply_supersede` methods on `SurrealDBLedgerAdapter`
    • `ledger/queries.py` (+38, after adaptation): `get_canonical_id` and `find_decision_by_canonical_id` helpers
    • `tests/test_team_event_replay.py` (new file, +195): three round-trip tests
  • Refactor:
    • `handlers/ratify.py`: routes through `ledger.apply_ratify` for event emission
    • `handlers/resolve_collision.py` (supersede branch): routes through `ledger.apply_supersede` for event emission

Test plan

  • `tests/test_team_event_replay.py` — 3/3 pass locally (ratify replay, supersede replay with edge replay, ingest regression)
  • All ratify/resolve_collision/supersede tests — 4/4 pass locally (excluding two pre-existing-broken preflight tests on triage that fail on import — `test_v0412_preflight.py`, `test_v055_region_anchored_preflight.py` — both fail with `ImportError: cannot import name '_has_actionable_signal_in_search'` / `_merge_decision_matches` on triage's bare `origin/triage-from-dev` HEAD; unrelated to this cherry-pick)
  • Import smoke: `handlers.ratify`, `handlers.resolve_collision`, `SurrealDBLedgerAdapter.apply_ratify`, `SurrealDBLedgerAdapter.apply_supersede`, the two new queries — all import / resolve cleanly
  • CI green on `triage-from-dev`-bound checks

Risk assessment

L2 (modifies existing handler APIs — but routes through existing adapter pattern; semantics identical from caller POV per §10.5.3 adaptation clause condition (1)).

DEV_CYCLE references

  • §10.5.1 eligibility — small additive feature with isolated risk surface; canonical_id schema and events/ infrastructure pre-exist on triage
  • §10.5.3 adaptation clause — three documented adaptations, all dropping auto-merge collateral from missing prerequisites; no logic invented
  • §10.5.4 release scrutiny — adapted commits should be a small fraction; this is the first triage cherry-pick under §10.5 so by definition 100% adaptation, but the adaptations themselves are subtractive (drop bundled dev-only code) rather than additive

Linked issues

Refs #97 (RFC stays open per convention)

🤖 Generated with Claude Code

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>
(cherry picked from commit e6d4b8f)

Adaptation: ledger/queries.py — kept only #97's two new helpers (get_canonical_id, find_decision_by_canonical_id); auto-merge had inadvertently bundled the #77 update_decision_level block (PR #107, decision_level classifier, v0.16.0) which is a missing prerequisite on triage and not part of e6d4b8f's actual diff for this file
Adaptation: handlers/ratify.py — kept only e6d4b8f's import-list change (drop update_decision_status); dropped the auto-merged preflight_telemetry import which is a missing prerequisite on triage (#65 preflight telemetry capture loop) and not referenced by the cherry-picked body
Skip: tests/test_preflight_id_plumbing.py — kept triage's prior deletion of this file; e6d4b8f's update to its ratify mock is moot here
@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: 9bd5ac03-0222-4659-8afa-1b4bce000988

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/97-event-vocab-backport

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.

@jinhongkuan jinhongkuan merged commit 5f60eed into triage-from-dev Apr 30, 2026
2 checks passed
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