From 20a4bcce9db0618a52f64c97730a7822ab5663bc Mon Sep 17 00:00:00 2001 From: Evelyn Chen Date: Thu, 27 Aug 2026 18:36:13 +0000 Subject: [PATCH 1/3] Require scoped Bug titles Authored-By: Codex (GPT-5) --- README.md | 2 +- action.yaml | 2 +- check.sh | 3 +++ tests/run | 23 +++++++++++++---------- 4 files changed, 18 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 6636969..fa56042 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ action fails (exits 1) on any violation; `@v1` is the legacy warn-only release ``` Branch: /bug-/ e.g. dev/bug-x7k2m9/fix-terminal-resize Chore: chore/ bug-less trivia only (dep bumps, typos, CI tweaks) -Title: [bug-x7k2m9] Fix terminal resize loss (chore PRs: no [bug-id] prefix) +Title: [bug-x7k2m9] fix(terminal): preserve resize state ``` - `` must be a roster handle: `dev` | `ux` | `ops` | `security` | `perf` | `architect` | `support` diff --git a/action.yaml b/action.yaml index a052959..8bdf748 100644 --- a/action.yaml +++ b/action.yaml @@ -8,7 +8,7 @@ description: | Standard: branch: /bug-/ e.g. dev/bug-x7k2m9/fix-terminal-resize chore: chore/ bug-less trivia only - title: [bug-] Description (chore PRs: no [bug-id] prefix) + title: [bug-] type(scope): description Role must be a roster handle: dev | ux | ops | security | perf | architect | support Break-glass: PRs authored by dfritz are exempt. diff --git a/check.sh b/check.sh index ed81cea..7fc97bc 100755 --- a/check.sh +++ b/check.sh @@ -130,6 +130,9 @@ if [ "${BRANCH_KIND}" = "role-bug" ]; then elif [ "${TITLE_BUG}" != "${BRANCH_BUG}" ]; then echo "FAIL[check-naming]: bug-id mismatch — branch carries '${BRANCH_BUG}' but title carries '${TITLE_BUG}'" FAILED=1 + elif ! printf '%s\n' "${TITLE}" | grep -qE "^\\[${BRANCH_BUG}\\] [a-z][a-z0-9-]*\\([a-z0-9][a-z0-9-]*\\)!?: .+"; then + echo "FAIL[check-naming]: Bug-backed title must use '[${BRANCH_BUG}] type(scope): description'" + FAILED=1 fi tracking=$(printf '%s\n' "${VISIBLE_BODY}" | awk ' diff --git a/tests/run b/tests/run index 1ca7d5a..a63acde 100755 --- a/tests/run +++ b/tests/run @@ -48,7 +48,7 @@ check_contract() { local desc="$1" body="$2" base="$3" head="$4" diagnostic="$5" local out rc=0 out=$(cd "${FIXTURES}" && HEAD_BRANCH="architect/bug-x7k2m9/contract" \ - PR_TITLE="[bug-x7k2m9] Enforce contract" PR_AUTHOR="architect" \ + PR_TITLE="[bug-x7k2m9] fix(check): enforce contract" PR_AUTHOR="architect" \ PR_BODY="$body" GITEA_SERVER_URL="https://code.test" GITEA_TOKEN="test-token" \ GITEA_REPOSITORY="action/check-naming" GITEA_PR_NUMBER=1 PATH="${TEST_BIN}:$PATH" \ BASE_SHA="$base" HEAD_SHA="$head" bash "$SCRIPT" 2>&1) || rc=$? @@ -66,7 +66,7 @@ check_contract_pass() { local desc="$1" body="$2" base="$3" head="$4" local out rc=0 out=$(cd "${FIXTURES}" && HEAD_BRANCH="architect/bug-x7k2m9/contract" \ - PR_TITLE="[bug-x7k2m9] Enforce contract" PR_AUTHOR="architect" \ + PR_TITLE="[bug-x7k2m9] fix(check): enforce contract" PR_AUTHOR="architect" \ PR_BODY="$body" GITEA_SERVER_URL="https://code.test" GITEA_TOKEN="test-token" \ GITEA_REPOSITORY="action/check-naming" GITEA_PR_NUMBER=1 PATH="${TEST_BIN}:$PATH" \ BASE_SHA="$base" HEAD_SHA="$head" bash "$SCRIPT" 2>&1) || rc=$? @@ -103,13 +103,13 @@ check "dfritz exempt — invalid branch" 0 "totally/wrong-branch" "no prefix" check "dfritz exempt — mismatch" 0 "dev/bug-abc/thing" "[bug-xyz] Thing" "dfritz" # valid role/bug — all roster handles -check "dev/bug matching title" 0 "dev/bug-x7k2m9/fix-terminal-resize" "[bug-x7k2m9] Fix terminal resize" "dev" -check "architect/bug matching title" 0 "architect/bug-abc123/refactor-auth" "[bug-abc123] Refactor auth" "architect" -check "ops/bug matching title" 0 "ops/bug-zz9/deploy-tweak" "[bug-zz9] Deploy tweak" "ops" -check "security/bug matching title" 0 "security/bug-s1a2/patch-cve" "[bug-s1a2] Patch CVE" "security" -check "perf/bug matching title" 0 "perf/bug-p0p0/reduce-latency" "[bug-p0p0] Reduce latency" "perf" -check "ux/bug matching title" 0 "ux/bug-u1u1/polish-modal" "[bug-u1u1] Polish modal" "ux" -check "support/bug matching title" 0 "support/bug-sup9/clarify-error" "[bug-sup9] Clarify error" "support" +check "dev/bug matching title" 0 "dev/bug-x7k2m9/fix-terminal-resize" "[bug-x7k2m9] fix(terminal): preserve resize" "dev" +check "architect/bug matching title" 0 "architect/bug-abc123/refactor-auth" "[bug-abc123] refactor(auth): simplify boundary" "architect" +check "ops/bug matching title" 0 "ops/bug-zz9/deploy-tweak" "[bug-zz9] fix(delivery): preserve rollout" "ops" +check "security/bug matching title" 0 "security/bug-s1a2/patch-cve" "[bug-s1a2] fix(auth): close bypass" "security" +check "perf/bug matching title" 0 "perf/bug-p0p0/reduce-latency" "[bug-p0p0] perf(checker): reduce latency" "perf" +check "ux/bug matching title" 0 "ux/bug-u1u1/polish-modal" "[bug-u1u1] fix(modal): preserve focus" "ux" +check "support/bug matching title" 0 "support/bug-sup9/clarify-error" "[bug-sup9] docs(error): clarify recovery" "support" # valid chore form check "chore — no title prefix" 0 "chore/bump-deps" "Bump dependency versions" "dev" @@ -124,6 +124,9 @@ check "bug-id mismatch" 1 "dev/bug-x7k2m9/fix-resize" "[bug- # fail: chore branch with [bug-id] title prefix check "chore with bug-id title" 1 "chore/bump-deps" "[bug-abc123] Bump deps" "dev" check "role/bug Conventional title" 0 "dev/bug-x7k2m9/fix-resize" "[bug-x7k2m9] fix(hub): fix resize" "dev" +check "role/bug plain title" 1 "dev/bug-x7k2m9/fix-resize" "[bug-x7k2m9] Fix resize" "dev" +check "role/bug missing scope" 1 "dev/bug-x7k2m9/fix-resize" "[bug-x7k2m9] fix: fix resize" "dev" +check "role/bug path scope" 1 "dev/bug-x7k2m9/fix-resize" "[bug-x7k2m9] fix(hub/bugs): fix resize" "dev" check "chore Conventional title" 0 "chore/bump-deps" "chore(deps): bump deps" "dev" # fail: invalid branch forms @@ -214,7 +217,7 @@ canonical_body bug-x7k2m9 >> "${LARGE_BODY}" large_out="" large_rc=0 large_out=$(cd "${FIXTURES}" && HEAD_BRANCH="architect/bug-x7k2m9/contract" \ - PR_TITLE="[bug-x7k2m9] Enforce contract" PR_AUTHOR="architect" \ + PR_TITLE="[bug-x7k2m9] fix(check): enforce contract" PR_AUTHOR="architect" \ TEST_PR_BODY_FILE="${LARGE_BODY}" GITEA_SERVER_URL="https://code.test" GITEA_TOKEN="test-token" \ GITEA_REPOSITORY="action/check-naming" GITEA_PR_NUMBER=1 PATH="${TEST_BIN}:$PATH" \ BASE_SHA="$BASE" HEAD_SHA="$GOOD_HEAD" bash "$SCRIPT" 2>&1) || large_rc=$? -- 2.54.0 From 0789210d4e0e90cd9861898348dff064d8bc3bda Mon Sep 17 00:00:00 2001 From: Evelyn Chen Date: Thu, 27 Aug 2026 18:41:42 +0000 Subject: [PATCH 2/3] fix(check-naming): address title review feedback Authored-By: Codex (GPT-5) --- README.md | 9 ++++++--- check.sh | 4 ++-- tests/run | 2 ++ 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index fa56042..b9b3e3a 100644 --- a/README.md +++ b/README.md @@ -73,9 +73,12 @@ The check validates four things for every non-break-glass Agent PR: Unknown roles, missing `bug-` segment, uppercase bug-ids, and empty kebab descriptions all produce a `FAIL[check-naming]` log line. -2. **Title form** — for a `role/bug` branch the title must start with - `[bug-] `. For a `chore` branch the title must have no `[bug-id]` - prefix. If both carry a bug-id they must match. +2. **Title form** — for a `role/bug` branch the title must be + `[bug-] type(scope): description`. The type starts with a lowercase + letter and the type and one-component scope contain only lowercase letters, + digits, and hyphens. An optional `!` may follow the scope, and the description + must contain a non-whitespace character. For a `chore` branch the title must + have no `[bug-id]` prefix. If both carry a bug-id they must match. 3. **Tracking and attribution** — on Bug-backed work, `## Tracking` contains both the literal `Fixes bug-` automation token and the matching navigable diff --git a/check.sh b/check.sh index 7fc97bc..0297804 100755 --- a/check.sh +++ b/check.sh @@ -125,12 +125,12 @@ if [ "${BRANCH_KIND}" = "role-bug" ]; then if [ -z "${TITLE_BUG}" ]; then echo "FAIL[check-naming]: title must lead with [${BRANCH_BUG}]" echo " have: ${TITLE}" - echo " want: [${BRANCH_BUG}] ${TITLE}" + echo " want: [${BRANCH_BUG}] fix(scope): description" FAILED=1 elif [ "${TITLE_BUG}" != "${BRANCH_BUG}" ]; then echo "FAIL[check-naming]: bug-id mismatch — branch carries '${BRANCH_BUG}' but title carries '${TITLE_BUG}'" FAILED=1 - elif ! printf '%s\n' "${TITLE}" | grep -qE "^\\[${BRANCH_BUG}\\] [a-z][a-z0-9-]*\\([a-z0-9][a-z0-9-]*\\)!?: .+"; then + elif ! printf '%s\n' "${TITLE}" | grep -qE "^\\[${BRANCH_BUG}\\] [a-z][a-z0-9-]*\\([a-z0-9][a-z0-9-]*\\)!?: .*[^[:space:]]$"; then echo "FAIL[check-naming]: Bug-backed title must use '[${BRANCH_BUG}] type(scope): description'" FAILED=1 fi diff --git a/tests/run b/tests/run index a63acde..da90bf1 100755 --- a/tests/run +++ b/tests/run @@ -127,6 +127,8 @@ check "role/bug Conventional title" 0 "dev/bug-x7k2m9/fix-resize" "[bug- check "role/bug plain title" 1 "dev/bug-x7k2m9/fix-resize" "[bug-x7k2m9] Fix resize" "dev" check "role/bug missing scope" 1 "dev/bug-x7k2m9/fix-resize" "[bug-x7k2m9] fix: fix resize" "dev" check "role/bug path scope" 1 "dev/bug-x7k2m9/fix-resize" "[bug-x7k2m9] fix(hub/bugs): fix resize" "dev" +check "role/bug empty description" 1 "dev/bug-x7k2m9/fix-resize" "[bug-x7k2m9] fix(hub): " "dev" +check "role/bug whitespace description" 1 "dev/bug-x7k2m9/fix-resize" "[bug-x7k2m9] fix(hub): " "dev" check "chore Conventional title" 0 "chore/bump-deps" "chore(deps): bump deps" "dev" # fail: invalid branch forms -- 2.54.0 From ca4dccfbbf532431d23e2ce41def9921568c6fd4 Mon Sep 17 00:00:00 2001 From: Evelyn Chen Date: Thu, 27 Aug 2026 18:43:32 +0000 Subject: [PATCH 3/3] Document safe edited-event wiring Authored-By: Codex (GPT-5) --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index b9b3e3a..f7c35d0 100644 --- a/README.md +++ b/README.md @@ -48,7 +48,8 @@ jobs: The explicit `edited` activity is part of the enforcement contract: changing the PR description must issue a new naming status for the same commit. -Description-only events may skip unrelated validation jobs. +Keep required code-validation jobs in a separate workflow that does not run on +`edited`; Gitea treats a skipped required context as passing. To wire a new repo warn-only first, add `continue-on-error: true` to the job — the step still fails, but the job cannot block the PR. -- 2.54.0