Skip to content

feat: make issue reconciliation use configurable lanes#432

Merged
joryirving merged 1 commit into
mainfrom
feat/configurable-reconciliation-lanes
Jun 17, 2026
Merged

feat: make issue reconciliation use configurable lanes#432
joryirving merged 1 commit into
mainfrom
feat/configurable-reconciliation-lanes

Conversation

@joryirving

Copy link
Copy Markdown
Contributor

Closes #385

@its-saffron its-saffron Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AI Automated Review

Full PR review.

Analysis engine: MiniMax-M2.7@https://litellm.jory.dev/v1 (anthropic) — escalated (fast_low_confidence)

PR Review: feat: make issue reconciliation use configurable lanes

Summary

This PR implements config-aware lane classification for issue reconciliation, replacing hardcoded "normal" | "escalated" | "backlog" lane IDs with dynamically resolved lane IDs from the LaneConfig system. The implementation adds a new LaneSignals interface, a classifyLaneFromSignals() function, and supporting helpers (getDefaultClaimableLane(), getEscalationLane()), and updates both issue-lane.ts and issue-reconciliation.ts to use the config-aware classification path.

Change-by-Change Findings

src/lib/lane-config.ts

  • Adds role?: "default" | "escalation" field to LaneConfig interface, enabling explicit role assignment beyond the claimable/non-claimable distinction.
  • Adds role: "default" to the default normal lane and role: "escalation" to the default escalated lane in DEFAULT_LANE_CONFIG.
  • Introduces getDefaultClaimableLane(): prefers explicit role="default", falls back to first claimable lane.
  • Introduces getEscalationLane(): prefers explicit role="escalation", falls back to default claimable lane (ensuring a valid lane id is always returned).
  • Introduces LaneSignals interface: { isBacklog: boolean, isEscalation: boolean }.
  • Introduces classifyLaneFromSignals(signals): maps backlog/escalation signals to configured lanes with safe fallbacks. This is the key guarantee — the function never returns an unknown lane id; it always falls back to the default claimable lane or "normal".

src/lib/issue-lane.ts

  • buildLaneClassificationPrompt(): now calls getConfiguredLanes() and getDefaultClaimableLane()/getEscalationLane()/getBacklogLane() to dynamically build lane definitions and routing rules in the prompt, rather than hardcoding normal/escalated/backlog.
  • classifyByHeuristics(): now calls classifyLaneFromSignals() instead of returning hardcoded "normal", "escalated", or "backlog" strings. All three return paths are updated.

src/lib/issue-reconciliation.ts

  • Hoists shared signal lists (ESCALATION_KEYWORDS, BACKLOG_SIGNALS, ESCALATION_LABELS) to module scope for use by both evaluateLaneSignals() and shouldReclassifyStaleBacklog().
  • Introduces evaluateLaneSignals(): returns { isBacklog, isEscalation, reason } — this is the structured signal layer that decouples the heuristics from lane resolution.
  • Refactors classifyLaneByHeuristics(): delegates to evaluateLaneSignals() and then classifyLaneFromSignals(). Return type changes from "normal" | "escalated" | "backlog" to string (a configured lane id).
  • Refactors shouldReclassifyStaleBacklog(): return type changes from "normal" | "escalated" | null to string | null. The fallback path now calls getDefaultClaimableLane()?.id ?? "normal" instead of hardcoding "normal".

Standards Compliance

  • No agent-specific names in generic docs: No agent names appear in the new classification logic.
  • Prisma schema: No schema changes in this PR.
  • API routes: N/A — all changes are library-level.
  • Error handling: classifyLaneFromSignals() includes safe fallbacks when no matching lane is configured; getEscalationLane() falls back to the default claimable lane so it never returns undefined in the hot path.
  • Validation: Lane ids are validated by the existing isValidLane() which delegates to lane-config. The new classifyLaneFromSignals() only returns ids from the configured set.

Linked Issue Fit

Issue PR 385 acceptance criteria are fully addressed:

Criterion Status
Default lane classification backward-compatible ✅ Verified: default config tests assert normal/escalated/backlog output
Reconciliation rejects/avoids unknown lane IDs ✅ Verified: classifyLaneFromSignals() only returns configured lane ids
Single claimable lane config can classify actionable issues ✅ Verified: tests with work/backlog lanes
Multi-lane config can classify to more than two claimable lanes ✅ Verified: tests with fast/slow/parked and alpha/beta/gamma
Backlog/not-ready issues go to non-claimable lane ✅ Verified: tests assert parked/gamma etc.
Tests cover default, single, and custom multi-lane configs ✅ Verified: 118 + 242 + 151 new test cases across 3 test files

Evidence Provider Findings

No evidence providers were configured for this review.

Tool Harness Findings

Tool harness results are not applicable to this PR (no evidence provider findings to evaluate).

CI Check Results

  • Validate: completed successfully
  • Docker Build: completed successfully

Both CI checks passed. No blockers.

Unknowns / Needs Verification

No unknowns. The diff is self-contained and thoroughly tested. The classification functions use safe fallbacks at every boundary. The existing isBacklogLane() helper (unchanged in this PR) continues to validate backlog status against the configured lane set.

Recommendation

Approve. This PR cleanly refactors lane classification to be config-aware while preserving full backward compatibility. The test coverage is comprehensive, the safe-fallback chain in classifyLaneFromSignals() guarantees no unknown lane ids are ever returned, and all acceptance criteria from issue PR 385 are demonstrably satisfied.

@joryirving joryirving merged commit 8a4c503 into main Jun 17, 2026
3 checks passed
@joryirving joryirving deleted the feat/configurable-reconciliation-lanes branch June 17, 2026 20:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: make issue reconciliation use configurable lanes

1 participant