Skip to content

feat(receipt): rollback owner + no-observed-change disclosure - #299

Open
mikehasa wants to merge 1 commit into
mainfrom
feat/receipt-reconciliation-noop
Open

mikehasa wants to merge 1 commit into
mainfrom
feat/receipt-reconciliation-noop

Conversation

@mikehasa

Copy link
Copy Markdown
Owner

What

Two derived, read-only signals on the receipt outcome dimension:

Rollback owner (rollback) — when a run ends unverified (blocked / failed / failing check) but recorded touched files, the receipt names the trusted session that owns reverting them, lists the at-risk files, and raises a gap line on every surface (CLI / TUI / app / pasteable markdown). A half-applied change is no longer silently left behind.

No observed change (no_observed_change) — a Task that reached verified on a passing check but touched zero files is flagged with a gap line, so a no-op can't hide behind a green check.

Why

A work receipt should describe partial and failed runs, not only the happy path, and stay honest about the gap between what an agent claims and what was observed. These two signals close the "what got left behind" and "green check, empty change" cases without changing how outcomes are graded.

Honesty guarantees (by design)

  • Neither signal demotes the decision word or touches evidence strength — they are pure disclosures on the "what happened" axis.
  • rollback.status = "unreconciled" means no reconciliation was recorded, never "not reverted" — agentacct captures no working-tree/diff and never auto-reverts.
  • revert_owner is the trusted {client, client_session_id} session identity the receipt already exposes; section_owner_hint is a clearly-labeled unverified self-report.
  • no_observed_change is gated on a real passing check, so the legitimate check-less strong_without_checks verified path never trips it.
  • Adds no agent-writable field, so nothing here can be forged into a "reverted" / "verified" claim.

Notes for review

  • The human disclosure is the gap line (rendered everywhere via the gaps roll-up). The structured rollback block is intentional machine-readable wire data for a future rollback-owner affordance; no UI consumes the structured fields yet (the Swift decoder tolerates the additive keys). Flag if you'd prefer it trimmed to the gap line only.
  • No RECEIPT_SCHEMA_VERSION bump — additive optional fields, consistent with prior additions (e.g. quiet_since).
  • Key named rollback to avoid colliding with the unrelated usage_reconciliation concept on the /v1 surface.

Scope / testing

  • Touches only src/agentacct/receipt.py (_outcome_dimension + one call-site refactor) and tests/test_receipt.py (+7 tests). Full suite green: 3020 passed.
  • Part 1 of 2 responding to work-receipt design feedback; part 2 adds refused/denied tool calls as their own first-class receipt signal.

…-change

Add two derived, read-only signals to the receipt outcome dimension.

- rollback: when a run ends unverified (blocked/failed/finding) yet recorded
  touched files, name the trusted session that owns reverting them and the
  at-risk files, plus a gap line rendered on every surface. Never auto-reverts;
  status "unreconciled" means only that no reconciliation was recorded, never
  "not reverted" (agentacct has no working-tree/diff signal).
- no_observed_change: flag a Task that reached "verified" on a passing check but
  touched zero files, so a no-op cannot hide behind a green check. Discloses
  without demoting the decision word and without touching evidence strength.

Both are gated so they never couple to the evidence tier and add no
agent-writable field, so nothing here can be forged. Full suite green (3020).
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