Skip to content

feat(core): add obstruction receipt skeleton#339

Merged
flyingrobots merged 6 commits into
mainfrom
stack/obstruction-receipt-skeleton
May 14, 2026
Merged

feat(core): add obstruction receipt skeleton#339
flyingrobots merged 6 commits into
mainfrom
stack/obstruction-receipt-skeleton

Conversation

@flyingrobots
Copy link
Copy Markdown
Owner

@flyingrobots flyingrobots commented May 13, 2026

Summary

Adds the first Echo-side obstruction receipt skeleton for capability grant intent refusals.

Core doctrine:

  • refusal is causal evidence, not an unrealized legal world
  • ObstructionReceipt is not an admission ticket
  • ObstructionReceipt is not a LawWitness
  • ObstructionReceipt is not a CounterfactualCandidate
  • counterfactual candidates require prior legal admission and scheduler non-selection

What changed

  • adds ObstructionReceipt
  • adds RewriteDisposition
  • attaches obstruction receipts to CapabilityGrantIntentPosture
  • records deterministic receipt input bytes and BLAKE3 digest for refused grant intents
  • exports the new receipt/disposition types from warp-core
  • adds the regression obstructed_intent_does_not_create_counterfactual_candidate

What this is not

  • no admission ticket
  • no LawWitness
  • no scheduler retention
  • no admitted grant
  • no invocation success
  • no WASM ABI changes
  • no application nouns
  • no Continuum schema

Verification

RED:

  • cargo test -p warp-core obstructed_intent_does_not_create_counterfactual_candidate failed before implementation because ObstructionReceipt, RewriteDisposition, OBSTRUCTION_RECEIPT_KIND, and the posture receipt field did not exist.

GREEN:

  • cargo test -p warp-core obstructed_intent_does_not_create_counterfactual_candidate
  • cargo test -p warp-core capability_grant_intent
  • cargo check -p warp-core
  • scripts/ban-nondeterminism.sh
  • npx markdownlint-cli2 docs/design/obstruction-receipt-boundary.md CHANGELOG.md
  • git diff --check

Push hook also passed full local verification lanes: fmt, guards, clippy-core, tests-warp-core, rustdoc.

Summary by CodeRabbit

  • New Features

    • Capability grant intent refusals now attach obstruction receipts recording the causal refusal context and associated authority policy information.
    • Obstruction receipts are explicitly marked with the appropriate disposition, preventing confusion with other receipt types.
  • Documentation

    • Added design documentation clarifying obstruction receipt behavior and contents.

Review Change Stack

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 13, 2026

Warning

Rate limit exceeded

@flyingrobots has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 11 minutes and 59 seconds before requesting another review.

You’ve run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 525255ac-d6ae-4b10-81fb-9e88bce1f95b

📥 Commits

Reviewing files that changed from the base of the PR and between 0e4de2e and 50e9379.

📒 Files selected for processing (9)
  • .github/workflows/ci.yml
  • CHANGELOG.md
  • crates/warp-core/src/optic_artifact.rs
  • crates/warp-core/tests/capability_grant_intent_tests.rs
  • docs/design/obstruction-receipt-boundary.md
  • docs/design/optic-capability-grant-intent-boundary.md
  • scripts/ban-globals.sh
  • scripts/ban-nondeterminism.sh
  • scripts/ban-unordered-abi.sh
📝 Walkthrough

Walkthrough

This PR introduces ObstructionReceipt to formally record causal refusal context for obstructed capability grant intents. Receipts embed intent identity, authority policy metadata, obstruction classification, and a BLAKE3-hashed digest of deterministic receipt input bytes. The gate is wired to generate and attach receipts to obstructed postures.

Changes

Obstruction Receipt Type & Integration

Layer / File(s) Summary
Receipt Type Contract & Labeling Infrastructure
crates/warp-core/src/optic_artifact.rs
Define OBSTRUCTION_RECEIPT_KIND constant, RewriteDisposition enum (distinguishing obstructed outcomes), and ObstructionReceipt struct with for_capability_grant_intent constructor. Add internal receipt_label methods to AuthorityPolicyEvaluation and CapabilityGrantIntentObstruction for deterministic enum-to-string mapping during receipt serialization.
Receipt Generation & Gate Integration
crates/warp-core/src/optic_artifact.rs
Update CapabilityGrantIntentPosture to carry receipt field. Thread authority_context through the gate's obstructed_grant_intent helper. Implement receipt generation: serialize intent identifiers, authority policy context, obstruction classification, and rights/scope/expiry/delegation basis into deterministic receipt-input bytes, hash with BLAKE3, and populate the posture receipt with result and Obstructed disposition.
Public API Exports
crates/warp-core/src/lib.rs
Re-export RewriteDisposition and OBSTRUCTION_RECEIPT_KIND from optic_artifact module.
Test Infrastructure & Verification
crates/warp-core/tests/capability_grant_intent_tests.rs
Refactor expected_obstructed_posture helper to accept &AuthorityContext and populate expected receipt via ObstructionReceipt::for_capability_grant_intent. Add receipt_for extraction helper. Update all obstruction regression tests to thread authority_context. Add tests asserting receipt echoes refusal-context fields and is deterministic across registries. Add regression test verifying obstructed intent does not create counterfactual candidate with comprehensive receipt-field assertions.
Documentation & Changelog
CHANGELOG.md, docs/design/obstruction-receipt-boundary.md, docs/design/optic-capability-grant-intent-boundary.md
Add obstruction-receipt-boundary.md design clarification documenting receipt semantics, disposition, and exclusions. Update optic-capability-grant-intent-boundary.md: formalize ObstructionReceipt as generic refusal payload, update gateway behavior and gate flow/sequence diagrams to route through receipt, expand class model with receipt field and schema, add ER entity definition, augment current-shape section with receipt construction details and emission cases, and add admission-receipt prohibition. Add CHANGELOG entry documenting receipt attachment and policy context inclusion.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • flyingrobots/echo#335: Both PRs extend the capability-grant-intent obstruction handling by threading AuthorityContext/AuthorityPolicyEvaluation through the gate and updating obstruction variants; this PR additionally constructs and attaches a deterministic ObstructionReceipt to obstructed postures.

Poem

Receipt-bound refusals now carry their reason,
Each hash a snapshot of scope-breach season,
No counterfactual ghosts, just truth in bytes—
Blake3 digests hold obstruction's rights. 🔐📋

🚥 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 accurately identifies the main change—introducing an obstruction receipt skeleton for capability grant intent refusals—which is the core objective across all file modifications.
Docstring Coverage ✅ Passed Docstring coverage is 80.00% which is sufficient. The required threshold is 80.00%.
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.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch stack/obstruction-receipt-skeleton

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 and usage tips.

@flyingrobots
Copy link
Copy Markdown
Owner Author

Reconciled overlap with PR #336.\n\nPorted forward the useful pieces from #336 into this generic receipt path:\n- authority policy id/posture on ObstructionReceipt when present\n- explicit refusal-context regression coverage\n- explicit deterministic receipt regression coverage\n- grant-intent design doc diagrams now show ObstructionReceipt as the durable refusal carrier\n\nPR #336 is now superseded/closed so we do not keep both the specialized CapabilityGrantIntentObstructionReceipt shape and the generic ObstructionReceipt shape alive.

@flyingrobots
Copy link
Copy Markdown
Owner Author

@coderabbitai review please 🥕

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 13, 2026

@flyingrobots On it. Reviewing the reconciled obstruction receipt skeleton now.

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@crates/warp-core/src/optic_artifact.rs`:
- Around line 241-264: The receipt input buffer is created with Vec::new()
causing reallocations; in capability_grant_intent_receipt_input replace
Vec::new() with Vec::with_capacity(...) using an estimated capacity computed
from the sum of the .len() of each byte slice you push (intent.intent_id,
intent.proposed_by.id, intent.subject.id, intent.artifact_hash,
intent.operation_id, intent.requirements_digest, policy_id.unwrap_or_default(),
policy_posture, obstruction_kind, intent.rights entries, intent.scope_bytes, and
any optional expiry/delegation bytes) plus a small fixed overhead for the length
prefixes (roughly 13 × 8 bytes) to avoid reallocations, then use that pre-sized
Vec for the subsequent push_receipt_field/ push_receipt_field_list/
push_optional_receipt_field calls.
- Around line 164-197: The ObstructionReceipt currently stores
receipt_input_bytes redundantly; remove the receipt_input_bytes field from the
struct and keep only receipt_digest to minimize memory, then add a method on
ObstructionReceipt (e.g., impl ObstructionReceipt { fn
build_receipt_input_bytes(&self) -> Vec<u8> }) that reconstructs the
deterministic input bytes on demand using the existing fields (kind, intent_id,
proposed_by, subject, artifact_hash, operation_id, requirements_digest,
policy_id, policy_posture, obstruction_kind, disposition) and the two
label/serialization helpers used elsewhere; update any code that previously
relied on the receipt_input_bytes field to call the new
build_receipt_input_bytes() method and verify that receipt_digest is computed
from the reconstructed bytes when needed.
- Around line 199-265: The policy_id is serialized as an empty field via
unwrap_or_default() causing None and Some("") to collide; in
capability_grant_intent_receipt_input replace push_receipt_field(...,
policy_id.unwrap_or_default().as_bytes()) with the optional encoder
push_optional_receipt_field(..., policy_id.map(|s| s.as_bytes())) so policy_id
presence is tagged like expiry_bytes/delegation_basis_bytes; update the call
site in ObstructionReceipt::capability_grant_intent_receipt_input to use
push_optional_receipt_field for policy_id and ensure types match the helper
signature (Option<&[u8]>).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 1f827917-6371-4790-a941-e7b271bea243

📥 Commits

Reviewing files that changed from the base of the PR and between a0e8f86 and 0e4de2e.

📒 Files selected for processing (6)
  • CHANGELOG.md
  • crates/warp-core/src/lib.rs
  • crates/warp-core/src/optic_artifact.rs
  • crates/warp-core/tests/capability_grant_intent_tests.rs
  • docs/design/obstruction-receipt-boundary.md
  • docs/design/optic-capability-grant-intent-boundary.md

Comment thread crates/warp-core/src/optic_artifact.rs
Comment thread crates/warp-core/src/optic_artifact.rs
Comment thread crates/warp-core/src/optic_artifact.rs Outdated
@flyingrobots
Copy link
Copy Markdown
Owner Author

Issue Severity First reported Addressed by Regression coverage Outcome
Obstruction receipts stored deterministic digest input bytes redundantly. P5 CodeRabbit thread PRRT_kwDOQH8Wr86B1s-0 9b21329 capability_grant_intent_obstruction_receipt_rebuilds_digest_input_bytes; cargo test -p warp-core capability_grant_intent_obstruction_receipt Resolved
policy_id receipt input collapsed absent and empty policy ids into the same digest domain. P2 CodeRabbit thread PRRT_kwDOQH8Wr86B1s-3 9b21329 capability_grant_intent_obstruction_receipt_distinguishes_absent_and_empty_policy_id; cargo test -p warp-core capability_grant_intent_obstruction_receipt Resolved
Obstruction receipt input construction did not pre-size the buffer. P5 CodeRabbit thread PRRT_kwDOQH8Wr86B1s_H 9b21329 capability_grant_intent_obstruction_receipt_rebuilds_digest_input_bytes; cargo test -p warp-core capability_grant_intent_obstruction_receipt Resolved
Determinism Guards could hang on apt-get install ripgrep when Ubuntu mirrors stall. P2 CI job log on PR #339 46c0c3d determinism-guards no apt ripgrep install; bash -c 'if awk "/determinism-guards:/,/Ban globals/" .github/workflows/ci.yml \| rg -q "apt-get install -y ripgrep"; then exit 1; fi' Resolved

@flyingrobots
Copy link
Copy Markdown
Owner Author

Follow-up on the Determinism Guards hang: 46c0c3d intentionally removed the apt install but exposed that the runner lacks rg. The actual CI-stable fix is 6bc0c63, which removes the workflow dependency on installing/verifying ripgrep and gives the static guard scripts a grep -P fallback. Local verification passed: bash -n scripts/ban-globals.sh scripts/ban-nondeterminism.sh scripts/ban-unordered-abi.sh, all three guard scripts, npx markdownlint-cli2 CHANGELOG.md, and git diff --check.

@flyingrobots
Copy link
Copy Markdown
Owner Author

Second CI follow-up: 6bc0c63 still failed because the fallback used grep -P semantics and missed local no-rg parity. 50e9379 replaces that with Perl regex fallback scanning and was locally exercised with PATH=/usr/bin:/bin to hide rg: scripts/ban-globals.sh, scripts/ban-nondeterminism.sh, and scripts/ban-unordered-abi.sh all pass without ripgrep. The normal rg path also still passes.

@flyingrobots flyingrobots merged commit f4cd123 into main May 14, 2026
32 checks passed
@flyingrobots flyingrobots deleted the stack/obstruction-receipt-skeleton branch May 14, 2026 03:46
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