feat(privacy): refuse untrusted intake without a grant - #141
Conversation
A disclosure receipt binds a purpose to field codes sent to a model provider. Source text, source identity, and blanket masking fail closed (ADR 0009).
Documents, serialized records, checkpoints, and LLM outputs stay outside the analysis boundary until a purpose-bound grant is present (ADR 0009). Size, identity, and provenance bounds are not that grant. Recovery is the computed share of grant-presence flags that match known truth versus accepting every intake.
|
Warning Review limit reachedNext included review available in 6 minutes. View limit detailsLimit 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. Review configuration: ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (18)
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. Comment |
# Conflicts: # CHANGELOG.md # docs/TRACEABILITY.md # docs/adr/0009-purpose-bound-pii-governance.md # docs/adr/README.md # docs/validation/temporal-event-foundation.md
|
Current head |
# Conflicts: # CHANGELOG.md # docs/TRACEABILITY.md # docs/adr/0009-purpose-bound-pii-governance.md # docs/adr/README.md # docs/research/standards-and-literature.md # docs/validation/temporal-event-foundation.md
|
Current-head validation update (387e42d): fixed the quality contract to derive the Rust crate count from scripts/check_workspace_contract.py instead of hard-coding 10. Local evidence: 89 quality tests passed; coverage 100% (991/991 statements, 442/442 branches); workspace, docstring, documentation, and diff checks passed. Please review and rerun Checks against this exact head; merge remains subject to the repository's two independent approvals and protected rules. |
… review/pr114-current # Conflicts: # ARCHITECTURE.md # CHANGELOG.md # Cargo.toml # README.md # docs/TRACEABILITY.md # docs/adr/0009-purpose-bound-pii-governance.md # docs/adr/README.md # docs/validation/temporal-event-foundation.md # scripts/check_workspace_contract.py # tests/quality/test_check_docstrings.py
|
Fixed the current workspace drift at exact head Local evidence: provider_receipt tests (6 passed), fmt, clippy, documentation validation, workspace contract, Rust docstring contract, and Python quality (89 tests; 100% statement/branch, 991/442) passed. Exact-head GitHub checks are re-running after this push. |
|
@opencode-agent @cwl-noema-review Review-only request for exact current head `a562adde8375426ac75e1681d85b90d280d5b4ee`. Re-review privacy-grant boundary, purpose-bound PII alternatives, untrusted intake tests, docs/APA traceability, and protected-merge requirements. Do not merge or enable auto-merge. |
|
Queued @cwl-noema-review and @opencode-agent for PR #141 at head |
|
Current-head review refresh for a562add:
|
|
Rebased current head d558a4b onto origin/main. The changelog and ADR conflicts were resolved by retaining both feature and current-main decisions; inherited documentation trailing whitespace was removed. Local merge-tree, git diff --cached --check, and cargo fmt --all -- --check pass. Exact-head hosted checks and required independent approvals remain required before protected merge. |
|
Current-head disposition for the Devin findings on d558a4b: the exact current tree already includes the descendant workspace/doc fixes. Cargo.toml and the contract checker list twelve crates, README lists all twelve including provider_receipt and intake_authorization, and CHANGELOG has entries for both. No patch is needed for the predecessor finding. Please refresh independent review for d558a4b only; no approval or merge bypass is being issued. |
|
Current-head review request: exact head |
Maintainer exact-head disposition
|
…ation # Conflicts: # ARCHITECTURE.md # CHANGELOG.md # Cargo.lock # Cargo.toml # README.md # docs/PRIVACY_DATA_GOVERNANCE.md # docs/TRACEABILITY.md # docs/adr/0009-purpose-bound-pii-governance.md # docs/adr/README.md # docs/validation/temporal-event-foundation.md # scripts/check_workspace_contract.py # tests/quality/test_check_docstrings.py
| "crates/tepp_simulation", | ||
| "crates/validation_core", | ||
| "crates/tepp_api", | ||
| "crates/provider_receipt", |
There was a problem hiding this comment.
🟡 provider_receipt duplicated as workspace member
provider_receipt was already a workspace member, and it is now listed a second time in both members and default-members (default-members line 56), alongside the new intake_authorization. The EXPECTED_CRATES contract in check_workspace_contract.py and README.md were duplicated to match, so the approved-crate-list check enforces the redundant entry instead of rejecting it.
Prompt for agents
provider_receipt was already a workspace member before this PR (it still appears at Cargo.toml members line 34 and default-members line 76). This PR mistakenly re-adds it at members line 14 and default-members line 56 while adding the genuinely new intake_authorization. Remove the duplicate provider_receipt entries so it appears once in each list. The same duplicate was introduced into EXPECTED_CRATES in scripts/check_workspace_contract.py (the new entry near line 26 duplicates the existing one near line 46) and into the crate listing in README.md (line 46 duplicates line 66); remove those duplicates too. Keep intake_authorization as the only newly added crate. Verify member ordering stays consistent across Cargo.toml, the contract script, and the README.
Was this helpful? React with 👍 or 👎 to provide feedback.
| | purpose-bound PII handling without blanket masking | ADR 0009; `docs/PRIVACY_DATA_GOVERNANCE.md` | `tepp_api` export authorization, elevated re-identification, and provider-payload minimization are implemented-main; migration `0007` retention/deletion/legal-hold SQL contracts are implemented-main; `encrypted_mapping` AES-256-GCM envelope is active on this PR; deployment/provider evidence remains accepted-target | active-PR | | ||
| | tenant/purpose/role/lifetime access and identity separation | ADR 0009; Threat Model | `tepp_api` time-bounded `PurposeGrant` + cross-tenant denial implemented-main; persistent `access_grant` storage remaining | partial | | ||
| | TDT detection/tracking vs CHRONOS schema/prediction/temporal consistency | ADR 0016; PRD/research | future `event_intelligence` | accepted-target | | ||
| | evidence-bounded LLM interpretation | ADR 0010/0012; PRD | future `interpretation_gateway` | accepted-target | |
There was a problem hiding this comment.
🔍 Traceability entry for evidence-bounded LLM interpretation quietly dropped tepp_api router claim
TRACEABILITY.md changed the "evidence-bounded LLM interpretation" row from partial (tepp_api router plus future interpretation_gateway) to accepted-target (future interpretation_gateway only), removing the reference to the existing tepp_api router. The very next row (TRACEABILITY.md) still lists tepp_api::route_orchestration as an active-PR/partial capability, so the router itself was not removed. This appears to be a deliberate re-scoping of what counts as "evidence-bounded interpretation" rather than a code change, but the downgrade of maturity is unrelated to this PR's stated intent (untrusted-intake grant presence). Worth confirming the maturity change is intended and not an accidental regression in the traceability ledger.
Was this helpful? React with 👍 or 👎 to provide feedback.
| let mut matches = 0_u32; | ||
| for (truth_flag, decided_flag) in truth.iter().zip(decided) { | ||
| if truth_flag == decided_flag { | ||
| matches += 1; | ||
| } | ||
| } | ||
| Ok(f64::from(matches) / truth.len() as f64) |
There was a problem hiding this comment.
📝 Info: identity_recovery_rate match counter is u32 while inputs are unbounded slices
In intake.rs, matches is a u32 accumulated over truth.len() iterations while truth is an unbounded &[bool]. If a caller ever passed more than u32::MAX (~4.29e9) elements, the counter could overflow (panic in debug, wraparound in release). This is not realistic for practical inputs (would require multi-GB slices) so it is not a real-world bug, but using usize/u64 for the counter would be more robust and consistent with the usize denominator. Noting rather than flagging since it is not reachable in practice.
Was this helpful? React with 👍 or 👎 to provide feedback.
Untrusted documents, serialized records, checkpoints, and LLM outputs cannot be accepted without a purpose-bound grant (ADR 0009; AGENTS.md). Size, identity, and provenance bounds are not that grant.
Complementary to #79 (`purpose_authorization`: one grant, one purpose) and #135 (`payload_bound`: identity/provenance/size/depth). This crate owns grant presence at intake.
Local gates:
Does not allocate migration `0008`. Does not recreate `checkpoint_authority`, `purpose_authorization`, or `payload_bound`.
Keep this PR draft. Preferred merge remains #46 only when exact-head required Checks pass and a qualifying independent (non-Cursor/CodeRabbit) APPROVE exists. Do not empty-commit.