Skip to content

fix: give the catch-all zones a real owner, and catch silent CODEOWNERS breakage - #203

Merged
qiuethan merged 1 commit into
stagingfrom
qiuethan/codeowners-catchalls
Aug 16, 2026
Merged

fix: give the catch-all zones a real owner, and catch silent CODEOWNERS breakage#203
qiuethan merged 1 commit into
stagingfrom
qiuethan/codeowners-catchalls

Conversation

@qiuethan

Copy link
Copy Markdown
Collaborator

What this changes

Closes two CODEOWNERS gaps, both of which fail silently — no error, no red X, reviews just quietly go to the wrong person or nobody.

No ownership is assigned here. Every line is still @qiuethan; this is the structural groundwork so that adding real owners is safe.

Why

1. Unregistered services and packages had no owner

docs/CODE-OWNERSHIP.md flagged this as "latent, not yet biting": services/other and packages/other had no CODEOWNERS line and resolved through the * fallback. Invisible while every owner is one person — wrong the moment they diverge, because a new service would auto-request whoever holds * rather than anyone who knows it.

Bare /services/ and /packages/ lines now own those buckets.

Their position is load-bearing, and it's the mirror image of pr-zone-check.yml:

Resolution So the catch-all goes
zone_for() first match wins below the specific arms
CODEOWNERS last match wins above the specific lines

Put /services/ below and it swallows every service — services/llm would be reviewed by the catch-all owner instead of its own. check-labels.mjs now enforces the position, not just the presence.

root still resolves through *, and always will: it isn't a directory, and "every top-level file" is exactly what * already means.

2. A broken owner entry is completely silent

Name someone who isn't a collaborator, or who has read-only access, and GitHub never requests them and never says why. The zone looks owned. You find out when something merges unreviewed.

codeowners-valid.yml asks GitHub's own parser (/codeowners/errors) on every change to the file. This is deliberately a separate job from label-consistency — that one is offline and structural (does the zone list agree with itself); this one is a live lookup against org membership. check-labels.mjs structurally cannot catch it: it sees a line per zone, not whether the handle on that line can review.

Zone

.github · docs · scripts

Three zones. The CODEOWNERS change, the check that enforces it, and the doc describing it have to land together or label-consistency fails on its own first run.

How to verify

make labels

Injected failures into a copy of the tree, all caught:

  • catch-all moved below the specific lines → "'/services/connectors/' is listed ABOVE the '/services/' catch-all, so the catch-all overrides it (last match wins)"
  • catch-all line deleted → "zone 'packages/other' has no owner: add a '/packages/' line…"

The new workflow was tested against a deliberately broken CODEOWNERS on a throwaway ref (created and deleted via the API). Both failure modes are reported with file, line and column:

::error file=.github/CODEOWNERS,line=31,col=8::Unknown owner on line 31: make sure
@definitely-not-a-real-user-9f3a exists and has write access to the repository
::error file=.github/CODEOWNERS,line=32,col=11::Invalid owner on line 32:

That test also caught a bug in my first draft: the API's message field is multi-line (it quotes the offending line and points a caret at the column), which broke both the markdown summary and the annotation. Fixed — summary takes the full message in a code block, annotation takes the first line only.

Checklist

  • Branched off staging and targeting staging.
  • make labels clean; all workflow YAML parses; the new run: block passes bash -n.
  • Docs updated — the zone table's CODEOWNERS column, the "latent" note, and the opposite-resolution-order explanation.
  • Python suites not run — this PR touches no Python.

Deployment notes

Nothing to do at deploy time. codeowners-valid is not a required status check; add it in branch protection if you want it to gate.

Anything you're unsure about

The /services/ and /packages/ lines change who gets auto-requested for an unregistered service — from the * fallback owner to the workspace catch-all owner. Identical today (both @qiuethan), diverges as soon as owners do. That's the intent, but it's the line to look hardest at.

🤖 Generated with Claude Code

…RS breakage

Two ownership gaps, both of which fail silently.

An unregistered service or package had no CODEOWNERS line and resolved
through the `*` fallback, so it auto-requested whoever holds `*` rather
than anyone who knows it. docs/CODE-OWNERSHIP.md flagged this as "latent,
not yet biting" — invisible while every owner is the same person, wrong
the moment they diverge. Bare `/services/` and `/packages/` lines now own
those two buckets.

Their position is load-bearing and inverted relative to pr-zone-check.yml:
CODEOWNERS is last-match-wins, so a catch-all must sit ABOVE the specific
lines to be overridden by them. Below, it would swallow every service.
check-labels.mjs now enforces the position, the presence, and the
services/packages -> */other mapping.

Second gap: naming an owner who is not a collaborator, or who has
read-only access, produces no error anywhere. GitHub simply never requests
them — the zone looks owned and reviews go nowhere. codeowners-valid.yml
asks GitHub's own parser and fails on it. Verified against a deliberately
broken file on a throwaway ref: both an unknown handle and a malformed
owner are reported with file, line and column.

check-labels.mjs cannot cover this — it sees a line per zone, not whether
the handle on that line can review — so it is a separate job.

`root` still resolves through `*` and always will: it is not a directory,
and "every top-level file" is exactly what `*` already means.

No ownership is assigned here; every line is still @qiuethan.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@github-actions github-actions Bot added size/l < 500 lines changed zone: docs Owned by the docs zone (docs/CODE-OWNERSHIP.md) zone: scripts Owned by the scripts zone (docs/CODE-OWNERSHIP.md) zone: .github Owned by the .github zone (docs/CODE-OWNERSHIP.md) zone: root Owned by the root zone (docs/CODE-OWNERSHIP.md) and removed size/l < 500 lines changed labels Aug 16, 2026
@qiuethan
qiuethan merged commit bb59bd7 into staging Aug 16, 2026
18 checks passed
@qiuethan
qiuethan deleted the qiuethan/codeowners-catchalls branch August 16, 2026 23:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/l < 500 lines changed zone: docs Owned by the docs zone (docs/CODE-OWNERSHIP.md) zone: .github Owned by the .github zone (docs/CODE-OWNERSHIP.md) zone: root Owned by the root zone (docs/CODE-OWNERSHIP.md) zone: scripts Owned by the scripts zone (docs/CODE-OWNERSHIP.md)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant