Skip to content

Feat/receipt auto approve - #485

Merged
plind-junior merged 7 commits into
testfrom
feat/receipt-auto-approve
Jul 15, 2026
Merged

Feat/receipt auto approve#485
plind-junior merged 7 commits into
testfrom
feat/receipt-auto-approve

Conversation

@plind-junior

Copy link
Copy Markdown
Member

What changed

Why

What might break

VEP

Tests

  • make check passes locally (lint + mypy + pytest)
  • New / changed behaviour has a test
  • CHANGELOG.md updated under ## [Unreleased]

the atom the fidelity pivot rests on: a claim's evidence can now carry a
byte-offset span [byte_start, byte_end) into the cited source's raw bytes,
and receipts.verify_receipt checks the quoted text against the source bytes
by string comparison alone — no llm, no judge. the quoted span is in the
source at those offsets or it is not.

three receipt states, kept distinct because the review gate treats them
differently: VERIFIED (span decodes to exactly the quote), FORGED (span
claimed but out of range / inverted / undecodable / mismatched, or the
source is absent from the kb), NO_RECEIPT (no offsets to verify). byte
offsets rather than char offsets because sources are stored as raw
content-addressed bytes and utf-8 char indices diverge from byte indices at
the first multibyte codepoint.

verify_evidence loads the source from the store and delegates; a receipt
whose source is missing is reported forged, never verified, so an
unverifiable citation can never read as approved. purely additive — two
optional evidence fields and one new module, no existing path changes
behaviour yet. this is the primitive phase d's auto-approve will call.
the quote step of phase a's retrieve-then-quote loop. locate_span finds the
byte offsets of a quote's first exact occurrence in a source's raw bytes, or
None when the quote is not present verbatim. the match is deliberately exact
and case-sensitive — no normalization, no fuzzy match — because the receipt's
value is that it is checkable by string comparison, so a paraphrase must fail
to locate and be dropped.

receipt_for_quote composes the locator with the schema: it returns an
Evidence whose byte-offset receipt is guaranteed to verify against the same
bytes, or None to drop an unquotable claim — the mechanical form of "drops
any claim it cannot quote." a property test ties the two halves together:
anything the locator produces verifies VERIFIED.
propose_quoted_claim wires the span locator into the gated write path: given
a source and the quote that supports a claim, it locates the verbatim span,
stores a receipt-backed Evidence, and files a normal claim proposal citing
it. when the quote is not in the source it returns None and files nothing —
the mechanical form of "drops any claim it cannot quote."

the write still goes through propose_claim and the review gate; what is new
is that the filed claim now carries a byte-offset receipt the gate can verify
by string comparison. intake is idempotent: receipt_for_quote mints a
content-addressed evidence id from the span, so re-filing the same span reuses
the existing Evidence instead of duplicating it.

layering kept honest — proposals depends on the receipts primitive, not the
reverse. receipt_for_quote's evidence_id is now optional (content-addressed
default).
evaluate_claim_receipts is the function phase d's auto-approve will call: it
returns approve=True only when a claim cites at least one thing and every
citation is a receipt that verifies. a forged receipt, a bare source id (no
byte-offset span), an unknown id, or an empty citation list all reject, with
reasons naming each failure. the verdict is the conjunction of per-citation
string comparisons — no llm, no judge.

this completes the verification machinery for "human leaves the loop": schema
-> per-evidence verify -> receipt-backed intake -> per-claim verdict. what it
deliberately does NOT do yet is touch approve(); wiring the verdict into
automatic approval is the phase d step, gated behind the step 0 gate-integrity
and step 1 concurrency work so the auto-gate is not forgeable or
race-corruptible.
phase d of the fidelity pivot: the human leaves the loop. when
review.auto_approve_on_receipt is on, a claim whose byte-offset receipts all
verify clears self-approval with no human — the mechanical string comparison
(evaluate_claim_receipts, no llm, no judge) is the reviewer. a claim that
cannot quote its source (bare source id, forged or missing receipt) does not
qualify and still falls through to the human gate: the gate degrades to
asking, it never rubber-stamps. off by default, so the review gate stays on
until a kb opts in.

_approval_block_reason gains the receipt path alongside the trusted-agent
opt-out; _review_config dries the config.yaml load the block reason and the
new drain share; _claim_receipts_verify wraps the verdict.

auto_approve_receipts(store) drains the pending queue — approves every
receipt-verified claim, leaves everything else pending — which is what makes
"run vouch and it just captures knowledge, no review" real end to end:
ingest a source, quote it into receipt-backed claims, auto-approve with no
human, recall the knowledge (including from a reopened kb).

builds on the phase-a receipt machinery (span-receipts).
phase b: the capture step with no human, so the loop runs without a
hand-written quote. extract.segment_source deterministically splits an
ingested source into verbatim quotable spans; extract_receipt_claims files
each as a claim that quotes itself, so its byte-offset receipt verifies by
construction; ingest_source runs the whole loop — store the doc, extract the
claims, and (when the gate is on) auto-approve every one whose receipt
verifies.

new `vouch ingest FILE`: "run vouch on a doc and it captures the knowledge."
with review.auto_approve_on_receipt on, verifying claims are approved with no
human and are immediately recallable via vouch search / recall; without the
gate they are filed pending for review. a span that is not verbatim in the
source is dropped, never trusted.

deterministic and llm-free by design: the receipt check is the guardrail, so
the pipeline runs in the base install and under test with no external command.
selection — which spans are worth a claim — is a later quality knob; today it
is every substantive sentence (ingesting a 28kb doc yields ~500 claims), which
proves the pipeline but is not yet compression. builds on phase d's
auto_approve_receipts.
@coderabbitai

coderabbitai Bot commented Jul 15, 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: f17d3136-1bd4-4b0f-9826-0821c9bc24dd

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/receipt-auto-approve

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 cli command line interface storage kb storage, migrations, schemas, and proposals tests tests and fixtures size: XL 1000 or more changed non-doc lines labels Jul 15, 2026
the evidence model gained byte_start/byte_end for span receipts but
schemas/evidence.schema.json was not regenerated, so the schema-check
drift gate failed. regenerated with scripts/gen_schemas.py; only the
evidence schema changed.
@github-actions github-actions Bot added the schemas json schemas and generated schema assets label Jul 15, 2026
@plind-junior
plind-junior merged commit d0605b7 into test Jul 15, 2026
10 checks passed
boskodev790 pushed a commit to boskodev790/vouch that referenced this pull request Jul 16, 2026
wire the session path into phase-d's receipt-gated auto-approve (vouchdev#485) so the
zero-friction loop runs end to end: ask a question in one session and the answer
is saved with no human; a fresh session recalls it from memory without
re-reading the project files.

a new claude-code Stop hook runs `vouch capture answer`. capture.last_exchange
pulls the turn's (question, answer) from the transcript; the answer is ingested
as a content-addressed source; extract.extract_receipt_claims files a
receipt-backed claim per quotable span; and each is self-approved only where
proposals.approve already allows it (review.approver_role: trusted-agent or
review.auto_approve_on_receipt, whose receipts verify by construction). with
neither opt-in the claims stay pending — the review gate is honoured, never
bypassed, and no parallel write path is added.

quiet and idempotent by design: answers below a length floor (acknowledgements)
are skipped, and an answer already ingested (same bytes) is not re-captured, so
the every-turn Stop hook never duplicates or floods the kb. selection stays
coarse — one claim per sentence, same stance as vouchdev#485 — a later quality knob.

the existing tool-activity page capture is untouched.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cli command line interface schemas json schemas and generated schema assets size: XL 1000 or more 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.

1 participant