feat(foreman): label/assignee heuristics driven by agents.json #468

Merged
code-lead merged 1 commit from dev/452 into main 2026-04-27 16:04:25 +00:00
Collaborator

Move suggestLabels/suggestAssignee regexes out of source and into agents.json::types.foreman.{label_rules,assignee_rules,default_assignee}. Operators can now add new area labels and routing rules without a code edit. Built-in constants serve as fallback when config is absent.

Test plan

  • All 57 foreman tests pass (bun test apps/server/src/http/handlers/foreman.test.ts)
  • Each existing routing rule verified via config-driven path: design→designer, security→reviewer, dashboard/api/testing→dev
  • exclude_pattern on area:testing suppresses match when body contains "user story"
  • default_assignee override respected
  • just qa clean

Closes #452

Move `suggestLabels`/`suggestAssignee` regexes out of source and into `agents.json::types.foreman.{label_rules,assignee_rules,default_assignee}`. Operators can now add new area labels and routing rules without a code edit. Built-in constants serve as fallback when config is absent. ## Test plan - [ ] All 57 foreman tests pass (`bun test apps/server/src/http/handlers/foreman.test.ts`) - [ ] Each existing routing rule verified via config-driven path: design→designer, security→reviewer, dashboard/api/testing→dev - [ ] `exclude_pattern` on `area:testing` suppresses match when body contains "user story" - [ ] `default_assignee` override respected - [ ] `just qa` clean Closes #452
feat(foreman): label/assignee heuristics driven by agents.json
All checks were successful
qa / qa (pull_request) Successful in 9m19s
qa / dockerfile (pull_request) Successful in 12s
abffc8aa33
Move hardcoded suggestLabels/suggestAssignee regexes into
agents.json::types.foreman.{label_rules,assignee_rules,default_assignee}.
Functions read from resolved config at runtime; built-in constants
serve as fallback when config is absent (bare test environments).
Defaults match existing hardcoded behaviour exactly. (#452)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
dev requested review from reviewer 2026-04-27 16:01:40 +00:00
reviewer approved these changes 2026-04-27 16:04:03 +00:00
reviewer left a comment

CI green. All ACs met.

Schema correct: label_rules, assignee_rules, default_assignee land on AgentTypeConfig, parsed with full validation in parseType(), stored as frozen arrays. agents.json values are byte-for-byte identical to BUILTIN_* constants, satisfying "defaults match current hardcoded behaviour exactly". Config-absent fallback chain (rulesOverride ?? cfg?.types.foreman?.label_rules ?? BUILTIN_LABEL_RULES) is correct. suggestAssignee handles both when_label and when_pattern branches. Tests cover every existing routing rule plus exclude_pattern, when_pattern, first-match wins, and custom default_assignee.

Nit (not blocking): parseType() validates that pattern / exclude_pattern / when_pattern are non-empty strings but doesn't compile them as RegExp. An invalid pattern (e.g. [unclosed) would pass the loader and throw at runtime inside suggestLabels / suggestAssignee. Worth a try { new RegExp(ro.pattern) } catch { throw … } guard in the loader if you edit these fields again.

CI green. All ACs met. Schema correct: `label_rules`, `assignee_rules`, `default_assignee` land on `AgentTypeConfig`, parsed with full validation in `parseType()`, stored as frozen arrays. `agents.json` values are byte-for-byte identical to `BUILTIN_*` constants, satisfying "defaults match current hardcoded behaviour exactly". Config-absent fallback chain (`rulesOverride ?? cfg?.types.foreman?.label_rules ?? BUILTIN_LABEL_RULES`) is correct. `suggestAssignee` handles both `when_label` and `when_pattern` branches. Tests cover every existing routing rule plus `exclude_pattern`, `when_pattern`, first-match wins, and custom `default_assignee`. Nit (not blocking): `parseType()` validates that `pattern` / `exclude_pattern` / `when_pattern` are non-empty strings but doesn't compile them as `RegExp`. An invalid pattern (e.g. `[unclosed`) would pass the loader and throw at runtime inside `suggestLabels` / `suggestAssignee`. Worth a `try { new RegExp(ro.pattern) } catch { throw … }` guard in the loader if you edit these fields again.
code-lead deleted branch dev/452 2026-04-27 16:04:25 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
charles/claude-hooks!468
No description provided.