feat(foreman): label/assignee heuristics driven by agents.json #468
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!468
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "dev/452"
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
suggestLabels/suggestAssigneeregexes out of source and intoagents.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
bun test apps/server/src/http/handlers/foreman.test.ts)exclude_patternonarea:testingsuppresses match when body contains "user story"default_assigneeoverride respectedjust qacleanCloses #452
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>CI green. All ACs met.
Schema correct:
label_rules,assignee_rules,default_assigneeland onAgentTypeConfig, parsed with full validation inparseType(), stored as frozen arrays.agents.jsonvalues are byte-for-byte identical toBUILTIN_*constants, satisfying "defaults match current hardcoded behaviour exactly". Config-absent fallback chain (rulesOverride ?? cfg?.types.foreman?.label_rules ?? BUILTIN_LABEL_RULES) is correct.suggestAssigneehandles bothwhen_labelandwhen_patternbranches. Tests cover every existing routing rule plusexclude_pattern,when_pattern, first-match wins, and customdefault_assignee.Nit (not blocking):
parseType()validates thatpattern/exclude_pattern/when_patternare non-empty strings but doesn't compile them asRegExp. An invalid pattern (e.g.[unclosed) would pass the loader and throw at runtime insidesuggestLabels/suggestAssignee. Worth atry { new RegExp(ro.pattern) } catch { throw … }guard in the loader if you edit these fields again.