Monitor regulatory compliance
Read what the guardrails caught against GDPR, HIPAA, the EU AI Act and six more frameworks, open findings, freeze evidence and simulate a stricter policy.
- Version: 0.4
- Feature: compliance
- Role: admin_user, viewer
- Type: task
Regulatory Compliance maps every detection the gateway made onto the regulation articles it touches, estimates the statutory exposure behind them, lets a person take ownership of one as a finding, and freezes a period so the figures signed off in September still read the same in March.
What do I need?
- Licence
- Any
- Role
admin_userviewer
Prerequisites
- The appliance has traffic: the page is built entirely from detections already recorded, and computes nothing of its own.
- At least one detection channel is reporting — managed chat, the browser extension, the inline proxy, document analysis, Claude Code or the image API.
- For the PDF exports, the report-renderer service is running and reachable at REPORT_RENDERER_URL.
The page is read by four roles. admin_user and superadmin can use every control; auditor
reads everything except raw matched values, which are replaced by the entity-type placeholder;
viewer reads the page and every change it attempts is refused with READ_ONLY_ROLE. Any other
role is shown Access denied with Your role does not have permission to view this page. Ask
an administrator if you need access.
The nine frameworks are seeded, not configured: GDPR, HIPAA, EU AI Act, KVKK, NIS2, BDDK, DORA, ISO/IEC 42001 and ISO/IEC 27001. You cannot add a tenth from the dashboard.
/assets/screenshots/compliance@0.4.pngHow the page is organised
One scope — period, channel, tenant, display currency — feeds six views:
| View | Answers |
|---|---|
| Impact Summary | What did the guardrails prevent in this period, and what exposure remains |
| Regulations | Which NIST CSF 2.0 controls are holding, and the seeded regulation catalogue behind them |
| Detections | The individual rows every figure above is built from |
| Decision Simulator | What a stricter policy would have avoided |
| Findings | Which detections a person took responsibility for |
| Evidence | Frozen periods, their checksums, dossiers and evidence packs |
A detection counts toward every regulation its entity types map to, so the per-regulation counts add up to more than the total. That is deliberate — a jailbreak is an EU AI Act event and an ISO 42001 event and a NIS2 event at once — and it means the per-regulation column is not a partition and must never be summed.
Scope the page to a period and a surface
Open the page
Select Security & Compliance → Compliance.
The page opens on Impact Summary over the last 30 days.
Set the period
Choose 7d, 30d, 90d or All time.
Every tab, chart and export on the page reads this window. The Findings tab is the one exception: a worklist framed by 30 days would hide a July finding still due in September, so it ignores the period deliberately.
Narrow to one channel
Open the Channel selector and pick one of Managed chat, Browser extension, Inline proxy (SWG), Document analysis, Claude Code or API / image, or leave it on All channels.
A channel with no records in the window is still listed with a zero, so a surface that is switched off is distinguishable from one that is clean.
Narrow to one tenant
Open Tenant and pick an account, or leave All tenants.
Detections that carry no tenant, or a tenant id no account matches, cannot be reached by this filter. The scope bar says how many there are so the per-tenant views are not mistaken for a partition of the whole.
Choose the display currency
Select the currency chip and pick the currency the cross-regulation totals are expressed in.
Only the totals convert. Each regulation keeps the currency its authority actually fines in,
and the chip shows the rate date and whether the rates are the shipped reference set or
manually adjusted. Changing a rate is admin_user only; an auditor reads the rates and
cannot edit them.
Warning
On a window with fewer than 20 detections the money figures are suppressed and the panel says so. The exposure model is a saturation curve, and below that count one extra detection moves a projected figure by roughly 2.4% of the statutory cap. Trend lines need seven days that actually carry a detection.
Open the detections behind a figure
Select a row or a segment
On Impact Summary, select a row in Exposure by regulation or a segment in Where these detections came from.
The page scopes to that regulation or channel and the chip appears in the scope bar. Selecting it again clears it.
Switch to the detections
Select the Detections tab.
The table lists date, entity types, action, regulations, articles, risk, direction and review state for the active scope. Filters for Entity Type, Risk Level, Action and a date range are applied by the gateway before paging, so the total under the table counts the filtered set.
Read one detection
Select a row.
The dialog names the action taken, the risk level, the articles the detection would have
violated, the potential fine and the session it came from. For an auditor the matched values
are replaced by the entity-type placeholder and the dialog says Matched values are hidden
for your role — the entity type is shown instead.
Export the filtered set
Select Download PDF or Export HTML in the table toolbar.
Both export the full filtered set, not the visible page, capped at 500 rows. The PDF cover prints the subject, the active filters, the period and the number of rows actually laid out.
Open a finding and track it
A finding is the one record on this page a person writes: the answer to and what did you do about it? Everything else is derived from detections and read-only.
Open the finding
In the Detections table row actions — or in a detection's audit drawer on All detections — select Open as finding.
The control checks first and renders the answer: if a finding is already live for that detection it shows the status chip and links to it instead of creating a second one.
Assign an owner and a due date
Go to the Findings tab, select the row, and fill in Owner and Due.
Owner is an email address — the responsible person is often not a gateway user. Leave Due empty for no deadline. An overdue open finding is marked Past due and still open.
Record what happens next
Write the plan in Next step and set Status to Open, In progress or Closed.
Closing stamps the closure date; reopening clears it, because a reopened finding that still carried a closure timestamp would read on every report as closed on that day.
Link the external ticket
If the finding became a ticket in your own system, paste its identifier in Ticket reference and its link in Ticket link.
Ticket link must be an absolute http or https URL or the save is refused. The reported
ticket status is displayed but is never mapped onto Status — this finding's status is what
CID recorded a person deciding, and a remote workflow must not be able to rewrite a compliance
record.
Note
The snapshot fields — the detection reference, the regulations and the recommended action — are fixed at the moment the finding was opened and cannot be edited. There is no delete: the way to end a finding is to close it, which keeps the closure and its date.
Freeze a period as evidence
Every other figure on the page is recomputed from tables that keep moving. A capture records the window as it stands and never recomputes it.
Set the scope you want frozen
Set the period, and the channel, tenant and regulation filters if the record should be narrower than the whole appliance.
The capture takes the scope bar as it stands, so what you see is what is frozen.
Capture
Go to Evidence, type an optional note in What is this capture for? and select Capture this period.
A Period captured. toast confirms it. Re-freezing the same window is allowed — refusing would make a first mistaken capture permanent — and the toast then reads Captured. These are the same figures as an earlier record for this window.
Check that a record is unchanged
Select Check on a row.
The gateway re-hashes the stored bytes and the chip reads Unchanged or Altered. This is a checksum, not a signature: it shows whether a record changed after capture, carries no trusted timestamp, and does not stop anyone with database access.
Download the record or the pack
Select the download action for the raw record, or Evidence pack for the archive.
The raw download is the exact bytes that were hashed, so sha256sum on the file reproduces the
value shown in the row. The pack adds the rendered report, per-regulation dossiers, a
checksum manifest, a MANIFEST.json and a VERIFY.txt with the commands to check it offline.
Read what the pack cannot show
Select What's inside before downloading.
The popover lists every file, the mapping version the figures were computed under, and a What it cannot show list of gaps. It also carries the reconciliation chip: Report matches the record, Report and record disagree, or Not checked — and the pack download refuses on either of the last two rather than shipping a document that looks complete.
Produce a per-regulation dossier
Select Dossier, choose GDPR, KVKK or EU AI Act, then Download JSON or Download PDF.
Sections marked From record are filled from the frozen figures; sections marked Deployer are evidence no gateway can hold — a DPIA, a record of processing activities, a human-oversight procedure. Neither an unfilled automatic section nor a deployer section is dropped: both render and both appear in the closing evidence-gap list.
Warning
Completed periods are also frozen automatically — the schedule defaults to enabled with a
monthly cadence — but the dashboard has no screen for it. Reading or changing the cadence is
GET/PUT /admin/compliance/snapshots/schedule only.
Simulate a stricter policy (Decision Simulator)
The Decision Simulator tab is the GRC/CRQ model: a deterministic with-and-without projection of fine exposure over the detections already in the window. It is not Monte Carlo and not a probabilistic annual loss estimate, and every run returns the formula notes behind its numbers.
Three projections are computed on one model,
exposure = statutory cap × (1 − 0.5 ^ (detections / 50)):
| Projection | What it assumes |
|---|---|
| Without CID-Core | Every historical detection in the window reached the model |
| With CID-Core | Masked and rejected detections were neutralised; only flagged content still carries exposure |
| Simulation | The same, with your what-if targets applied to the detections that remain risky |
Open the simulator
Select the Decision Simulator tab.
The three cards Without CID-Core, With CID-Core and Reduction load over the page's period, channel and tenant scope.
Choose how you want to express the change
Tier 1. Each slider is one regulation's coverage. Drag it above its current coverage to model a stricter policy — moving a rule from Flagged to Masked, for example — and the cards above update.
The cards and the coverage rows recompute on every change; nothing is saved.
Read the methodology before quoting a number
Scroll to Methodology.
The notes state the arithmetic for the run you are looking at. The exposure ceiling is the statutory maximum applied per detection; an actual fine depends on incident scope and the authority's discretion.
Export the run
Select Download PDF.
The gateway re-runs the simulation server-side and renders it with the subject, channel and period printed on the cover, so a run scoped to one team is not filed as if it described the organisation. The PDF exists for the two slider modes only.
Warning
Control baselines are seed defaults from nist-csf-2.0.json, not measurements of your own
filter pass rates, and the exchange rates behind the totals are the shipped reference set unless
somebody edited them. The simulator is an indicative projection for policy tuning, not legal
advice.
Control coverage and its floor
The Regulations tab opens with Controls and the articles they answer to. A control grades on the share of the detections carrying its articles' entity types that were masked or blocked — not on how much traffic it saw. Four states:
| State | Meaning |
|---|---|
| Holding | At or above the coverage floor |
| Short of floor | Inside the band just under the floor. Counts as half a holding control, never as a pass |
| Below floor | Under the band |
| No traffic | Nothing exercised this control in this period. Not the same as healthy |
Select Floor: 95% to change the default floor for every control. The help text is exact about
what that does: Grading only. A control below the floor changes what this page says and sends
nothing anywhere — no alert, no export. The floor in force is recorded with each daily
observation, so past grades stay explainable after you move it. Per-control overrides exist in the
API and are deliberately absent from the form. Moving the floor is admin_user only.
Fields reference
Scope bar
| Control | Values | What it does |
|---|---|---|
| Period | 7d, 30d (default), 90d, All time | The window every view and export reads, except Findings |
| Channel | All channels or one of the six surfaces | Restricts every figure to one capture point |
| Tenant | All tenants or one account | Restricts to one account. Cannot reach detections that carry no resolvable tenant |
| Currency | The supported display currencies | Converts the cross-regulation totals only |
Finding
| Field | Required | Rule | What it does |
|---|---|---|---|
| Finding | No | Free text | Title. Defaults to a title derived from the detection |
| Owner | No | Email address | The accountable person. Shown as Unassigned while empty |
| Due | No | Date | Deadline. Empty means no deadline |
| Status | Yes | Open, In progress, Closed | Where the work stands. Closing stamps a date; reopening clears it |
| Next step | No | Free text | What happens next, in your own words |
| Ticket reference | No | Free text | Your ticketing system's own identifier |
| Ticket link | No | Absolute http(s) URL | Rendered as a link in the list. A relative or non-HTTP value is refused |
Snapshot row
| Column | Shows |
|---|---|
| Period | The window that was frozen |
| Note | Your capture note, or empty |
| Captured | When, and by whom |
| Check | Unchanged or Altered after you select Check |
| Mapping version | The entity-to-regulation ledger version the figures were computed under, or unknown (pre-versioning) |
Verify
- The scope bar restates what you selected, and the totals move when you change the period.
- Capture a period, then select Check. The row reads Unchanged. Download the record and
run
sha256sumon the file: the digest equals the one the row shows. - Download an evidence pack and follow the
VERIFY.txtcommands inside it. The listed checksums reproduce, and rebuilding the same snapshot produces a byte-identical archive. - Open Event logs — and expect little. This module writes almost nothing to the audit trail: a mapping override, a fine-structure override, an exchange-rate change, a snapshot capture and a simulator run all leave no event row. Opening and updating a finding does write an audit row, but under an event type the shipped event-type registry does not carry, so the gateway logs a warning and no feed on the Event logs page displays it.
Warning
Treat the audit trail as covering the traffic this page reports on, not the administration
of this page. If you need a record of who changed a mapping or a fine structure, read the
mapping-version ledger through GET /admin/compliance/mapping-versions — it records the
acting administrator on every entry — because no dashboard screen shows it.
If it fails
- Access denied with Your role does not have permission to view this page. Ask an
administrator if you need access. — your role is not admitted to this page. Only
superadmin,admin_user,auditorandviewerare. - A 403 with
FEATURE_NOT_LICENSED— the installed licence does not carry thecompliancecapability. It ships in all three tiers, so this normally means the licence itself is missing or invalid; see Licensing and activation. - This is a read-only demo account (viewer role) — actions and changes are disabled. — the
request was refused with
READ_ONLY_ROLE. Sign in with an account that is not a viewer. - No data yet — this is a new install — nothing has passed through the guardrails in this scope. The page fills in on its own as traffic arrives.
- Projection hidden or Trend hidden — the window has fewer than 20 detections, or fewer than seven days that carry one. Widen the period.
- Rate editing is unavailable on this deployment — totals stay in EUR. — the rate endpoint
refused. On an
auditoraccount this is expected: reading the rate is permitted, changing it is not. - Capture failed. with a 400 start_date and end_date must be dates or start_date must be before end_date — the window is malformed. Reselect the period.
- The pack was not produced. — reconciliation between the rendered report and the frozen record failed, or could not run. Open What's inside: the popover names the identifiers that differ. The refusal is deliberate.
- A 400 naming the supported regulations — you asked for a dossier for a regulation that has no template. Only GDPR, KVKK and EU AI Act have one.
- The dossier report could not be rendered … The dossier JSON is unaffected and remains
downloadable. (503) — the report renderer is unreachable. Take the JSON, or check
REPORT_RENDERER_URL. - Failed to render impact PDF / Failed to render detections PDF / Failed to render executive summary PDF (503) — the same renderer is down. The on-screen figures are unaffected.
Next steps
- Compliance reports — the graded scorecard per tenant or group, and the ranked evidence behind it.
- AI governance — the other half of the question: not what the controls caught, but what AI the organisation is accountable for.
- All detections — the unified feed every channel on this page reports into.
Last updated on