diff --git a/docs/ci-cd.md b/docs/ci-cd.md index 77148ec70..8355de83b 100644 --- a/docs/ci-cd.md +++ b/docs/ci-cd.md @@ -106,8 +106,8 @@ commit in the range (see the `decisions.md` header) — routine lifecycle metada > tag-protection rule (`name_pattern: v*`, `whitelist_usernames: ["timothy"]`, > `release.tag-protection-v-star`), because a `v*` push builds and publishes `:prod`. A push from > any other account is expected to be refused — configured, not exercised, since only the - > `timothy` credential is available here. **The positive half of that rule is UNVERIFIED too**: it was applied - > 2026-09-04 and only its negative half was measured (a non-`v*` tag still pushes), because + > `timothy` credential is available here. **The positive half is UNVERIFIED too**: the rule was + > applied 2026-09-04 and only its negative half was measured (a non-`v*` tag still pushes), because > pushing a `v*` tag outside a real cut would publish `:prod`. This cut is its first real > exercise. If the tag push is refused, unblock with > `DELETE /api/v1/repos/timothy/ersatztv/tag_protections/1`, push, then re-`POST` the rule @@ -1459,12 +1459,13 @@ re-opens the hole this section exists to close. Practical consequences: **every** change to `main` goes through a PR, including a one-line docs fix; and the client-side Husky guards (H6/H11/H13) remain useful friction but were never the control — they are fail-open and `--no-verify` bypasses them. Tag pushes go through a separate mechanism and -are unaffected for the release operator: since ersatztv#885 `tag_protections` carries one rule, -`v*` whitelisted to `timothy` (`release.tag-protection-v-star`), which is meant to leave the release -cut in "Cutting a release" working unchanged while refusing a `v*` tag from the `renovate` bot — a push -that would otherwise have published a `:prod` image. Both halves of that are EXPECTED, UNVERIFIED: only -the `timothy` credential exists here, so neither a real release cut nor a refused bot push has been -exercised. `release.tag-protection-v-star` carries the same caveat and is waiting for the next cut. +are meant to stay unaffected for the release operator: since ersatztv#885 `tag_protections` carries +one rule, `v*` whitelisted to `timothy` (`release.tag-protection-v-star`), which is intended to leave +the release cut in "Cutting a release" working unchanged while refusing a `v*` tag from the `renovate` +bot — a push that would otherwise have published a `:prod` image. Both halves of that are EXPECTED, +UNVERIFIED: only the `timothy` credential exists here, so neither a real release cut nor a refused bot +push has been exercised. `release.tag-protection-v-star` carries the same caveat and waits on the +next cut. **A fourth arm: guard-scope freshness (ersatztv#787).** `scripts/tests/test_ci_dropped_step_guard.py` decides which CI jobs must carry per-step execution markers by DERIVING that scope from