feat(flows): NF-6 Phase 4A — issue.labeled label-routing flow #380
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!380
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "feat/flows-issue-labeled-route"
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?
First Phase 4 cutover candidate. Mirrors legacy
webhook-handlers.ts::handleIssueLabeledend-to-end so anode_flows.suppress_legacy: ["issue.labeled"]cutover keeps every guard rail.What
Pipeline:
src.labelsAfter→forge.route_label→agent.resolve_by_type→agent.render_skill→agent.dispatch.Two new nodes:
agent.resolve_by_type— parallel toagent.resolve_by_loginbut goes throughresolveAgentByType(label routes return type names, not Forgejo logins). SameResolvedAgentEnvelopeoutput, same FILTER_DROP-on-miss semantics. Refactored the 12-field FILTER_DROP envelope into a sharedemitResolvedEnvelopehelper.forge.route_label— table-driven first-match. Walksinputs.labels: string[]againstargs.routes: Record<label, {agent, skill}>and emits(type, skill, matched_label)for the first matching label (FILTER_DROP otherwise). Mirrors legacywebhook-routing.ts::routeForLabels.New baked-in flow at
apps/server/src/domain/flows/issue-labeled-graph.{json,ts}. Same load-time validation + seed-time version-bump migration as the default flow. Seeded alongside the default flow at boot viaseedDefaultFlowAtBoot.flow-dispatch.tsgains a parallelresolveAgentByTypeinjection sharing a newenvelopeFromAgentprojection helper.Tests
area:design→ designer/implement,area:design-review→ design-reviewer/review, non-routing labels silent skip, first-match-wins (legacy parity — no double-dispatch when both routing labels present), unconfigured agent no-op.Cutover
After a soak window of zero divergence on
GET /flows/divergence/summary, set:and the legacy
handleIssueLabeledarm is dead.Phase 4 ship order (from research map)
issue-labeled-routepr-approved-mergereview-requestedslash-breakdownpr-changes-requestedissue-closed-depsissue.assignedcutoverpr-fixci-probe🤖 Generated with Claude Code
First Phase 4 cutover candidate. Mirrors legacy `webhook-handlers.ts::handleIssueLabeled` end-to-end so a `node_flows.suppress_legacy: ["issue.labeled"]` cutover keeps every guard rail. Pipeline: src.labelsAfter → forge.route_label (table-driven first-match against `area:design` / `area:design-review`) → agent.resolve_by_type (envelope from `resolveAgentByType`) → agent.render_skill (template + appendices) → agent.dispatch (enable_dedup + cancel_stale). New nodes: - `agent.resolve_by_type` — parallel to `agent.resolve_by_login` but via `resolveAgentByType` (label routes return type names, not Forgejo logins). Same `ResolvedAgentEnvelope` output, same FILTER_DROP-on-miss semantics. - `forge.route_label` — table-driven first-match. Walks `inputs.labels: string[]` against `args.routes: Record<labelName, {agent, skill}>` and emits `(type, skill, matched_label)` of the first match (FILTER_DROP otherwise). Matches legacy `routeForLabels`. Refactor: shared `emitResolvedEnvelope` helper between the two resolve nodes (was duplicated 12-field FILTER_DROP-on-miss block). `flow-dispatch.ts` gains a parallel `resolveAgentByType` injection sharing the same `envelopeFromAgent` projection helper. New baked-in flow: `apps/server/src/domain/flows/issue-labeled-graph.{json,ts}`. Same load-time validation + seed-time version-bump migration as the default flow. Seeded alongside the default flow at boot. Tests: 6 new e2e on the flow (area:design / area:design-review / non- routing labels silent skip / first-match-wins / unconfigured agent no-op) + 1 schema sanity. All green; 1861 server tests pass total (was 1855 pre-Phase-4A); 5 pre-existing failures unchanged. Cutover: after a soak window of zero divergence on `GET /flows/divergence/summary`, set `node_flows.suppress_legacy: ["issue.assigned", "issue.labeled"]` and the legacy `handleIssueLabeled` arm is dead. Risk-ordered next per Phase 4 design map: `pr-approved-merge` (S), then `review-requested` (S), then `slash-breakdown` (S), then `pr-changes-requested` (M), `issue-closed-deps` (M), `pr-fixci-probe` (L). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>