Regulatory driver
Two independent regulations demand the same request to produce different redaction outputs depending on who is asking and why:
- PCI DSS v4.0.1 Req 3.4.1 — PAN display defaults to last-4 only, but "personnel with a legitimate business need" may see first-6 + last-4. Same document, two audiences, two masks.
- CCPA §1798.105(d) — nine enumerated retention exceptions (fraud detection, legal obligation compliance, security incident detection, internal-uses-compatible-with-context, …). A deletion request must delete unless the retained data falls under one of these purposes. Same document, "delete-all" for most callers, "keep the fraud-relevant subset" for the anti-fraud pipeline.
Both cases share a shape: the policy is the same regulatory template; the predicate branches on request-scoped context.
Current gap
AuditContext currently carries languages, countries, tags, and correlation_id — but nothing that names the requester's purpose or role. Predicates today can key off entity facts (LabelOneOf, TagOneOf, Confidence, CoRef) or document-level facts (DocumentPredicate), but not off request-scoped context. Hosts today either:
- submit different policy sets per role/purpose (denormalising the same regulatory template into N variants), or
- pre-annotate reviewer overrides on the audit (moving compliance logic into the caller).
Both defeat the point of shipping a single canonical HIPAA/PCI/CCPA template.
Proposed shape
Add request-scoped context fields, mirrored to elide's Scope:
// nvisy-schema::plan::ScopeParams
pub struct ScopeParams {
// ...existing fields...
/// Named business purpose driving this request. Compared to
/// `Predicate::PurposeIs`. Free-form string; policies define
/// their own vocabulary (e.g. "fraud_detection", "audit",
/// "customer_support"). Empty means unscoped.
pub purpose: Option<String>,
/// Named roles the requester holds. Compared to
/// `Predicate::RoleContains`. Multi-value because a caller
/// may hold several (e.g. `["support_agent", "fraud_reviewer"]`).
pub roles: Vec<String>,
}
And two matching Predicate variants:
Predicate::PurposeIs { purpose: String }, // scope.purpose == purpose
Predicate::RoleContains { role: String }, // scope.roles.contains(role)
Composable via existing All/Any/Not. Threaded onto AuditContext so anonymize sees the same purpose/roles analyze did.
Elide-side dependency
None. This is a nvisy-schema/nvisy-policy/nvisy-engine change; the predicates evaluate on runtime-side context before compiling to elide's Anonymizer. Elide's scope stays as-is.
Acceptance
- PCI DSS template ships a single policy whose PAN rule masks to last-4 by default and to first-6+last-4 when
roles contains "pci_business_need".
- CCPA template ships a single policy whose PII erase rule is bypassed when
purpose is one of the nine §1798.105(d) exception values.
- End-to-end test: same document + same policy, two requests differing only in
purpose/roles, produce different redacted outputs.
Regulatory driver
Two independent regulations demand the same request to produce different redaction outputs depending on who is asking and why:
Both cases share a shape: the policy is the same regulatory template; the predicate branches on request-scoped context.
Current gap
AuditContextcurrently carrieslanguages,countries,tags, andcorrelation_id— but nothing that names the requester's purpose or role. Predicates today can key off entity facts (LabelOneOf,TagOneOf,Confidence,CoRef) or document-level facts (DocumentPredicate), but not off request-scoped context. Hosts today either:Both defeat the point of shipping a single canonical HIPAA/PCI/CCPA template.
Proposed shape
Add request-scoped context fields, mirrored to elide's
Scope:And two matching
Predicatevariants:Composable via existing
All/Any/Not. Threaded ontoAuditContextso anonymize sees the same purpose/roles analyze did.Elide-side dependency
None. This is a nvisy-schema/nvisy-policy/nvisy-engine change; the predicates evaluate on runtime-side context before compiling to elide's
Anonymizer. Elide's scope stays as-is.Acceptance
rolescontains"pci_business_need".purposeis one of the nine §1798.105(d) exception values.purpose/roles, produce different redacted outputs.