Skip to content

Deepen Triage recommendation interpretation #2147

Closed

Description

@JacobStephens2

What to build

Give the Triage run one deep module for interpreting a session's recommendation, so fixes to category, state, questionnaire and target rules apply equally to the initial session, its correction, recommend-only and publication. Preserve the current user-visible behavior: for example, unpermitted ready-for-agent publication becomes needs-triage for a Report and ready-for-human for an existing issue, while recommend-only still reports what the session recommended.

This is one standalone Ticket, sized for one session. It has no release, host-setup or sibling-Ticket prerequisite.

Acceptance criteria

  • Initial and corrected session output cross the same recommendation interface. Successful interpretation returns complete, associated publication facts; callers cannot construct a partially resolved recommendation or must-fill optional state.
  • The module owns category fallback and repository spelling, state fallback, confirmation-blocked state, questionnaire normalization/eligibility, existing-target rules and readiness permission. Correction, investigation and publication no longer repeat those decisions or patch a shared filing after checking it.
  • Each proposed issue stays associated with its resolved category/state/readiness facts, and each proposed comment with its parsed target. Remove the independent recommendation/filing and comment/target vectors whose association currently depends on positional zip or index access.
  • Preserve current validation and correction behavior, including combined category/structural diagnostics, existing-issue cardinality and Agent Brief requirements, comment-only Reports, and the distinction between correctable recommendation errors and GitHub or Harness failures.
  • Preserve recommendation JSON, notification wording and sanitization, applied output updates, existing category preservation, read-only preflight, publication order and partial-publication links. Recommend-only and publication continue rejecting the same GitHub-invalid targets before any write.
  • Exercise combined interpretation rules through the deep module's interface and keep the existing CLI regressions for correction, Report/existing-issue readiness, recommend-only output, comment-target preflight, partial publication and private-finding notices passing.
  • Update the domain-to-code index to identify the new owner. This refactor introduces no new domain concept or ADR decision; existing Triage run and Report definitions continue to apply.
  • Run the repository's affected-test selector against main for final local validation.

Blocked by

None (can start immediately).

Decisions

The design tree is settled in the following rounds; each later round depends on the earlier round's choices.

Round 1 — responsibility and dependencies

  1. Deepen the Triage run's recommendation interpretation as one private module, absorbing the existing parsing, resolution and mode-policy fragments. These rules change together, but their present interface makes callers remember their order. Moving only the parsing functions would leave that shallow interface intact.
  2. Keep the dependency category in-process. Supply the captured repository category names, Report/existing-target mode and effective readiness permission as values. The module performs no GitHub reads, launches no sessions and needs no new adapter or trait; those facts already arrive through the existing GitHub and session adapters.

Round 2 — representation and policy

  1. Use one construction interface over the session's final message and the supplied context. Its result owns the validated recommendation, with an existing-target case containing exactly one issue and a Report case containing a collection. Keep resolved metadata mandatory and private to construction. This removes caller-side cardinality assumptions and the skipped optional resolved state.
  2. Keep each issue's proposed output and resolved filing facts together, and each comment's proposed output and parsed Issue URL together. Expose read-only publication projections and explicit recording of actual publication results. This supplies leverage to both publishing paths without making callers reconnect independent collections.
  3. Preserve the wire representation separately from derived facts. Overall category/state, spelling and omitted per-issue defaults stay as recommended; whitespace-only questionnaires still disappear, and existing-target output still receives the selected target's URL. Recommend-only must not eagerly replace recommendation fields with canonical or held filing values. Publication records body/category/state/URL updates at the same successful-effect points as today. This preserves stdout and notification compatibility, including failures partway through publication.
  4. Preserve every current interpretation rule: per-issue category overrides and fallback; case-insensitive category matching with repository spelling for filing; factory-label exclusion; per-issue state fallback; confirmation-blocked outcomes becoming ready-for-human; questionnaires required only for needs-info and forbidden otherwise after blank normalization; complete issue/comment text; syntactically valid comment targets; and existing-issue cardinality, allowed states, Agent Brief and self-comment rules. Category membership remains checked for proposed issues, so a comment-only Report still accepts a nonempty overall category without requiring it to be a repository label. These are compatibility decisions, not opportunities to broaden validation.
  5. Resolve permission holds inside interpretation: unpermitted ready-for-agent becomes needs-triage for a Report and ready-for-human for an existing target; permitted readiness remains ready-for-agent. Keep recommended state, confirmation-adjusted state and applied filing state distinct. This removes the investigation caller's special mutation while preserving the Agent Brief requirement based on the recommended/confirmation-adjusted outcome, even when readiness will be held.
  6. Retain the existing error aggregation contract: report a category error together with the structural or existing-mode error when both are present. Both session attempts use the same construction interface. A second interpretation failure still ends after the one correction; the refactor must not turn this into a new retry policy.

Round 3 — effects and compatibility

  1. Leave GitHub preflight outside the pure module. It checks every parsed comment target's repository and open status before any write, and rechecks the selected existing target after the session. It consumes already resolved projections rather than resolving categories or readiness again. GitHub failures remain outside the correction loop because another session cannot repair a failed read or a closed target.
  2. Keep the two publication adapters and their ordering. Report publication creates issues, cross-links them, closes wontfix issues and then comments; existing-target publication comments, edits labels while preserving existing categories, closes wontfix and then comments elsewhere. Record each landed create/comment immediately in the existing published-links bookkeeping. A failed effect must not mark untouched proposals as filed or lose successful links. Existing target title/body stay unchanged.
  3. Keep JSON serialization and readable notification projection with the owned recommendation. Preserve field sanitization and actual-result reporting. Keep private-finding notification replacement and failure redaction in their current caller, preserving ADR 0015; session launch, trust, sandbox and Claim lifetime remain governed by their existing modules and ADRs. No ADR is reopened.
  4. Preserve the currently merged questionnaire policy and leave Confirm Triage should reject questionnaires on ready-for-human (reversed by #2135) #2144's human decision untouched. Credential authority (Triage run: a session can label its own issue ready-for-agent with the user's gh login #1725), Triage Pass settling (A Triage Pass doesn't wait for an issue to settle, so it can triage a Spec before its Tickets are published #1965), prompt changes and new readiness behavior are outside this Ticket. The domain-to-code index changes because ownership moves; no glossary term is needed for an internal module named after the existing Triage run concept.

Round 4 — verification and size

  1. The interface is the test surface. Add focused in-process cases that combine category/state fallback, confirmation-blocked handling, blank/nonblank questionnaires, both target modes, readiness permission and combined errors. Assert returned publication projections, serialized output and diagnostics rather than internal storage or helper call order. Keep recommended output and applied output distinguishable in these cases so an eager-normalization regression is visible.
  2. Retain the CLI behavior tests as the highest seam for session correction, GitHub preflight and writes, recommend-only parity, actual-result serialization, existing-category preservation, partial failures and private notifications. Their fake Harness/GitHub adapters already provide the second adapter at those seams. Reuse them instead of creating another effect abstraction. Delete tests tied solely to any removed private helpers if such tests are introduced or encountered; retain the end-to-end regressions.
  3. Publish one Ticket because this is one interpretation implementation plus its existing callers and tests, with no independently useful intermediate release. Final validation uses the affected-test selector against main. The review itself is read-only and makes no product change to test.

Architecture review

Strength: Strong · Dependencies: in-process

Files: src/triage.rs, src/triage/correction.rs, src/triage/existing.rs, tests/triage_correction.rs, tests/triage_run.rs, tests/triage_issue.rs, tests/triage_spec_regressions.rs, docs/code-navigation.md

Before

flowchart LR
  R[Triage run] --> C[Correction]
  C --> S[State resolution]
  C --> K[Category resolution]
  C --> E[Existing-issue rules]
  R -. mode readiness .-> P[Publication checks]
  P -. category resolution .-> K
  R --> W[Publication adapters]
  W -. positional entries .-> P
  classDef leak stroke:#dc2626,stroke-width:2px;
  class P,W leak
Loading

After

flowchart LR
  R[Triage run] --> C[Correction]
  C --> I
  subgraph I[Triage run recommendation module]
    S[State resolution]
    K[Category resolution]
    E[Existing-issue rules]
  end
  R --> P[Publication checks]
  P -->|resolved projections| I
  R --> W[Publication adapters]
  W -->|associated entries| I
  classDef deep stroke-width:3px;
  class I deep
Loading

Problem: The shallow recommendation interface exposes resolution order and mode rules across correction, investigation and publication, reducing locality.

Evidence: At review head 69c8689b, correction resolves category/state, publication repeats category resolution and expects optional resolved state, investigation patches existing-target readiness, and publication zips independent collections; recent fixes #2018, #2019 and #2052 crossed the same seam.

Solution: Deepen the module by concentrating interpretation in one implementation whose interface owns associated resolved facts, keeping effects in the existing adapter implementations.

Deletion test: Removing the fragments eliminates caller knowledge; deleting the deep module would scatter the same policy back across callers.

Wins

  • Depth: complete interpretation per call
  • Locality: one recommendation policy
  • Leverage: both publication modes
  • Tests cross one interpretation seam

Covered by: No open issue proposes this deepening; all 188 open issue titles and bodies were reviewed. #2144 concerns questionnaire policy and #1725 credential trust, rather than this module's depth.

ADR fit: Preserves ADR 0013's session-launch decisions and ADR 0015's private-finding handling.

Activity

  1. added
    needs-triageMaintainer needs to evaluate this issue
    ready-for-agentFully specified, ready for an AFK agent
    architect-planAn Architect plan: the Spec or Ticket an Architecture review published
    in-progressA Claim: thirdshift has taken this issue
    and removed
    needs-triageMaintainer needs to evaluate this issue
    ready-for-agentFully specified, ready for an AFK agent
    in-progressA Claim: thirdshift has taken this issue
    on Nov 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    architect-planAn Architect plan: the Spec or Ticket an Architecture review published

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions