Skip to content

chore(hygiene): give the commit gate teeth and guard against the blobs returning - #34

Merged
hyperpolymath merged 2 commits into
mainfrom
chore/blob-guard-and-hook-honesty
Sep 21, 2026
Merged

hyperpolymath merged 2 commits into
mainfrom
chore/blob-guard-and-hook-honesty

Conversation

@hyperpolymath

Copy link
Copy Markdown
Owner

Two defects with the same shape: a control documented as enforcing something
it could not enforce.

1. The commit-msg hook could never have run

docs/compliance/standards-alignment.md:49 claimed commit conventions were
"Enforced ✅" by .githooks/commit-msg. That hook was committed mode
100644
. Git refuses to execute a non-executable hook, so it had never run
for anyone, ever — and it failed to nothing, silently, rather than to a
visible exit 126.

It was also wired nowhere. core.hooksPath is local config and cannot be
committed
; the only place it appeared was one line in CONTRIBUTING.md, so it
was unset in every clone that had not read that line.

Fixed rather than documented around:

  • git update-index --chmod=+x on the hook — git will now run it;
  • a just hooks recipe, made a dependency of just bootstrap, so
    enablement follows from bootstrapping instead of from remembering;
  • CONTRIBUTING.md points at just hooks rather than the raw git incantation.

The doc row is now split honestly — CI is the gate, the hook is local
pre-flight
, marked ⚠ opt-in per clone, because that is what a per-clone
setting can be and no more.

Note this corrects a stale premise: repo-hygiene is no longer blanket
advisory
. 67f2faaf's unconditional continue-on-error: true has since
become continue-on-error: ${{ github.repository != 'hyperpolymath/MetaManifold-WebUI' }}
— advisory upstream, binding here. So the CI leg of that claim was true;
only the hook leg was false.

2. Nothing stopped the 269 MiB coming back

.gitattributes had no fastq or LFS rules. Once the history rewrite reclaims
~96.6% of the pack, anyone could re-add the same data the next day.

scripts/check-blob-hygiene.sh is the guard, with one implementation and two
callers
— .githooks/pre-commit and a new CI Blob hygiene check step. That
is deliberate: a hook and a CI check that re-implement one rule drift apart, and
the drift is invisible because both keep reporting success.

The primary rule is a 4 MiB size ceiling, not a path list. A path list can
only forbid paths somebody already thought of — which is exactly how the
Multiplex pool survived a history rewrite: it was reachable under a second path
(inputs/fastq/) the census never enumerated, because git rev-list --objects
pairs each object with only one of its paths. Path rules are kept, but as
better error messages rather than as the gate.

The six data/MiSeq_SOP/run_[AB]/*.fastq.gz fixtures (0.6–2.6 MiB, whitelisted
at .gitignore:294-304) are allowlisted by glob. The ceiling sits above the
largest (2,723,348 B) with headroom.

Verified by mutant, not by a green run

A guard that passes proves nothing until it refuses something.

mutant result
uncompressed .fastq refused
a 5 MiB blob refused
a node_modules/ path refused
an inputs/ second-path copy refused
a logs_*.zip CI artefact refused
allowlisted 2.6 MiB fixture admitted ✅
ordinary source file admitted ✅

Positive control over the live tree: 335 files examined, all 6 fixtures seen,
passes.

The commit-msg hook was mutant-tested too. The subject it rejects in the test
is CI and PR fixes. — verbatim the historical commit 84c7efb, which landed
on main in violation of this very rule. The repaired hook catches it.

Both hooks ran for real on this PR's own commit (blob hygiene: ok appears in
the commit output). check-spdx.sh, check-format.sh and check-lint.sh all
pass locally.

🤖 Generated with Claude Code

https://claude.ai/code/session_01X3hgXxWm6umMgZkjYyHnnm

…s returning

Two defects with the same shape: a control that is documented as enforcing
something it cannot enforce.

## The commit-msg hook could never have run

`docs/compliance/standards-alignment.md:49` claimed commit conventions were
"Enforced ✅" by `.githooks/commit-msg`. That hook was committed **mode 100644**.
Git refuses to execute a non-executable hook, so it had never run for anyone,
ever -- and it failed to *nothing*, with no error, rather than to a visible
exit 126.

It was also wired nowhere. `core.hooksPath` is local config and cannot be
committed, and the only place it appeared was a line in CONTRIBUTING.md, so it
was unset in every clone that had not read that line. Mine included.

Fixed rather than documented around:
  - `git update-index --chmod=+x` on the hook, so git will run it;
  - a `just hooks` recipe, made a dependency of `just bootstrap`, so enablement
    follows from bootstrapping instead of from remembering;
  - CONTRIBUTING.md points at `just hooks` rather than the raw git incantation.

The doc row is now split honestly: CI is *the gate* (binding on this repo,
advisory upstream), the hook is *local pre-flight* and marked ⚠ opt-in per
clone, because that is what a per-clone setting can be and no more.

## Nothing stopped the 269 MiB coming back

`.gitattributes` had no fastq or LFS rules. After the history rewrite reclaims
~96.6% of the pack, anyone could have re-added the same data the next day.

`scripts/check-blob-hygiene.sh` is the guard, with **one implementation and two
callers** -- `.githooks/pre-commit` and a new CI `Blob hygiene check` step. That
is deliberate: a hook and a CI check that re-implement one rule drift apart, and
the drift is invisible because both keep reporting success.

The primary rule is a **4 MiB size ceiling, not a path list**. A path list can
only forbid paths somebody already thought of, and that is exactly how the
Multiplex pool survived a history rewrite -- it was reachable under a second
path (`inputs/fastq/`) that the census had never enumerated, because
`git rev-list --objects` pairs each object with only one of its paths. Path
rules are kept, but as better error messages rather than as the gate.

The six `data/MiSeq_SOP/run_[AB]/*.fastq.gz` fixtures (0.6-2.6 MiB, whitelisted
at .gitignore:294-304) are allowlisted by glob. The ceiling sits above the
largest of them (2,723,348 B) with headroom.

## Verified by mutant, not by a green run

A guard that passes proves nothing until it refuses something. Five
reintroduction attempts, each refused:

  uncompressed .fastq · a 5 MiB blob · a node_modules/ path ·
  an inputs/ second-path copy · a logs_*.zip CI artefact

and two negative controls admitted: an allowlisted 2.6 MiB fixture, and an
ordinary source file. The positive control over the live tree examines 335
files, sees all 6 fixtures, and passes.

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

coderabbitai Bot commented Sep 21, 2026 •

Copy link
Copy Markdown

Warning

Review limit reached

Next included review available in 12 minutes.

Check out review usage here.

View limit details

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

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

Learn how review limits work.

Review configuration:

⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Advanced

Run ID: 9e7cac10-f0a4-4cd9-8710-ba49c887bd02

📥 Commits

Reviewing files that changed from the base of the PR and between 76c92f1 and fa40539.

📒 Files selected for processing (8)
  • .gitattributes
  • .githooks/commit-msg
  • .githooks/pre-commit
  • .github/workflows/ci.yml
  • CONTRIBUTING.md
  • Justfile
  • docs/compliance/standards-alignment.md
  • scripts/check-blob-hygiene.sh

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.

@hyperpolymath
hyperpolymath merged commit 3fc5aa6 into main Sep 21, 2026
1 check passed
@hyperpolymath
hyperpolymath deleted the chore/blob-guard-and-hook-honesty branch September 21, 2026 17:32
@sonarqubecloud

Copy link
Copy Markdown

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