Skip to content

fix(root_hygiene): accept the repo deed <repo>_chora.deed as the AI manifest - #960

Merged
hyperpolymath merged 4 commits into
mainfrom
claude/kind-clarke-aqpe7a
Oct 27, 2026
Merged

hyperpolymath merged 4 commits into
mainfrom
claude/kind-clarke-aqpe7a

Conversation

@hyperpolymath

Copy link
Copy Markdown
Owner

Summary

A2ML is retired (D312). A repo's facts now live in a single <repo>_chora.deed at the root, and the estate template rsr-template-repo ships no 0-AI-MANIFEST file. But root_hygiene still required 0-AI-MANIFEST.a2ml (or .deed / AI.a2ml). So every repo that followed the retirement got a high "Required file missing" finding, including the canonical template and hyperpolymath/echo-types, which retired its .a2ml files on 2026-09-30 (commit 6eafe81).

Change

lib/rules/root_hygiene.ex, in scan_required_missing:

  • Now satisfies the rule: any root file matching *_chora.deed. The deed is named for the repo, not the checkout directory, so any prefix is accepted.
  • Legacy files still accepted: 0-AI-MANIFEST.a2ml, 0-AI-MANIFEST.deed and AI.a2ml still satisfy the rule until their repos migrate. No repo gains a finding from this PR.
  • When missing: the finding names the deed the repo needs. scan/2 (the CLI path) derives <repo> from the repository directory, for example echo-types_chora.deed. The filename-only scan/1 uses the placeholder repo.

Not changed: other rules that still mention 0-AI-MANIFEST (structural_drift SD003/SD007, rsr_conformance 2.3.1, dogfooding). Those are separate decisions and are out of scope here.

Testing

Mix deps couldn't be fetched in this environment, so I compiled the module standalone and ran its ExUnit suite with plain Elixir 1.14:

  • test/root_hygiene_test.exs passes 34/34 on this branch, up from 30/30 on main. One test is updated and five are new.
  • Run against the old rule, three of the new tests fail, so they test the change.
  • mix format --check-formatted passes on both files.

Full mix test will run in CI.


Generated by Claude Code

… manifest

A2ML is retired (D312): a repo's facts live in one `<repo>_chora.deed` at
the root, and the estate template (rsr-template-repo) ships no
0-AI-MANIFEST at all. root_hygiene still required 0-AI-MANIFEST.a2ml (or
.deed / AI.a2ml), so it raised a HIGH "Required file missing" on every repo
that followed the retirement, including the canonical template and
echo-types after its 2026-09-30 retirement of every .a2ml file.

The manifest requirement is now met by any root `*_chora.deed`. The legacy
spellings still satisfy it until their repos migrate, so no repo gains a
finding from this change. When the manifest is missing, the finding names
the deed it needs: scan/2 derives `<repo>` from the repository directory;
the filename-only scan/1 uses the placeholder `repo`.

Tests: test/root_hygiene_test.exs 34/34 (was 30). Three of the new tests
fail against the old rule.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P4yFkxW5Heb8p2YW7ZYs9F
@coderabbitai

coderabbitai Bot commented Oct 26, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

Finishing Touches
📝 Generate docstrings
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 26, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-27T00:11:56.715729Z d5f9750 New commits
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

hyperpolymath added a commit to hyperpolymath/echo-types that referenced this pull request Oct 26, 2026
…indings, part 1) (#354)

## Summary

This is part 1 of fixing the Hypatia scan findings on echo-types. It
fixes **9 of the 10 findings visible** in the PR scan comment by taking
the estate template's versions of three workflows
(`hyperpolymath/rsr-template-repo`) instead of patching the drifted
local copies.

| Finding | Severity | File | Fix |
|---|---|---|---|
| WH014: masked scanner feeds the SARIF upload | high |
`hypatia-scan.yml` | Template version: `set -euo pipefail`, no `\|\|
true`, and `jq -e` checks the findings JSON and the SARIF before upload
|
| RE001: uses `secrets.*` without harden-runner | medium |
`hypatia-scan.yml` | Template no longer references `secrets.*` |
| WH006 + missing_timeout_minutes (job `sync`) | medium ×2 |
`labels.yml` | `timeout-minutes: 10` |
| WH006 + missing_timeout_minutes (job `triage`) | medium ×2 |
`label-triage.yml` | `timeout-minutes: 10` |
| RE001 | medium ×2 | `labels.yml`, `label-triage.yml` | `github.token`
instead of `secrets.GITHUB_TOKEN` |

**Why WH014 mattered.** When the scanner failed, the old workflow still
uploaded a SARIF file with zero results. GitHub then auto-closes every
open alert in that category, with the job showing green. The template
already guards against this, so re-syncing fixes it at the source rather
than patching a fork of it.

**Dropped from `hypatia-scan.yml`, because the template doesn't carry
them:**
- the findings artifact upload;
- the PR comment, which only ever showed the first 10 of 38 findings;
- the gitbot-fleet submission, whose push was being denied (`403`).

## ⚠ Read the new finding count with care: 38 → 3 is not 35 fixes

This branch's Hypatia run reports **3 findings** (0 critical, 1 high),
down from 38 on `main`. The scanner versions are effectively the same:
the template pins `d73f76b5`, committed five minutes before the `main`
(`edc6608`) the old workflow used. But **the template does not pass
`GITHUB_TOKEN` to the scan.** Hypatia's API-backed rule modules need a
token and return `[]` silently without one: `code_scanning_alerts`,
`dependabot_alerts`, `secret_scanning_alerts`, `branch_protection`,
`baseline_health` and similar. Most of the 28 findings the old PR
comment never showed most likely came from those modules. They are now
unscanned, not fixed.

Re-enabling them means passing `GITHUB_TOKEN: ${{ github.token }}` in
the scan step's `env`. That uses `github.token`, not `secrets.*`, so
RE001 stays clear. The right place for that is the template itself, in
`rsr-template-repo`, so every synced repo gets the same coverage. That
decision is with the owner; this PR deliberately stays byte-identical to
the template.

## `actions.lock`

- The `hypatia-scan.yml` entry now matches the template's lock exactly.
It uses SHA-pinned cache, checkout, setup-beam and codeql-action, all of
which were already recorded under `dependencies`.
- I removed the three dependency records that no workflow uses any more:
`github-script@v9.0.0`, `upload-artifact@v7.0.2` and
`setup-beam@v1.24.1`.
- This was edited by hand, because `gh actions-lock` isn't available in
my environment. I checked that every workflow ref resolves to a
dependency and that no dependency is unreferenced. **It still needs `gh
actions-lock --verify-local`.** The Governance `actions-lock-verify` job
would do that, but it is currently failing at startup on the
Actions-allowlist issue from echo-types#352.

## Not in this PR

- **Harden-runner (RE001) on `push-email-notify.yml`.** That job
genuinely needs SMTP secrets. Per the owner's decision, adopting
`step-security/harden-runner` is deferred to a single estate-wide
decision via the allowlist in `metadatastician/standards`.
- **Missing `0-AI-MANIFEST.a2ml` (high).** This file was retired on
purpose (`6eafe81`). The rule is being fixed upstream in
hyperpolymath/hypatia#960, which accepts `<repo>_chora.deed`. Once that
lands, this finding becomes "missing `echo-types_chora.deed`", which is
accurate debt tracked by the `.deed` conversion (rsr-template-repo#209).
- **The token-gated findings above.** Part 2, once the template passes
the token.

## Testing

- All three workflows parse as YAML.
- The lock's hypatia-scan entry is identical to `rsr-template-repo`'s.
- This branch's Hypatia run passes the new pre-upload checks and reports
0 critical, 1 high and 3 total. Read that count with the caveat above.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

https://claude.ai/code/session_01P4yFkxW5Heb8p2YW7ZYs9F

Co-authored-by: Claude <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Oct 27, 2026

Copy link
Copy Markdown
Contributor

Add Carrot credits or activate Agent usage billing to use Autofix

@hyperpolymath
hyperpolymath merged commit 789ca60 into main Oct 27, 2026
19 checks passed
@hyperpolymath
hyperpolymath deleted the claude/kind-clarke-aqpe7a branch October 27, 2026 00:10
hyperpolymath added a commit to hyperpolymath/rsr-template-repo that referenced this pull request Oct 27, 2026
…enSSF check (#258)

## Summary

This PR fixes two problems in the estate template's CI.

1. **Hypatia's GitHub-API rules got no token.** Hypatia's scan step ran
without credentials, so its rules that query the GitHub API quietly
returned nothing in every repo synced from this template. When
hyperpolymath/echo-types re-synced to this workflow
(hyperpolymath/echo-types#354), its finding count fell from 38 to 3,
mostly for this reason.
2. **The licence checks rejected `LICENSE.adoc`.** That's the file this
template ships, so the checks were red on the template and in every repo
minted from it.

## Changes

**`hypatia-scan.yml`**
- **Token:** pass `GITHUB_TOKEN: ${{ github.token }}` to the scan step
only, not the whole job. It's `github.token` rather than
`secrets.GITHUB_TOKEN`, so the scan doesn't raise its own harden-runner
finding (RE001).
- **Permissions:** grant `vulnerability-alerts: read`, which Hypatia's
Dependabot-alert rules need. `security-events` only covers code-scanning
alerts. The key is valid in GitHub's workflow schema (SchemaStore): the
edited workflow passes, and a made-up key fails.
- **Cache key:** the key now reads `${{ env.HYPATIA_SHA }}` instead of
repeating the SHA. Before, bumping the pin without also editing the key
would reuse the old scanner build.

**Licence checks** (`ossf-best-practices.yml`, and `just verify` /
`self-assess` in `build/just/assess.just`)
- They now accept `LICENSE`, `LICENSE.txt`, `LICENSE.md` or
`LICENSE.adoc`.
- They also accept a REUSE `LICENSES/` directory, but only if it holds a
non-empty, non-hidden `<SPDX-ID>.<ext>` licence text (not a README).
- `just verify` runs inside `just repo-init`, so its old `LICENSE`-only
check failed every mint. That's the Proven suite's template-mint E2E
lane.
- No licence file is changed.

## What the token can and can't reach

- **Code-scanning alerts:** reachable, through `security-events`.
- **Dependabot alerts:** reachable, through `vulnerability-alerts:
read`, which this PR adds.
- **Secret-scanning alerts:** not reachable. No `GITHUB_TOKEN`
permission covers them; they need a GitHub App or PAT. That's an owner
decision (it would add a secret to the template), so it's left out.
- **Branch protection:** may be refused for the job token.
- **When a call is refused:** the rule logs a warning and returns `[]`,
so a refusal costs coverage but never produces a false finding. BH001
("no protection at all") fires only on a genuine "Branch not protected"
answer.

## Evidence from CI

Compared with `main` (`0d3fcfe`), the Hypatia Security Scan on this PR:
- **no longer logs the three "GITHUB_TOKEN not set" warnings.** That
shows the alert queries ran with a token. It doesn't show they all
succeeded; see the section above.
- **reports 30 findings instead of 5.**
- **restored the same cache entry**, because the new key resolves to the
same string.

OpenSSF Compliance is now green.

## Still red, and why

Details are in [this
comment](#258 (comment)).

- **Hypatia critical finding (missing `LICENSE`):** waits on
hyperpolymath/hypatia#963. Once it merges, I'll bump `HYPATIA_SHA` here
and in the two other workflows that pin the same SHA. That bump also
brings in hyperpolymath/hypatia#960, which clears the old
`0-AI-MANIFEST` high finding.
- **estate-rules, Central Estate CI/CD Audit, and the `root_shape`
benchmark:** fixed by #260.

## Testing

- **Licence checks:** run against seven layouts, and all three checks
agree on each.
  - Pass: `LICENSE.adoc`, and `LICENSES/MPL-2.0.txt`.
- Fail: `.gitkeep` only, README only, an empty licence file, a dotfile
only, and no licence at all.
- **`just verify` on this tree:** the old recipe exits 1 with the CI
message; the new one exits 0.
- **shellcheck 0.9.0:** clean.
- **SchemaStore workflow schema:** both edited workflows validate.

## RSR Quality Checklist

### Required

- [x] No banned language patterns
- [x] SPDX license headers present on all modified files (unchanged)
- [x] No secrets, credentials, or `.env` files included. The scan uses
the job token, not a secret.
- [x] Linter is clean (Workflow Security Linter green)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

https://claude.ai/code/session_01P4yFkxW5Heb8p2YW7ZYs9F

---------

Signed-off-by: Jonathan D.A. Jewell <6759885+hyperpolymath@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>
hyperpolymath added a commit that referenced this pull request Oct 27, 2026
…SES/ dir (#963)

## Summary

`root_hygiene` only counts `LICENSE` or `LICENSE.txt` as the repo's
licence file. The estate template `rsr-template-repo` ships
`LICENSE.adoc` and a REUSE `LICENSES/` directory. So the template, and
every repo synced from it, gets a **critical** "Required file missing"
finding, which fails the template's zero-critical Hypatia gate.
hyperpolymath/rsr-template-repo#258 shows this, and so does that repo's
`main`.

## Change

`lib/rules/root_hygiene.ex`, in `scan_required_missing`:

- **More licence file names:** `LICENSE.md` and `LICENSE.adoc` now
satisfy the requirement, alongside `LICENSE` and `LICENSE.txt`.
- **REUSE `LICENSES/` directory:** `scan/2` (the CLI path) also accepts
a `LICENSES/` directory, as long as it holds at least one REUSE licence
text.
- A licence text means a non-empty, non-hidden `<SPDX-ID>.<ext>` file
that isn't a README, as the REUSE spec requires.
- An empty `LICENSES/`, or one holding only `.gitkeep`, a README, an
empty file or an extensionless file, declares nothing and still produces
the finding.
- The filename-only `scan/1` can't see the directory, because
`list_root_files` drops directories. It behaves as before.
- **No new findings anywhere:** every name accepted before is still
accepted.

## Testing

Mix deps can't be fetched in this environment. As with
#960, I compiled the module standalone and ran
`test/root_hygiene_test.exs` with plain Elixir.

- **New tests:** four. They cover `.adoc` and `.md`, reject
`LICENSE.adoc.orig`, check the REUSE directory both empty and with a
licence in it, and reject non-licence files in `LICENSES/`.
- **This branch:** 38 of 38 tests pass, up from 34 on `main`.
- **Against the old rule:** the positive tests fail, and the
non-licence-files test fails against the earlier "any file counts"
version of this PR.
- **Formatting:** `mix format --check-formatted` passes.

The full `mix test` runs in CI.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

https://claude.ai/code/session_01P4yFkxW5Heb8p2YW7ZYs9F
hyperpolymath added a commit to hyperpolymath/rsr-template-repo that referenced this pull request Oct 27, 2026
#261)

## Summary

The template pins Hypatia at `d73f76b`. That version predates two fixes:
- hyperpolymath/hypatia#960: accepts the repo deed `<repo>_chora.deed`
as the AI manifest.
- hyperpolymath/hypatia#963: accepts `LICENSE.adoc` and REUSE
`LICENSES/` as the licence.

Under the old pin the template raised a **critical** "Required file
missing: LICENSE" and a **high** `0-AI-MANIFEST` finding, so the
zero-critical gate in the Hypatia Security Scan and the Static Analysis
Gate failed. This was the bump promised in
#258.

## Changes

- The pin moves from `d73f76b` to Hypatia `main` at `7c10e5d`, which
includes #960, #963 and #969.
- It's updated in all three workflows that carry it, so they stay on one
version: `hypatia-scan.yml` (`HYPATIA_SHA`), `static-analysis-gate.yml`
and `dogfood-gate.yml`.
- `hypatia-scan.yml`'s cache key reads `HYPATIA_SHA` since #258, so it
follows on its own.
- The other two have the SHA in their cache keys, and those are updated
in place.

## Testing

- **Root hygiene at `7c10e5d`:** I ran the rule against this repo's root
and it returns **no findings**. At `d73f76b` it returned the critical
and the high.
- **Schema:** all three workflows validate against the GitHub workflow
schema (SchemaStore).
- **Old pin:** no copy of the old SHA remains in the tree.
`actions.lock` is unaffected, because this SHA is a git ref, not an
action pin.
- **Full scan:** I couldn't build the full scanner locally because Hex
is unreachable. This PR's Hypatia Security Scan and Static Analysis Gate
runs are the end-to-end check.

## Follow-up

hyperpolymath/hypatia#970 (open) makes SC-010, a Low-severity finding
that doesn't block, accept `LICENSE.adoc`. It also adds pagination and a
timeout to the secret-scanning sweep. Once it merges, a second small
bump picks it up.

---
_Generated by [Claude
Code](https://claude.ai/code/session_01P4yFkxW5Heb8p2YW7ZYs9F)_

Co-authored-by: Claude <noreply@anthropic.com>
hyperpolymath added a commit to hyperpolymath/echo-types that referenced this pull request Oct 27, 2026
…pe, 7c10e5d (Hypatia findings, part 2) (#356)

## Summary

Part 2 of fixing the Hypatia findings on echo-types. Part 1 (#354) took
the template's `hypatia-scan.yml` as it stood then. That version
silently dropped every API-backed rule, because it passed the scanner no
token. The fix went into the template first
(hyperpolymath/rsr-template-repo#258 and #261). This PR takes the merged
result, byte-identical.

| Change | Why |
|---|---|
| The scan step gets `GITHUB_TOKEN: ${{ github.token }}`, scoped to that
step | Hypatia's code-scanning, Dependabot, branch-protection and
baseline-health rules return `[]` without a token. It is `github.token`,
not `secrets.*`, so RE001 stays clear. |
| `vulnerability-alerts: read` on the job | Lets the Dependabot (DA)
rules read alerts. `security-events: write` covers only code scanning. |
| `HYPATIA_SHA` `d73f76b` → `7c10e5d` | This scanner accepts
`LICENSE.adoc` and REUSE `LICENSES/` (hyperpolymath/hypatia#963). It no
longer demands `0-AI-MANIFEST.a2ml` (hyperpolymath/hypatia#960). |
| Cache key `…-${{ env.HYPATIA_SHA }}` | A pin bump now rebuilds the
scanner. Before, it reused the old build under a hard-coded key. |
| `upload-sarif` moves to codeql-action v4.39.1 (`9b32540`) | Matches
the template. |

`actions.lock` is updated to match. `hypatia-scan.yml` now lists
codeql-action at `9b32540`, and that pin has its dependency entry. The
v4.38.0 entry stays, because the `metadatastician/standards` reusable
workflows still pin it.

## What this does not cover

- **Secret-scanning alerts.** No `GITHUB_TOKEN` permission can read
them, so the per-repo scan never sees them. The workflow comment says
so. They will come from a separate, private estate-wide sweep with a
dedicated read-only token, not from this repository.
- **The finding count will go up.** The API-backed rules are scanning
again, so expect findings that were unscanned under #354, not new
problems.

## Verification

- `hypatia-scan.yml` is `cmp`-identical to `rsr-template-repo@4f4536e`.
That file passed GitHub-workflow schema validation and the template's CI
in #258 and #261.
- `actions.lock` parses, and its `hypatia-scan.yml` list now names
exactly the four pins the workflow uses.
- I could not run `gh actions-lock` here. The lock edit mirrors the
format that tool writes, and this PR's CI run is the check that matters.

---
_Generated by [Claude
Code](https://claude.ai/code/session_01P4yFkxW5Heb8p2YW7ZYs9F)_

Co-authored-by: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants