Skip to content

Add issue-triage: which issues to work on today, in four buckets - #20

Merged
aarora79 merged 2 commits into
mainfrom
issue-triage
Oct 7, 2026
Merged

aarora79 merged 2 commits into
mainfrom
issue-triage

Conversation

@aarora79

@aarora79 aarora79 commented Oct 7, 2026

Copy link
Copy Markdown
Owner

A pull request carries a diff, so a tool can ask a model what reviewing it will cost. An issue carries prose, and the cost of the fix is not in it. So this sample asks only questions an issue body can settle, takes everything else from the GitHub API, and hands both to a second call that answers one question: when should somebody pick this up.

It writes one markdown file grouping the queue into today, this week, this month, and when time permits.

How it works

Two Jev calls per issue.

Stage one asks eight questions about the text: the kind of report, whether it touches security or performance, which of six coarse areas it concerns, whether somebody says they are blocked, whether there is a repro, whether it proposes a fix, and how urgently the body says it is needed.

Stage two reads a dozen lines of facts and no body at all, so a persuasively written issue has to win on its evidence rather than its adjectives. The facts are days open, days idle, whether a pull request is linked, who filed it, and who has been commenting, all of which GitHub knows exactly.

The decision is a Score whose four levels are the buckets, so the fraction Jev returns between levels orders the issues inside each one. Go rounds the score, caps today at five and this week at fifteen, spills the overflow down one bucket and records that it moved.

What measurement decided

The areas are coarse because the fine ones did not work. Over 284 closed issues whose fixes could be checked, asking about an externally visible area agreed with where the fix landed 74% to 91% of the time. Asking about one internal service package against another dropped to 10% to 16%. A reporter knows their problem showed up in the browser or while deploying; they do not know which package owns it.

Rounding is enough, so there is no clustering. The 106 open issues spread 4 / 15 / 67 / 20 across the four buckets. The binary prints that distribution every run and warns if three quarters ever land in one.

The comment role counts overlap rather than partition. A maintainer who files an issue and then replies on it has written both a reporter comment and a maintainer comment. Treating the roles as exclusive left the maintainer count at zero, so the thread read as an outside reporter nobody had answered. The maintainer filed 49 of these 106 issues, and counting the roles independently took the "waiting on a reply" count from 23 to 5. Both survivors were checked against GitHub by hand.

Nothing is fitted, and nothing pretends to be. The obvious target is how long an issue took to close, and over 374 closed issues the ones labelled security took thirty times longer than the ones labelled bug. That is a record of delay, so fitting weights to it would make the delay the goal. The weights live in questions.yml and the thresholds in score.go, declared where a diff shows them. The output is judged by reading it: every row names the signal that put it there, and -explain prints the whole decision.

What this removes

build_module_map.py and modules.yml measured a twelve-destination map from git history and priced an effort estimate from it. That estimate scored 23% on one tier and called ten large changes trivial, and the fine-grained areas are the ones that measured at 10% to 16%. Dropping both also removes the per-repository setup, so the tool now needs owner/repo and nothing else.

It also removes samples/pr-triage/install.sh, a superseded draft of pr-triage/vend/install.sh that was never committed and that nothing references. It installed the binary only when none was on PATH, so re-running it left an old binary beside a current skill.

Verified

Against agentic-community/mcp-gateway-registry on 7 October 2026:

  • 106 open issues in 10 seconds for $0.0093 over 221,768 input tokens
  • a seeded sample of 25 closed issues, whose single Today pick was #1834, a login regression behind a proxy that somebody did fix
  • gofmt, go vet and 17 tests clean
  • build.sh producing five static targets with SHA256SUMS
  • every flag the vended skill names present in -h, every relative link in the docs resolving
  • no key, emoji or binary in the diff

Both committed runs are in samples/issue-triage/data/, and the design is written up in explainer.md with a self-contained HTML twin.

After merge

The vended skill fetches from main and go/install.sh resolves the newest issue-triage/ tag, so the release has to follow the merge. I will cut issue-triage/0.1.0 from a clean clone and confirm vcs.modified=false before uploading, since a dirty-tree build publishes checksums nobody can reproduce.

An issue carries no diff, so Jev cannot be asked what a fix will cost. It can be
asked where the fix will land, and build_module_map.py measures what landing
there has cost before, from git log.

The file splits in two. The measured half (cost_median_files, cost_p75_files,
variance_ratio, obligations) comes from history and from the workflow path
filters. The judgement half (description, globs, risk) is written by hand, so a
cold run proposes clusters and leaves it blank, and --refresh recomputes the
measurements while preserving everything a person wrote.

Two heuristics did not survive measurement on mcp-gateway-registry, so both are
gone. Classifying obligations by commit share put the core package in with the
test suite: tests touches 36% of commits and registry 33%. The solo-change rate
was worse, with registry at 10% and auth_server at 8%, both below tests at 15%,
because registry cannot change without its tests and the pairing looks the same
from either side. Obligations are now a name list, and the script records both
figures as evidence for whoever curates the file.

--check enforces one invariant: every tracked file maps to a destination or an
obligation. An unmapped path gets no cost lookup and fails quietly, which is how
registry/utils went missing from an earlier draft of the map, caught only when a
live Jev call disagreed with it.

Verified against ~/repos/mcp-gateway-registry: 1633 commits over 240 days, a
cold run proposing 14 destinations, then the curated 12 with coverage clean and
measured costs from 3 median files for docs-and-skills to 12 for registry-core.
ruff check, ruff format --check and py_compile all clean.
A pull request carries a diff, so a tool can ask a model what reviewing it will
cost. An issue carries prose, and the cost of the fix is not in it. So this asks
only questions a body can settle, takes everything else from the GitHub API, and
hands both to a second call that answers one question: when should somebody pick
this up.

Two calls per issue. The first asks eight questions about the text: what kind of
report it is, whether it touches security or performance, which of six coarse
areas it concerns, whether somebody says they are blocked, whether there is a
repro, whether it proposes a fix, and how urgently the body says it is needed.
The second reads a dozen lines of facts and no body at all, so a persuasively
written issue has to win on its evidence rather than its adjectives. Facts are
days open, days idle, whether a pull request is linked, who filed it, and who
has been commenting.

The decision is a Score whose four levels are the output buckets, so the
fraction Jev returns between levels orders the issues inside each bucket. Go
rounds the score, caps today at five and this week at fifteen, spills the
overflow down one bucket and records that it moved. Rounding is enough on a real
queue: 106 open issues spread 4 / 15 / 67 / 20 across the four, and the binary
prints the distribution every run and warns if three quarters ever land in one.

The areas are coarse because measurement said so. Over 284 closed issues whose
fixes could be checked, asking about an externally visible area agreed with
where the fix landed 74% to 91% of the time, and asking about one internal
service package against another dropped to 10% to 16%. A reporter knows their
problem showed up in the browser or while deploying; they do not know which
package owns it.

The comment counts split by role with bots excluded, and the two role counts
overlap rather than partition. A maintainer who files an issue and then replies
on it has written both a reporter comment and a maintainer comment, and treating
the roles as exclusive left the maintainer count at zero so the thread read as
an outside reporter nobody had answered. On this repository the maintainer filed
49 of 106 open issues, and counting the roles independently took the "waiting on
a reply" count from 23 to 5. Both survivors were checked against GitHub by hand.

Nothing here is fitted, and nothing pretends to be. The obvious target is how
long an issue took to close, and over 374 closed issues the ones labelled
security took thirty times longer than the ones labelled bug. That is a record
of delay, so fitting weights to it would make the delay the goal. The weights
live in questions.yml and the thresholds in score.go, declared where a diff
shows them, and the output is judged by reading it: every row in the report
names the signal that put it there, and -explain prints the whole decision.

This deletes the Python that preceded it. build_module_map.py and modules.yml
measured a twelve-destination map from git history and priced an effort estimate
from it; that estimate scored 23% on one tier and called ten large changes
trivial, and the fine-grained areas are the ones that measured at 10% to 16%.
Dropping both removes the per-repository setup as well, so the tool now needs
owner/repo and nothing else.

Also removes samples/pr-triage/install.sh, a superseded draft of
pr-triage/vend/install.sh that was never committed and that nothing references.
It only installed the binary when none was on PATH, so re-running it left an old
binary beside a current skill.

Verified against agentic-community/mcp-gateway-registry on 7 October 2026: 106
open issues in 10 seconds for $0.0093 over 221,768 input tokens, and a seeded
sample of 25 closed issues whose single Today pick was #1834, a login regression
behind a proxy that somebody did fix. gofmt, go vet and 17 tests clean,
build.sh producing five static targets with checksums, every flag the skill
names present in -h, every relative link in the docs resolving, and no key,
emoji or binary in the diff.
@aarora79
aarora79 merged commit 0088a56 into main Oct 7, 2026
1 check passed
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.

1 participant