AI Data & Privacy Inspector
ProThe AI pack's privacy contract, on screen: what is masked, what is deliberately not, which rules do not compile, whether content can be unmasked, copied or sent to analytics — and what a policy let through when run against real prompts, transcripts and tool arguments. 4 variants: policy, scan, retention and surfaces.
import { SvAiPrivacyInspectorComponent } from '@styloviz-pro/ai-privacy-inspector';Demo & usage
Basic usage
ProUsage example — open the gallery for the full interactive demo.
An interactive demo for this component lives in the gallery.
Open live demoMore examples
Run it against your own content
ProCompare two policies
ProWhen to use
- Answering "what do you redact, can it be unmasked, and does content reach analytics" without reading a TypeScript file.
- Checking a policy against real prompts and tool arguments before deciding it is finished.
- A settings or admin screen where the person configuring the AI pack should see what their configuration actually does.
- Not for end users mid-conversation: this is a review surface, and the masking itself happens in the components that render the content.
Async states
- loading
- error
- retry
Item identity & owned state
- Restorable state
- openSampleIds
Bind these to put a saved view back — the open sections, the hidden columns, the selected rows — and read their
Changeevents to store what the user does.
Inputs
| Name | Type | Default | Description |
|---|---|---|---|
| loading | boolean | false | True while the host is fetching what it needs to inspect. |
| error | SvDataError | string | null | null | Load failure. Use `toSvDataError()` from `@styloviz/core` to normalize an `HttpErrorResponse`. |
| variant | PrivacyInspectorVariant | 'policy' | The contract as configured, or the contract run against content. |
| policy | SvAiPrivacyPolicy | null | null | The policy to inspect. Unset means the one in force. THE AMBIENT POLICY BY DEFAULT, WHICH IS THE ONLY USEFUL DEFAULT: the question is always "what is THIS app doing", and a component that made you pass the answer in could be passed a policy nothing is using. An explicit `[policy]` is for the other job — holding two of them side by side to see whether staging and production agree. |
| samples | readonly SvPrivacySample[] | [] | Content to run the policy against, for the `scan` variant. Real samples, bound by the host: a prompt, a couple of transcript turns, a tool argument, a retrieved chunk. Four is usually enough to learn something and few enough that a reader reads them. |
| openSampleIds | ReadonlySet<string> (two-way) | new Set<string>() | Which sample rows are expanded, by id. A `model()` rather than private state: a reviewer who has opened the one row that matters and follows a link should come back to it, and a host cannot restore what it cannot read. |
| retention | readonly SvRetentionRule[] | [] | How long content is kept, declared by the host. Declared, because no component can detect a retention job — and each row says whether anything actually shows the deletion happening. |
| consent | readonly SvConsentRecord[] | [] | Consent records in force. |
| destinations | readonly SvDataDestination[] | [] | Where content goes after it leaves these components. THE QUESTION MASKING DOES NOT ANSWER. `svAiMask` runs in the renderer, so everything upstream — the model call, the log line, the analytics event — receives the original. A team that sees masked transcripts on screen will tell an auditor their data is redacted, and this input is where that gets corrected. |
| surfaces | readonly SvSurfaceAdoption[] | SV_AI_PACK_SURFACES | Which surfaces read the shared policy. |
| now | number | null | null | The clock, for expiry and staleness. An input so a spec and a screenshot can pin it; `Date.now()` otherwise. |
Outputs
| Event | Payload type | Description |
|---|---|---|
| retry | void | The host should re-run the failed load. |
| riskSelect | SvPolicyRisk | A risk row was activated, for a host that wants to link to its own docs. |
| openSampleIdsChange | ReadonlySet<string> | Emits the new `openSampleIds` whenever it changes — the output half of `[(openSampleIds)]`. |
Wire it to your API
This component is headless about transport: it renders what you give it and reports what the user asks for. Nothing below requires @styloviz/data — drive it from whatever you already use.
Template
ProBound to the names this component actually exposes.
Host class
ProDrive the three async inputs from your own fetch.
- This component does not emit a query, so it renders what you give it. Fetch on your own trigger and bind `samples`, `loading` and `error`.
- Normalize failures with `toSvDataError()` from `@styloviz/core`. It derives `retryable` from the status, so a 404 does not get a "Try again" button that can only fail again.
Full walkthrough: Connecting to a backend.
Customization & theming
- Four variants via `variant`: `policy` (the contract, its rules, its switches and what is wrong with it), `scan` (the contract run against bound samples), `retention` (how long content is kept, on what basis, who else receives it) and `surfaces` (which components read the shared policy).
- Reads the policy from `provideSvAiPrivacy()` by default — the question is always "what is THIS app doing", and a component you had to pass the answer to could be handed a policy nothing is using. `[policy]` overrides it, for holding two side by side.
- `[samples]` are host-bound: a prompt, a transcript turn, a tool argument, a retrieved chunk. Four is usually enough to learn something and few enough that a reader reads them.
- `openSampleIds` is two-way, so a reviewer who opened the one row that matters can be put back on it.
- No score, no percentage, no green tick. You cannot know what share of the secrets in arbitrary text a pattern set catches, and one invented number spends the panel's credibility for good — so it states what is looked for and what is not, by name, and refuses to add them up.
- A rule that does not compile is reported as a hole, not a warning: `svAiMask` reports it with one console line in a dev build and then masks nothing for the life of the app, which on screen is indistinguishable from a rule that matched nothing.
- A miss is reported by its SHAPE — length and last two characters — never its value. The panel exists to say a card number got through; printing the card number to make that point would be the leak it is warning about.
- A category the policy has a rule for that got through anyway is reported separately from one nothing looks for. The first is a rule that does not work; the second is a decision to review.
- `svPolicyRules`, `svPolicyRisks`, `svCoverageStatement`, `svPolicyFingerprint`, `svScanSample` and `svScanSummary` are exported, so a host can put the same findings in its own admin UI or assert them in a test.
- Nothing leaves the browser. There is no fetch, no telemetry and no output carrying sample text anywhere in this component, and the panel says so rather than leaving it in a README.
- `[retention]`, `[consent]` and `[destinations]` are host declarations, because no component can detect a deletion job or a consent record — and each row says which it is. A retention window with nothing showing the deletion happening renders as a stated policy, not a verified one; evidence older than `SV_VERIFICATION_STALE_DAYS` (90) is reported as too old to stand for anything, because a deletion report from last year is not evidence that deletion ran last night.
- An expired grant is not consent, and the `retention` variant will not render it as one. Withdrawal beats a live grant whatever the dates say, and `unknown` is kept apart from `declined`: treating “nobody asked” as a refusal looks safe and hides the actual finding.
- `[destinations]` is where the sharpest thing in this component gets said: `svAiMask` runs in the RENDERER, so the model call, the log line and the analytics event all receive the original. A team that sees masked transcripts on screen will tell an auditor their data is redacted — so a content destination marked unmasked produces the sentence “masking applies to what these components render” in as many words.
- `[surfaces]` defaults to the kit’s own `X-2` audit (`SV_AI_PACK_SURFACES`) and is labelled a declaration rather than a detection, because Angular gives a component no way to ask which others injected a token. An exemption with no reason recorded is named as an omission wearing the word.
- `[now]` pins the clock for a screenshot or a test; `Date.now()` otherwise.
Best practices
- Do: Bind real samples. A pattern list tells you what is looked for; only your own prompts tell you whether that is the right list.
- Do: Read the two header lines together. "Looks for" without "does not look for" is the half that flatters the policy.
- Don't: Do not treat "nothing matched" as "nothing sensitive". With no patterns configured, nothing is being looked for — the panel says so in those words for that reason.
- Don't: Do not put this in front of end users as a reassurance badge. It is a review tool, and it is deliberately not scored.
- Tip: The fingerprint in the header answers "are staging and production on the same policy" in one glance, which two panels of prose cannot.
Accessibility
- Findings are ordered so that everything which leaks content comes first. A panel that opened with "copy enabled — worth knowing" while content was flowing to analytics further down would be worse than no panel, because the reader would believe they had read it.
- Each switch states On or Off in words as well as colour, and the sentence beside it describes the state the policy is in rather than naming the flag — "reveal: false" tells a reader nothing they can act on.
- Sample rows are real buttons with `aria-expanded`, and the masked text sits in a focusable `<pre>` so a keyboard reader can scroll it.
- Every risk row is activatable and emits `riskSelect`, so a host can link a finding to its own policy documentation.
- Consent state, retention staleness and adoption status are each rendered as a WORD as well as a colour — the difference between granted and expired is the whole row, and a hue cannot carry it.
- The empty state names the variant’s own subject: one message about “samples” on the retention view reads as a broken panel rather than as nothing declared, and “nothing declared” is said in those words rather than as a clean bill.
Feedback on AI Data & Privacy Inspector
Spotted a gap in this page, or something that didn't work as described? Comments are GitHub Discussions in the public styloviz/community repo, so posting needs a GitHub account.