Code / tools/new_finding.py
tools/new_finding.py
119 lines
#!/usr/bin/env python3
# =============================================================================
# Project : anomaly-atlas
# File : tools/new_finding.py
# Purpose : Scaffold a compliant atlas entry — refuses incomplete provenance
# Author : Simon-Pierre Boucher
# Contact : contact@spboucher.ai
# Data src : hfmarketdata.io (sole data source)
# Created : 2026-08-12
# Modified : 2026-08-12
# Platform : macOS / Apple Silicon (arm64)
# License : All rights reserved (research code)
# =============================================================================
"""Create atlas/<anomaly_id>/<version>/ from a completed finding payload.
Refuses to create an entry unless BOTH a complete provenance.json and a
confidence.md are supplied (CLAUDE.md §3, §10). Level 0 findings are refused
outright — in-sample-only output never enters the atlas.
Usage:
python3 tools/new_finding.py <anomaly_id> <version> \\
--finding finding.json --provenance provenance.json --confidence confidence.md
Required provenance keys:
commit, config, data_manifest_hash, hardware_manifest, generated_utc,
n_hypotheses_tested, correction_method, oos_status
Required confidence.md content: a 'Level: <1|2|3>' line plus front matter.
"""
from __future__ import annotations
import argparse
import json
import re
import shutil
import sys
from pathlib import Path
REPO_ROOT = Path(__file__).resolve().parent.parent
PROVENANCE_KEYS = (
"commit",
"config",
"data_manifest_hash",
"hardware_manifest",
"generated_utc",
"n_hypotheses_tested",
"correction_method",
"oos_status",
)
FINDING_ATTRIBUTION = {
"author": "Simon-Pierre Boucher",
"contact": "contact@spboucher.ai",
"data_source": "hfmarketdata.io",
}
def fail(msg: str) -> None:
sys.exit(f"REFUSED: {msg}")
def validate_provenance(path: Path) -> dict:
try:
prov = json.loads(path.read_text())
except (OSError, json.JSONDecodeError) as exc:
fail(f"provenance.json unreadable/invalid: {exc}")
missing = [k for k in PROVENANCE_KEYS if not prov.get(k)]
if missing:
fail(f"provenance.json incomplete — missing/empty: {', '.join(missing)}")
return prov
def validate_confidence(path: Path) -> int:
try:
text = path.read_text()
except OSError as exc:
fail(f"confidence.md unreadable: {exc}")
m = re.search(r"^Level:\s*([0-3])\b", text, re.MULTILINE)
if not m:
fail("confidence.md must contain a 'Level: <0-3>' line with evidence")
level = int(m.group(1))
if level < 1:
fail("Level 0 (in-sample only) never enters the atlas — scan output only")
return level
def main() -> None:
ap = argparse.ArgumentParser(description=__doc__)
ap.add_argument("anomaly_id")
ap.add_argument("version")
ap.add_argument("--finding", required=True, type=Path)
ap.add_argument("--provenance", required=True, type=Path)
ap.add_argument("--confidence", required=True, type=Path)
args = ap.parse_args()
prov = validate_provenance(args.provenance)
level = validate_confidence(args.confidence)
try:
finding = json.loads(args.finding.read_text())
except (OSError, json.JSONDecodeError) as exc:
fail(f"finding.json unreadable/invalid: {exc}")
finding.update(FINDING_ATTRIBUTION)
finding.setdefault("anomaly_id", args.anomaly_id)
finding["confidence_level"] = level
dest = REPO_ROOT / "atlas" / args.anomaly_id / args.version
if dest.exists():
fail(f"{dest.relative_to(REPO_ROOT)} already exists — bump the version")
dest.mkdir(parents=True)
(dest / "finding.json").write_text(json.dumps(finding, indent=2) + "\n")
(dest / "provenance.json").write_text(json.dumps(prov, indent=2) + "\n")
shutil.copy(args.confidence, dest / "confidence.md")
print(f"atlas entry created: {dest.relative_to(REPO_ROOT)} (Level {level})")
if __name__ == "__main__":
main()