feat(routing): hoist webhook-routing tables to agents.json (#450) #472
No reviewers
Labels
No labels
area:agents
area:dashboard
area:database
area:design
area:design-review
area:flows
area:infra
area:meta
area:security
area:sessions
area:webhook
area:workdir
security
type:bug
type:chore
type:meta
type:user-story
No milestone
No project
No assignees
2 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
charles/claude-hooks!472
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "boss/450"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Move every routing constant out of
webhook-routing.tsand into per-type fields onagents.json(role,routes_labels,reviews_authors,reviews_labels,skill_overrides,dispatchable) plus a top-leveldefault_reviewer_type; the loader compiles them into the routing snapshot at boot viaapplyRoutingFromConfig.Closes #450
Test plan
bun x turbo run typecheckclean (4 packages)bun x @biomejs/biome@^2 format .cleanbun x @biomejs/biome@^2 check .exits 0 (only pre-existing infos)bun test— every existing routing test passes against the baked defaults; new#450 — agents.json drives the routing tablesdescribe exercises the config-driven path (label re-route, dispatchable flip, default-reviewer swap, reviews_authors / reviews_labels, skill_overrides)just devto verify the productionagents.jsonboots and the dispatcher still routesarea:design→ designer /area:dashboard→ design-reviewera5763e03058f0d8157c9All six per-type routing fields land correctly in
agents.jsonandAgentTypeConfig,parseTypeRoutingvalidates every field loud-on-error with pre-#450 defaults as fallback,applyRoutingFromConfigwires the compiled snapshot at boot, and the bakedBAKED_DEFAULT_INPUTfaithfully mirrors the old hardcoded tables.Nit (not blocking):
applyRoutingFromConfigguards against a non-dispatchabledefault_reviewer_typebut silently accepts one that isn't ininput.typesat all — the loader catches this upstream, so no runtime gap exists today, but a future direct caller could slip through. Worth a one-linerif (!input.types[input.default_reviewer_type]) throw …for completeness in a follow-up.