Skip to content

fix(lifecycle): reject claim self-contradiction#437

Merged
plind-junior merged 2 commits into
vouchdev:testfrom
davion-knight:fix/contradict-self-reference
Jul 13, 2026
Merged

fix(lifecycle): reject claim self-contradiction#437
plind-junior merged 2 commits into
vouchdev:testfrom
davion-knight:fix/contradict-self-reference

Conversation

@davion-knight

Copy link
Copy Markdown
Contributor

summary

lifecycle.contradict() had no guard against claim_a == claim_b, unlike its sibling supersede(), which explicitly rejects old_claim_id == new_claim_id. calling contradict() with the same id on both sides wrote a self-loop contradicts reference onto the claim and flipped its status to contested with no actual counterparty — durable, nonsensical on-disk state with no way to recover short of manual yaml editing. all three surfaces (cli, mcp, jsonl) reach the unguarded function with zero pre-checks.

what changed

added the same self-reference guard supersede() already has, at the top of contradict() in src/vouch/lifecycle.py.

test plan

new regression test test_contradict_rejects_self_reference in tests/test_storage.py — asserts LifecycleError is raised and the claim is left untouched on disk (fails on the old code, which raised nothing and corrupted the claim).

.venv/bin/python -m ruff check src tests
.venv/bin/python -m mypy src
.venv/bin/python -m pytest tests/ -q --ignore=tests/embeddings

all three clean on the rebased branch (rebased onto test after the recent CI incident was resolved).

contradict() had no guard against claim_a == claim_b, unlike its
sibling supersede() which explicitly rejects self-reference. calling
it with the same id on both sides wrote a self-loop contradicts
reference and flipped the claim to contested with no real
counterparty -- durable, nonsensical state with no way to recover
short of manual yaml editing.
@coderabbitai

coderabbitai Bot commented Jul 7, 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 Plus

Run ID: 48c52181-d695-4ef7-a543-67420129665b

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

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.

@github-actions github-actions Bot added docs documentation, specs, examples, and repo guidance storage kb storage, migrations, schemas, and proposals tests tests and fixtures size: XS less than 50 changed non-doc lines labels Jul 7, 2026
@plind-junior plind-junior merged commit 950151f into vouchdev:test Jul 13, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

docs documentation, specs, examples, and repo guidance size: XS less than 50 changed non-doc lines storage kb storage, migrations, schemas, and proposals tests tests and fixtures

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants