Repository navigation
feat(skills): add analyze-upstream-pr to judge an upstream PR for an AMD deployment - #1851
Conversation
0383dc7 to
d74f164
Compare
chaojhou
left a comment
There was a problem hiding this comment.
Thanks @okorzh-amd. The scripts are sound:
- References parsed from comments are validated before any
gh apicall. - The header-forgery normalisation matches the description.
- The probe gets its arguments as an array.
One must-fix, in the procedure:
Step 6 never excludes the PR under analysis from the check-prior-art run.
analyze-upstream-pr/SKILL.md:208-210sends the open-PR question to check-prior-art, withfiles.txtas the planned paths, and carries back itsDUPLICATEandOVERLAPPINGclasses.overlap.shhas no exclusion, and check-prior-art defines DUPLICATE as "does what the mechanism says, in the same code path".- For an open PR, the PR itself is an
overlap.tsvrow that matches every planned path. Followed literally, it comes back as its own DUPLICATE, and theWAIT-FOR-MERGErow ("a competing open PR") can fire instead ofCARRY-AS-PATCH. - review-pr's
fetch.shdrops the PR itself ($1 == self), and that is the check this step replaces. - Please say in Step 6 to leave
<owner/name>#<N>out of the shortlist and the classes, or giveoverlap.shan exclusion.
This PR also contains #1847, whose must-fix applies here too.
|
Gate job conclusion: success (run) on The report below was uploaded by that run; the conclusion above is the result. Code metrics gate: PASSEDJudged: the 17 files this change touches. Files it does not touch never fail it; anything found there is listed under Outside this change for information.
116 findings in files this change does not touchOutside this change (informational): 116
...and 91 more; the job log lists every row.
Thresholds and sources: |
d74f164 to
9e3cf82
Compare
chaojhou
left a comment
There was a problem hiding this comment.
PR #1851 -- feat(skills): add analyze-upstream-pr to judge an upstream PR for an AMD deployment
What it does: Adds a contributor skill (.claude/skills/analyze-upstream-pr/) that takes an upstream framework or kernel-library PR plus a target AMD deployment and writes a report on whether the deployment runs the changed code, whether the local tree already has it, and one of five recommendations. It collects upstream-only data with fetch_upstream.sh, reuses check-prior-art for duplicate PRs (drop_self.sh keeps the PR out of its own check), and moves the shared comment and PR-state jq into check-prior-art/lib.sh. The GitHub diff also carries the stacked #1850 (check-prior-art) and #1847 (inclusion probe).
Blocking issues: 1
- [X2] Description is stale after the last commit: "14 tests" and no drop_self.sh [verified]
Problem: the body says test_analyze_upstream_pr.py has 14 tests and never mentions drop_self.sh, but head commit 9e3cf82 adds .claude/skills/analyze-upstream-pr/drop_self.sh and five more tests, 19 in total. scripts/tests/test_analyze_upstream_pr.py:400
Impact: the description no longer matches the diff at head: a reader misses a new script that rewrites check-prior-art's candidates.tsv and overlap.tsv, and the stated test count is wrong.
Action: update the body: add drop_self.sh to the collection/Step 6 description, list the two drop_self tests it pins, and change "14 tests" to 19.
SKIPPED: V4 -- PARTIAL overlap for #1032, #1154, #1276, #1675 (each cut at its first 100 files), overlap there unchecked
Checked: analyze-upstream-pr/{SKILL.md Step 6 and recommendation table, drop_self.sh, fetch_upstream.sh}, check-prior-art/{lib.sh PR_JQ/render_comments/replace_file, search.sh, overlap.sh, SKILL.md Steps 2-4}, AGENTS.md row, .importlinter, test_analyze_upstream_pr.py at head and head~1, body.txt, comments.txt, openprs.txt, ci.txt; earlier self-duplicate hypothesis rechecked and fixed at head | Ran: hl_fetch.py 1851; git show of head files; python ..\pr_tools\c901.py on the 7 changed src/kernelforge units (max head complexity 10); shell scripts reviewed statically, nothing run; gh run list --commit 9e3cf82 after approving the fork runs (9 workflows success, the 2 label-gated E2E skipped) | Base: 1a444f6 | Head: 9e3cf82
chaojhou
left a comment
There was a problem hiding this comment.
PR #1851 -- feat(skills): add analyze-upstream-pr to judge an upstream PR for an AMD deployment
What it does: Adds .claude/skills/analyze-upstream-pr/, a procedure that takes an upstream framework or kernel-library PR plus a target AMD deployment and writes a report: does the deployment run the changed code, is the change already in the tree, and one of five recommendations. It collects with review-pr's fetch.sh plus a new fetch_upstream.sh, reuses check-prior-art for duplicate PRs (with drop_self.sh to keep the PR out of its own check), and moves the shared comment and PR-state jq into check-prior-art's lib.sh. The diff also carries the stacked #1850 and #1847.
Blocking issues: 2
-
[free:merged-duplicate] A PR whose change already landed through another PR comes out
CARRY-AS-PATCH[verified]
Problem: Step 6 carries check-prior-art's DUPLICATE and OVERLAPPING classes intoconflicts.txt(SKILL.md:206-211), but the recommendation table reads another PR only as "a competing open PR" underWAIT-FOR-MERGE(SKILL.md:29); no row handles a merged DUPLICATE, and Step 4 checks the inclusion of this PR only. An open PR that isON-PATHwith no surviving blocking risk therefore falls toCARRY-AS-PATCH. .claude/skills/analyze-upstream-pr/SKILL.md:31
Impact: the user is told to apply the PR's diff as a local patch (SKILL.md:54) although upstream already merged the change through another PR, which the tree may already run or can take withADOPT-NOW.
Action: run check-prior-art through its verdict and map it into the table:EXISTS-MERGED-INCLUDED->NOT-APPLICABLE -- already in tree via <ref>,EXISTS-MERGED-NOT-IN-TREE-> analyze<ref>instead,EXISTS-OPEN->WAIT-FOR-MERGE. -
[X2] The description is stale after the last commit [verified]
Problem: unchanged since the last round at this head: it saystest_analyze_upstream_pr.pyhas "14 tests" and never mentionsdrop_self.sh; head 9e3cf82 addsdrop_self.shand five more test cases, 19 in total. scripts/tests/test_analyze_upstream_pr.py:400
Impact: the description does not match the diff at the head.
Action: update the body to the final shape (ifdrop_self.shgoes as suggested below, describe that instead).
Design review (requested by the maintainer; beyond the blocking bar)
The aim of this section is a smaller PR, not more guards: each point says what to delete or merge.
Purpose, route, files. Skill files: SKILL.md (292 lines), references/dimensions.md (lenses L1-L11), references/measurement.md; scripts fetch_upstream.sh and drop_self.sh; tests scripts/tests/test_analyze_upstream_pr.py (19 cases); check-prior-art's lib.sh gains the shared helpers and read.sh / search.sh use them; one AGENTS.md row.
1. Completeness. Item 1. Step 6 notices when the PR's diff no longer applies to the target commit (SKILL.md:216-218), but no row or qualifier reads that, and CARRY-AS-PATCH then tells the user to apply that same diff; with no local patches the check does not run at all (:219) -- always run git apply --check against the target commit. For a kernel-library PR the code that selects the kernel lives in the framework, but target.txt holds one tree, so on-path and inclusion cannot both be checked. When GitHub refuses the diff, fetch.sh exits before writing files.txt, and Steps 1 and 6 lose their input with only SKIPPED: fetch in the report. Without a tree every on-path line stays UNKNOWN; ask for a tree at Step 0.
2. Simpler / smaller.
- Collection: check-prior-art's
read.shalready writes the state lines, comments, cross-references, per-file counts and a diff with its own SKIPPED line, through the samelib.shfunctions; only CI at the head commit is missing (twogh apilines). Using it removesfetch_upstream.sh's comment, state and timeline parts and thefetch.sh-then-read.shfallback. linked.txt: onlyreverted-byandsuperseded-byare read (SKILL.md:26-27);closes(a separate GraphQL call),supersedesandrevertsare only described, and Step 9 re-proves a revert from its diff anyway. Reading the titles inxrefs.tsvand the comments is enough.drop_self.sh: delete it. The sentence atSKILL.md:210("keep<owner/name>#<N>out of the shortlist and classes") is sufficient because the agent writes the shortlist, and the script both misses the third source (pathlog.txt) and rewrites another skill's tables. My earlier must-fix offered "a sentence, or an exclusion inoverlap.sh"; the sentence is the right one.- Lenses: L2 repeats Steps 1-2, L3, L4 and L10 repeat Step 3's caller walk, L11 overlaps
WAIT-FOR-MERGE. Keep the AMD-specific L5-L9 plus a dependency-pin lens, each citing the PR it was learned from, as review-pr requires of its rules; foldmeasurement.mdinto Step 8.
3. Redundancy and silent failure. Comments are fetched twice (fetch.sh and fetch_upstream.sh), open PRs are scanned twice (openprs.txt and check-prior-art), the merge commit is read three ways, the probe is called two ways, and the PR is excluded in three places. A failed reference lookup, rate limit included, becomes an unresolved row with no retry and is not listed in coverage, so a failed "Reverted by #N" lookup cannot trigger the reverted row; a probe crash (exit 1 or 2) is recorded and the script still exits 0, and SKILL.md never names that outcome.
4. Docs and comments. Item 2; fetch_upstream.sh:18-19 says anything that cannot be collected exits non-zero except an unresolvable reference, but :149-152 record a failed probe and carry on; SKILL.md:109 says read.sh's files.txt "still lists every path", but read.sh writes it under prs/<owner>/<name>/<N>/ with extra columns, not the $WORK/files.txt that Steps 3 and 6 read.
5. Tests. Keep two and move them into test_check_prior_art.py, run against read.sh: the forged-header test (test_analyze_upstream_pr.py:189) and the ordering-and-roles test (:132). Both pin render_comments, which read.sh now depends on and test_check_prior_art.py checks only by its first line. The rest pin incidental detail or duplicate other tests: the exact 14-row table (:227), the repeated "#41" case (:297), the merge-commit rule already pinned in test_check_prior_art.py (:319), a literal string (:341), the unused GraphQL call (:349), usage messages (:356, :416), printf padding (:409), and the drop_self.sh tests if the script goes.
Starting from zero. A skill with no scripts of its own: read.sh plus one CI command for collection, one probe snippet for the PR and for each merged revert, Steps 1-5 and 9-10, and about 50 lines of AMD-specific lenses. It is worth a separate skill: the on-path step, the operating-point gaps and the recommendation table do not fit check-prior-art's search-driven flow.
Change list, in order of impact:
- Item 1: run check-prior-art through its verdict and map it into the table.
- Delete
drop_self.shand its tests; keep the one-sentence exclusion. - Collect with
read.shplus one CI command; deletefetch_upstream.sh's comment, state and timeline parts and stop usingfetch.sh(SKILL.md:64-65,93-110,204-205). - Replace
linked.txtwithxrefs.tsvplus one sentence; dropcloses,supersedes,revertsand the GraphQL call (or, if a helper stays, list itsunresolvedrows under coverage). - One probe snippet; treat exit 1 and 2 as
SKIPPED. - Close the gaps in point 1: always
git apply --checkagainst the target commit and qualify the recommendation; an input for the tree that holds the selection code; ask for a tree at Step 0. - Cut
dimensions.mdto the AMD-specific lenses with their source PRs; foldmeasurement.mdinto Step 8. - Move the two comment tests; delete the others; revert
lib.sh:5. - Rewrite the description (item 2).
Checked: SKILL.md (recommendation and next-step tables, Step 6), drop_self.sh, fetch_upstream.sh, references/dimensions.md and measurement.md, check-prior-art's lib.sh / read.sh / SKILL.md Steps 4-7, test_analyze_upstream_pr.py, the description against the head | Ran: static review only (no bash or jq on this host); no test suite | Base: 1a444f6 | Head: 9e3cf82
5b729b2 to
f8bc23d
Compare
chaojhou
left a comment
There was a problem hiding this comment.
PR #1851 -- feat(skills): add analyze-upstream-pr to judge an upstream PR for an AMD deployment
What it does: PR #1851 adds a contributor skill, .claude/skills/analyze-upstream-pr/ (SKILL.md plus references/dimensions.md, and one row in the AGENTS.md table). The skill judges an upstream framework or kernel-library PR against an AMD deployment and ends in one recommendation. It collects the PR with check-prior-art's read.sh plus two gh calls, finds the selection site that decides whether the deployment runs the changed code, probes the local tree with the pr_knowledge inclusion probe, runs check-prior-art for competing PRs, runs git apply --check on the diff at the target commit, checks six AMD-specific risk lenses, refutes each claim, and maps the result to one row of the recommendation table. It is cleanly stacked on #1850: origin/pr-1850 (56702fb) is an ancestor of the head, and git diff origin/pr-1850 origin/pr-1851 touches only those three files, so the check-prior-art files, the inclusion probe and test_check_prior_art.py are identical to #1850 and belong to that PR's review.
Blocking issues: 1
- [desync-body-describes-removed-design] The PR description still describes the earlier design: fetch_upstream.sh, a 14-test file, measurement.md, the lib.sh lift and a new comments.txt shape, none of which exist at head [verified]
Problem: The live body (checked with gh at head f8bc23d, updated 2026-10-20) describes a design that later commits replaced. Commits 100feb6 ('collect an upstream PR with check-prior-art's read.sh and one probe snippet') and d6b3c78 ('keep only the AMD-specific risk lenses') did the replacing.
What the body says:
- Collection uses review-pr's fetch.sh plus a new fetch_upstream.sh, which writes comments_untrusted.txt, linked.txt and inclusion.txt.
- It adds scripts/tests/test_analyze_upstream_pr.py with 14 tests.
- It adds references/measurement.md.
- It lifts the comment collection and the PR-state jq into check-prior-art's lib.sh.
- check-prior-art's read.sh comments.txt changes shape (the 'Observable effect' section).
- There are 'eleven risk lenses' and SKILL.md is 292 lines.
- It gives a five-row recommendation list.
What the head has:
- Collection is read.sh plus a
gh pr viewcall for checks.json and agh apicall for inline.jsonl (SKILL.md:89-94). - None of those scripts, tests or files exist (
git ls-tree origin/pr-1851lists only SKILL.md and dimensions.md under analyze-upstream-pr). - lib.sh and read.sh are byte-identical to #1850. read.sh writes no comments.txt at all.
- dimensions.md has six lenses (L1-L6).
- SKILL.md is 280 lines.
- The recommendation table (SKILL.md:25-39) adds four NOT-APPLICABLE rows the body omits: already in tree, merged as, superseded by, and off path. It also adds the
-- does not apply at <commit>qualifier. .claude/skills/analyze-upstream-pr/SKILL.md:89
Impact: The 'Observable effect' and 'Breaking changes' sections claim that check-prior-art's per-PR comments.txt changes shape, which this PR does not do. The 'Tests' section claims 14 tests that the PR does not add. A reviewer or the release notes would describe scripts, artifacts and a refactor that do not ship, and would miss the recommendation rows that actually decide the outcome.
Action: Rewrite the body for the head: - Name the three files.
- Describe collection as read.sh plus checks.json and inline.jsonl.
- Say the PR adds no scripts or tests, and why (only markdown procedure; scripts are #1850's).
- Give the six lenses.
- Give the ten-row recommendation table and its qualifiers.
- Drop the lib.sh, comments.txt and fetch_upstream.sh paragraphs.
- Name #1850 explicitly as the dependency.
Checked: I read the following:
- At head: the full analyze-upstream-pr/SKILL.md and references/dimensions.md, and the AGENTS.md diff.
- check-prior-art read.sh, lib.sh, SKILL.md (Steps 4-7 and the verdict table) and the gotchas G1-G8 headings.
- inclusion.py at head against main's kernelforge.llm.git git/git_bytes signatures.
- The live PR body via gh, plus body.txt, files.txt, numstat.txt, commits.txt, comments.txt (earlier review cards) and ci.txt (all green; label-gated E2E skipped).
I ran the following:
git merge-base --is-ancestor origin/pr-1850 origin/pr-1851: stacked.git diff --stat origin/pr-1850 origin/pr-1851: 3 files.git merge-tree origin/main origin/pr-1851: clean.- The inclusion probe on an archive of the merged tree: exit 3, works.
- The Step 6 binary-exclusion awk plus
git apply --checkin a scratch repo: the binary stanza fails without $BIN and passes with it.
Not run: pytest (Windows) and the shell procedure end to end against a real upstream PR.
Base b7004d1, head f8bc23d, main 1cdc6ff. | Base: b7004d1 | Head: f8bc23d
Nothing answered "is upstream PR N already in this tree or commit?", so an agent could take up a PR that its framework tree already carries. probe_inclusion reads local git only. Revisions resolve through rev-list with a --missing action, so a sha that a partial clone lacks is not fetched. It checks ancestry of the PR's merge commit when that commit is present, then looks for a reachable commit whose subject ends in a (#N) suffix run, which is how squash merges and fork cherry-picks record the PR. It answers not_included only when a complete history gives a definite not-ancestor answer and no subject matches. Every other case, including a git call that fails, cannot start or times out, is unknown, with the reason in the evidence. Each git call is bounded by a timeout. The verdict is available as python -m kernelforge.knowledge.pr_knowledge.inclusion (JSON on stdout; exit 0, 4 or 3 for included, not included or unknown, 2 on a usage error; 1 stays the status of an uncaught error) and as the pr_check_inclusion tool of the PR stdio MCP server, whose commit defaults to the tree's HEAD. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The stub that fails one git command was a lambda wrapping a call, which CodeQL reports as an unnecessary lambda. A nested function does the same job without the wrapper. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…ncluded probe_inclusion answered not_included whenever the merge commit was present but not an ancestor and no subject ended in (#N). A PR the tree does carry read as absent when a fork cherry-picked the squash commit under a rewritten subject, or, under an upstream that merges with merge commits, cherry-picked the PR's own commits. Before answering not_included, the probe now compares the non-merge commits the merge commit brought in (merge^1..merge: the squash commit itself, or the PR's commits under a merge commit) with the commits reachable from the checked commit, using git rev-list --cherry. A commit counts as carried when the tree has it by sha or by patch-id. All carried is included, through the new method patch_id; none is not_included; some is unknown, and so is a call that fails or times out. Both calls run as rev-list with --missing=print, which turns lazy fetching off, so a partial clone that lacks a blob a patch-id needs answers unknown and fetches nothing. A backport without the suffix whose diff was edited still reads as not_included; the module docstring and the MCP tool description now say so, and a test pins it. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
… is carried Under an upstream that merges with merge commits, the patch-id step compares each of the PR's commits on its own. A fork that carries a multi-commit PR folded into one commit, with git cherry-pick -m 1 of the merge or by squashing the PR's commits, matches none of their patch-ids, and the default cherry-pick -m 1 subject "Merge pull request #N from ..." has no (#N) suffix. Such a tree read as not_included, exit 4. When the merge brought in several commits and none is carried one by one, the probe now answers unknown, and the evidence names the fold. A squash or rebase merge brings in one commit and still answers not_included when that commit has no patch-id match. A patch-id of the merge's first-parent diff would match the fold, but computing it needs git diff-tree -p or git log -p. Neither takes --missing, and only git 2.44 and later can stop them lazily fetching blobs in a partial clone (GIT_NO_LAZY_FETCH), while the probe must fetch nothing. Tests: the none-carried case of the two-commit merge test is now unknown, and git cherry-pick -m 1 of the merge is included for a one-commit PR and unknown for a two-commit PR. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The module docstring said the patch-id step finds a cherry-pick under any subject, and the pr_check_inclusion description named only an edited backport as a miss. A patch-id hashes the diff with its context lines and compares one commit at a time, so a backport with no (#N) suffix that git applied cleanly still reads as not_included when the fork had changed a line next to a hunk, and so does one that carries a squash-merged PR as the PR's own commits picked one by one. The docstring now says a patch-id matches only a commit whose diff, whitespace and line numbers aside, is identical to the commit the merge brought in, and names the misses: an edit or a resolved conflict, a change landed next to fork changes, a squash-merged PR carried as its commits, a fold into a larger commit, and a fork that squashed a rebase-merged PR. The MCP tool description, which is what an agent reads, says the same in short. rev-list --cherry cannot compare with less context: it rejects -U0 and ignores diff.context. A new test pins the clean backport next to a fork change as not_included. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Inclusion and InclusionMethod used a StrEnum with a Python 3.10 shim copied from the quantization driver, but nothing formats them with str(): to_record reads .value, and the PR-state enum next to them is a plain (str, Enum). They are now the same, and the shim is gone. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Local history can show that a PR is in a tree, never that it is absent:
a backport that was edited, had a conflict resolved or was folded into
a larger commit looks the same as no carry. The probe still answered
not_included (exit 4) for such trees, so a caller could take up a PR the
tree already carries.
The probe now answers included, with the git evidence, or unknown, with
the reason. not_included, exit status 4, the shallow-history check and
the one-commit and several-commit branches are gone.
With a merge commit sha, one call,
git rev-list --missing=print --no-merges --cherry-pick --right-only \
<head>...<merge> ^<merge>^1 --
replaces the ancestry check, the commit count and the --cherry pass. It
lists the non-merge commits the merge brought in that head has neither
by sha nor by patch-id, so an empty list is included: for a merge
commit that is an ancestor, and for a cherry-pick under another
subject. A sha the tree lacks fails the call, and nothing is fetched.
Subjects are now searched first, because they need no sha.
Every git call goes through the shared wrapper with its exit status
checked. A non-zero exit, a timeout or a git that cannot start is caught
once in probe_inclusion and answered unknown with the error as the
evidence (git's own message for a non-zero exit), so a timed-out
resolve no longer reads "is not in the tree". At most three
calls run, each bounded at 15 s, inside the 60 s the Forge agent gives a
pr_monitor tool call. The revision to check reaches git after
--end-of-options: rev-list accepts --output=<file> and creates that
file, so a leading-dash value is now a bad revision, not an option.
The methods are now subject, merge_commit and none. The module
docstring, the pr_check_inclusion description and cli.md state the rule,
and cli.md names the check-prior-art contributor skill as the consumer
that passes the merge commit sha on the command line.
Tests keep the subject hits and misses, non-UTF-8 output, the
merge-commit cases, the partial-clone no-fetch cases, one hang, one
exit 128, a bad and a leading-dash revision, a directory outside git,
the command line and the MCP tool. The not_included cases, the
ten-case failure matrix and the schema restatement test are gone.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
An upstream that lands PRs with merge commits records the PR as "Merge pull request #N from <branch>", and so does a fork's git cherry-pick -m 1 of that merge. The subject search only knew the trailing (#N) of a squash merge, so without a merge commit sha such a tree answered unknown. The search now also greps for that subject and counts a commit whose subject starts with it for exactly N; #N followed by another digit, or the phrase inside a revert subject, does not count. Two cases pin it: the subject for AMD-AGI#12 is included, and the one for AMD-AGI#123 is not taken for AMD-AGI#12. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…gent cannot supply pr_check_inclusion took merge_commit_sha and passed it through, but no tool the Forge Implementer can call returns one: pr_get_reference carries the PR's state and merge time, not its merge commit. The argument only ever arrived from tests, so the merge-commit check never ran for the one consumer of the tool. The tool now answers from commit subjects alone, and its schema and description say so. The command line keeps --merge-commit-sha for the check-prior-art contributor skill, which reads the sha from the GitHub API. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…he probe The module docstring said the check-prior-art skill passes the sha it "reads from the GitHub API". The skill reads the PR's mergeCommit with gh pr view, and avoids REST's merge_commit_sha, which names a test merge for an open PR. Say which field it passes. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…lanned change upstream Before building an optimization, nothing checked whether the same change already sat in an open or merged upstream PR, or was already in the tree being measured. .claude/skills/check-prior-art runs top to bottom like review-pr: every step writes an artifact into a work directory, every DUPLICATE or OVERLAPPING class and every not_included answer is refuted once, and a step that cannot run is recorded as SKIPPED. search.sh sends one GitHub search per repository, state (open, merged) and phrase, pacing itself by the search rate-limit headers, and records every query with what it listed out of what matched. overlap.sh pages GraphQL over a repository's open PRs, newest first, up to 10000, and names every cut (page cap, a stopped scan, a PR whose file list GitHub truncated) as PARTIAL. read.sh collects one PR for a deep read and records merge_commit_sha only once the PR merged. Merged candidates are checked against the tree with python -m kernelforge.knowledge.pr_knowledge.inclusion. The report is one of five verdicts with its evidence, coverage and next step; nothing is posted to GitHub. references/gotchas.md holds the generic traps, and AGENTS.md links the skill. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…misses The probe now compares patch-ids before answering not_included, so a cherry-pick with the same diff is found under any subject. G5 still said a cherry-pick that rewrote its subject was invisible to the probe; it now names the backports that still read as not_included. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
… PRs too The inclusion probe now answers only included or unknown, so check-prior-art no longer reads a not_included answer, exit 4 or a subject_suffix method. Step 5 probes every DUPLICATE, open or merged, and no longer probes OVERLAPPING PRs, whose answer fed no verdict. Step 6 searches the tree's own log for every DUPLICATE whose answer is not included, so a fork that carries an open PR under its own subject is reported in the tree instead of being told to apply it. EXISTS-MERGED and EXISTS-OPEN now share one qualifier: "-- in your tree" when Step 5 or 6 found the PR there, otherwise "-- inclusion unchecked", because local git cannot show that a PR is absent. G5 says what the probe's subject and patch-id checks miss and that Step 6 covers them. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Step 4 classed a PR that carries part of the mechanism in another file as OVERLAPPING, while Step 6 dropped every OVERLAPPING PR to UNRELATED unless it changed a planned path or function. An upstream PR doing the same trick in a sibling backend's file therefore ended UNRELATED, and the verdict could be NOT-FOUND with "proceed". Step 4's table is now the only definition, read top to bottom with the first row that applies winning; SUPERSEDED moves to the top and names a reverted PR, so a reverted duplicate is SUPERSEDED in both steps. Step 6 no longer restates the classes: a refuted PR takes the first row of that table it still meets. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…s in Coverage Step 4 reads at most 12 candidates and keeps the rest as "# cut:" lines, but neither Coverage nor the "-- incomplete" qualifier looked at them, so a bare NOT-FOUND could rest on 12 of 76 candidates chosen by title. Coverage now says "read N of M shortlisted" and names the cut PRs, any "# cut:" line makes PARTIAL-OVERLAP and NOT-FOUND "-- incomplete", and the shortlist takes every candidates.tsv row so that M counts them all. Coverage also states what no check searches: closed-unmerged PRs, issues and RFCs, repositories outside repos.txt, and a planned path absent upstream, which matches nothing while the scan says COMPLETE. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…s, not its wording The overlap tests compared scan.txt line for line, so rewording a status line or appending the lines in another order failed them with no change in what the scan covered. A helper now reads each line as its repository or PR, its status and the numbers it states, and the tests compare those. The refused-diff and stray-path tests check the SKIPPED status and the offending paths.txt line instead of the sentence around them. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The test fed search.sh an empty repos.txt and a URL in place of owner/name and checked the error text. Both are one-line input checks at the script's entry; the overlap test with a planned path for a repository outside repos.txt already pins that a bad input line stops a script with a non-zero exit that names the line. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
SKILL.md listed the six verdicts in one table and their next steps in another, and described Coverage both in the output contract and in Step 7's template. The verdict table now carries each verdict line with when it applies and its next step, and Step 7's template is the one description of Coverage. The script headers restated the artifact layout SKILL.md gives, a second copy that had already drifted once (read.sh's header said only a refused diff was SKIPPED). Each header now names the step of SKILL.md that describes its output and keeps only the rule a maintainer needs: queries.tsv is the coverage, an empty overlap.tsv means nothing outside COMPLETE, and any diff failure is SKIPPED while every other failure exits non-zero. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
G4 recommended a --filter=blob:none clone for an installed package and said the probe reports the objects it lacks. The probe answers by subject and by merge-commit ancestry from such a clone, but a cherry-pick matched by patch-id needs the blobs, and without them the probe answers unknown rather than fetch them. G4 now says so, so a contributor who needs that match clones in full. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…s on the planned paths Step 3's path log read a merged PR only from a squash commit's "(#N)" suffix. On an upstream that lands PRs as merge commits, a path-limited git log drops the merge commit, which is TREESAME to the PR side, and lists the PR's own commits, which name no PR. Merged PRs on the planned paths then never reached the shortlist, and nothing in Coverage said so. In this repository, the path log from 5b4ac6f~1 to a56028d for pr_knowledge/references.py prints only 5b4ac6f; with --first-parent it prints the "Merge pull request AMD-AGI#1846 from ..." commit. Write the path log with --first-parent and read both a "(#N)" suffix and a "Merge pull request #N from" subject as a merged PR. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…erge commit's body Step 5 and G1 called every subject match whose subject is not the PR's title a collision, and so unknown. GitHub writes a merge commit as "Merge pull request #N from <branch>" with the title in its body, so that rule turned every correct merge-subject match into unknown, although the probe accepts that subject and G5 says it finds the carry. On this repository, the probe answers included/subject for AMD-AGI#1846 at a56028d with the merge commit fc25a6d, whose body's first line is the PR's title. The same rule also missed a squash of a single commit, which keeps that commit's subject: AMD-AGI#1763 here is titled "Re-Order Tasks by TraceLens Sorting Order" and landed as "Reorder tasks by TL order (AMD-AGI#1763)", with the PR's four files. Compare the title with the subject of a "(#N)" match and with the body of a "Merge pull request #N from" match. G1 says where GitHub writes the title, and accepts a "(#N)" commit with another title when it changes the PR's files.txt paths. Any other mismatch stays a collision. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…robe cannot run Step 5 writes "SKIPPED: inclusion" both when there is no tree and when the probe cannot run (exit 1 or 2), and Step 6 let every such line stand as having "no tree to search". With a tree whose probe failed, for example because the package cannot be imported, the log search that attacks an unknown answer never ran, so a fork that carries the PR got "-- inclusion unchecked". A SKIPPED line with no tree or no commit (G4's version that names none) still stands; a probe that could not run on a tree and commit is attacked like unknown. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…n fields read.sh asks for The stub gh ignored --json and printed the whole fixture, so the deep-read test's "mergeCommit is None" restated the fixture: dropping mergeCommit from read.sh's --json list left all 10 tests passing, although Step 5 reads mergeCommit.oid from pr.json and would then probe a merged PR by its subject alone. The SKIPPED: diff count read changedFiles the same way. Print only the fields asked for, as gh does. Dropping mergeCommit or changedFiles from read.sh's --json now fails the deep-read test. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…AMD deployment Nothing turned an upstream pull request into a grounded answer to three questions: does the ROCm deployment run the code it changes, is it already in the tree being measured, and what should be done with it. .claude/skills/analyze-upstream-pr collects the PR with review-pr's fetch.sh, and fetch_upstream.sh adds what fetch.sh leaves out upstream: every comment under an untrusted-data header (fetch.sh's write-access filter keeps only the author there), the closing, supersede, revert and mention links, and the inclusion probe's answer for a given tree and commit. Each step writes one artifact: the mechanism, the operating point quoted from the body and comments, the selection site that puts the changed code on or off the target's path (UNKNOWN until cited), inclusion, a predicted effect, conflicts with open PRs (through check-prior-art) and local patches, eleven risk lenses in references/dimensions.md, an optional control-versus-change plan the user runs, and one refutation per claim. The report is one of ADOPT-NOW, CARRY-AS-PATCH, WAIT-FOR-MERGE, NOT-APPLICABLE or NEEDS-MEASUREMENT with its evidence; nothing is posted to GitHub and nothing is benchmarked. fetch_upstream.sh sources check-prior-art's lib.sh, which gains the comment collection and rendering, the untrusted-data header and the PR-state jq rules it uses. AGENTS.md links the skill. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
analyze-upstream-pr's Step 6 sends the open-PR question to check-prior-art
with files.txt as the planned paths, and nothing left the PR under
analysis out of that run. An open PR is an overlap.tsv row on every
planned path, and its title words make it a candidates.tsv row too, so
followed literally it came back as its own DUPLICATE, and the
WAIT-FOR-MERGE row ("a competing open PR") could fire instead of
CARRY-AS-PATCH. review-pr's fetch.sh, whose open-PR check this step
replaces, drops the PR itself.
The new drop_self.sh removes OWNER/NAME#NUMBER from check-prior-art's
candidates.tsv and overlap.tsv, matching the repository without regard
to case and the number exactly, and changes neither table unless both
exist. Step 6 runs it before check-prior-art's Step 4 and keeps the PR
out of the shortlist and the classes, which covers pathlog.txt, where a
merged PR the tree lacks shows up.
SKILL.md stays at its 292-line budget: Step 3's selection-site
paragraph is reflowed, and Step 0's note on G4 is shortened.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…ck by one sentence
drop_self.sh rewrote check-prior-art's candidates.tsv and overlap.tsv to
remove the PR under analysis, and still missed the third source of the
shortlist, pathlog.txt. The agent writes check-prior-art's shortlist and
classes itself, so the sentence Step 6 already carried ("keep
<owner/name>#<N> out of its shortlist and classes") is the whole
exclusion. drop_self.sh and its two tests go; no script edits another
skill's tables any more.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…sh and one probe snippet analyze-upstream-pr collected a PR three ways: review-pr's fetch.sh, a new fetch_upstream.sh, and check-prior-art's read.sh as the fallback when GitHub refused the diff. Comments were fetched twice, open PRs scanned twice, the merge commit read three ways and the probe called two ways. Step 0 now runs read.sh, which writes pr.json (state, draft flag, mergeCommit, body, comments, reviews), files.txt, diff.txt or its SKIPPED line, and xrefs.tsv, plus two gh commands: the head sha, base branch and checks at the head into checks.json, and the inline review comments, which gh pr view does not return, into inline.jsonl. Step 1 reads reverts and successors from xrefs.tsv and the comments in one sentence instead of linked.txt's six relation kinds and GraphQL call. Step 4 runs check-prior-art's Step 5 snippet for the PR and each merged revert, and names exit 1 and 2 as SKIPPED: inclusion; the probe answers included or unknown, and Step 9 attacks unknown in the tree's history. fetch_upstream.sh and its test file go. lib.sh returns to check-prior-art's own helpers: the comment rendering it carried for fetch_upstream.sh has no user, since read.sh keeps comments as gh pr view's JSON, where a comment cannot forge a header and needs no ordering test. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
… recommendation Step 6 carried check-prior-art's DUPLICATE and OVERLAPPING classes into conflicts.txt, but the recommendation table read another PR only as "a competing open PR" under WAIT-FOR-MERGE. No row handled a merged duplicate, and Step 4 probed this PR alone, so an open PR whose change upstream had already merged through another PR fell through to CARRY-AS-PATCH: apply this diff as a local patch. Step 6 now runs check-prior-art through its verdict and writes the verdict line into conflicts.txt, which the table reads: - EXISTS-MERGED or EXISTS-OPEN -- in your tree: NOT-APPLICABLE -- already in tree via <ref>, since the tree already runs the change; - EXISTS-MERGED -- inclusion unchecked, for a PR that is not merged: NOT-APPLICABLE -- merged as <ref>, with "analyze <ref> instead"; - EXISTS-OPEN -- inclusion unchecked: WAIT-FOR-MERGE for an open PR, and NOT-APPLICABLE -- superseded by <ref> for one closed unmerged. Its incomplete Coverage goes into the report's Coverage, and Step 9 refutes the verdict like any other claim. Each row of the table now carries its own next step, as check-prior-art's verdict table does, instead of a second table keyed by the first. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…k for the trees it needs Step 6 noticed a diff that no longer applied at the target commit only while checking local patches: with no patches the check did not run, no row or qualifier read its result, and CARRY-AS-PATCH then told the user to apply that same diff. target.txt also held one tree, so for a kernel-library PR, whose selection code lives in the framework, on-path and inclusion could not both be checked, and a missing tree left every on-path line UNKNOWN without asking for one. - Step 6 always runs git apply --check of diff.txt in a scratch worktree at the target commit. FAILS qualifies ADOPT-NOW and CARRY-AS-PATCH with "-- does not apply at <commit>"; a diff that applies only in reverse means the tree already has the change and settles a Step 4 unknown as included. Local patches are then applied one by one and checked again, as before. - target.txt gains selection: <work tree>@<commit> for the code that selects the changed code when the PR's tree does not hold it; Step 3 walks the callers there. - Step 0 asks the user for what is missing before collecting: a deployment, a tree, and for a kernel-library PR the selection tree. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…he upstream PR it came from Of the eleven lenses, L2 (premise) repeated Steps 1 and 2; L1, L3, L4 and L10 (semantics, gate or default, other paths, blast radius) repeated Step 3's caller walk; and L11 (upstream fit) overlapped WAIT-FOR-MERGE. None of them is specific to an AMD deployment. references/dimensions.md keeps the lenses the author's platform hides, renumbered L1-L6: parity with the CUDA path, weights and quantization, numeric formats and bounds, collectives and parallelism, tests and whether ROCm CI ran them, and a new dependency-pin lens. Each cites, like review-pr's rules, the public upstream PR it was learned from (vllm-project/vllm #34543, #57425, #56359, #46730, #39953, #16010, #48654, #48155, #47072). 139 lines become 91. references/measurement.md (50 lines) folds into Step 8 as one paragraph: two arms that differ by the PR alone, the noise floor, correctness before speed, the operating point, a decision rule written first, proof the changed code ran, and results labeled measured. Step 5 drops its label line, which only restated that the effect is always predicted. SKILL.md is 278 lines against a budget of 280. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…upstream-pr's Step 6 check-prior-art's Step 0 sets $WORK, so an agent that runs it "in $WORK/prior-art" by setting WORK there writes this skill's conflicts.txt and every later artifact into the wrong directory. Step 6 now says $WORK/prior-art is check-prior-art's work directory and $WORK stays this skill's. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…and apply steps meet A GAP line is check-prior-art's G6 (a validated operating point may differ from yours), and a diff that does not apply at the target commit can be a path the tree lays out elsewhere (G7), not only drift from the PR's base. Step 2 and Step 6 now say so. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
… once Step 0 restated the field list of check-prior-art's Step 4 collection, and report parts 4 and 5 restated the Coverage and Next step lines of Step 10's template. Both now point at the text that states them; Step 0 keeps only that mergeCommit is null until the PR merges, which Step 4's probe depends on. Two sentences lose a trailing orphan line. SKILL.md goes from 280 to 275 lines, so the next two fixes fit the 280-line budget. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…R's diff read.sh writes diff.txt as a "SKIPPED: diff" line when gh pr diff fails, as it does past 300 files (HTTP 406). Step 1 then had nothing to read the mechanism from, and Steps 5 and 7 nothing to cite. The files endpoint still returns each file's patch: on vllm-project/vllm#12628 (1012 files) the diff is refused, and the endpoint returns hunks for all 1012 paths. Step 0 now writes hunks.txt from that endpoint only when diff.txt is skipped, and it stands in wherever the diff is read. The apply check still records "SKIPPED: apply", since hunks without file headers do not apply. hunks.txt joins the untrusted inputs. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
GitHub writes a binary file as a "Binary files a/x and b/x differ"
stanza with an abbreviated index line, which git apply never applies
("cannot apply binary patch ... without full index line"). Any PR that
touches a binary file therefore read FAILS in both directions, so it
got "-- does not apply at <commit>" and could not settle an unknown
inclusion by the reverse check.
Step 6 now builds $BIN, an --exclude for each binary stanza's old and
new path, passes it to every check, and records each such path as
"SKIPPED: apply -- <path>: binary". On vllm-project/vllm#50243, which
changes a PNG: without $BIN the diff fails at the PR's parent; with it,
it applies at the parent and applies with --reverse at the merge
commit. Both names are excluded because a reversed rename is matched by
its old name.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…uccessor Step 1 took any PR a title or comment called this one's "replacement, follow-up or reland" as a successor, and the superseded row fired for any unmerged PR with one, with no Step 9 block behind it. A follow-up builds on a PR rather than ending it: on vllm-project/vllm#60833, open, xrefs.tsv lists #61271 "Mono decode follow-up", a draft stacked on #60833's commits, and the skill read literally answered "NOT-APPLICABLE -- superseded by #61271" for a live PR. A successor is now a PR that either PR's title, body or comments call this one's replacement or reland, the test check-prior-art's SUPERSEDED class uses; a stacked or follow-up PR is not one. Each successor gets a successor:<ref> block in Step 9, attacked in both PRs' bodies, and the superseded row, like the revert row, needs one that survived. The file stays at its 280-line budget. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
f8bc23d to
88bd0be
Compare
…as in tree Step 6 applied each local patch in the scratch worktree and checked the PR's diff forward only, and a failure that appeared only after the patch was a CONFLICT. A patch that already carries the PR fails the same way: with the PR's own diff as the local patch, the check at commit applies, --numstat reports OVERLAP, and after the patch it fails with "patch failed: m.py:1" while "git apply --check --reverse" succeeds. The skill then recommended "CARRY-AS-PATCH -- conflicts with <its own patch>", whose next step applies diff.txt a second time, or, for a merged PR, ADOPT-NOW with a false CONFLICT row. CARRY-AS-PATCH itself creates that patch, so its own rerun reached the case. A failure after a local patch now runs the same --reverse check as the one at commit. Applying backwards is local:<patch> REVERSE, which makes Step 4 included like a REVERSE at commit, and the already-in-tree row names it as "-- already in tree via <patch>". Only a failure both ways is a CONFLICT, as for a patch carrying an older head of the PR. The file stays at its 280-line budget. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
|
@chaojhou Thanks for the review. The description is now rewritten against 6cc6611, and it covers each item in your Action list:
|
Resolved at the current head; see the follow-up review comment.
PR #1851 -- feat(skills): add analyze-upstream-pr to judge an upstream PR for an AMD deploymentWhat it does: adds the Blocking issues: none The earlier blocker ([desync-body-describes-removed-design] at f8bc23d: the description described fetch_upstream.sh, a 14-test file, measurement.md and the lib.sh lift) is resolved. The description now lists the three Markdown files the PR actually adds. Checked: the PR's own three files at 6cc6611. Also the check-prior-art scripts and test it carries from #1850, with the same CI-safety result: they call only LGTM |
Description: what and why
Someone who finds an upstream PR (a framework or kernel-library change) has three questions before taking it up for an AMD deployment: does my deployment run the code it changes on my GPU architecture and dtype; is the change already in the tree I measure, through this PR or another one; and should I take it now, carry it as a patch, wait, or drop it. Nothing in this repo answers them. review-pr is built for this repo's own PRs, and check-prior-art answers a different question ("is my planned change already upstream?"). An upstream PR is reviewed and measured on its author's platform, so a reader tends to take its benchmark, its green CI and "merged" as facts about their own deployment.
What this PR changes: three files, all Markdown.
.claude/skills/analyze-upstream-pr/SKILL.md(new, 280 lines): the procedure..claude/skills/analyze-upstream-pr/references/dimensions.md(new, 91 lines): the six risk lenses.AGENTS.md: one row in the "Where things are documented" table.It adds no script and no test, and it changes none of check-prior-art's files. The scripts this skill runs (
read.sh, itslib.sh, and the inclusion probe) belong to feat(skills): add check-prior-art, a contributor skill that finds a planned change upstream #1850 and feat(pr_knowledge): probe whether an upstream PR is in a local git tree #1847 and keep the output they have there.Like review-pr and check-prior-art, the skill is written for an agent to run top to bottom. Every step writes an artifact into a work directory. A step that cannot run is recorded as
SKIPPEDand carried into the report, and every claim is refuted once before the report is written. The skill reads GitHub and never posts to it, and it never starts a server, a benchmark or a GPU job. It reuses check-prior-art for collection, for the inclusion probe and for the search for other PRs, and it cites that skill's gotchas (G3-G7).Inputs.
target.txtholds:selection: a second tree and commit for the code that selects the changed code when the PR's tree does not hold it, such as the framework that calls a kernel library's op;Step 0 asks the user for whatever is missing before collecting: a deployment with no model or flags, a tree, and, for a kernel-library PR, the selection tree. Without a tree, the on-path, inclusion and apply checks are
SKIPPED.Collection (
SKILL.mdlines 89-94) is check-prior-art'sread.shplus twoghcommands, and a third when GitHub refuses the diff:read.shwrites four files:pr.json:number,title,state,isDraft,mergedAt,mergeCommit(null until the PR merges),changedFiles,body,comments,reviewsandurl;files.txt: every changed path with its status and line counts;diff.txt, or aSKIPPED: diffline when GitHub will not render the diff;xrefs.tsv: every PR that links to this one, with its state and title.gh pr view --json headRefOid,baseRefName,statusCheckRollupwriteschecks.json: the head sha, the base branch and every check at the head.gh api --paginate .../pulls/<N>/comments --jq ...writesinline.jsonl, one JSON object per inline review comment, with its author association.gh pr viewhas no field for inline review comments, sopr.jsonlacks them.diff.txtis aSKIPPED: diffline,gh api --paginate .../pulls/<N>/files --jq ...writeshunks.txt, each file's hunks. GitHub refuses a diff past 300 files, but its files endpoint still lists up to 3,000 files with each one's patch (none for a binary file). Sohunks.txtstands in wherever the diff is read, though not where it is applied.Comments stay JSON. An untrusted-input section treats every title, body, comment, diff and hunk as data. It reads a comment's
authorAssociationas whose word the comment is, not as proof that it holds.Steps, one artifact each:
mechanism.txt: two sentences from the diff, namingpath:symbol. Then the step readsxrefs.tsvand the comments:SUPERSEDEDclass likewise rests on a named replacement.SUCCESSOR: <ref> <state>. The agent asks the user about it, and it goes to Step 9.operating_point.txt: hardware, model, dtype, batch, lengths, parallelism, flags and reported results. Each is a verbatim quote with its source, orNOT STATED. Then oneGAPline for each dimension that differs from the target.on_path.txt: each changed source path startsUNKNOWN. It moves toON-PATHorOFF-PATHonly on a cited selection site at the target commit: platform, arch, capability and dtype checks, backend registries, environment reads, tuning tables. The walk uses theselectiontree when that tree holds the site.inclusion.txt: check-prior-art's Step 5 snippet runs once for the PR and once for each merged revert, with the merge commit frompr.json.includedand 3 forunknown.SKIPPED: inclusionwith the probe's error.unknownmeans nothing in local git showed the PR. It never means the PR is absent.effect.txt: the metric, the direction at the target and why. It is always labelledpredicted. The author's numbers reach the report asquoted.conflicts.txt:$WORK/prior-art, with this PR's mechanism, tree, commit and changed paths. Its search and path scan also find the PR under analysis, and any PR stacked on it. One sentence tells the agent to keep those out of the shortlist and classes it writes. The verdict line goes intoconflicts.txt. When the verdict says-- incomplete, check-prior-art's Coverage goes into the report.git apply --checkofdiff.txtruns every time, in a scratch worktree at the target commit.APPLIES, orFAILSwith the first failing hunk.--reversemeans the tree already has the change. That settles anunknowninclusion asincluded.--reversecheck. If the diff applies backwards, the line islocal:<patch> REVERSE: the patch already carries the PR, and inclusion becomesincluded. A failure in both directions is aCONFLICT, as for a patch that carries an older head of the PR. Any other failure is drift.Binary files ... differstanza never applies. Every check therefore passes$BIN, an--excludefor each binary stanza's old and new path, and records each such path asSKIPPED: apply -- <path>: binary.risks.txt: one line per lens inreferences/dimensions.md.measure.md(optional): a plan the user runs, never the skill. It has:measured.refutations.txt: oneFINDING/ATTEMPT/OUTCOMEblock for each of these: risk, on-path line, gap,unknowninclusion, effect, check-prior-art verdict, conflict, merged revert and successor.unknowninclusion is attacked in the tree's own history, as check-prior-art's Step 6 does.report.md: the recommendation, the mechanism, the evidence rows, Coverage and the next step, plus the head sha and base branch fromchecks.json. Each evidence row is labelledverified,quoted,predicted,measuredorinferred.Recommendation (
SKILL.mdlines 25-39). One table with ten rows. The first row that applies wins, the last row takes every case left, and each row carries its next step:NOT-APPLICABLE -- reverted by <ref>: a merged revert survived refutation., relanded in <ref>when there is a merged reland, and the next step is to analyze that reland.NOT-APPLICABLE -- already in tree: the probe or the reverse apply found the PR. It reads-- already in tree via <patch>when the reverse apply after a local patch found it. It reads-- already in tree via <ref>when check-prior-art's verdict isEXISTS-MERGED -- in your treeorEXISTS-OPEN -- in your tree, because then the tree already runs the change through another PR.NOT-APPLICABLE -- merged as <ref>: the PR is not merged, and check-prior-art's verdict isEXISTS-MERGED -- inclusion unchecked. The next step is to analyze<ref>instead.NOT-APPLICABLE -- superseded by <ref>: the PR is not merged and either:EXISTS-OPEN -- inclusion unchecked.NOT-APPLICABLE -- off path: <condition>: every changed path isOFF-PATH.NEEDS-MEASUREMENT: an on-path line the effect rests on stayedUNKNOWN, or a blocking risk that only a run can settle survived.WAIT-FOR-MERGE -- <risk>: the PR is open and upstream is settling a surviving risk. That risk is changes requested, an open design question, a check failing at the head, or a competing open PR (check-prior-art'sEXISTS-OPEN -- inclusion unchecked).ADOPT-NOW: merged, on path, no blocking risk survived. It adds-- inclusion uncheckedwhen the probe answeredunknownor wasSKIPPED.CARRY-AS-PATCH: open, or closed unmerged with no surviving successor; on path; no blocking risk survived. It adds-- conflicts with <patch>from Step 6.NOT-APPLICABLE -- <lens>: <condition>: everything else, such as a confirmed blocking risk.ADOPT-NOWandCARRY-AS-PATCHalso add-- does not apply at <commit>when the apply check failed. Their next step then starts by resolving the hunk it names.Risk lenses.
references/dimensions.mdholds six lenses. Each is a way a change that is right on its author's platform turns out wrong, slower or inert on a ROCm deployment. What the change does, which paths reach it and whether it is in the tree are covered by Steps 1 to 4. Each lens says where to look, what makes it a risk and when it stays clear. Like review-pr's rules, each cites the public upstream PR it was learned from:e4m3fnuzon gfx942 against OCPe4m3fnon gfx950, and offset width): #46730, #39953;Dependency. This PR depends on feat(skills): add check-prior-art, a contributor skill that finds a planned change upstream #1850 ("feat(skills): add check-prior-art, a contributor skill that finds a planned change upstream"). This skill uses that PR's
read.sh, its Step 5 snippet, its procedure through the verdict, and its gotchas. feat(skills): add check-prior-art, a contributor skill that finds a planned change upstream #1850 in turn depends on feat(pr_knowledge): probe whether an upstream PR is in a local git tree #1847, the inclusion probe. The kernel-names refactor that feat(pr_knowledge): probe whether an upstream PR is in a local git tree #1847 used to stack on has landed in main as refactor(kb_store): move derive_kernel_names into kb_store.identity.kernel_names #2028. This PR no longer carries that refactor.Every PR in the stack targets main. Until feat(pr_knowledge): probe whether an upstream PR is in a local git tree #1847 and feat(skills): add check-prior-art, a contributor skill that finds a planned change upstream #1850 merge, this diff also carries their commits: 10 from feat(pr_knowledge): probe whether an upstream PR is in a local git tree #1847, 16 from feat(skills): add check-prior-art, a contributor skill that finds a planned change upstream #1850 and 14 from this PR. Against main that is 17 files, +1967/-20. feat(skills): add check-prior-art, a contributor skill that finds a planned change upstream #1850's head
75d77c943is an ancestor of this head, andgit diff 75d77c943 6cc661136touches only the three files above (+372/-0).Linked issue(s): none.
Tests: added/updated? commands run? (what to test; if a test was replaced, where its assertions live now):
No test is added, because this PR adds no script and no Python: its three files are Markdown. The collection it runs is check-prior-art's
read.sh, whichscripts/tests/test_check_prior_art.pyin feat(skills): add check-prior-art, a contributor skill that finds a planned change upstream #1850 pins, plus threeghcommands and oneawkline written out inSKILL.md.read.shkeeps comments as the JSON thatgh pr viewreturns, andinline.jsonlis JSON too, so there is no rendered comment format for a test to pin.scripts/check_cli_references.pychecks thepython -mmodules andsrc/script paths in everySKILL.md. This one names neither, so nothing checks itsread.shpath or itsghandawkcommands automatically. They were checked by running them, below.Commands run at head
6cc661136(main7ac8c1229):pytest scripts/tests/test_check_prior_art.py scripts/tests/test_check_cli_references.py src/kernelforge/tests/knowledge/pr_knowledge/test_inclusion.py: 47 passed (10 + 4 + 33).pytest -n 16 scripts/tests: 742 tests, 738 passed. Main has 732, 728 passed. The 10 extra tests aretest_check_prior_art.pyfrom feat(skills): add check-prior-art, a contributor skill that finds a planned change upstream #1850. The same 4test_code_metrics.pyfork-comment tests fail on both, from the host: apackage.jsonwith"type": "module"above the pytest temp directory makes Node.js load theirharness.jsas an ES module (ReferenceError: require is not defined).pre-commit run --fileson the three files passed these hooks: trailing whitespace, end of file, merge conflicts, large files, private key, line endings, reuse, gitleaks, codespell and check-cli-references.python scripts/check_cli_references.py: exit 0.lint-imports: 10 kept, 0 broken.python scripts/code_metrics.py:--base-refset to feat(skills): add check-prior-art, a contributor skill that finds a planned change upstream #1850's head: PASSED, 3 files judged;--base-ref origin/main, which includes the stacked PRs: PASSED, 17 files judged.ruff check,ruff format --checkandscripts/check_broad_suppress.pyon the 7 Python files the stacked PRs change: clean. This PR changes no Python file.Live, read-only run against public vLLM PRs, at
88bd0be46; the last commit changes only how Step 6 reads a failure after a local patch. The tree was a local vLLM fork ata9b39d6dcb, a commit from 2026-08-05, and the probe ran from this source tree.pr.json,files.txt,diff.txtandxrefs.tsv.checks.jsonwith the head sha, basemainand 87 checks.inline.jsonlwith the 3 inline review comments, whichpr.jsondoes not carry.gh pr view --json statusCheckRollupreturned the same number of check contexts as GraphQL'stotalCountfor six PRs. They had 10 to 254 contexts each; #50243's 254 is more than one GraphQL page of 100.read.shwroteSKIPPED: diff(GitHub's HTTP 406 past 300 files), and thehunks.txtcommand wrote hunks for all 1012 paths, exit 0. On #50243, whose diff GitHub renders, the command wrote nothing and exited 0.included, methodsubject, exit 0.unknown, methodnone, exit 3.SKILL.md:FAILSforward and applies with--reverse, so the tree has it.FAILSboth forward and with--reverse, because the tree's copy offused_indexer_q.pydiffers from the PR's base. The qualifier is-- does not apply at a9b39d6dcb.FAILS, because its path is absent at that commit.$BIN, the diff fails at the PR's parent, on the binary stanza alone ("cannot apply binary patch ... without full index line"). With$BIN, it applies at the parent, and applies with--reverseat the merge commit.$BIN, the diff applies forward at the parent and with--reverseat the child. Excluding only the new name fails the reverse check on the rename.6cc661136: the diff applies at the commit and the patch isOVERLAP. After the patch, the forward check fails with "patch failed: m.py:1" and the--reversecheck applies, so the line islocal:<patch> REVERSE, notCONFLICT. With a patch that changes the same line differently, both directions fail:CONFLICT.search.sh, run with two terms for #57425's mechanism (SparseAttnIndexerKpool forward_nativeandforward_cuda forward_native ROCm), listed #57425 itself among its 18 candidates. That is the case the Step 6 exclusion sentence covers.Size/complexity triggers crossed: split, or why the shape is right: none.
origin/mainand reports 253 production Python lines. All of them come from feat(pr_knowledge): probe whether an upstream PR is in a local git tree #1847: its head alone gives 253. feat(skills): add check-prior-art, a contributor skill that finds a planned change upstream #1850 and this PR give 0 (0 against feat(skills): add check-prior-art, a contributor skill that finds a planned change upstream #1850's head).SKILL.mdis 280 lines and states 280 as its budget, as review-pr (350) and check-prior-art (240) state theirs.references/dimensions.md(91 lines), which is opened only at Step 7.If this simplifies or refactors: which mechanism was removed, which contract was preserved, and the tests that show it: not a refactor; a new skill.
Observable effect: what an operator will now see, and what the old behaviour cost them (if none, why the change is unobservable):
analyze-upstream-prskill, listed in AGENTS.md. Given an upstream PR and a target deployment, it writes a work directory that ends inreport.md, with one of the ten recommendations and its next step.NOT-APPLICABLE -- merged as <ref>, with "analyze<ref>instead". It is not reportedCARRY-AS-PATCH.NOT-APPLICABLE -- superseded by <ref>.NOT-APPLICABLE -- already in tree via <ref>.NOT-APPLICABLE -- already in tree via <patch>. It is not told the PR conflicts with its own patch and to applydiff.txta second time.CARRY-AS-PATCHcreates such a patch, so a rerun after it reaches this case.NOT-APPLICABLE -- off path: <condition>.WAIT-FOR-MERGE).ADOPT-NOWandCARRY-AS-PATCHsay so (-- does not apply at <commit>). They no longer tell the user to apply a diff that fails.SKIPPED: apply. Without the exclusion,git applywould read every such PR as-- does not apply, and the reverse check could not show that the tree already has it.SKIPPED, which the report's Coverage shows.supersededby a PR stacked on it or following it up (Step 1). A PR stacked on it does not hold it atWAIT-FOR-MERGEeither, because Step 6 keeps that PR out of check-prior-art's shortlist and classes. An example is [ROCm][Perf][Qwen3.8] Mono decode layer for Qwen3.8 on MI355X vllm-project/vllm#60833 and #61271, a draft stacked on it.SKIPPED: inclusionwith its error. It is not read as an answer.UNKNOWN.git worktree add, thengit worktree remove).jqandgh, andghmust be authenticated because check-prior-art's path scan uses GraphQL.Breaking changes: no. The PR only adds files and one AGENTS.md row. check-prior-art's
read.sh,lib.shand their outputs are unchanged.PR addresses single concern: yes. The skill is one capability. The other commits in the diff belong to the stacked PRs beneath it, feat(pr_knowledge): probe whether an upstream PR is in a local git tree #1847 and feat(skills): add check-prior-art, a contributor skill that finds a planned change upstream #1850.
Root cause is upstream (Magpie/TraceLens/GEAK/IntelliKit/AgentKernelArena), ticket filed: no; not applicable.