Skip to content

feat(triage): classify fix availability across main, RC, and stable releases (#1097) - #1144

Draft
danielgap wants to merge 9 commits into
Gentleman-Programming:mainfrom
danielgap:feat/1097-fix-availability
Draft

feat(triage): classify fix availability across main, RC, and stable releases (#1097)#1144
danielgap wants to merge 9 commits into
Gentleman-Programming:mainfrom
danielgap:feat/1097-fix-availability

Conversation

@danielgap

Copy link
Copy Markdown
Contributor

🔗 Linked Issue

Closes #1097


🏷️ PR Type

  • type:feature — New feature

(label request: type:feature, I am pull-only so a maintainer needs to apply it)


📝 Summary

  • Deterministic fix-availability classification for confirmed canonical issue matches: unresolved, reachable from main, earliest containing SemVer prerelease, or earliest containing stable release.
  • Fix evidence comes only from timeline cross-referenced PRs proven merged (merge commit required); tags and commit reachability come from the compare API with pinned contained statuses; any ambiguity degrades to a conservative ambiguous verdict and never fails the run.
  • Reporter version from the bug form's Engram Version field drives routing: minimum fixed version, possible-regression routing instead of silent consolidation, and explicit "not yet generally available" wording for main-only and RC fixes.

📂 Changes

File Change
internal/triage/fixavail.go New: evidence types, FixEvidenceSource, self-contained SemVer tag parsing, pure ClassifyFixAvailability, bounded CollectFixEvidence, reporter-version extraction
internal/triage/fixavail_test.go New: parsing/comparison/extraction tables, 21-case classification decision table, fake-backed conservativeness tests (caps, budgets, error paths)
internal/triage/rest.go RESTClient implements FixEvidenceSource: MergedFixPRs, ListTags, CommitContainedIn (compare statuses pinned)
internal/triage/rest_test.go httptest coverage: timeline filtering, pagination caps, accepted compare statuses
internal/triage/triage.go Optional Options.FixSource; Run classifies accepted candidates; evidence failures never fail the run
internal/triage/comment.go renderFixAvailability: one availability line plus one routing line per classified match
internal/triage/score.go Match.Fix optional field
internal/triage/run_test.go TestRunFixAvailabilityWiring: nil-source byte-identical baseline, rendering, conservative degradation
cmd/engram/triage.go Default-off --fix-availability flag with injectable source
cmd/engram/triage_test.go Flag parsing and wiring tests

🧪 Test Plan

  • Unit tests pass locally: go test ./... (clean, under umask 022 due to the known pre-existing socket-test environment sensitivity)
  • E2E tests pass locally: go test -tags e2e ./internal/server/...
  • Lint passes locally: golangci-lint is not available locally; gofmt and go vet are clean on all changed files, and the errcheck/staticcheck patterns from feat(triage): detect potential duplicate issues (#1095) #1107's CI round were checked during review
  • Strict TDD: classifier tables written RED first, then implemented to GREEN; independent read-only verification agent mapped all 9 acceptance criteria to file:line evidence and reported zero blockers

Manual: nil FixSource proven byte-identical to the pre-change renderer output (wiring test plus an out-of-tree baseline comparison of 714ef68 vs this tree).


🤖 Automated Checks

Run automatically; the type:* label check needs a maintainer to apply type:feature.


✅ Contributor Checklist

  • I linked an approved issue above (Closes #1097)
  • I added exactly one type:* label to this PR (requested: type:feature, maintainer-side)
  • I ran unit tests locally: go test ./...
  • I ran e2e tests locally: go test -tags e2e ./internal/server/...
  • I ran lint locally (gofmt + go vet; golangci-lint delegated to CI)
  • Docs updated if behavior changed (feature is default-off; no user-visible behavior change without the flag)
  • Commits follow conventional commits format
  • No Co-Authored-By trailers in commits
  • I checked every changed path against the Transient Artifact Policy

💬 Notes for Reviewers

Chain context

Stacked on #1107 (the triage package this builds on), which targets main from a fork branch, so this PR cannot target the parent branch directly and also targets main. Until #1107 merges, the Changes tab shows the union of both; review this PR as commit 90b874b and the file table above. Draft on purpose: it flips to ready as soon as #1107 lands, at which point the diff collapses to just this work unit. Closes #1097 takes effect on merge.

#1107 (feat: detect duplicate issues, targets main)  ← merges first
  └── 📍 THIS PR (feat: fix availability, targets main, stacked)
        └── follow-up: #1096 (consolidate confirmed duplicates)

Size note

+2027/−7 with roughly two thirds being new tests. One honest slicing pass found no split that lands independently: the classifier, its REST evidence source, and the wiring are one cohesive unit and the tests must stay with the unit they verify. Recommend accepting as size:exception; review focus is fixavail.go (classifier conservativeness), rest.go (timeline decoding, compare status pinning), and comment.go (wording).

Verification provenance

TDD evidence plus an independent read-only verification pass (9/9 acceptance criteria mapped to code and tests, 4 behavioral spot-checks, zero blockers). The native four-lens review could not run this round: the START consent seam looped with instantly-expiring bindings (gentle-pi#748, recurrence documented there); it will be re-run once that defect is fixed.

Known conservative limitations (deliberate)

  • Default branch assumed main; other defaults degrade every compare to ambiguous.
  • Regression routing is defined against the earliest STABLE fix only, matching the issue's wording.
  • Evidence is collected before the rejection-stands check; wasted API calls only, output unaffected.
  • Per-candidate tag scans are not cached yet; the feature is default-off in the workflow, so this is follow-up optimization territory, not a blocker.

…tion (Gentleman-Programming#1095)

Extend the client-failure table with ensure-label, remove-label, and
update-comment failures: EnsureLabel failure must prevent add-label,
RemoveIssueLabel failure must leave the anchored comment untouched, and
UpdateComment must fail on both the candidate-update and no-candidates
reconciliation paths, each with its exact expected call log.
…age --repo fallback

Address both CodeRabbit findings from the 2026-09-10 review round:

- rejectDeleteHelpTarget now also rejects the literal "help" target, so
  "engram delete project help" can never cascade-delete a project named
  "help"; covered by TestCmdDeleteRejectsLiteralHelpTargets (session and
  project subtests seed records named "help" and assert usage routing
  with rows intact).
- The triage-duplicates usage text now states that --repo is optional
  when GITHUB_REPOSITORY (OWNER/NAME) is set.
…eleases (Gentleman-Programming#1097)

Deterministic fix-availability classification for confirmed canonical
issue matches, stacked on the Gentleman-Programming#1095 triage package.

Evidence contract: a fix is inferred only from timeline cross-referenced
PRs that are proven merged (merge commit SHA required); issue prose and
non-merged PRs never count. Tags and commit reachability come through
the compare API with pinned contained statuses; any error, cap
exhaustion, or budget limit degrades to conservative ambiguous and never
fails the run.

Classification covers unresolved, reachable from main, earliest
containing SemVer prerelease, and earliest containing stable release,
with per-channel unions across multiple fix commits and backports. The
reporter's version is parsed from the bug form's Engram Version field:
reports older than the earliest stable fix get the minimum fixed
version, same-or-newer reports route as possible regressions instead of
silent consolidation, and main-only or RC fixes are stated as not yet
generally available.

The classifier is pure and table-tested; Run gains an optional FixSource
dependency that is nil by default and byte-identical to the previous
behavior, and the triage-duplicates command gains a default-off
--fix-availability flag.
@coderabbitai

coderabbitai Bot commented Sep 11, 2026

Copy link
Copy Markdown

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

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(triage): classify fix availability across main, RC, and stable releases

1 participant