History
Save every verify report with --save,
then render a score-over-time trend with paranoid
history: one self-contained HTML file, or a JSON series
for scripting. Everything stays on disk, local to the repo.
Saving reports
verify --save writes the report verify computed to
.paranoid/history/<utc-timestamp>-<short-sha>.json,
in addition to whatever --format and
--output already do. The directory is created on
demand. The timestamp is the run's own
generated_at value (the injectable clock used elsewhere in the tool), not a separate wall-clock read. The short SHA is the current HEAD commit, truncated to 7 characters, which keeps file names short and collisions rare.
$ paranoid verify --save
...
$ ls .paranoid/history/
20260826T120000Z-3f2a9c1.json
Rendering the trend
paranoid history [path] loads every file under
.paranoid/history/, sorts them oldest to newest by
generated_at, and renders an HTML page with:
- A score-over-time line chart, drawn as inline SVG, with no charting library and no remote fetch.
- A runs table: date, base..head, score, verdict, and finding count by category.
- One sparkline per finding category, showing how its count moved across the same runs.
$ paranoid history
$ ls paranoid-history.html
A file that cannot be read, cannot be parsed, or was written by
a build that used a different history_version is
skipped, with one line on stderr naming the file and why. A bad file does not block the rest of the series.
Determinism
The same history directory always renders the same HTML bytes.
Every value in the page, chart included, comes from the saved
reports themselves (scores, dates, category counts); nothing is
stamped in at render time. Runs are plotted at even, index-based
steps along the x-axis rather than scaled to calendar time, because verify --save runs are irregular. Even spacing keeps the chart simple and reproducible.
The history envelope, version 1
Each saved file wraps the full verify report
(identical to --format json's own output, including
its own schema_version) in a small envelope with
its own version number, independent of the report's:
| Field | Type | Meaning |
|---|---|---|
| history_version | integer | Always 1 today |
| report | object | The full verify report, same shape as --format json |
A change to the report schema does not require a change to the envelope version, and the reverse also holds. The baseline file and the fix-prompt schema are versioned the same way. See Report & schema.
JSON series (--format json)
paranoid history --format json prints the parsed,
derived series instead of rendering HTML: one entry per run,
plus the fixed, alphabetically sorted list of categories every
per-run breakdown uses. Output goes to stdout by default.
{
"history_version": 1,
"runs": [
{
"generated_at": "2026-08-26T12:00:00Z",
"base": "7db5cfb...",
"head": "worktree",
"score": 90,
"verdict": "pass",
"total_findings": 1,
"findings_by_category": {"test-integrity": 1}
}
],
"categories": ["test-integrity"]
}
Privacy
History is local. Saving, loading, and rendering make no network calls. Add .paranoid/ to your repository's .gitignore; the files are local run records and are not meant to be committed.
Flags
| Flag | Default | Meaning |
|---|---|---|
| --format | html | Output format: html or json |
| --output | paranoid-history.html for html, stdout for json | Write the output to this file instead |
verify accepts one more flag: --save (off by default). It has no effect on
verify's own score, verdict, or exit code.