Skip to content

Commit 98ed897

Browse files
Claude/intelligent faraday 5 x ou u (#201)
Co-authored-by: Claude <noreply@anthropic.com>
1 parent 30824f5 commit 98ed897

6 files changed

Lines changed: 761 additions & 0 deletions

File tree

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
{
2+
"$schema": "https://json-schema.org/draft/2020-12/schema",
3+
"$id": "https://github.com/hyperpolymath/standards/blob/main/.machine_readable/hypatia-baseline.schema.json",
4+
"title": "Hypatia per-repo baseline",
5+
"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.",
22+
"type": "string",
23+
"enum": ["critical", "high", "medium", "low", "info"]
24+
},
25+
"rule_module": {
26+
"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.",
47+
"type": "string",
48+
"enum": ["critical", "high", "medium", "low", "info", "advisory"]
49+
},
50+
"expires_at": {
51+
"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.",
61+
"type": "string",
62+
"pattern": "^[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+#[0-9]+$"
63+
}
64+
}
65+
}
66+
}
67+
}
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
<!-- SPDX-License-Identifier: PMPL-1.0-or-later -->
2+
# Proposal: `hyperpolymath/standards``.hypatia-baseline.json` consumer
3+
4+
**Target repo:** `hyperpolymath/standards`
5+
**Author:** drafted from `hyperpolymath/gitbot-fleet` issue triage of PR #198
6+
**Date:** 2026-05-24
7+
8+
## Problem
9+
10+
`hyperpolymath/standards/.github/workflows/governance-reusable.yml@main` runs
11+
`Language / package anti-pattern policy` against every repo that calls it.
12+
The rule scans the working tree for banned-language files (e.g. ReScript `.res`)
13+
and fails the gate if any are present.
14+
15+
Repos in the estate carry a per-repo `.hypatia-baseline.json` listing
16+
acknowledged findings — same shape as the Hypatia findings themselves
17+
(`severity`, `rule_module`, `type`, `file`). The convention is well-formed,
18+
in active use (`hyperpolymath/gitbot-fleet/.hypatia-baseline.json` has 59
19+
entries), and structurally exactly what an exemption mechanism needs.
20+
21+
**But the governance gate does not consume it.** PR #198
22+
(`hyperpolymath/gitbot-fleet#198`) has been blocked for hours by the
23+
`banned_language_file` rule firing on exactly the `.res` files that are
24+
*already listed* in that repo's baseline. The PR author tried inventing a
25+
second format (`.hypatia-ignore`, never read by anything) as a workaround.
26+
27+
## Fix
28+
29+
Make `governance-reusable.yml` read the calling repo's
30+
`.hypatia-baseline.json` and filter findings before the gate decides.
31+
32+
This proposal ships:
33+
34+
1. **`scripts/apply-baseline.sh`** — pure bash + jq, no external deps.
35+
Reads a findings file + the calling repo's baseline, emits filtered
36+
findings, exits non-zero only if unfiltered blocking findings remain.
37+
2. **`.machine_readable/hypatia-baseline.schema.json`** — JSON Schema
38+
formalising the file shape. Includes the existing required fields
39+
(`severity`, `rule_module`, `type`, `file`) plus three optional
40+
forward-compatible extensions (`file_pattern`, `severity_override`,
41+
`expires_at`, `note`).
42+
3. **`workflows/governance-reusable.yml.patch`** — the YAML diff to wire
43+
the baseline step into the existing reusable workflow. Drop-in.
44+
4. **`docs/HYPATIA-BASELINE-FORMAT.adoc`** — authoritative format doc.
45+
5. **`docs/EXEMPTION-MECHANISMS.adoc`** — convention doc clarifying when
46+
to use `.hypatia-baseline.json` vs the estate-wide
47+
`bot_exclusion_registry.a2ml` vs (proposed) per-PR exemptions.
48+
49+
## File map
50+
51+
| File in this proposal | Target path in `hyperpolymath/standards` |
52+
|---|---|
53+
| `scripts/apply-baseline.sh` | `scripts/apply-baseline.sh` |
54+
| `.machine_readable/hypatia-baseline.schema.json` | `.machine_readable/hypatia-baseline.schema.json` |
55+
| `workflows/governance-reusable.yml.patch` | apply to `.github/workflows/governance-reusable.yml` |
56+
| `docs/HYPATIA-BASELINE-FORMAT.adoc` | `docs/HYPATIA-BASELINE-FORMAT.adoc` |
57+
| `docs/EXEMPTION-MECHANISMS.adoc` | `docs/EXEMPTION-MECHANISMS.adoc` |
58+
59+
## Rollout plan
60+
61+
1. Land `apply-baseline.sh` + schema + docs in `standards/` (no behaviour
62+
change yet).
63+
2. Land the workflow patch in **advisory mode** first (gate still passes
64+
on suppressed findings, but logs unfiltered count). One week of soak.
65+
3. Flip to **blocking mode**: gate fails only on findings *not* matched
66+
by baseline.
67+
4. Open coordinator tracking issues per consumer repo to either
68+
(a) accept new findings into baseline, or (b) fix the underlying code.
69+
70+
## Why not just merge `.hypatia-ignore` support too?
71+
72+
Two formats with overlapping semantics is what got us into this mess.
73+
The proposal kills `.hypatia-ignore` explicitly (see
74+
`docs/EXEMPTION-MECHANISMS.adoc`). If a per-PR exemption slot is needed,
75+
it should be a designed mechanism (PR-body marker or label), not another
76+
drive-by file convention.
77+
78+
## Companion upstream work (out of scope for this PR)
79+
80+
- **`hyperpolymath/hypatia`** scanner should emit `baseline_status` on
81+
every finding (`new` / `acknowledged` / `expired`). That lets the gate
82+
do baseline matching at finding-emission time and produce richer PR
83+
comments. Tracked separately.
84+
- **`hyperpolymath/hypatia`** should grow a `--stale-baseline-check`
85+
mode that fails if the baseline references files that no longer exist
86+
(after `hyperpolymath/gitbot-fleet#148` migrates the ReScript subtree,
87+
most of its baseline entries will become ghosts).
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
// SPDX-License-Identifier: PMPL-1.0-or-later
2+
= Exemption mechanisms in the hyperpolymath estate
3+
:toc:
4+
5+
Three concentric exemption layers exist in the estate. Each addresses a
6+
different question and lives in a different file. Mixing them up is the
7+
single most common cause of "I added an ignore file but CI still fails"
8+
confusion.
9+
10+
== Quick decision tree
11+
12+
[source]
13+
----
14+
Are you trying to stop bots from WRITING to a path?
15+
-> use the estate-wide bot_exclusion_registry.a2ml
16+
17+
Are you trying to stop the governance gate from FAILING on a
18+
pre-existing finding?
19+
-> use the per-repo .hypatia-baseline.json
20+
21+
Are you trying to make a finding GO AWAY for one specific PR only?
22+
-> currently unsupported. See "per-PR exemptions" below.
23+
----
24+
25+
== Layer 1: Estate-wide bot write denylist
26+
27+
**File:** `hyperpolymath/standards/.machine_readable/bot_exclusion_registry.a2ml`
28+
29+
**Scope:** All bots, all repos. Authoritative across the entire estate.
30+
31+
**Purpose:** Tells bots what they may not *write* to. Read-only scanning
32+
is always allowed; only write actions (Write, Commit, CreatePr,
33+
CreateBranch, etc.) are gated.
34+
35+
**Format:** A2ML (TOML-shaped). Three axes:
36+
1. `external-repos` — exact `owner/repo` matches that bots must skip.
37+
2. `vendored-directory-patterns` — globs that should never be edited.
38+
3. `remote-origin-patterns` — bail-if-origin-matches patterns.
39+
40+
**Consumer:** Every bot via `shared-context::ExclusionRegistry::check()`.
41+
The registry is fail-closed: if the file fails to load, all bot writes
42+
are denied.
43+
44+
**Edit when:** A new repo should be off-limits to bots, or a new
45+
vendored subtree should never be modified.
46+
47+
**Don't use for:** Suppressing CI findings. This layer doesn't touch
48+
CI at all.
49+
50+
== Layer 2: Per-repo Hypatia finding baseline
51+
52+
**File:** `.hypatia-baseline.json` at the calling repo's root.
53+
54+
**Scope:** One repo. Acknowledged findings only — not a "ignore these
55+
forever" file.
56+
57+
**Purpose:** Tells the governance gate which Hypatia findings have been
58+
seen, triaged, and accepted as known debt. Findings matched by a baseline
59+
entry don't block CI; they're surfaced in the run summary as
60+
"acknowledged."
61+
62+
**Format:** JSON array of `{severity, rule_module, type, file | file_pattern, ...}`
63+
objects. See `docs/HYPATIA-BASELINE-FORMAT.adoc` for the full schema.
64+
65+
**Consumer:** `apply-baseline.sh` invoked from
66+
`hyperpolymath/standards/.github/workflows/governance-reusable.yml`.
67+
Suppresses matching findings from the gate, downgrades severity if
68+
`severity_override` is set, fails on expired entries.
69+
70+
**Edit when:**
71+
* Pre-existing debt is tracked for migration (link a `tracking_issue`).
72+
* Vendored / third-party code triggers a rule the team can't fix.
73+
* Test fixtures intentionally violate a rule (with `note` explaining).
74+
75+
**Don't use for:**
76+
* Newly-introduced findings on freshly-authored code. The rule exists
77+
for a reason; baselining the new file defeats it. Fix the code.
78+
* One-off PR-scoped suppression. Baseline edits are merged to main; they
79+
affect all subsequent PRs. See Layer 3.
80+
81+
== Layer 3: Per-PR exemptions (NOT YET IMPLEMENTED)
82+
83+
There is currently no supported per-PR exemption mechanism. PR authors
84+
attempting one (e.g. by inventing a `.hypatia-ignore` file) will find
85+
nothing reads it, and the gate will still fail. **Do not invent new
86+
file conventions.** If you need per-PR exemption, file an issue against
87+
`hyperpolymath/standards` proposing a designed mechanism.
88+
89+
If a mechanism is added, it should be one of:
90+
91+
1. **PR-body marker**, e.g. a fenced block:
92+
+
93+
[source,markdown]
94+
----
95+
```hypatia-exempt
96+
- rule: code_safety/obj_magic
97+
file: bots/sustainabot/bot-integration/src/Analysis.res
98+
reason: Pre-migration debt; tracked in #148
99+
```
100+
----
101+
+
102+
Pros: lives with the PR, vanishes when the PR closes, reviewable in
103+
the same UI as the change. Cons: requires a PR-body parser.
104+
105+
2. **Label-driven**, e.g. apply `gate:exempt:code_safety` and require an
106+
exemption-justification comment from a CODEOWNER.
107+
108+
3. **Sidecar file under `.github/pr-exemptions/`** — committed for one
109+
PR's lifetime, deleted at merge by a workflow.
110+
111+
A formal proposal should pick one and document it explicitly.
112+
113+
== Anti-patterns to reject
114+
115+
These have been attempted and should be refused at review:
116+
117+
* `.hypatia-ignore` (any format) — never read by anything. Reject; point
118+
the author at `.hypatia-baseline.json`.
119+
* Adding `pragma: ignore-rule` comments in source. Hypatia scans by AST
120+
and ignores comments; suppression has to be data-driven, not
121+
source-comment driven.
122+
* Setting `continue-on-error: true` on the governance gate. This makes
123+
CI lie. Use a baseline entry with `severity_override: advisory`
124+
instead — keeps the finding visible while unblocking the gate.
125+
* Adding the offending path to `.gitignore`. The file still exists in
126+
history; Hypatia and other estate scanners still see it.
127+
* Forking `hyperpolymath/standards` to disable the rule for one repo.
128+
If a rule is wrong for one repo, the rule needs scoping in the
129+
upstream, not a fork.
130+
131+
== Cross-references
132+
133+
* `docs/HYPATIA-BASELINE-FORMAT.adoc` — the baseline file format.
134+
* `.machine_readable/hypatia-baseline.schema.json` — machine schema.
135+
* `hyperpolymath/standards#????` — proposal that landed this consumer.
136+
* `hyperpolymath/hypatia` — the scanner that emits findings.

0 commit comments

Comments
 (0)