Extends the #303 hook program with H11, H12, and a PR-scoped format CI gate — all prompted by the #309 session, where a stale branch merged main in, dragged legacy-BOM .cs it never touched into the commit, and the pre-commit format hook then blocked on code that wasn't the author's.
.claude/hooks/prepush-rebase-check.sh, wired into .husky/pre-push: blocks a push whose branch is behind origin/main with git rebase origin/main guidance. Rebasing keeps your diff to what you touched; merging main in drags in others' files. Fail-open (offline / no origin/main / not-a-repo → allow, since a git hook has no "ask"); escape ETV_SKIP_REBASE_CHECK=1. Dogfooded live: this very branch was behind main after #309 merged, H11 blocked, I rebased, then the push passed.
PR-scoped format CI job (#311, the "CI never checks charset" fix)
New blocking job runs dotnet format --verify-no-changesscoped to the PR's changed .cs (vs merge-base) — enforcing fix-formatting-as-you-touch (style + charset=utf-8/no-BOM) without a big-bang reformat of the ~2500 legacy BOM files. A .cs-free PR (like this one) skips the expensive steps and passes trivially → always reports a status (safe as a required check). Closes the gap that let #269 land 17 BOM files (#310), since the pre-commit hook alone is --no-verify-bypassable.
scripts/issue-qualification-audit.sh: lists OPEN issues missing a priority: label (the #237 ranking keys off priority/gate labels, so an unlabeled issue is invisible to it). Milestone deliberately NOT required (backlog is unmilestoned). Advisory (exit 1 if any unqualified); fail-open without creds. Wired into the kickoff session-end protocol. Tested live (flagged #237, #22) + no-creds no-op.
Docs (same PR)
docs/contributing.md §7 — the fix-as-you-touch convention.
docs/handoffs/chicorytv-issue-queue.md — lore flipped from "merge main in" → "rebase on main" (H11); H12 added to the session-end step + a lore bullet.
docs/decisions.md — new entry (+ TOC) for the formatting-as-you-touch + rebase-not-merge decisions.
Verification
bash -n + shellcheck clean on both scripts; H11 pipe-tested (behind→block, current→allow, escape hatch, fail-open); H12 run against live Gitea + no-creds path; workflow YAML parses. Not docs-only → the H6/H10 merge gate applies (Review-verdict comment to follow after review).
fixes #311
fixes #312
Extends the #303 hook program with **H11**, **H12**, and a **PR-scoped format CI gate** — all prompted by the #309 session, where a stale branch *merged main in*, dragged legacy-BOM `.cs` it never touched into the commit, and the pre-commit format hook then blocked on code that wasn't the author's.
## H11 — rebase-before-push hook (#311)
`.claude/hooks/prepush-rebase-check.sh`, wired into `.husky/pre-push`: blocks a push whose branch is **behind `origin/main`** with `git rebase origin/main` guidance. Rebasing keeps your diff to what you touched; merging main in drags in others' files. Fail-open (offline / no origin/main / not-a-repo → allow, since a git hook has no "ask"); escape `ETV_SKIP_REBASE_CHECK=1`. **Dogfooded live**: this very branch was behind main after #309 merged, H11 blocked, I rebased, then the push passed.
## PR-scoped `format` CI job (#311, the "CI never checks charset" fix)
New blocking job runs `dotnet format --verify-no-changes` **scoped to the PR's changed `.cs`** (vs merge-base) — enforcing *fix-formatting-as-you-touch* (style + `charset=utf-8`/no-BOM) **without** a big-bang reformat of the ~2500 legacy BOM files. A `.cs`-free PR (like this one) skips the expensive steps and passes trivially → always reports a status (safe as a required check). Closes the gap that let #269 land 17 BOM files (#310), since the pre-commit hook alone is `--no-verify`-bypassable.
## H12 — session-end issue-qualification audit (#312)
`scripts/issue-qualification-audit.sh`: lists OPEN issues missing a `priority:` label (the #237 ranking keys off priority/gate labels, so an unlabeled issue is invisible to it). Milestone deliberately NOT required (backlog is unmilestoned). Advisory (exit 1 if any unqualified); fail-open without creds. Wired into the kickoff session-end protocol. **Tested live** (flagged #237, #22) + no-creds no-op.
## Docs (same PR)
- `docs/contributing.md` §7 — the fix-as-you-touch convention.
- `docs/handoffs/chicorytv-issue-queue.md` — lore flipped from "merge main in" → "rebase on main" (H11); H12 added to the session-end step + a lore bullet.
- `docs/decisions.md` — new entry (+ TOC) for the formatting-as-you-touch + rebase-not-merge decisions.
## Verification
`bash -n` + shellcheck clean on both scripts; H11 pipe-tested (behind→block, current→allow, escape hatch, fail-open); H12 run against live Gitea + no-creds path; workflow YAML parses. Not docs-only → the H6/H10 merge gate applies (Review-verdict comment to follow after review).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
- H11: .husky/pre-push calls .claude/hooks/prepush-rebase-check.sh, which blocks a
push whose branch is behind origin/main (rebase first; do not merge main in — a
merge drags in files you didn't touch, e.g. legacy-BOM .cs, tripping the format
hook on code that isn't yours). Fail-open; escape ETV_SKIP_REBASE_CHECK=1.
- New blocking `format` CI job: dotnet format --verify-no-changes scoped to the
PR's changed .cs only (style + charset=utf-8/no-BOM), enforcing fix-as-you-touch
without a big-bang reformat of the ~2500 legacy BOM files. .cs-free PRs skip and
pass (always reports a status). Closes the "CI never checks charset" gap that let
#269 land 17 BOM files (#310).
Docs (contributing.md §7 / decisions.md / lore) follow in the next commit.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- contributing.md §7: document fix-formatting-as-you-touch (normalize a legacy file you
edit, incl. BOM strip; no big-bang), enforced by the pre-commit hook + the new format CI job.
- kickoff lore: flip "merge main into PR branch" -> "rebase on origin/main" (H11 enforces it);
keep the regenerate-generated-artifacts-on-conflict nugget.
- decisions.md: new entry (+ TOC) for both decisions.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
scripts/issue-qualification-audit.sh: lists OPEN issues missing a `priority:` label
(the #237 ranking keys off priority:/gate labels, so an unlabeled issue is invisible
to it). "Fully qualified" = has a priority: label; gate-vs-backlog derives from the
review label / milestone, and a milestone is NOT required (backlog is unmilestoned).
Advisory (exit 1 if any unqualified); fail-open without Gitea creds. Wired into the
kickoff session-end protocol + a lore bullet. Tested live (flagged 2) + no-creds no-op.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Adversarial review (fork, scoped) verified all three artifacts empirically, not just by reading:
H11: ancestor logic correct across 9 cases (equal/ahead/rebased → allow; behind/diverged → block; offline/no-origin/not-a-repo → fail-open; escape hatch). No false-block of a genuinely-current push.
format CI job: changed-file detection mirrors the proven api-docs/docs-reminder pattern; skip-path passes trivially (safe as required check); --no-restore valid; migration-file false-fail neutralized (dotnet format skips <auto-generated> files, so BOM'd EF migrations don't trip it).
H12: jq label logic confirmed with crafted inputs (null/[]/PR/literal-prefix); pagination terminates; fail-open verified; live run flags #237/#22.
LOW by-design notes, none blocking: H11 keys off HEAD (not the pushed ref) — harmless, escape hatch covers the rare --delete; the format job verifies whole touched files (intended §7 "normalize when you touch it" friction).
Accepted deferral: the format job's active fail path (a touched .cs with a BOM → red) is logic-verified but not live-exercised by this PR (it touches no .cs, so only the skip→green path runs in this PR's CI). The next .cs-touching PR exercises it for real; #310 (de-BOM the 17 files) is a natural first exercise.
Review-verdict: MERGEABLE @ f1b25212
Adversarial review (fork, scoped) verified all three artifacts empirically, not just by reading:
- **H11**: ancestor logic correct across 9 cases (equal/ahead/rebased → allow; behind/diverged → block; offline/no-origin/not-a-repo → fail-open; escape hatch). No false-block of a genuinely-current push.
- **format CI job**: changed-file detection mirrors the proven `api-docs`/`docs-reminder` pattern; skip-path passes trivially (safe as required check); `--no-restore` valid; **migration-file false-fail neutralized** (`dotnet format` skips `<auto-generated>` files, so BOM'd EF migrations don't trip it).
- **H12**: jq label logic confirmed with crafted inputs (null/[]/PR/literal-prefix); pagination terminates; fail-open verified; live run flags #237/#22.
LOW by-design notes, none blocking: H11 keys off HEAD (not the pushed ref) — harmless, escape hatch covers the rare `--delete`; the format job verifies whole touched files (intended §7 "normalize when you touch it" friction).
**Accepted deferral**: the format job's active *fail* path (a touched `.cs` with a BOM → red) is logic-verified but not live-exercised by this PR (it touches no `.cs`, so only the skip→green path runs in this PR's CI). The next `.cs`-touching PR exercises it for real; #310 (de-BOM the 17 files) is a natural first exercise.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
fixes #311
fixes #312
Extends the #303 hook program with H11, H12, and a PR-scoped format CI gate — all prompted by the #309 session, where a stale branch merged main in, dragged legacy-BOM
.csit never touched into the commit, and the pre-commit format hook then blocked on code that wasn't the author's.H11 — rebase-before-push hook (#311)
.claude/hooks/prepush-rebase-check.sh, wired into.husky/pre-push: blocks a push whose branch is behindorigin/mainwithgit rebase origin/mainguidance. Rebasing keeps your diff to what you touched; merging main in drags in others' files. Fail-open (offline / no origin/main / not-a-repo → allow, since a git hook has no "ask"); escapeETV_SKIP_REBASE_CHECK=1. Dogfooded live: this very branch was behind main after #309 merged, H11 blocked, I rebased, then the push passed.PR-scoped
formatCI job (#311, the "CI never checks charset" fix)New blocking job runs
dotnet format --verify-no-changesscoped to the PR's changed.cs(vs merge-base) — enforcing fix-formatting-as-you-touch (style +charset=utf-8/no-BOM) without a big-bang reformat of the ~2500 legacy BOM files. A.cs-free PR (like this one) skips the expensive steps and passes trivially → always reports a status (safe as a required check). Closes the gap that let #269 land 17 BOM files (#310), since the pre-commit hook alone is--no-verify-bypassable.H12 — session-end issue-qualification audit (#312)
scripts/issue-qualification-audit.sh: lists OPEN issues missing apriority:label (the #237 ranking keys off priority/gate labels, so an unlabeled issue is invisible to it). Milestone deliberately NOT required (backlog is unmilestoned). Advisory (exit 1 if any unqualified); fail-open without creds. Wired into the kickoff session-end protocol. Tested live (flagged #237, #22) + no-creds no-op.Docs (same PR)
docs/contributing.md§7 — the fix-as-you-touch convention.docs/handoffs/chicorytv-issue-queue.md— lore flipped from "merge main in" → "rebase on main" (H11); H12 added to the session-end step + a lore bullet.docs/decisions.md— new entry (+ TOC) for the formatting-as-you-touch + rebase-not-merge decisions.Verification
bash -n+ shellcheck clean on both scripts; H11 pipe-tested (behind→block, current→allow, escape hatch, fail-open); H12 run against live Gitea + no-creds path; workflow YAML parses. Not docs-only → the H6/H10 merge gate applies (Review-verdict comment to follow after review).🤖 Generated with Claude Code
Review-verdict: MERGEABLE @
f1b25212Adversarial review (fork, scoped) verified all three artifacts empirically, not just by reading:
api-docs/docs-reminderpattern; skip-path passes trivially (safe as required check);--no-restorevalid; migration-file false-fail neutralized (dotnet formatskips<auto-generated>files, so BOM'd EF migrations don't trip it).LOW by-design notes, none blocking: H11 keys off HEAD (not the pushed ref) — harmless, escape hatch covers the rare
--delete; the format job verifies whole touched files (intended §7 "normalize when you touch it" friction).Accepted deferral: the format job's active fail path (a touched
.cswith a BOM → red) is logic-verified but not live-exercised by this PR (it touches no.cs, so only the skip→green path runs in this PR's CI). The next.cs-touching PR exercises it for real; #310 (de-BOM the 17 files) is a natural first exercise.