Path allowlists
Reads are limited to data, configs, artifacts, and eval. Writes stay in artifacts. Traversal and absolute escapes are rejected before the pipeline starts.
Grounding
Trust in this product is not a brand color. It is path allowlists, claim overlap, outbound URL policy, and a review state machine. Generated language that cannot point at evidence stays in the report with a reason — never promoted to a fact.
Reads are limited to data, configs, artifacts, and eval. Writes stay in artifacts. Traversal and absolute escapes are rejected before the pipeline starts.
Each sentence is scored against evidence overlap. Unsupported claims stay visible with a reason — they are not deleted in shame, and they are not promoted to facts.
Prometheus hosts and webhook URLs are allowlisted. Private networks and plain HTTP require an explicit opt-in. Failed deliveries are still logged.
The workstation does not host weights. Heuristic compose is deterministic. OpenAI is optional and keyed only via INCIDENT_AGENT_OPENAI_API_KEY.
Draft → reviewed → approved | rejected. Every transition stores reviewer, note, and timestamp. Webhooks only fire for approved reports.
.env is gitignored. .env.example never carries secret values. The generic OPENAI_API_KEY variable is ignored so a stray shell export cannot silently activate a provider.
Threat model, local edition
An operator on the same machine, or a trusted network. There is no end-user auth. Do not expose :8000 to the public internet.
Path traversal, writes outside artifacts, webhook URLs that are not exact allowlist matches, Prometheus hosts that were never opted in.
Request ids, stage durations, grounding summaries, review history, webhook delivery attempts. If it happened, it is in JSON.
Grounding policy
configs/default.yaml sets grounding.enabled and grounding.policy. Policy warn keeps unsupported claims and flags them. Policy fail drops the report if overlap is below minimum_support_overlap (0.34 by default). Use warn while you are tuning detectors. Use fail before a report is allowed to leave through a webhook.
supported
Overlap with an evidence id or hypothesis rationale above minimum_support_overlap (0.34).
unsupported
Fluent sentence, no bundle overlap. Stays in the report with a reason.
contradictory
Reserved for claims that fight detector output. Policy fail can drop the report.
not_applicable
Remediations and advice. They are not facts about the past.
Review machine
draft
Default after compose. The machine wrote it. A human has not looked.
reviewed
A named reviewer looked and left a note. Still not allowed to leave the building.
approved
Owner agrees. The only state that may POST to a webhook.
rejected
Graph or copy was wrong. JSON stays. The note is how the next run is not gaslit.
Allowlists
Read
Traversal and absolute escapes are rejected before the pipeline starts. Bring logs from inside those trees.
Write & outbound
Failed deliveries still append JSONL. A missing reviewer name is a 400, not a silent approve.
What we do not store
Trusted workstation
No end-user auth. Path allowlists and URL policy are foot-gun guards, not a multi-tenant security model.
Jobs are memory
Restarting uvicorn clears the board. Artifacts remain. Re-run a scenario to refill incidents and reports.
Heuristic compose
Default narrative is assembled from evidence JSON. It is precise, not lyrical. OpenAI is opt-in on top of the same contracts.
Graph is yours
Wrong edges produce wrong origins. Reject the report and fix configs/service_dependencies.yaml — do not edit facts.
Credential hygiene: .env is gitignored. .env.example never carries secret values. Only INCIDENT_AGENT_OPENAI_API_KEY can activate the optional rewriter. A generic OPENAI_API_KEY export in the shell is ignored on purpose.