chore(flows): align default graph with real TriggerEventIssueAssigned shape (#361) #362

Merged
code-lead merged 1 commit from chore/361-default-graph-refs into main 2026-04-24 15:50:39 +00:00
Collaborator

NF-6 dry-run smoke test caught a shape mismatch between the baked default graph (NF-4) and the actual TriggerEventIssueAssigned payload emitted by NF-1. Fixing the references is a small mechanical chore; behavior verified via the dry-run harness.

Root cause

Default graph referenced:

  • src.out.routedType (driving router.switch) — doesn't exist on the trigger.
  • src.out.issueNumber, src.out.labels — flat fields; the real trigger has them under src.out.issue.number / src.out.issue.labels.

Result: agent.dispatch errored with type: expected non-empty string, got undefined.

Fix

  • Route on src.out.assignee (Forgejo username = agent type 1:1 in the shipped agents.json).
  • Rewrite src.out.issueNumbersrc.out.issue.number; src.out.labelssrc.out.issue.labels.
  • Kept the designer / design-reviewer / assignee-fallback three-way branch. Routing policy stays inside the graph — no new fields on the shared TriggerEvent contract.
  • Bumped DEFAULT_GRAPH_VERSION 1 → 2 so the seed migration rewrites the flows row on next restart. Graph.version (DSL schema version) stays at 1 — separate concept.

Verified end-to-end

Dry-run harness against three assignees on the shadow DB:

assignee=dev              → dispatch_by_assignee     intent {type:"dev"      skill:"implement"}  status=ok
assignee=designer         → dispatch_designer         intent {type:"designer" skill:"implement"}  status=ok
assignee=design-reviewer  → dispatch_design_reviewer  intent {type:"design-reviewer" skill:"review"}  status=ok

Other branches correctly marked skipped in each run; flow_node_runs.intent rows populated as expected.

Test plan

  • bun test apps/server/src/domain/flows/default-graph.test.ts — 14/14 (updated version assertion).
  • bun test apps/server/src/domain/flows/flow-dispatch.test.ts — 20/20.
  • bun test apps/server — 1735 pass / 4 pre-existing fails (sweeper + foreman, unrelated).
  • bun x turbo run typecheck — clean.
  • bun x biome check — clean on touched files.

Out of scope

  • Adding a util.route_agent_type registry node for reusable label-based routing — defer until a second consumer needs it (YAGNI).
  • Expanding default-graph coverage to PR review / CI / slash-command paths — NF-6 follow-up work tracked in the spec.

Closes #361.

🤖 Generated with Claude Code

NF-6 dry-run smoke test caught a shape mismatch between the baked default graph (NF-4) and the actual `TriggerEventIssueAssigned` payload emitted by NF-1. Fixing the references is a small mechanical chore; behavior verified via the dry-run harness. ## Root cause Default graph referenced: - `src.out.routedType` (driving `router.switch`) — doesn't exist on the trigger. - `src.out.issueNumber`, `src.out.labels` — flat fields; the real trigger has them under `src.out.issue.number` / `src.out.issue.labels`. Result: `agent.dispatch` errored with `type: expected non-empty string, got undefined`. ## Fix - Route on `src.out.assignee` (Forgejo username = agent type 1:1 in the shipped `agents.json`). - Rewrite `src.out.issueNumber` → `src.out.issue.number`; `src.out.labels` → `src.out.issue.labels`. - Kept the designer / design-reviewer / assignee-fallback three-way branch. Routing policy stays inside the graph — no new fields on the shared `TriggerEvent` contract. - Bumped `DEFAULT_GRAPH_VERSION` 1 → 2 so the seed migration rewrites the `flows` row on next restart. `Graph.version` (DSL schema version) stays at 1 — separate concept. ## Verified end-to-end Dry-run harness against three assignees on the shadow DB: ``` assignee=dev → dispatch_by_assignee intent {type:"dev" skill:"implement"} status=ok assignee=designer → dispatch_designer intent {type:"designer" skill:"implement"} status=ok assignee=design-reviewer → dispatch_design_reviewer intent {type:"design-reviewer" skill:"review"} status=ok ``` Other branches correctly marked `skipped` in each run; `flow_node_runs.intent` rows populated as expected. ## Test plan - [x] `bun test apps/server/src/domain/flows/default-graph.test.ts` — 14/14 (updated version assertion). - [x] `bun test apps/server/src/domain/flows/flow-dispatch.test.ts` — 20/20. - [x] `bun test apps/server` — 1735 pass / 4 pre-existing fails (sweeper + foreman, unrelated). - [x] `bun x turbo run typecheck` — clean. - [x] `bun x biome check` — clean on touched files. ## Out of scope - Adding a `util.route_agent_type` registry node for reusable label-based routing — defer until a second consumer needs it (YAGNI). - Expanding default-graph coverage to PR review / CI / slash-command paths — NF-6 follow-up work tracked in the spec. Closes #361. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
chore(flows): align default graph with real TriggerEventIssueAssigned shape (#361)
All checks were successful
qa / qa (pull_request) Successful in 4m43s
qa / dockerfile (pull_request) Successful in 12s
1c7cf740cf
NF-6 dry-run smoke test exposed a shape mismatch between the baked
default graph (NF-4) and the actual `TriggerEventIssueAssigned` payload
from the NF-1 converter. The graph referenced `src.out.routedType` +
`src.out.issueNumber` + `src.out.labels`, none of which exist on the
real trigger — `agent.dispatch` was erroring with `type: expected
non-empty string, got undefined`.

Fix: rewrite every input ref to match the real shape. Route on
`src.out.assignee` (the Forgejo username — which matches the agent
type 1:1 in today's agents.json). Nested fields become
`src.out.issue.number` / `src.out.issue.labels`.

Kept the designer / design-reviewer / assignee-fallback three-way
branch. Routing policy stays inside the graph — did NOT add a
`routedType` to the trigger (would pollute the shared contract).

Bumped DEFAULT_GRAPH_VERSION 1 → 2 so the seed migration detects the
drift + rewrites the `flows` row on next restart. Graph DSL schema
version stays at 1 (that's the `Graph.version` schema marker, a
separate concept).

Verified end-to-end via the dry-run harness against three assignees:
- assignee=dev → dispatch_by_assignee fires with type=dev
- assignee=designer → dispatch_designer fires with skill=implement
- assignee=design-reviewer → dispatch_design_reviewer fires with skill=review

All runs recorded `status=ok` with correct `flow_node_runs.intent`
rows; the other branches correctly marked `skipped`.

Closes #361.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
code-lead deleted branch chore/361-default-graph-refs 2026-04-24 15:50:39 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
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!362
No description provided.