Skip to content

Bind provenance label to typed-identity origin (#224) - #251

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

Bind provenance label to typed-identity origin (#224)#251
George-RD merged 1 commit into
mainfrom
George-RD/dev-224

Conversation

@George-RD

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

Copy link
Copy Markdown
Owner

What

Generalizes the proven learned_artifacts::Provenance::ProducedBy lineage so its identity binding is the typed ProvenanceOrigin (#222) instead of a bare counterparty-scope Ulid, and carries that origin on each classified briefcase item alongside its disclosure_class.

Why

The deterministic egress gate could tell an item's sensitivity class but not whose data it is — the Immune-system gap for Bell and the Auditor (spec #220, canon D-174). This ticket lands the binding half of the hybrid; the runtime origin-vs-recipient egress closure and the grant caveat allowlist are the following tickets (#225#227 / dev-226, kept untouched here).

Key decisions

  • Wire format. The merged ProvenanceOrigin (Introduce ProvenanceOrigin and IdentityRef typed vocabulary #222) serializes as an internally-tagged object ({"kind":"counterparty","identity":"…"}), not a bare Ulid. The field name source_scope is kept so the JSON path stays $.produced_by.source_scope, but the value is now an object.
  • AD-140 preserved. Erasure SQL/triggers re-pointed to the tagged counterparty identity ($.produced_by.source_scope.identity) and keyed on .kind = 'counterparty'; only counterparty origins are erasable, system/owner/LegacyMigration never match. migrate_provenance_column rewraps legacy scalar source_scope into the tagged form (idempotent).
  • Stale-trigger hazard fixed. Triggers switched from CREATE ... IF NOT EXISTS to DROP-then-CREATE, owned solely by migrate_provenance_column (run after the row-shape rewrite), so an upgraded DB replaces the pre-D-174 trigger text instead of silently disabling closure enforcement. Guarded by a new test.
  • Fail-closed origin. origin is Option<ProvenanceOrigin> on BriefcaseSection/ClassifiedBriefcaseItem, mirroring the existing disclosure_class: Option<…> precedent — an unresolved counterparty slice yields None (not a wrong System label). Egress coverage still keys only on disclosure_class; origin participates in PreparedQuery::binding_matches.
  • Append-only. Extracted establish_or_preserve_origin (the reconfirmation seam) with a dedicated invariant test: a minted origin is never rewritten by a later authorization/reconfirmation.

Tests

New: append-only origin invariant, legacy scalar→tagged migration, stale-trigger replacement, and a binding_matches origin regression. All existing counterparty-erasure and disclosure suites stay green. scripts/check.sh passes (fmt, clippy -D warnings, full workspace tests incl. the shell-binary kernel E2E, file-size, claims, capability-map, openspec validate).

Scope

Kept to the label/lineage binding; no changes in the grant/caveat area (dev-226 runs there in parallel).

Implementation-notes summary

  1. Widened Provenance::ProducedBy.source_scope from Ulid to the typed ProvenanceOrigin (Introduce ProvenanceOrigin and IdentityRef typed vocabulary #222), keeping the field name so the JSON path is stable.
  2. Re-pointed AD-140 erasure SQL/triggers to the tagged counterparty identity and added a DROP-then-CREATE upgrade so stale triggers can't silently disable closure; migration rewraps legacy scalar source_scope.
  3. Added Option<ProvenanceOrigin> to BriefcaseSection and ClassifiedBriefcaseItem, populated deterministically in pack, top-up, and provenance_from_sections, without changing egress-coverage semantics.
  4. Origin participates in the prepared-query binding (new binding_matches regression) and the append-only invariant has a dedicated unit test.
  5. Full gate (scripts/check.sh) green; all existing erasure/disclosure suites stay green.

Closes #224


Summary by cubic

Bind learned-artifact provenance to a typed identity and carry that origin through briefcase sections and prepared-query bindings. Previously source_scope was a bare counterparty Ulid and bindings ignored origin; now we serialize a tagged ProvenanceOrigin (system/owner/counterparty), include it in binding equality, and update erasure/closure to key only on counterparty identities.

  • Wire format: keep $.produced_by.source_scope but change value to an internally tagged object, for example {"kind":"counterparty","identity":"…"} or {"kind":"system"}.
  • DB/closure: rewrite migrations to rewrap legacy scalar source_scope into the tagged form; install closure triggers via DROP-then-CREATE keyed on $.produced_by.source_scope.kind = 'counterparty' and …identity; system/owner never match erasure.
  • Runtime: add origin: Option<ProvenanceOrigin> to BriefcaseSection and ClassifiedBriefcaseItem; pack/top-up set system for kernel-produced sections and counterparty for the slice (unresolved stays None); egress still keys only on disclosure_class for now; PreparedQuery::binding_matches now compares origin.
  • Invariants: enforce append-only origin via establish_or_preserve_origin; reconfirmation establishes system origin for LegacyMigration and preserves any existing ProducedBy origin.

Rollout

  • No manual ops required; opening the store runs the idempotent migration and replaces stale triggers.
  • Consumers that parse $.produced_by.source_scope must accept the new tagged object instead of a scalar Ulid.

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

Review in cubic

Generalize the proven `Provenance::ProducedBy` lineage so its identity
binding is a typed `ProvenanceOrigin` (#222) instead of a bare
counterparty-scope `Ulid`, and carry that origin on each classified
briefcase item alongside its `disclosure_class`.

Why: the deterministic egress gate could tell an item's sensitivity but
not *whose* data it is — the Immune-system gap for Bell/Auditor (spec
#220, D-174). This lands the binding half; the egress origin-closure and
grant caveat are later tickets (#225-#227 / dev-226).

- `source_scope: Ulid` -> `ProvenanceOrigin`; field name kept so the JSON
  path stays `$.produced_by.source_scope`.
- AD-140 erasure SQL/triggers re-pointed to the tagged counterparty
  identity (`.source_scope.identity`), keyed on `.kind = 'counterparty'`.
  Only counterparty origins are erasable; system/owner/legacy never match.
- Triggers switched to DROP-then-CREATE and owned solely by
  `migrate_provenance_column` (after the row-shape rewrite) so an upgraded
  DB replaces the stale pre-D-174 trigger text instead of silently
  disabling closure. Migration rewraps legacy scalar `source_scope`.
- `Option<ProvenanceOrigin>` added to `BriefcaseSection` and
  `ClassifiedBriefcaseItem`, populated in `pack`, top-up, and
  `provenance_from_sections`; egress coverage still keys only on
  `disclosure_class`. Origin participates in `PreparedQuery::binding_matches`.
- Append-only origin extracted into `establish_or_preserve_origin` with a
  dedicated invariant test; new migration + stale-trigger tests.

Closes #224
@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: 27 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: 7979d101-d533-4de6-954d-d2771d1b630a

📥 Commits

Reviewing files that changed from the base of the PR and between 9dda552 and fa75900.

📒 Files selected for processing (24)
  • crates/openspine-kernel/src/api/eval_gate_production_tests.rs
  • crates/openspine-kernel/src/api/nominate_tests.rs
  • crates/openspine-kernel/src/counterparty_erasure_tests.rs
  • crates/openspine-kernel/src/disclosure/disclosure_messaging_tests.rs
  • crates/openspine-kernel/src/disclosure/disclosure_regression_tests.rs
  • crates/openspine-kernel/src/disclosure/disclosure_tests.rs
  • crates/openspine-kernel/src/disclosure/preparation.rs
  • crates/openspine-kernel/src/export_restore_e2e_tests.rs
  • crates/openspine-kernel/src/overlay_compat_tests.rs
  • crates/openspine-kernel/src/overlay_persona_admission.rs
  • crates/openspine-kernel/src/overlay_recovery_tests.rs
  • crates/openspine-kernel/src/pipeline/artifact_activation.rs
  • crates/openspine-kernel/src/pipeline/artifact_reconfirmation.rs
  • crates/openspine-kernel/src/store/learned_artifacts.rs
  • crates/openspine-kernel/src/store/learned_artifacts_tests.rs
  • crates/openspine-kernel/src/store/personality_seed.rs
  • crates/openspine-kernel/src/store/personality_seed_tests.rs
  • crates/openspine-kernel/src/store/standing_rules_activation_tests.rs
  • crates/openspine-schemas/src/briefcase.rs
  • crates/openspine-schemas/src/briefcase/ops.rs
  • crates/openspine-schemas/src/briefcase/tests.rs
  • crates/openspine-schemas/src/disclosure_policy.rs
  • crates/openspine-schemas/src/disclosure_policy_tests.rs
  • crates/openspine-schemas/src/provenance.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 8f9ae1c into main Aug 21, 2026
3 checks passed
@George-RD
George-RD deleted the George-RD/dev-224 branch August 21, 2026 03:54
George-RD added a commit that referenced this pull request Aug 21, 2026
…iteral (refs #251/#252)

Cross-merge fixup: #251 added the required BriefcaseSection.origin field and
updated existing literals; #252 landed a private_section() test literal
without it. Their combination on main broke cargo test compilation. Add the
missing 'origin: None,' matching the sibling literal in the same file.

Coordinator-approved cross-merge fixup unblocking the #244 gate.
George-RD added a commit that referenced this pull request Aug 21, 2026
…244) (#255)

Scoped-admission failures record once (executor_recorded on DispatchedEffect); includes the #251/#252 cross-merge repair (BriefcaseSection.origin). Closes #244.
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.

Bind provenance label to typed-identity origin (generalize ProducedBy)

1 participant