Skip to content

feat(core,ledger): decision mutation contract B1+B2 (GH-330)#337

Merged
fagemx merged 1 commit intomainfrom
feat/GH-330-mutation-contract
Mar 20, 2026
Merged

feat(core,ledger): decision mutation contract B1+B2 (GH-330)#337
fagemx merged 1 commit intomainfrom
feat/GH-330-mutation-contract

Conversation

@fagemx
Copy link
Owner

@fagemx fagemx commented Mar 20, 2026

Summary

  • B1 (Status Sync): Add status_to_is_active() helper enforcing COMPAT-01 invariant. append_event() and insert_imported_decision() now write both status and is_active in sync. Deactivation UPDATE sets status = 'superseded' alongside is_active = FALSE.
  • B2 (DecisionPayload fields): Extend DecisionPayload with 5 optional fields (authority, affected_paths, tags, review_after, reversibility). Decision materialization reads these from payload with safe defaults. extract_decision() parses new fields from event JSON.
  • All existing callers updated to compile with new struct shape (explicit None for new fields).
  • Pre-existing clippy warnings fixed in edda-derive and edda-serve test modules.

Contract compliance

  • COMPAT-01: is_active and status always agree — verified by integration test
  • MUTATION-01: All UPDATE decisions statements are in sqlite_store.rs only
  • CLIPPY-01: cargo clippy --workspace --all-targets -- -D warnings passes

Test plan

  • test_status_to_is_active — unit test for the mapping helper
  • test_status_is_active_sync_on_insert — insert + supersede cycle with COMPAT-01 check
  • test_decision_payload_new_fields_roundtrip — write with all new fields, read back correctly
  • test_decision_payload_defaults_when_none — verify defaults (human/[]/[]/NULL/medium)
  • test_decision_payload_serde_backward_compat — old JSON without new fields deserializes
  • test_decision_payload_serde_with_new_fields — new JSON round-trips correctly
  • cargo clippy --workspace --all-targets -- -D warnings zero warnings
  • cargo test -p edda-core -p edda-ledger all pass (2 pre-existing failures on main excluded)

Closes #330

🤖 Generated with Claude Code

… fields (GH-330)

B1: Add status_to_is_active() helper as single source of truth for
the is_active/status mapping (COMPAT-01). Modify decision materialization
in append_event() and insert_imported_decision() to always write both
columns in sync. Deactivation UPDATE now also sets status='superseded'.

B2: Extend DecisionPayload with 5 optional fields: authority,
affected_paths, tags, review_after, reversibility. Decision
materialization reads these from the payload instead of hardcoded
defaults. All existing callers pass None and get safe defaults.
extract_decision() updated to parse new fields from event JSON.

Contract: COMPAT-01, MUTATION-01
Refs: GH-decision-deepening Track B1, B2

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@fagemx fagemx merged commit 2925e56 into main Mar 20, 2026
4 of 7 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.

feat(ledger): mutation contract — status sync + create_candidate

1 participant