Skip to content

ci(hygiene): measure branch drift and enforce the two pull-request rules - #285

Merged
hyperpolymath merged 3 commits into
mainfrom
arena/30a2502a-metamanifold-webui
Oct 25, 2026
Merged

hyperpolymath merged 3 commits into
mainfrom
arena/30a2502a-metamanifold-webui

Conversation

@hyperpolymath

Copy link
Copy Markdown
Owner

Change and reason

main's remote held fifteen heads: main, the orphan data branch the badge publisher force-pushes, and thirteen branches cut from snapshots between 5 and 119 commits old — every one of them carrying an open pull request. Six required contexts (Julia tests, Agda proofs, Code relevance, Occupancy relevance, Occupancy disagreement test, Occupancy typed peak) mean a branch in that state reports BLOCKED indefinitely, so a reviewer saw thirteen blocked pull requests and no signal about which of them was alive. Each also started a full CI run that could never go green, which is the mechanism that made the pile stable rather than self-correcting.

CONTRIBUTING.md already required a branch to start at the tip of main (rule 1) and to carry no merge commits from it (rule 2). Nothing enforced either sentence. This PR adds the enforcement, the measurement, and the record — and nothing that deletes anything:

Path What it is
scripts/maintenance/check-pr-freshness.sh Answers rules 1 and 2 from the merge base and the commit graph. Annotates the failure for the checks API. Exits 2 rather than passing when it cannot judge.
scripts/maintenance/triage-branches.sh Classes every remote head as base, unrelated, contained, fresh, salvage or stale. Read-only: --format table|markdown|json, --fail-on.
.github/workflows/pr-freshness.yml Runs the freshness check on pull request open, push, reopen and ready-for-review.
.github/workflows/branch-hygiene.yml Weekly: runs the triage into one rolling issue that updates in place and closes itself when no drifted branch remains. A job that opens an issue every week is the mechanism that produced the pile it is meant to clear.
scripts/tests/test-*.sh Fixture-repository tests for both scripts: merged, drifted-with-nothing-new, drifted-with-a-file-the-base-lacks, orphan, unrelated history, shallow, and the Actions annotation path. Wired into the Advisory scan contract job beside the other shell tests.
docs/maintenance/repository-hygiene.md The classes, what happens to each, the recovery path, the 2026-10-25 measurement, the order the work was done in, and the four decisions left to the owner.
CONTRIBUTING.md, .gitignore Points at the doc above; !docs/maintenance/ follows the existing whitelist pattern (docs/* is ignored except published notes).

Two things both scripts refuse to do, because a wrong answer is worse than none: report on a shallow clone (it reports its graft point as the merge base, which makes every branch look fresh), and delete anything. governance-badges is classed unrelated and left alone — it is an output, not a spare branch: README.md reads it through img.shields.io/endpoint.

Work already done on the remote with these scripts

The cleanup is not in this diff, because it is not a file change. Measured, then closed, then the branch deleted — in that order, so each pull request keeps its head reachable at refs/pull/<n>/head:

Every close comment carries its own branch's numbers and the git fetch origin pull/<n>/head recovery command. The remote is now main + governance-badges; triage-branches.sh reports 2 heads, 0 stale.

Validation

Run here, on this branch:

bash scripts/tests/test-triage-branches.sh        # 13 passed, 0 failed
bash scripts/tests/test-check-pr-freshness.sh     # 11 passed, 0 failed
bash scripts/check-governance-contract.sh         # 70 checks passed
bash scripts/tests/test-governance-contract.sh    # all mutations rejected
bash scripts/tests/test-scanner-boundaries.sh     # ok
bash scripts/tests/test-ci-logging.sh             # ok
bash scripts/ci/check-shell-secrets.sh            # no credentials in tree or history
bash scripts/lint-sonar-reliability.sh            # OK: no S2871 or S7758 in frontend/src
bash scripts/maintenance/triage-branches.sh       # 2 heads after the cleanup
bash scripts/maintenance/check-pr-freshness.sh    # OK: at the base tip, no merge commits

Both new workflows were parsed as YAML and their embedded shell extracted and checked with bash -n; the rolling-issue upsert was exercised against a stub gh for all three paths (create, update, close). Not run: the Julia suite and the frontend suite — neither is touched by this diff, and neither can run in this sandbox; CI is the first execution of anything in this PR on a runner.

Scope

Deliberately not done, each recorded in docs/maintenance/repository-hygiene.md under Decisions for the owner:

  1. Branch freshness is not a required context yet. It cannot be: a required check that no workflow produces blocks every pull request, including the one that would add it. Add it to the Branch-Floor ruleset after this merges.
  2. Push-run concurrency on main is untouched. cancel-in-progress: false for pushes serialises the queue — at the time of measurement the run for a3a4a8e was still going and the run for f3816e5a had not started 25 minutes later. Changing it trades a per-commit result for latency; that is the owner's call, not a CI fix I should make silently.
  3. The SonarCloud gate is untouched. It failed on most of those pull requests with C Security Rating on New Code, is not a required context, and is already documented in docs/sonar-quality-gate.md. It was a symptom of the huge stale diffs, not a defect in this repository.
  4. docs/milestones/02-deferred-issues.md is referenced by issue feat(analysis): Symbolic engine for formula manipulation #4 and absent from main. The pre-sync archive had it. Restoring it re-adds content that overlaps docs/statistics/method-catalogue-v1.md; editing the issue's reference may be the better answer.

No lockfile, dependency, generated or vendored file changes.

Contribution checks

  • I followed CONTRIBUTING.md.
  • This branch starts at current upstream main and contains no merges from fork main (merge base f3816e5a = main tip).
  • CI has run and passes — the branch's first CI run is this pull request.
  • Existing licensing, citation and acknowledgement text is unchanged.

main's remote held fifteen heads on 2026-10-25: 'main', the orphan data
branch the badge publisher force-pushes, and thirteen branches cut from
snapshots between 5 and 119 commits old. Every one of the thirteen had an
open pull request, so a reviewer saw thirteen blocked pull requests and no
way to tell which was alive, and each started a full CI run that could not
go green.

CONTRIBUTING.md already required a branch to start at the tip of main (rule
1) and to carry no merge commits from it (rule 2). Nothing enforced either
sentence. This adds the enforcement and the measurement, and nothing that
deletes anything:

- scripts/maintenance/check-pr-freshness.sh answers rules 1 and 2 from the
  merge base and the commit graph, annotating the failure for the checks
  API; pr-freshness.yml runs it on every pull request.
- scripts/maintenance/triage-branches.sh classes every remote head as base,
  unrelated, contained, fresh, salvage or stale, so cleanup is decided on
  measurement. branch-hygiene.yml runs it weekly into ONE rolling issue
  that closes itself when no drifted branch remains.
- Both refuse a shallow clone instead of reporting its graft point as the
  merge base, which would pass every branch.
- Both are tested against fixture repositories: merged, drifted with
  nothing new, drifted with a file the base no longer has, orphan,
  unrelated history and shallow, plus the Actions annotation path.
- docs/maintenance/repository-hygiene.md records the classes, the cleanup
  order and the measurement; CONTRIBUTING.md points at it.

The work already done with these scripts is on the remote rather than in this
diff: the thirteen superseded pull requests are closed and their branches
deleted, each with its own measured rationale, and each recoverable from
refs/pull/<n>/head. governance-badges is untouched: it is an output, not a
spare branch.

Co-authored-by: arena-agent <297053741+arena-agent@users.noreply.github.com>
@chatgpt-codex-connector

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 ⚠️ Failed 2026-10-25T08:46:40.425392Z
We couldn’t complete this review. Comment @codex review to try again.
c73b1da PR opened
ℹ️ 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.

@coderabbitai

coderabbitai Bot commented Oct 25, 2026 •

Copy link
Copy Markdown

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 25 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

Learn how review limits work.

Review configuration:

Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Organization UI
  • Review profile: ASSERTIVE
  • Plan: Advanced
  • Run ID: 2117ef94-19eb-4c0e-beba-dc1d13a73441
Commits

Reviewing files that changed from the base of the PR and between f3816e5 and b0c2f91.

Files selected for processing: 10
  • .github/workflows/branch-hygiene.yml
  • .github/workflows/hypatia-scan.yml
  • .github/workflows/pr-freshness.yml
  • .gitignore
  • CONTRIBUTING.md
  • docs/maintenance/repository-hygiene.md
  • scripts/maintenance/check-pr-freshness.sh
  • scripts/maintenance/triage-branches.sh
  • scripts/tests/test-check-pr-freshness.sh
  • scripts/tests/test-triage-branches.sh
  • 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

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, you can upgrade your account or add credits to your account and enable them for code reviews in your settings.

@github-actions

github-actions Bot commented Oct 25, 2026 •

Copy link
Copy Markdown

Fork governance

Lane Status Run
DEED syntax (repo deed) 🟢 conformant run 40178146950
K9 conformance (L0–L2; L3 not verified) green (job: success) same run
Hypatia verdict grid purple (job: success) same run

Hypatia grid purple

🟣 critical · commit b0c2f9198df0 · run 40178146950

Reporter Status Critical High Medium Minor Since previous revision
Hypatia scan 🟣 critical 18 29 29 0 ↔ unchanged
panic-attack assail 🔴 high 0 7 1 0 ↔ unchanged
pons asinorum 🟢 clean 0 0 0 0 ↔ unchanged
rhodibot (RSR compliance) 🟠 indeterminate 0 0 0 0 — indeterminate
panicbot (panic recovery, error handling) 🟠 indeterminate 0 0 0 0 — indeterminate
echidnabot (formal verification: proofs/) 🟠 indeterminate 0 0 0 0 — indeterminate
seambot (integration health: API routes) 🟠 indeterminate 0 0 0 0 — indeterminate
finishingbot (release readiness) 🟠 indeterminate 0 0 0 0 — indeterminate
accessibilitybot (WCAG on the React UI) 🟠 indeterminate 0 0 0 0 — indeterminate
glambot (presentation quality) 🟠 indeterminate 0 0 0 0 — indeterminate
cipherbot ⚪ not applicable 0 0 0 0 ↔ unchanged
sustainabot ⚪ not applicable 0 0 0 0 ↔ unchanged
Hypatia scan: 76 finding(s)
  • critical cicd_rules/banned_language_file — frontend/src/utils/text.test.ts — TypeScript file detected -- banned language
  • critical cicd_rules/banned_language_file — frontend/src/cladistics/cumulativeLayout.ts — TypeScript file detected -- banned language
  • critical cicd_rules/banned_language_file — frontend/src/cladistics/cumulativeLayout.test.ts — TypeScript file detected -- banned language
  • critical cicd_rules/banned_language_file — frontend/src/api/ijsonJcs.ts — TypeScript file detected -- banned language
  • critical cicd_rules/banned_language_file — frontend/src/api/ijsonJcs.test.ts — TypeScript file detected -- banned language
  • critical cicd_rules/banned_language_file — frontend/src/components/ordinationModel.test.ts — TypeScript file detected -- banned language
  • critical cicd_rules/banned_language_file — frontend/src/components/ordinationModel.ts — TypeScript file detected -- banned language
  • critical cicd_rules/banned_language_file — scripts/tests/test_null_calibration_failures.py — Python file detected -- banned language
  • critical cicd_rules/banned_language_file — scripts/tests/test_format_readiness.py — Python file detected -- banned language
  • critical cicd_rules/banned_language_file — scripts/formats/process.py — Python file detected -- banned language
  • critical cicd_rules/banned_language_file — scripts/formats/probe_kyq.py — Python file detected -- banned language
  • critical cicd_rules/banned_language_file — scripts/formats/descendants.py — Python file detected -- banned language
  • critical cicd_rules/banned_language_file — scripts/formats/inventory.py — Python file detected -- banned language
  • critical cicd_rules/banned_language_file — scripts/formats/conformance.py — Python file detected -- banned language
  • critical cicd_rules/banned_language_file — test/references/check_ordination_references.py — Python file detected -- banned language
  • critical cicd_rules/banned_language_file — test/references/check_high_precision_references.py — Python file detected -- banned language
  • critical cicd_rules/banned_language_file — test/references/exact_summary_reference.py — Python file detected -- banned language
  • critical cicd_rules/banned_language_file — bench/null_calibration/report_failures.py — Python file detected -- banned language
  • high code_scanning_alerts/CSA001 — frontend/src/utils/text.test.ts — Code scanning (Hypatia): hypatia/cicd_rules/banned_language_file -- Hypatia cicd_rules: banned_language_file -- 5 day(s) old
  • high code_scanning_alerts/CSA001 — test/references/exact_summary_reference.py — Code scanning (Hypatia): hypatia/cicd_rules/banned_language_file -- Hypatia cicd_rules: banned_language_file -- 2 day(s) old
  • 56 more; see the structured report in the artifact.
panic-attack assail: 8 finding(s)
  • high DynamicCodeExecution — src/pipeline/dada2/context.jl — eval/Meta.parse in src/pipeline/dada2/context.jl
  • high DynamicCodeExecution — src/analysis/analysis.jl — eval/Meta.parse in src/analysis/analysis.jl
  • high DynamicCodeExecution — src/analysis/differential.jl — eval/Meta.parse in src/analysis/differential.jl
  • high DynamicCodeExecution — src/analysis/ordination.jl — eval/Meta.parse in src/analysis/ordination.jl
  • high DynamicCodeExecution — src/core/provenance.jl — eval/Meta.parse in src/core/provenance.jl
  • high DynamicCodeExecution — scripts/check-julia-syntax.jl — eval/Meta.parse in scripts/check-julia-syntax.jl
  • high DynamicCodeExecution — test/unit/test_permanova.jl — eval/Meta.parse in test/unit/test_permanova.jl
  • medium UnsafeFFI — src/core/memory_probe.jl — 3 ccall/FFI calls in src/core/memory_probe.jl
rhodibot (RSR compliance): not_run — enrolled, but no report-back was received
  • 🟠 indeterminate: enrolled, but no report-back was received
panicbot (panic recovery, error handling): not_run — enrolled, but no report-back was received
  • 🟠 indeterminate: enrolled, but no report-back was received
echidnabot (formal verification: proofs/): not_run — enrolled, but no report-back was received
  • 🟠 indeterminate: enrolled, but no report-back was received
seambot (integration health: API routes): not_run — enrolled, but no report-back was received
  • 🟠 indeterminate: enrolled, but no report-back was received
finishingbot (release readiness): not_run — enrolled, but no report-back was received
  • 🟠 indeterminate: enrolled, but no report-back was received
accessibilitybot (WCAG on the React UI): not_run — enrolled, but no report-back was received
  • 🟠 indeterminate: enrolled, but no report-back was received
glambot (presentation quality): not_run — enrolled, but no report-back was received
  • 🟠 indeterminate: enrolled, but no report-back was received
cipherbot: not_applicable — no cryptography is implemented in this repository
  • ⚪ not applicable: no cryptography is implemented in this repository
sustainabot: not_applicable — fleet adapter slot reserved; no adapter exists yet (gitbot-fleet README)
  • ⚪ not applicable: fleet adapter slot reserved; no adapter exists yet (gitbot-fleet README)

Scope: static findings reported by each row's tool at the named commit. Purple, red, yellow and blue grade the worst finding present; orange is evidence missing, malformed or a scanner that did not run; grey is an explicit scope exclusion with its reason. No row is a security certification. report.json, badge.json and the raw findings are in the verdict-grid artifact on the linked run.

K9 L0–L2 green

🟢 conformant · commit b0c2f9198df0 · run 40178146950 · validator hyperpolymath/standards@c6d78606f392

Category Status Pass Fail Indeterminate N/A Since previous revision
K9 contract typecheck 🟢 conformant 1 0 0 0 ↔ unchanged
K9 validator self-test 🟢 conformant 37 0 0 0 ↔ unchanged
K9 live corpus (L0–L2) 🟢 conformant 3 0 0 0 ↔ unchanged

Scope: K9 components L0–L2 against contract v1.0.0 at the named standards commit. L3 signature verification and routed coordination-dialect files are not certified. Green is limited to this scope. Orange is missing evidence; yellow is grandfathered debt or warnings; grey is an explicit scope exclusion. report.json, badge.json and the validator logs are in the k9-grid artifact on the linked run.

Arena Agent and others added 2 commits October 25, 2026 08:47
The first run of the new freshness check failed on its own pull request:
actions/checkout checks out refs/pull/<n>/merge for a pull_request event, and
that commit is a merge by construction, so rule 2 failed on every branch.

Check out github.event.pull_request.head.sha instead, and have the script name
the case it cannot distinguish from a real violation: the head being a merge
means either the author merged the base in, or CI checked out the merge ref.
The hint says how to tell, and a test covers it.

Co-authored-by: arena-agent <297053741+arena-agent@users.noreply.github.com>
Not all thirteen touched src/: #274 touched bench/null_calibration and the
workflow, #278 touched the workflows and scripts/. The point stands - none was
a docs-only diff - but the sentence named the wrong evidence.

Co-authored-by: arena-agent <297053741+arena-agent@users.noreply.github.com>
@sonarqubecloud

Copy link
Copy Markdown

@hyperpolymath
hyperpolymath merged commit 4b05b4b into main Oct 25, 2026
27 checks passed
@hyperpolymath
hyperpolymath deleted the arena/30a2502a-metamanifold-webui branch October 25, 2026 09:26
hyperpolymath added a commit that referenced this pull request Oct 25, 2026
## Change and reason

Three follow-ups to #285. One of them is a **correction of a mistake
#285 made**, which is the main reason this exists.

### 1. Declared lanes are not drift — and #285 got this wrong

The deed (`MetaManifold-WebUI_chora.deed`, routing `:upstream-candidates
"upstream/*"`) declares `upstream/*` a lane: work destined for the
upstream remote, squash-merged there (`notes/commit-signing.md` records
#192 landing that way). `CONTRIBUTING.md` declares `archive/*` and
`governance-badges`. The triage in #285 classed branches **by commit
graph alone**, so it reported `upstream/placement-evidence` as `salvage`
— a class whose documented remedy is "close it, or re-apply it
elsewhere" — and #270 was closed with it.

Deleting a laned branch discards a routing decision, not a commit. The
content is recoverable (`refs/pull/270/head`), but the lane is gone and
re-cutting it is the owner's call. So:

- lanes are read from the **deed** (with `upstream/*` as the fallback
for a bare clone that has no deed checked out) plus the two documented
in `CONTRIBUTING.md`;
- the triage prints a `LANE` column and counts laned branches
separately;
- **a laned branch does not raise `--fail-on`** unless `--include-lanes`
is passed;
- `branch-hygiene.yml` now takes its counts from the triage's own
summary lines instead of grepping table rows (which would have broken
the moment a column was added, and would have counted lanes as drift),
and the issue body says how many laned branches it is deliberately not
counting.

Corrected in the docs under *Declared lanes are not spare branches*,
with decision 5 recording what to do about that candidate.

### 2. Dependabot PRs would have gone red for the wrong reason

Dependabot does not rebase by default. With two open updates, the second
goes behind `main` the moment the first merges, and the new **Branch
freshness** check fails a one-line dependency bump for a rule the bump
did not break. Both ecosystems now set `rebase-strategy: auto`, so red
on that check means what it says: a conflict a person has to resolve.

### 3. Pins and template

- `actions/checkout` was `v4.4.0` in the `standards` job and `v7.0.1` in
five others; the `occupancy` job's copy carried **no version comment at
all**, which makes Dependabot's diff for it unreadable. All six now
match.
- The PR template names the **Branch freshness** check and the local
command.

### Also: a new "Looks wrong, is not" section

`JoshuaJewell/MetaManifold-WebUI` appears in `README.md` badges,
`CITATION.cff`, the Codecov `slug`, `CONTRIBUTING.md`,
`frontend/src/about.ts` and `SECURITY.md`. In the last pass I reported
that as a stale owner to be "fixed" to `hyperpolymath`. That was
**wrong**: it is the upstream this repository forks, recorded in
`0-AI-MANIFEST.a2ml`, the deed (`:fork-of`, `:upstream`) and
`must.k9.ncl` (`upstream_repository`). Repointing the Codecov slug would
send uploads at a project that may not have the token — and with
`fail_ci_if_error: false` nobody would notice. Nothing in this PR
touches those references; the doc now says why not, next to the
standards-pin note and the `docs/` whitelist.

## Validation

Run here, on this branch, against the merged tree:

```
bash scripts/tests/test-triage-branches.sh        # 24 passed, 0 failed
bash scripts/tests/test-check-pr-freshness.sh     # 12 passed, 0 failed
bash scripts/check-governance-contract.sh         # 70 checks passed
bash scripts/tests/test-governance-contract.sh    # all mutations rejected
bash scripts/tests/test-scanner-boundaries.sh     # ok
bash scripts/tests/test-ci-logging.sh             # ok
bash scripts/lint-sonar-reliability.sh            # OK: no S2871 or S7758 in frontend/src
```

The triage tests now also cover: a lane declared in the deed is
recognised; the deed pattern **replaces** the built-in fallback; without
a deed the fallback still lanes; laned branches alone do not raise
`--fail-on` (and `--include-lanes` reproduces the match); the JSON
carries `lane` as a string or `null`. Every workflow was parsed as YAML,
its embedded shell extracted and checked with `bash -n`, and the
rolling-issue upsert exercised against a stub `gh` (create, update,
close, and now the laned-branch paragraph).

**Not run:** the Julia and frontend suites — this diff touches no Julia
or TypeScript, and neither runtime exists in the sandbox.
`scripts/ci/check-shell-secrets.sh` refuses on a shallow clone, so it
was not run here either; CI runs it on a full clone.

## Scope

- The **standards SHA pins** stay as they are. Some are contract-bound
(`c6d78606…` for K9/secret-scanner/Scorecard, `01c9b0c9…` for the
verdict-grid renderer), so reconciling them has to move
`scripts/check-governance-contract.sh`'s constants and the allowlist
digest together. Recorded as decision 6.
- The **`Branch freshness` ruleset entry** is still an owner action.
- No lockfile, dependency, generated or vendored file changes; no
`renv.lock`, `Manifest.toml` or `tool_versions.yml` edits.

## Contribution checks

- [x] I followed [CONTRIBUTING.md](../CONTRIBUTING.md).
- [x] This branch starts at current upstream main and contains no merges
from fork main (`merge base 4b05b4b`).
- [x] CI has run and passed for this branch (see checks).
- [x] Existing licensing, citation and acknowledgement text is
unchanged.

Co-authored-by: Arena Agent <agent@arena.ai>
Co-authored-by: arena-agent <297053741+arena-agent@users.noreply.github.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.

1 participant