Repository navigation
Add issue-triage: which issues to work on today, in four buckets - #20
Merged
Merged
Conversation
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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
Scorewhose 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
securitytook thirty times longer than the ones labelledbug. That is a record of delay, so fitting weights to it would make the delay the goal. The weights live inquestions.ymland the thresholds inscore.go, declared where a diff shows them. The output is judged by reading it: every row names the signal that put it there, and-explainprints the whole decision.What this removes
build_module_map.pyandmodules.ymlmeasured 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 needsowner/repoand nothing else.It also removes
samples/pr-triage/install.sh, a superseded draft ofpr-triage/vend/install.shthat 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-registryon 7 October 2026:gofmt,go vetand 17 tests cleanbuild.shproducing five static targets withSHA256SUMS-h, every relative link in the docs resolvingBoth committed runs are in
samples/issue-triage/data/, and the design is written up inexplainer.mdwith a self-contained HTML twin.After merge
The vended skill fetches from
mainandgo/install.shresolves the newestissue-triage/tag, so the release has to follow the merge. I will cutissue-triage/0.1.0from a clean clone and confirmvcs.modified=falsebefore uploading, since a dirty-tree build publishes checksums nobody can reproduce.