feat(engine): TAG-SIGNED — a tag that names a signer, not just write access
The check sat parked as "blocked on an operator decision" on the strength of 0 of 18 repos signing. That zero was never evidence against it: it is what a practice nobody has adopted yet looks like, and reasoning from it makes the gate ratify the status quo it exists to move. The rule that settled it asks something else — would a public AAA+ repository do this? Yes, and unlike the two conventions that killed VERSION-DRIFT, there is no second convention under which release tags are better left unattributable. The measurement then decided the SCOPE, not the yes. Across 20 clones: 158 v* tags, 144 annotated, 14 lightweight, 0 signed, and not one dated after 2026-08-12. A boolean "this org signs" would have failed 20 correct repositories on day one with force-moving 144 published refs as its only remedy — the mechanism that gets gates switched off. So the policy is a DATE in the register (never in the engine, the rule that keeps the org-profile exemption a flag): nothing fires today, teeth at each repo's next release. Verified both directions, because a sweep returning zero proves nothing on its own — a dead check returns zero too. 21 repos: 18 PREPOLICY + 3 NONE, 0 ERROR, 0 WARN; then against real git objects an unsigned post-policy newest tag does fire ERROR. Two exclusions keep one defect from being counted twice: a lightweight tag has no object to carry a signature (byDesign skip naming TAG-ANNOTATED as owner), and a pre-policy tag was correct when cut (OK, said out loud, never silence). It answers "is it signed", never "does the forge vouch for it". The README row ships in this commit, not after it, and the stale test count in CLAUDE.md (230 → 241) is corrected here rather than left for the next reader. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XsPsVsvhrSaejK3cLPmnN2
This commit is contained in:
parent
9f08ebc5ed
commit
e6cd8983ca
9 changed files with 415 additions and 17 deletions
48
CLAUDE.md
48
CLAUDE.md
|
|
@ -282,16 +282,42 @@ would recreate, in data, exactly the drift this plugin exists to remove.
|
|||
has no convention on either side because it has no subject. Do not re-derive
|
||||
it from "18/18" alone — the fire rate is a proxy, and reasoning from the proxy
|
||||
is what would resurrect this check the first time one repo publishes an asset.
|
||||
- **`TAG-SIGNED` is BLOCKED ON AN OPERATOR DECISION, not rejected — and filing it
|
||||
with the rejections is the error to avoid.** 0 of 18 repos sign their tags
|
||||
today, which looks like the same measurement that killed VERSION-DRIFT and is
|
||||
not: if the operator decides this org signs tags, the check acquires its whole
|
||||
subject the same day. A rejection is permanent; this is one yes/no away.
|
||||
Recorded here so the next session reads a pending question instead of
|
||||
re-measuring a settled one. The scope is also fixed in advance: `git cat-file
|
||||
tag` reads the signature block from the clone, so the check can answer *is it
|
||||
signed* and must never claim *the forge vouches for it* — the forge's
|
||||
"Verified" badge needs a key registered there.
|
||||
- **The question is "would a public AAA+ repo do this", NOT "how many of ours
|
||||
already do".** Operator rule, 2026-08-13, and it settled `TAG-SIGNED` — which
|
||||
had been parked as "blocked on an operator decision" on the strength of 0 of
|
||||
18 repos signing. That zero was never evidence against the check: it is what a
|
||||
practice nobody has adopted yet looks like, and reasoning from it makes the
|
||||
gate ratify the status quo it exists to move. The operator's word for being
|
||||
asked at all was that it "should almost be self-evident". This is genuinely
|
||||
different from the VERSION-DRIFT rejection, where two legitimate conventions
|
||||
coexisted; there is no second convention under which release tags are better
|
||||
left unattributable. **The test decides WHETHER; the corpus measurement then
|
||||
decides only HOW TO SCOPE** so the rule does not fail correct repositories on
|
||||
day one. Do not let a low adoption rate veto a yes.
|
||||
This does not reopen `RELEASE-ASSETS`, which was rejected for the stronger
|
||||
reason — no subject at all, 0 of 21 READMEs referencing an asset download.
|
||||
- **`TAG-SIGNED` ships as a policy DATE, and the date is what made it
|
||||
shippable.** Measured across 20 clones before the rule was locked (2026-08-13):
|
||||
158 `v*` tags, 144 annotated, 14 lightweight, **0 signed**, and not one tag
|
||||
dated after 2026-08-12. A boolean "this org signs" would have failed 20
|
||||
correct repositories the day it landed, with force-moving 144 published refs
|
||||
as its only remedy — the mechanism that gets gates switched off. The date
|
||||
(`tags_signed_from` in the register, never in the engine, the same rule that
|
||||
keeps the org-profile exemption a flag) fires nothing today and acquires teeth
|
||||
at each repo's next release, which is how signing is adopted in public.
|
||||
Verified by sweep: 21 repos, 18 `TAG-SIGNED-PREPOLICY` + 3 `TAG-SIGNED-NONE`,
|
||||
0 ERROR, 0 WARN — then positively controlled against real git objects, where
|
||||
an unsigned post-policy newest tag does fire `ERROR`. A sweep returning zero
|
||||
proves nothing on its own; a dead check returns zero too.
|
||||
Two exclusions keep one defect from being counted twice: a **lightweight** tag
|
||||
has no tag object to carry a signature (`TAG-ANNOTATED` owns it, and the skip
|
||||
names that owner), and a **pre-policy** tag was correct when it was cut — said
|
||||
out loud as an `OK`, never as silence. Scope fixed in advance and held:
|
||||
the signature is read from the clone, so the check answers *is it signed* and
|
||||
never *does the forge vouch for it* — that badge needs a key registered there.
|
||||
Read with `%(if)%(contents:signature)%(then)…` rather than by printing the
|
||||
block, which is multi-line and would break the line-oriented parser on exactly
|
||||
the tags that matter.
|
||||
- **A gate whose subject varies per repo MEASURES the subject; it does not read
|
||||
it off the class.** `VERIFY-COMMAND` fires only where something runnable
|
||||
exists (`scripts.test`, or a tracked executable test file), and answers
|
||||
|
|
@ -318,7 +344,7 @@ would recreate, in data, exactly the drift this plugin exists to remove.
|
|||
## Commands
|
||||
|
||||
```bash
|
||||
npm test # 230 tests
|
||||
npm test # 241 tests
|
||||
node scripts/repo-standard-check.mjs --dir "$PWD" # gate one repo
|
||||
node scripts/repo-standard-check.mjs --offline # no network call
|
||||
node scripts/repo-standard-check.mjs --json # machine output
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue