You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat: consume .hypatia-baseline.json in governance gate (#166)
## Summary
Adds a single, formal exemption convention to the estate governance
gate: `.hypatia-baseline.json`. Same shape as Hypatia findings
(severity, rule_module, type, file/file_pattern), so an acknowledged
finding can be listed once and silently suppressed by the gate.
Companion to `hyperpolymath/gitbot-fleet#148`.
### Why
The `language-policy` job runs `banned_language_file` across every
caller repo. In-flight migrations (e.g. the ReScript → AffineScript port
at `gitbot-fleet`) keep getting blocked on `.res` files that are already
acknowledged in the repo's baseline. PR authors started inventing
alternate ignore conventions (`.hypatia-ignore` flat-files) to work
around the gap. This PR formalises one convention so the estate stops
sprouting more.
### What
1. **`validate-baseline` job** (new) — detects the per-repo baseline
file, schema-validates it (`ajv` when available, `jq` fallback
otherwise), surfaces stale entries (referenced file no longer exists) as
warnings. Soft-failure throughout.
2. **`language-policy` job** (updated) — `is_exempt()` now consults
`.hypatia-baseline.json` before falling back to legacy `.hypatia-ignore`
and the inline `# hypatia:ignore` pragma. The legacy path stays for
back-compat; a follow-up PR retires it once the estate has converged.
3. **`.machine_readable/hypatia-baseline.schema.json`** — formal JSON
Schema (draft 2020-12). Required: `severity`, `rule_module`, `type`,
plus exactly one of `file` / `file_pattern`. Optional:
`severity_override`, `expires_at`, `note`, `tracking_issue`.
4. **`scripts/apply-baseline.sh`** — pure bash+jq filter. Used by the
richer findings-list flow this PR seeds; the current workflow
integration uses the inline `jq` lookup instead so the advisory-mode
landing has the smallest possible footprint.
5. **`docs/HYPATIA-BASELINE-FORMAT.adoc`** — authoritative format doc.
6. **`docs/EXEMPTION-MECHANISMS.adoc`** — convention doc: when to use
`.hypatia-baseline.json` vs the estate-wide
`bot_exclusion_registry.a2ml` vs per-PR labels.
### Rollout
**Advisory mode (default).** Exempting a finding via the baseline
removes it from the gate output. Blocking-mode promotion (via
`vars.HYPATIA_BASELINE_MODE = "blocking"`) is the follow-up after a
one-week soak. Documented inline at the top of
`governance-reusable.yml`.
## Test plan
- [ ] CI green on this branch.
- [ ] Manual: caller repo with a baseline file gets a `⏭️ exempt
(baseline)` line in the language-policy job logs and the gate passes
despite the banned file.
- [ ] Manual: caller repo without a baseline behaves identically to
before (legacy `.hypatia-ignore` + inline pragma still honoured).
- [ ] Manual: caller repo with a malformed baseline gets a
`validate-baseline` warning (not a hard failure during advisory soak).
- [ ] Follow-up after one-week soak: flip `HYPATIA_BASELINE_MODE` to
`blocking` and confirm the gate behaves identically across the estate.
https://claude.ai/code/session_01W3PAoaqgJj3mnM8kjhEqx4
---
_Generated by [Claude
Code](https://claude.ai/code/session_01W3PAoaqgJj3mnM8kjhEqx4)_
---------
Co-authored-by: Claude <noreply@anthropic.com>
"note": "One-shot v1 STATE.scm -> v2 STATE.a2ml directive-format migration script. Python is banned estate-wide (CLAUDE.md); this should be rewritten in Rust/AffineScript or retired once every estate repo has migrated to v2. Acknowledged here so the governance gate stops noise-flagging it on every PR."
"description": "Authoritative schema for `.hypatia-baseline.json` files in hyperpolymath estate repos. A baseline is an array of acknowledged Hypatia findings that should be suppressed from blocking governance gates.",
6
+
"type": "array",
7
+
"items": {
8
+
"$ref": "#/$defs/BaselineEntry"
9
+
},
10
+
"$defs": {
11
+
"BaselineEntry": {
12
+
"type": "object",
13
+
"additionalProperties": false,
14
+
"required": ["severity", "rule_module", "type"],
15
+
"oneOf": [
16
+
{ "required": ["file"] },
17
+
{ "required": ["file_pattern"] }
18
+
],
19
+
"properties": {
20
+
"severity": {
21
+
"description": "Severity of the finding as reported by Hypatia. Must match the finding's severity exactly for the entry to apply.",
"description": "Hypatia rule module that emitted the finding (e.g. `cicd_rules`, `code_safety`, `migration_rules`).",
27
+
"type": "string",
28
+
"pattern": "^[a-z][a-z0-9_]*$"
29
+
},
30
+
"type": {
31
+
"description": "Hypatia finding type within the rule module (e.g. `banned_language_file`, `obj_magic`, `deprecated_api`).",
32
+
"type": "string",
33
+
"pattern": "^[a-z][a-z0-9_]*$"
34
+
},
35
+
"file": {
36
+
"description": "Repo-relative path to a single file the entry exempts. Mutually exclusive with `file_pattern`.",
37
+
"type": "string",
38
+
"minLength": 1
39
+
},
40
+
"file_pattern": {
41
+
"description": "Glob pattern (gitignore-style) matching multiple files. Use to exempt a whole subtree without per-file enumeration. Mutually exclusive with `file`.",
42
+
"type": "string",
43
+
"minLength": 1
44
+
},
45
+
"severity_override": {
46
+
"description": "Optional. If set, the matched finding is downgraded to this severity in the gate (e.g. `low` for migration-window acknowledgement) instead of being silently suppressed. Useful for advisory-mode triage.",
"description": "Optional ISO-8601 date. After this date the entry is treated as expired and the gate fails again. Used to bound migration windows and prevent baseline rot.",
52
+
"type": "string",
53
+
"format": "date"
54
+
},
55
+
"note": {
56
+
"description": "Optional free-text human-readable rationale. Recommended for any non-obvious entry. Linked from the gate's summary output.",
57
+
"type": "string"
58
+
},
59
+
"tracking_issue": {
60
+
"description": "Optional GitHub issue reference (e.g. `hyperpolymath/gitbot-fleet#148`) that tracks the underlying work to remove the need for this exemption.",
0 commit comments