ADR-0017: Auto-Decompose Triage Path Excluded from Session Counter¶
Status: Accepted Enforced by: tests/test_state_machine.py Date: 2026-03-01
Context¶
In the triage phase (src/triage_phase.py), when an issue scores above the
epic_decompose_complexity_threshold and epic_auto_decompose is enabled,
_maybe_decompose() creates an epic plus child issues on GitHub, closes the
original issue, and marks it as "decomposed" in the state tracker.
Both call sites that execute increment_session_counter("triaged") sit
inside _triage_single:
- Normal plan routing (inside
_triage_single): counter incremented only when the issue is transitioned to theplanner_labelqueue — i.e., when decomposition did not fire (guarded byif not _maybe_decompose(...)). - ADR fast-path (inside
_triage_single): counter incremented when a valid ADR issue is routed directly toready— the function returns before_maybe_decomposeis called, so decomposition is never attempted for ADR issues.
When _maybe_decompose() returns True, the original issue is closed and
replaced by an epic + children. The "triaged" session counter is not
incremented for the original issue, nor for any of the newly created child
issues (those re-enter the pipeline as fresh find-labelled issues and will
be individually triaged and counted later).
This behaviour was introduced in PR #1689 (issue #1542) but was not explicitly documented as a design decision at the time. Memory #1729 flagged the gap: if epic auto-decomposition is used frequently, triage throughput metrics will be systematically lower than the actual number of issues processed by the triage phase.
Decision¶
The exclusion of auto-decomposed issues from the "triaged" session counter
is intentional and should remain as-is. The rationale:
-
Avoid double-counting. The original issue is closed, not planned. Its child issues will each be triaged individually and increment the counter when they reach the planning queue. Counting the parent would inflate the metric because the parent never enters planning or implementation.
-
Counter semantics = issues entering planning. The
"triaged"counter represents issues that successfully passed triage and were routed to the next pipeline phase (plan or ready). A decomposed issue is neither planned nor implemented — it is replaced. The counter should reflect actionable throughput, not raw processing volume. -
Decomposition is observable via other signals. The state tracker records
mark_issue(id, "decomposed"), therecord_issue_created()counter tracks child issue creation, and theEpicManagermaintains epic-to-child mappings. These provide sufficient visibility into decomposition activity without conflating it with triage throughput. -
HITL-routed issues are already excluded. Issues escalated to HITL during triage also do not increment the counter, establishing a consistent pattern: only issues that proceed forward in the pipeline are counted.
Consequences¶
Positive: - Triage throughput metrics accurately reflect issues entering planning/implementation, enabling reliable capacity planning. - No risk of double-counting when child issues are subsequently triaged. - Consistent counter semantics across all triage exit paths (plan, ready, HITL, decomposed).
Trade-offs:
- Dashboard triage counts will understate the total volume of issues
processed by the triage phase when decomposition is active. Operators
must check decomposition-specific metrics (epic count, child issue count)
for full visibility.
- If a future change introduces a "decomposed" session counter, callers
displaying "total triage work" will need to sum triaged + decomposed.
Alternatives considered¶
-
Increment
"triaged"for decomposed issues too. Rejected: inflates the counter with issues that never enter planning, making throughput metrics unreliable for capacity planning. Also risks double-counting when child issues are subsequently triaged. -
Add a separate
"decomposed"session counter. Viable future enhancement but not required today — decomposition activity is already observable viamark_issue(id, "decomposed")andrecord_issue_created(). A dedicated counter could be added if dashboard reporting needs evolve. -
Count decomposed as
triagedbut subtract children later. Rejected: introduces coupling between counter logic and epic lifecycle tracking, making the metric harder to reason about.
Related¶
- Source memory: #1729
- Original implementation: PR #1689 (issue #1542)
src/triage_phase.py—_maybe_decompose(),triage_issues()src/state.py—StateTracker.increment_session_counter(),StateTracker.mark_issue()- ADR-0001 (Five concurrent async loops — triage is loop 1)