Skip to content

review: tier the 27 paths that were falling to the router's default - #322

Merged
jwbron merged 2 commits into
mainfrom
review-tier-unrated-paths
Aug 5, 2026
Merged

review: tier the 27 paths that were falling to the router's default#322
jwbron merged 2 commits into
mainfrom
review-tier-unrated-paths

Conversation

@jwbron

@jwbron jwbron commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

The consumer-config checker from #317 reported that 27 of this repo's 430 tracked files matched no tier= rule and silently took the router's default low. Most were harmless. One group was not.

The one that matters

workflows/autofix/lib/*.ts was low. That code decides what the autofix workflow does, and autofix pushes commits to PRs. workflows/review/lib/** sits right next to it at high. There is no reading on which the autofix enforcement layer is lower-risk than the reviewer's; it was low purely because no rule named it.

Also raised to high

Path Why
.github/aw/actions-lock.json SHA pins for every third-party action our compiled workflows run; a diff changes which third-party code executes in our CI.
.github-staging/** A workflow staged for a human git mv into .github/workflows/ is CI the moment it moves. It is reviewed here or nowhere.
workflows/*/package.json, workflows/*/package-lock.json review.md's pre-agent step runs npm ci against the released lockfile inside a consumer's CI, so a dependency added here executes in every consuming repo.

Medium

Config that shapes releases, review routing, or what the reviewer itself can see, without being executable:

  • .changeset/config.json — shapes what gets versioned and tagged. Medium rather than high because the publish code in utils/ and its version-sync test are the actual gate.
  • .github/REVIEWERS — the router's only source of team ownership, so a wrong line silently routes reviews to the wrong team, or to nobody.
  • .gitattributes — decides which files the reviewer treats as generated and therefore skips entirely.
  • .cursor/rules/** — same reasoning as .claude/skills/** one directory over: Cursor rules steer an agent working in this repo, so they are executable instructions the broad docs rule would otherwise drop to trivial.
  • package.json, tsconfig.json.

Low, explicitly

Lint/format/test wiring, type shims, .github/NOTIFIED, and eval output. These were already effectively low; naming them means the next unrated file is a signal rather than noise.

Review fixes

Both review findings are addressed in ff66dcb.

.github-staging/** tier=high was silently defeated for .md files (blocking). Tier resolution is last-match-wins and the broad **/*.md tier=trivial rule sits below it, so a staged agentic workflow's .md source — the frontmatter carrying permissions, secrets and network, plus the prompt — routed as trivial, while only the compiled .lock.yml got high. Backwards, and it defeats the rule's only reason for existing. .github/workflows/*.md tier=high already exists to re-raise workflow sources after the docs rule; this adds the same re-raise for the staging pen:

.github-staging/review.md                  -> high  via .github-staging/**/*.md
.github-staging/workflows/review.md        -> high  via .github-staging/**/*.md
.github-staging/workflows/review.lock.yml  -> high  via .github-staging/**
.github-staging/review-smoke.yml           -> high  via .github-staging/**

risk-classification.md had drifted from ROUTING, and this PR would have codified the split. The two files are injected into the same reviewer, so shipping a disagreement in a PR whose whole purpose is making tiers deliberate would be self-defeating. Aligned in both directions: the autofix lib, the staging pen, workflows/*/package{,-lock}.json and the gh-aw action lockfile move to High; config/, types/, .eslintrc.js and pnpm-workspace.yaml drop to Low, where ROUTING already puts them and where their actual contents belong (config/ is only tests/setup.ts, types/ only ambient .d.ts shims); tsconfig.json splits out and stays Medium on its own footing, since it decides which shipped code pnpm typecheck covers at all.

Two remedies I declined, with reasoning in-thread: a leading ** tier=medium catch-all would not merely mute the unrated-file signal, it would delete the detector (the checker computes its unmatched set as !riskRules.some(...), which a ** rule satisfies for every path), and promoting the checker's warning to an error is already just its documented --strict flag, which needs a CI job in #317 rather than a config change here.

One divergence left in place deliberately: workflows/review/eval/*.ts is Medium in the prose and low in ROUTING. That predates this PR in both files, and closing it means deciding what review depth the eval suite deserves, which is a tier judgment rather than a consistency edit.

Verification

check-consumer-config.ts --files-from reported 0 errors, 0 warnings over all 430 files at the first commit (was 1 warning naming the 27). high goes 100 → 109.

Corrected after review: the honest number is now 0 errors and 1 expected warning. The .github-staging/**/*.md fix is the only pattern in the file matching no tracked file today, so once #317 lands it will surface in the checker's deadPatterns — anticipated by that code's own comment ("Deliberately dead patterns exist (a rule written ahead of the directory it guards), hence a warning rather than an error"). This is inherent to a prospective rule: .github-staging/ holds one tracked file today and it is a .yml, so no sweep over current files can exercise the .md path. Verified directly that the fix regresses nothing: the tier sweep over all 430 tracked files is byte-identical before and after it (111 high, 109 after the generated-file exemption for the two .lock.yml).

Each tier is checked with --explain rather than inferred, including the ordering case that matters — autofix's own tests must still land at low:

Explanation: workflows/autofix/lib/scope.ts
  tier    high
  rules   (last one wins)
            workflows/autofix/lib/**  tier=high

Explanation: workflows/autofix/lib/scope.test.ts
  tier    low
  rules   (last one wins)
            workflows/autofix/lib/**  tier=high
            **/*.test.ts  tier=low

No recompile: ROUTING is read at run time by the router, not embedded at compile time. No changeset: this changes only .github/aw/review/, this repo's own reviewer config, which ships in no package and is excluded from check-for-changeset (precedent: #277 changed ROUTING alone with no changeset).

One thing worth arguing with

workflows/*/package-lock.json at high puts a lockfile in the highest tier. Tier drives review depth and budget rather than whether the file is read line-by-line, and a dependency addition that lands in every consumer's CI seems worth the depth — but if you'd rather it were medium, that's a defensible read.

Follow-up, not this PR

tsconfig.json's include lists actions/**, utils/**, types/**, config/** and vitest.config.ts, so pnpm typecheck does not cover workflows/** at all — nothing typechecks the reviewer lib today. I hit that in #320, where a rename invalidated a call site and only the tests caught it. The review noted that a risk tier is the wrong layer to fix this with, which is correct; tsconfig.json's Medium tier stands on its own reasoning above, and the coverage gap wants its own PR.

…ng to the router's default

The consumer-config checker (#317) reported that 27 of this repo's 430 tracked
files matched no `tier=` rule and silently took the router's default `low`. Most
were harmless, but one group was not.

`workflows/autofix/lib/*.ts` was `low`. That code decides what the autofix workflow
does and it PUSHES COMMITS to PRs, so it has at least the blast radius of
`workflows/review/lib/**` sitting next to it at `high`. It was low purely because
no rule named it. Also now `high`: `.github/aw/actions-lock.json` (the SHA pins for
every third-party action our compiled workflows run), `.github-staging/**` (a
workflow staged for a human `git mv` into .github/workflows/ is CI the moment it
moves, and is reviewed here or nowhere), and `workflows/*/package{,-lock}.json`
(review.md's pre-agent step runs `npm ci` against the released lockfile inside a
consumer's CI, so a dependency added here executes in every consuming repo).

Medium for config that shapes releases, review routing, or what the reviewer can
see, without being executable: .changeset/config.json, .github/REVIEWERS (the only
source of the router's team ownership), .gitattributes (which files the reviewer
skips as generated), root package.json, and tsconfig.json.

Low, explicitly rather than by default, for the dev-only remainder: lint/format/test
wiring, type shims, .github/NOTIFIED, and eval output.

Checker now reports 0 errors and 0 warnings over all 430 files; high goes 100 -> 109.
Each tier is spot-checked with --explain rather than inferred, including that
autofix's own tests still fall to low via `**/*.test.ts`.
@changeset-bot

changeset-bot Bot commented Aug 4, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: ff66dcb

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@khan-actions-bot
khan-actions-bot requested review from a team, jeresig and kevinb-khan and removed request for a team August 4, 2026 01:13

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changes requested — see inline comments.

Comment thread .github/aw/review/ROUTING
Comment thread .github/aw/review/ROUTING
Comment thread .github/aw/review/ROUTING
Comment thread .github/aw/review/ROUTING
# The autofix workflow's enforcement layer. It PUSHES COMMITS to PRs in consuming
# repos, so it has at least the blast radius of the reviewer lib beside it; it was
# falling to the default `low` purely because no rule named it.
workflows/autofix/lib/** tier=high

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (non-blocking): This enumerates the 27 symptoms but leaves the fail-open root cause: unmatched paths still default to low. The PR's own diagnosis is 'it was low purely because no rule named it', and router.ts still hard-codes config.defaultTier ?? "low" (router.ts:530) with the only safety net being a checker warning the description says was already easy to miss. Since later rules win, a ** tier=medium rule placed FIRST would be overridden by every explicit rule below it and make unnamed files fail toward medium instead of low — though it would mute the 'next unrated file is a signal' property, so the alternative is promoting the checker's unmatched-file warning to an error.

A sketch, not a committable replacement:

Either add a leading `**  tier=medium` catch-all (last-one-wins means all existing rules still override it), or make check-consumer-config treat unmatched files as an error rather than a warning — one of the two closes the recurrence path this PR documents.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed on the diagnosis, declining both remedies here, and I went and read the checker rather than arguing from the description.

The ** tier=medium catch-all is worse than muting the signal; it deletes the detector. check-consumer-config.ts computes the unmatched set as !riskRules.some((rule) => matchesGlob(file.path, rule.pattern)). A leading ** rule matches every path by construction, so unmatched is permanently empty and the warning that produced this PR can never fire again. The warning was easy to miss, which is your point; a check that is structurally incapable of firing is not the fix for one that is easy to miss. It would also silently move every genuinely-low unrated file to medium, and tier drives review budget, so that is a repo-wide spend increase to guard a case the checker already names.

The warning-to-error promotion is the right idea and is already an invocation choice, not a code change. The checker takes --strict, documented as "errors exit 1; warnings exit 0 unless --strict". So there is no code to write; what is missing is a CI job that runs it that way. That job cannot be added in this PR because the checker is not on main yet: it lives in #317, still open. Adding it here would either duplicate the file or depend on an unmerged branch. It belongs in #317 or a follow-up once #317 lands, and I would rather it be --strict in CI than a catch-all in the config, because it fails loudly at the moment of introduction instead of quietly absorbing the file.

One thing this PR does owe you, though, and it is a real disclosure. Once #317 lands, the fix for the blocking finding above (.github-staging/**/*.md tier=high) will itself trip a warning: it is the only pattern in the file matching no tracked file today, so it lands in the checker's deadPatterns. That is anticipated by the checker's own comment ("Deliberately dead patterns exist (a rule written ahead of the directory it guards), hence a warning rather than an error"), and it is exactly the tradeoff this thread is about: a prospective rule cannot be verified by a sweep over current files. So the honest verification number is 0 errors and 1 expected dead-pattern warning, not 0/0. I updated the description to say that instead of leaving the earlier 0/0 claim standing.

…d align the prose with ROUTING

Two review findings on #322.

`.github-staging/** tier=high` was silently defeated for `.md` files. Tier
resolution is last-match-wins, and the broad `**/*.md tier=trivial` rule sits
below it, so a staged agentic workflow's `.md` source (the frontmatter carrying
permissions, secrets and network, plus the prompt) routed as trivial while only
the compiled `.lock.yml` got `high`. That is backwards, and it defeats the rule's
whole reason for existing. `.github/workflows/*.md tier=high` already exists to
re-raise workflow sources after the docs rule; this adds the same re-raise for
the staging pen. Verified with the repo's own parseRoutingConfig + matchesGlob:
`.github-staging/workflows/review.md` went trivial -> high, and
`.github-staging/**/*.md` matches at depth 1 as well as deeper. The sweep over
all 430 tracked files is byte-identical before and after (111 high, or 109 after
the generated-file exemption), confirming the rule is purely prospective: nothing
under `.github-staging/` is a `.md` today.

risk-classification.md (model-facing prose, injected into the same reviewer) had
drifted from ROUTING and this PR would have codified the split. Aligned: the
autofix lib, the staging pen, `workflows/*/package{,-lock}.json` and the gh-aw
action lockfile move to High; `config/`, `types/`, `.eslintrc.js` and
`pnpm-workspace.yaml` drop to Low, where ROUTING already puts them and where
their actual contents belong (vitest setup and ambient `.d.ts` shims);
`tsconfig.json` stays Medium on its own since it decides typecheck coverage;
`.changeset/config.json`, `.github/REVIEWERS`, `.gitattributes` and the
agent-steering prose dirs are named at Medium.

Left alone deliberately: `workflows/review/eval/*.ts` is Medium in the prose and
`low` in ROUTING. That divergence predates this PR and resolving it is a real
tier decision about eval review depth, not a consistency edit.
@khan-actions-bot
khan-actions-bot requested a review from a team August 4, 2026 17:37
@github-actions

github-actions Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Review Guidance

github-actions (2 files)
File Reason
ROUTING Sets the tiers and budgets every review of this repo runs at, so a wrong line under last-rule-wins silently sheds review depth on supply-chain files.
risk-classification.md Model-facing prose imported into the reviewer's prompt; it defines the risk tiers applied to every future PR, so an error here steers every review.

Common patterns

2 files: Parallel config + documentation update — the same paths (.github-staging/**, workflows/autofix/lib/**, workflows/*/package.json, workflows/*/package-lock.json, .github/aw/*.json) are promoted to tier=high in the machine-readable ROUTING file and simultaneously described with matching justifications in risk-classification.md.

- (no rule for workflows/autofix/lib/**)
+ workflows/autofix/lib/**     tier=high
---
- (no high-risk entry for autofix lib)
+ - **The autofix workflow's enforcement layer**: `workflows/autofix/lib/**`. It decides what autofix does, and autofix PUSHES COMMITS to consumer PRs...

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

3 of 4 prior review threads resolved; 1 still unaddressed as of ff66dcb:

1 non-blocking thread still open
  • suggestion (non-blocking) .github/aw/review/ROUTING:40: This enumerates the 27 symptoms but leaves the fail-open root cause: unmatched paths still default to low. The PR's ow...
Note: divergence tripwire re-armed a full review (unreviewed share 0.50).

Comment thread .github/aw/review/ROUTING
# defeated for exactly the file that carries the frontmatter -- permissions,
# secrets, network -- and the prompt. Nothing in the pen is docs; it holds files
# awaiting a `git mv` into .github/workflows/.
.github-staging/**/*.md tier=high

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thought (non-blocking): The .github-staging/**/*.md re-raise patches one instance of a structural ordering hazard the file keeps. **/*.md tier=trivial (line 56) still comes after every directory-high rule, so each new high directory must remember its own re-raise; workflows/*/*.md tier=high (line 58) is single-star and does not reach lib/ subdirectories. I checked: neither lib dir contains a .md today, so this is latent, but the PR itself is evidence the trap fires in practice.

A sketch, not a committable replacement:

Consider restructuring so broad demotions (`**/*.md`, `**/*.test.ts`) sit before the specific directory escalations — with last-wins, escalation-late/demotion-early makes high directories win by construction and retires the re-raise pattern (audit the few paths whose tier would shift, e.g. `actions/**/*.md`).

@jwbron
jwbron merged commit 20f3d4f into main Aug 5, 2026
10 checks passed
@jwbron
jwbron deleted the review-tier-unrated-paths branch August 5, 2026 16:05
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.

2 participants