Skip to content

feat(kernel): owner-originated counterparty crypto-erasure (#172) - #268

Merged
George-RD merged 1 commit into
mainfrom
George-RD/dev-172
Aug 21, 2026
Merged

feat(kernel): owner-originated counterparty crypto-erasure (#172)#268
George-RD merged 1 commit into
mainfrom
George-RD/dev-172

Conversation

@George-RD

@George-RD George-RD commented Aug 21, 2026

Copy link
Copy Markdown
Owner

What

Adds openspine.counterparty.erase, an authenticated owner command to originate a counterparty crypto-erasure locally — signed ledger entry first, then the local transactional erasure sweep — closing the origination gap disclosed at #130's creation.

Why

Counterparty crypto-erasure guards (AD-140) are production-wired and unconditionally reconciled at startup, but until now the erasure set could only be populated by an accepted external terminal ledger on restore. No production caller of record_terminal_erasure existed, so nothing on this terminal could begin an erasure. This is the missing local owner origination surface.

How

  • Surface: a non-delegable root-owner gate-mediated action, modeled exactly on openspine.overlay.export/restore (catalog entry, None/None egress, GatedShell effect path, tool descriptor, owner pack/agent wiring). Dispatched through the handler registry.
  • Ordering: reuses the merged erase_counterparty primitive unchanged — durable signed terminal-ledger entry first, then mark_learned_artifacts_erased (audit-before-effect, CI-enforced) and the irreversible key tombstone. Builds on the Whole-table erasure sweep makes one unparseable rule_json abort every erasure, and block boot #176 sweep isolation.
  • Auth: follows the root-owner grant-check pattern (owner principal, true root grant, non-delegable classification, exact effectively_allows). Hoisted into a shared api::root_owner_grant helper so overlay and erasure cannot diverge. No OwnerVerifiedProof minted (mint gate honored).
  • Handler: strict deny_unknown_fields payload, ULID validation, defense-in-depth SYSTEM_SCOPE rejection; returns only non-sensitive fields (never invalidated_identities).

Tests

  • Caller-level: owner_command_runs_generic_reviewed_scope_sweep_via_caller_path drives the generic reviewed-scope standing-rule sweep through the command (no learned-artifact provenance row), with a different-counterparty control rule that must survive; asserts audit-chain integrity and exactly one counterparty.erased event.
  • Negatives (overlay-parity): foreign principal, non-root/delegated-hop, owner-derived worker, wrong action id, malformed/unknown payload, invalid ULID, SYSTEM_SCOPE.
  • The scoped-reservation transactional recheck is proven by the existing Add test seams for the two UNPROVEN in-transaction erasure rechecks and the Telegram callback pending-write fence #177 seam test (the pre-transaction is_counterparty_erased guard refuses first, so a handler-first dispatch never reaches the reservation transaction) — carried forward and inventoried, not duplicated.

./scripts/check.sh passes.

Implementation notes (five-line summary)

  1. Deviations: 2 (skipped OpenSpec ceremony per DIRECTION.md; grant-check auth pattern, no OwnerVerifiedProof mint).
  2. Most likely to be revisited: the targeted #[allow(dead_code)] on ErasureReport::invalidated_identities if the handler ever surfaces it.
  3. Edge cases: test data root needs initialize_terminal_ledger() before erasure; generic reviewed-scope sweep revokes with no learned-artifact provenance row.
  4. Scope boundary: transactional recheck proven only by the Add test seams for the two UNPROVEN in-transaction erasure rechecks and the Telegram callback pending-write fence #177 seam test; fired-token rechecks stay latent (empty dark-window allowlist), not unblocked by origination.
  5. Read first next session: api/erase_counterparty.rs handler + the Ship recurring Gmail drafts as the first complete delegation proof #130 guard-test inventory.

Closes #172


Summary by cubic

Adds openspine.counterparty.erase, a non-delegable root-owner command to originate a counterparty crypto-erasure locally. Previously only an accepted external terminal ledger on restore could populate the erasure set; now the owner can initiate an erasure that writes a signed ledger entry first, then performs the local sweep and deletes the key.

  • Auth and surface: Cataloged non-delegable action with a GatedShell effect path and approval-required tool; enforced via shared api::root_owner_grant (owner principal, true root grant, exact effectively_allows).
  • Ordering and safety: Reuses erase_counterparty unchanged (ledger-first, then mark_learned_artifacts_erased and irreversible key tombstone); rejects SYSTEM_SCOPE; strict deny_unknown_fields payload with ULID validation; reply omits invalidated_identities.
  • Wiring: Handler registered in the action registry; None/None egress; main_assistant_agent and owner_control_basic_pack include openspine.counterparty.erase.
  • Tests: Positive caller path exercises the generic reviewed-scope sweep and preserves a different-counterparty control rule; negatives mirror overlay export/restore (foreign principal, non-root/delegated, wrong action id, malformed payload, invalid ULID, SYSTEM_SCOPE); audit chain verifies with one counterparty.erased event.
  • Rollout: No data migration; terminal ledger must be initialized before first erasure; operation is irreversible; overlay export/restore now shares the same root-owner check to avoid drift.

Written for commit d581c13. Summary will update on new commits.

Review in cubic

Counterparty crypto-erasure guards (AD-140) were production-wired and
reconciled at startup, but the erasure set could only be populated by an
accepted external terminal ledger on restore — there was no local owner
origination surface. Add `openspine.counterparty.erase`, a non-delegable
root-owner gate-mediated action modeled on `openspine.overlay.export`/
`restore`, that drives the existing `erase_counterparty` primitive:
signed terminal-ledger entry first, then the local transactional erasure
sweep and irreversible key deletion.

- Activate the `erase_counterparty` primitive (drop `#[allow(dead_code)]`;
  keep a targeted allow on the test-only `invalidated_identities` field the
  handler deliberately does not surface).
- Hoist the root-owner grant check into a shared `api::root_owner_grant`
  helper so overlay export/restore and erasure cannot diverge.
- Register the catalog action (non-delegable, `None/None` egress, GatedShell
  effect path, tool descriptor) and wire the owner conversational path.
- Add the gated handler with strict `deny_unknown_fields` payload parsing,
  ULID validation, and defense-in-depth SYSTEM_SCOPE rejection.
- Caller-level test drives the generic reviewed-scope standing-rule sweep
  through the command with a different-counterparty control rule, plus the
  overlay-style authorization/payload negatives. The scoped-reservation
  transactional recheck stays proven by the #177 seam test (the
  pre-transaction guard refuses first), carried forward and inventoried.

Closes #172
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@coderabbitai

coderabbitai Bot commented Aug 21, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@George-RD, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 5 minutes

Limit details: You’ve used the included review currently available.

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

Wait for the limit to reset, then comment @coderabbitai review or push new commits to the PR.

An organization admin can change what happens after included review limits in Billing.

How do review limits work?

CodeRabbit enforces per-developer PR review limits within each organization.

For paid Pro and Pro+ reviews, CodeRabbit uses a developer's included PR review attempts over the past 7 days to set the current hourly allowance. At typical activity levels, the full plan allowance applies. Higher sustained activity can lower the allowance until earlier attempts leave the 7-day window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 58903fce-fe33-4d42-a122-6e77dfbc39a4

📥 Commits

Reviewing files that changed from the base of the PR and between de8cd89 and d581c13.

📒 Files selected for processing (14)
  • artifacts/lyra/agents/main_assistant_agent.yaml
  • artifacts/lyra/packs/owner_control_basic_pack.yaml
  • crates/openspine-kernel/src/action_catalog.rs
  • crates/openspine-kernel/src/action_catalog_data.rs
  • crates/openspine-kernel/src/action_catalog_tests.rs
  • crates/openspine-kernel/src/action_catalog_tool_descriptors.rs
  • crates/openspine-kernel/src/api/erase_counterparty.rs
  • crates/openspine-kernel/src/api/erase_counterparty_tests.rs
  • crates/openspine-kernel/src/api/handler_registry.rs
  • crates/openspine-kernel/src/api/mod.rs
  • crates/openspine-kernel/src/api/overlay_export_restore.rs
  • crates/openspine-kernel/src/api/root_owner_grant.rs
  • crates/openspine-kernel/src/api/scoped_admission_support.rs
  • crates/openspine-kernel/src/counterparty_erasure.rs

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.

@George-RD
George-RD merged commit 1bde90b into main Aug 21, 2026
3 checks passed
@George-RD
George-RD deleted the George-RD/dev-172 branch August 21, 2026 09:14
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.

Counterparty erasure has no local origination surface: sweep guard is wired but only externally reachable

1 participant