Skip to content

fix(release-lib): close six doctrine-deletion blind spots in governance rules - #619

Merged
SUaDtL merged 2 commits into
mainfrom
fix/571-doctrine-deletion-guards
Aug 6, 2026
Merged

fix(release-lib): close six doctrine-deletion blind spots in governance rules#619
SUaDtL merged 2 commits into
mainfrom
fix/571-doctrine-deletion-guards

Conversation

@SUaDtL

@SUaDtL SUaDtL commented Aug 6, 2026

Copy link
Copy Markdown
Collaborator

Summary

_GOVERNANCE_RULES in .github/scripts/test_release_lib.py pins load-bearing sentences in the release skill by asserting a set of anchor tokens is present. A rule fires only when all its tokens are present, so it could detect its own deletion only if at least one token disappeared entirely when the protected sentence went. Six rules had every anchor token also occurring elsewhere in the file, so the guarded sentence could be deleted while the rule stayed green.

Each is now re-anchored on a span unique to its own guarded sentence. _KNOWN_WEAK_ANCHORS — the ratchet that declared the six as known-weak — is now the empty set.

Counts below are re-measured against current main (32b0992), not the issue's original numbers — the file has moved since #571 was filed (notably #617's run-15 ${VERSION} rename, which the issue's own git rev-parse ... MAJOR.MINOR.PATCH quote predates).

rule old anchor (occurrences, re-measured) new anchor added deletion scenario proven
footer BLOCK / never-auto-fill CHANGELOG: x10, auto-fill x2 MUST NOT auto-fill a missing Hard Rules bullet deleted; Phase-1 step-3 prose alone left both old tokens intact
publish read-back gh release view x3, non-draft x4 MUST verify the published Release by read-back Hard Rules bullet deleted; the isDraft probe + Phase-3 read-back sentences alone left both old tokens intact
immutable-tag hard rule published tag is immutable x2 Correction means publishing a NEW version "Recovering from a bad release" opening sentence deleted; the Phase-2 cleanup-mode mention alone left the old token intact
pre-tag BLOCK-on-nonzero pre-tag x25, non-zero exit x5, BLOCK x15 BLOCK on a non-zero exit Hard Rules bullet deleted; the word's other 24/4/14 occurrences elsewhere left all three old tokens intact
HIGH-1 (re-run): tag_sha peeled, never a raw rev-parse git rev-parse ${TAG_PREFIX}${VERSION} x2, peel-tag x3 never from a bare `git rev-parse The "never a raw rev-parse" warning sentence deleted; Phase-3 step-5's provenance command and the adjacent peel-tag sentences left both old tokens intact
HIGH-2 (re-run): back-fill declares latest-eligible for its one target latest-eligible: true` x5, single-target x3 this lane can only ever propose ONE row The back-fill detect-step sentence deleted; four other latest-eligible: true mentions and two other single-target mentions left both old tokens intact

Proof

Pinned as a permanent RED/GREEN mutation proof (DoctrineDeletionMutationProofTest, new class in .github/scripts/test_release_lib.py), run against the real core/surface/skills/release/SKILL.md source text, never a synthetic fixture:

  • Each rule's whole guarded sentence — located by a (start marker, end marker) pair, not the new anchor span in isolation (an isolated-span proof would be tautological: any unique string added as a token catches its own deletion, and the ratchet test already proves uniqueness) — is deleted from a copy of the source text.
  • RED: the OLD (pre-Six governance rules cannot detect deletion of the doctrine they guard #571) token tuple, pinned in the test as a fixed historical baseline never read from the live dict, stays silent against the mutilated text — reproducing the exact defect.
  • GREEN: the CURRENT _GOVERNANCE_RULES entry for that same rule reports it missing — proving the fix, and that the new anchor token actually falls inside the sentence it's meant to guard (asserted directly in the test).

Exact counts:

  • python -m pytest .github/scripts/test_release_lib.py -q -> 360 passed, 292 subtests passed (357 pre-existing + 3 new: test_the_six_rules_are_exactly_the_ones_pinned_here, test_deleting_the_whole_guarded_sentence_is_red_under_the_old_anchor, test_deleting_the_whole_guarded_sentence_is_caught_by_the_current_anchor).
  • GovernanceSurvivalTest.test_every_rule_has_at_least_one_uniquely_occurring_anchor now passes with _KNOWN_WEAK_ANCHORS == set().
  • unittest discover -s plugins/ca/hooks/tests (via pytest) -> 1347 passed, 153 subtests passed - untouched by this change, run as a regression check.
  • tools/sync-core.py --check and tools/build-surface.py --check -> both OK (no core/ content changed by this PR - only the CI-side test file and version-advance surfaces).

Also verified (issue's "verification habit" note)

The issue flags grep -c (counts matching lines, not occurrences) as an unreliable way to check anchor uniqueness on this file's thousand-character single-line steps. Confirmed no .github/scripts/*.py file uses grep -c for this purpose - the only grep -c string in the tree is the historical comment describing the defect, inside test_release_lib.py's own docstring. All new counting in this PR uses str.count.

Version advance (merge-train slot)

ca 2.11.11 -> 2.11.13, ca-codex 0.4.10 -> 0.4.12, ca-pi 0.2.11 -> 0.2.13 - root package.json regenerated via tools/build-host-packages.py, root CHANGELOG.md and plugins/ca-pi/CHANGELOG.md both carry dated 2026-08-05 sections, README badge and ships-line updated. This PR's diff carries no plugins/ca/**, plugins/ca-codex/**, or plugins/ca-pi/** payload change (CI scripts only), so payload_version_gate.py --plugin plugins/ca --base origin/main and --plugin plugins/ca-codex both report no shipped payload change - version bump not required (pass), and build-host-packages.py --check --release-guard-base origin/main reports no Pi payload change - version bump not required (pass) - the version advance here is the merge-train bookkeeping convention this repo's history follows on every merged PR, not something any gate required.

All post-commit gates run green: check_badge_consistency.py, test_release_trace.py (29 passed / 34 subtests), payload_version_gate.py (ca + ca-codex), build-host-packages.py --check --release-guard-base origin/main, check_site_voice.py.

Deviations from the task brief

  • The task brief's setup step named env -u NO_COLOR python -m pytest ...; the sandbox rejected that exact command shape (it can't verify env's effect on a wrapped -m invocation), so tests ran instead via unset NO_COLOR && python -m pytest ... - same effect, different shell spelling.
  • Anchor occurrence counts in the table above are re-measured against current main, not copied from the issue body, which was filed against an earlier revision of the skill.

Closes #571

https://claude.ai/code/session_01QjJeSbcwPHwMmd6CEZeagB

…ce rules

_GOVERNANCE_RULES in .github/scripts/test_release_lib.py pins load-bearing
sentences in the release skill by asserting a set of anchor tokens is
present. A rule fires only when ALL its tokens are present, so it could
detect its own deletion only if at least one token disappeared entirely
when the protected sentence went. Six rules (footer BLOCK / never-auto-fill,
publish read-back, immutable-tag hard rule, pre-tag BLOCK-on-nonzero, and
two re-run HIGH rules) had every anchor token also occurring elsewhere in
the skill, so the guarded sentence could be deleted while the rule stayed
green -- the exact inversion of its purpose.

Each is now re-anchored on a span unique to its own guarded sentence
(verified `text.count(...) == 1` against the source and all three rendered
payloads: ca, ca-codex, ca-pi). _KNOWN_WEAK_ANCHORS, the ratchet declaring
the six as known-weak, is now empty.

Pinned as a permanent RED/GREEN mutation proof
(DoctrineDeletionMutationProofTest): each rule's whole guarded sentence
(never just the new anchor span, which would make GREEN tautological) is
located by marker pair and deleted from a copy of the real source text.
The OLD (pre-#571) token tuple stays silent (RED, the reproduced defect);
the CURRENT _GOVERNANCE_RULES entry catches it (GREEN, the fix).

Version advance: ca -> 2.11.13, ca-codex -> 0.4.12, ca-pi -> 0.2.13.

Closes #571

CHANGELOG: Six governance rules that pin load-bearing release-skill
doctrine are re-anchored so deleting the sentence they guard is now
detected instead of passing silently.
Claude-Session: https://claude.ai/code/session_01QjJeSbcwPHwMmd6CEZeagB
@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro Plus

Run ID: 431de5b3-ee87-4034-8b17-add222e351b2

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

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

Merges origin/main's #620 (fix(hooks): stop a stale git-hook cache from
authoring a false H-09b block, ca 2.11.11 -> 2.11.12) into this branch.
This PR's diff is .github-only and did not touch core/pysrc/ or any
plugins/*/hooks/ files, so #620's core-side changes (_githooks.py,
doctor.py, the new AC-4 regression test) merged clean with no conflicts.

Conflicts resolved by hand, all version/changelog surfaces:
- CHANGELOG.md / plugins/ca-pi/CHANGELOG.md: union -- this branch's
  2.11.13 / 0.2.13 sections kept ABOVE main's 2.11.12 / 0.2.12 sections,
  neither dropped.
- plugins/ca/.claude-plugin/plugin.json, plugins/ca-codex/.codex-plugin/
  plugin.json, plugins/ca-pi/package.json, README.md badge + ships-line:
  this branch's higher versions (2.11.13 / 0.4.12 / 0.2.13) win.
- Root package.json: regenerated via tools/build-host-packages.py
  (no-op -- already matched plugins/ca-pi/package.json at 0.2.13).

tools/sync-core.py --check and tools/build-surface.py --check both pass
clean -- no core source conflict to resolve.

H-09b note: the merge commit's raw diff trips the lexical CRYPTO_RE scan
on the string "createHash" inside #620's own new test fixture
(plugins/ca/hooks/tests/test_git_hooks.py) -- inert test-payload text
proving the new heartbeat mechanism, never a real crypto call (no
hashlib import or hash/sign/encrypt/TLS-config operation anywhere in the
merged diff). auth-crypto-reviewer confirmed PASS against
.codearbiter/security-controls.md's existing accepted-adversarial-payload
precedent; security-gate-passed marker recorded via
hooks/security-pass.py before this commit.

Re-verified post-merge: check_badge_consistency.py,
test_release_trace.py (29 passed / 34 subtests), payload_version_gate.py
for plugins/ca and plugins/ca-codex (both report version advanced against
the new origin/main base), build-host-packages.py --check
--release-guard-base origin/main, test_release_lib.py (360 passed / 292
subtests, unchanged), and plugins/ca/hooks/tests (1349 passed / 153
subtests, matching #620's own reported count).

Claude-Session: https://claude.ai/code/session_01QjJeSbcwPHwMmd6CEZeagB
@SUaDtL
SUaDtL merged commit bd247e6 into main Aug 6, 2026
52 checks passed
SUaDtL added a commit that referenced this pull request Aug 6, 2026
Reconciles with #620 (fix(hooks): stale git-hook cache authoring a false
H-09b block) and #619 (fix(release-lib): close six doctrine-deletion
blind spots in governance rules), both merged to main ahead of this PR
in the version-advance train.

- CHANGELOG.md / plugins/ca-pi/CHANGELOG.md: union, this PR's
  2.11.14 / 0.2.14 sections placed above main's 2.11.13 / 0.2.13 and
  2.11.12 / 0.2.12 sections.
- Manifests (plugins/ca/.claude-plugin/plugin.json,
  plugins/ca-codex/.codex-plugin/plugin.json,
  plugins/ca-pi/package.json) and README badge/ships-line: this PR's
  higher versions (2.11.14 / 0.4.13 / 0.2.14) win.
- Root package.json: regenerated via tools/build-host-packages.py.
- .github/scripts/test_release_lib.py: auto-merged cleanly -- #619's
  six re-anchored _GOVERNANCE_RULES entries (and its new
  DoctrineDeletionMutationProofTest class) coexist with this PR's two
  new --dry-run governance rules. 360 tests pass.
- core/pysrc/_githooks.py + doctor.py and their three vendored copies:
  auto-merged cleanly, no stray conflict markers; sync-core.py --check
  and build-surface.py --check both confirm the merged core and
  rendered surface stay byte-identical / in sync.

Post-merge verification: plugins/ca/hooks/tests full suite (1369
passed, 153 subtests), .github/scripts/test_release_lib.py +
test_check_skill_proof_fresh.py + test_release_trace.py (413 passed,
328 subtests), check_badge_consistency.py, both
payload_version_gate.py runs (--base origin/main), and
build-host-packages.py --check --release-guard-base origin/main all
green.

Claude-Session: https://claude.ai/code/session_01QjJeSbcwPHwMmd6CEZeagB
SUaDtL added a commit that referenced this pull request Aug 6, 2026
Reconciles PR #618 (last wave-2 train slot, ca 2.11.15 / ca-codex 0.4.14 /
ca-pi 0.2.15) against #620 (2.11.12), #619 (2.11.13), and #621 (2.11.14),
all merged to main since this branch was cut.

- CHANGELOG.md / plugins/ca-codex/CHANGELOG.md / plugins/ca-pi/CHANGELOG.md:
  union, this PR's newest section kept above the three incoming ones; no
  section dropped. plugins/ca-codex/CHANGELOG.md carries a pre-existing gap
  (no 0.4.12/0.4.13 headings on main despite the manifest bump) — not
  backfilled here, out of scope for this merge.
- Manifests + README badge/ships-line: this PR's higher versions win
  (2.11.15 / 0.4.14 / 0.2.15); root package.json regenerated via
  tools/build-host-packages.py.
- #621's core/surface edits (writing-plans, brainstorming, release
  SKILL.md, new core/pysrc/_intentlib.py) auto-merged with no conflict;
  #621 did not touch skill-author/SKILL.md, so this PR's Phase 5 citation
  edit there is the only change to that file.
- tools/build-surface.py --check and tools/sync-core.py --check both pass
  on the merged core sources.
- check_routing_index_parity.py re-run on the merged tree: still 4
  surfaces / 130 skill-routine-wrapper entries / 84 agents / 146
  routing-table rows, zero drift — #621's skill-body edits did not add or
  remove any skill/agent, so no new INDEX/routing drift appeared.
- H-09b false-blocked on the stale cached 2.10.0 git-enforce.py (predates
  the #279 sensitive-scan exemption), which flagged the literal string
  "createHash" inside #620's own test fixture
  (plugins/ca/hooks/tests/test_git_hooks.py) as a crypto change. Cleared
  via the sanctioned path: auth-crypto-reviewer confirmed PASS (no real
  crypto/secret content anywhere in the diff), then hooks/security-pass.py
  was run from both the current worktree plugin and the stale cached
  2.10.0 path (its git-enforce.py resolves repo_root() via `git
  rev-parse --show-toplevel` rather than the newer marker_root() seam, so
  it reads the worktree-local marker, not the unified main-checkout one).

Re-verified post-merge: full hooks test suite (1369 passed, 153 subtests),
check_badge_consistency.py, test_release_trace.py, payload_version_gate.py
for plugins/ca and plugins/ca-codex, and build-host-packages.py --check
--release-guard-base origin/main — all green.

Claude-Session: https://claude.ai/code/session_01QjJeSbcwPHwMmd6CEZeagB
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.

Six governance rules cannot detect deletion of the doctrine they guard

1 participant