Skip to content

fix(sync): register inbound sources before evidence in gated apply#540

Open
tryeverything24 wants to merge 1 commit into
vouchdev:testfrom
tryeverything24:fix/sync-gated-evidence-order
Open

fix(sync): register inbound sources before evidence in gated apply#540
tryeverything24 wants to merge 1 commit into
vouchdev:testfrom
tryeverything24:fix/sync-gated-evidence-order

Conversation

@tryeverything24

@tryeverything24 tryeverything24 commented Jul 21, 2026

Copy link
Copy Markdown

what

vouch sync --as-proposals (the gated federation receive path from #536) crashes with an unhandled ValueError whenever the inbound KB carries a receipt-backed claim whose evidence and source are both new to the receiving KB — which is the standard shape for a peer sharing quoted/receipted knowledge.

_sync_apply_as_proposals registers pass-1 substrate in a single walk over sorted(check.new_files). evidence/... sorts ahead of sources/..., so store.put_evidence runs before the evidence's own source has been registered and raises evidence <id> cites unknown source <sha>. the exception is not caught (pass 2 only catches ProposalError), so the whole apply aborts partway:

  • vouch sync check has just called the same input ok (_check_graph_integrity deliberately accepts references that arrive in the same sync),
  • vouch import-proposals accepts the identical knowledge as a bundle (bundle.import_as_proposals registers all sources before any evidence, exactly to satisfy put_evidence's source-exists guard),
  • and any substrate already registered before the crash has no audit event, since sync.apply_proposals is only logged at the end.

fix

split pass 1 into two sub-passes — sources first, then evidence — matching the pass-1 order import_as_proposals already uses. no surface, on-disk, or audit-shape changes.

repro (fails on test, passes on this branch):

peer = KBStore.init(peer_root)
src = peer.put_source(b"the deploy runs at 03:00 UTC every night", title="runbook")
peer.put_evidence(Evidence(id="ev-runbook-span", source_id=src.id,
                           locator="bytes=0-40", quote="the deploy runs at 03:00 UTC every night",
                           byte_start=0, byte_end=40))
peer.put_claim(Claim(id="deploy-time", text="deploys run at 03:00 utc", evidence=["ev-runbook-span"]))

local = KBStore.init(local_root)
sync.sync_apply(local.kb_dir, peer_root, as_proposals=True)   # ValueError before this fix

validation

  • new regression test test_sync_apply_as_proposals_registers_sources_before_evidence — confirmed it fails on the previous code (raises at storage.put_evidence) and passes with the fix (verified via git stash)
  • python -m pytest tests/ -q --ignore=tests/embeddings — green
  • python -m mypy src — no issues in 102 files
  • python -m ruff check src tests — all checks passed

changelog entry added under ## [Unreleased]### Fixed.

Summary by CodeRabbit

  • Bug Fixes

    • Fixed a crash during vouch sync --as-proposals when newly imported evidence references a newly imported source.
    • Sync now completes successfully and records the imported source and evidence correctly.
  • Tests

    • Added regression coverage for source and evidence registration during proposal synchronization.
  • Documentation

    • Updated the unreleased changelog with details of the fix.

the as-proposals pass registered substrate in one sorted path walk, and
evidence/... sorts ahead of sources/..., so put_evidence raised
"cites unknown source" for any inbound evidence whose source arrived in
the same sync -- the standard shape for a peer sharing receipt-backed
claims. the whole gated apply crashed partway, after sync check had
called the same input ok, and with no audit event for anything already
registered. import_as_proposals (bundle.py) already registers sources
before evidence for exactly this reason; the sync path now uses the
same two-sub-pass order.

regression test: a peer kb with source + evidence + claim-citing-the-
evidence, all new to the receiving kb, fails on the previous code at
storage.put_evidence and passes now.
@coderabbitai

coderabbitai Bot commented Jul 21, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 141d1d0d-c03a-4d7c-abb0-12d4c87a4a21

📥 Commits

Reviewing files that changed from the base of the PR and between 1c9ca7c and 873d7c6.

📒 Files selected for processing (3)
  • CHANGELOG.md
  • src/vouch/sync.py
  • tests/test_sync.py

Walkthrough

vouch sync --as-proposals now registers inbound sources before evidence, preventing failures when evidence cites a source arriving in the same sync. A regression test validates registration counts and persisted links, and the changelog documents the fix.

Changes

As-proposals sync ordering

Layer / File(s) Summary
Register sources before evidence
src/vouch/sync.py, tests/test_sync.py, CHANGELOG.md
The sync flow uses separate source and evidence registration passes; regression coverage verifies successful registration and source linkage, and the fix is documented.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related PRs

  • vouchdev/vouch#91: Introduces the deterministic vouch sync behavior related to this source-before-evidence ordering.
  • vouchdev/vouch#536: Adds a gated import/proposal path with similar substrate import ordering.

Suggested reviewers: plind-junior

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly captures the main change: ordering source registration before evidence in gated sync apply.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ 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 sync sync, vault mirror, and diff flows tests tests and fixtures size: S 50-199 changed non-doc lines labels Jul 21, 2026
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: S 50-199 changed non-doc lines sync sync, vault mirror, and diff flows tests tests and fixtures

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant