Scope a PR with ripwire

SkillDev tools

Scope a kube-coder change before you open or update a PR — what the diff actually touches, which tests reach it, what the change made worse, and what is left untested. Use after the code is written and before kc-preflight/kc-ship-pr, so the PR description and the tests you run come from the call graph rather than from memory. Also the answer to "is this diff bigger than I think?" and "which tests should I run for this?".

Available today. Use it from your connected AI after setup.

Connect ahel once, and every AI you use reads what you have installed.

Then ask your AI: use the Scope a PR with ripwire skill

What this skill tells your AI

The instructions your AI receives, as published by imran31415/kube-coder in .claude/skills/kc-scope-pr/SKILL.md and read by ahel’s review.

Run after the change is written, before kc-preflight and kc-ship-pr.

ripwire is baked into the image (/usr/local/bin/ripwire, pinned in devlaptop/Dockerfile). Zero deps, and the whole workspace chart — 522 files, 10k symbols — maps in under two seconds, so this is cheap enough to run on a one-file change.

Why this exists

This repo has repeatedly shipped changes whose blast radius was larger than the diff looked. Two from recent history, both of which this skill's output would have named up front:

  • A run-preflight guard was added to BoardRunsManager.create and four board test suites created runs, not one. CI went red with 64 failures and 29 errors while the same tests passed locally.
  • mcp_dashboard.py and server.py disagreed about one constant. Nothing in either file's diff said the other existed.

The point is not the numbers, it is the direction: --test-gate answers "which tests reach what I touched" from the call graph, which is the question a human answers from memory and gets wrong.

The three calls

Scope is one root at a time. charts/workspace is the usual one; use charts/workspace-controller for controller work.

ROOT=charts/workspace

# 1. What does this change actually reach, and which tests cover it?
#    Defaults to the git diff. exit 4 = there are tests to run or untested
#    blast radius; that is an obligation, not a failure.
ripwire "$ROOT" --test-gate

# 2. What did I make WORSE? exit 2 only on a pre-existing symbol regressing.
#    A `new-symbol` row never gates — it is still your debt, so read it.
ripwire "$ROOT" --quality-delta

# 3. Did I change a contract someone depends on? (per symbol, ~ms)
ripwire "$ROOT" --edit-check=SomeChangedSymbol

--situ is the same information as --test-gate without the gate, for mid-task orientation rather than a pre-PR check.

Reading the output

It is minified XML with a long self-describing header comment — the header explains every attribute, so read it once rather than guessing. The attributes that carry the decision:

attributemeaning
changed=files in the diff
impacted=symbols transitively reaching them — the real blast radius
tests=test files that reach the change; each <t> may carry run="<cmd>"
untested=impacted symbols no test reaches — <u> rows, worst first by ccx
gating= on quality-deltaregressions that will fail the gate

counts_floor="1" means every count is a floor, not a total: dynamic dispatch and script-invoked harnesses are not call edges. untested=0 is therefore "nothing the graph can see", never "fully covered".

What to do with it

  1. Run the tests it names, not the ones you remember. If tests= lists a suite you did not expect, that is the finding — go look at why it reaches your change before assuming the tool is wrong.
  2. Put impacted= in the PR body when it is large. A reviewer seeing "3 files changed" and a four-figure blast radius reads the diff differently.
  3. Fix or justify each --quality-delta row. Do not game the number; a wrong abstraction beats a good score.
  4. Treat untested= rows as the test-writing list, highest ccx first.

Then hand off: kc-preflight runs the suites for real, kc-ship-pr opens the PR.

Honest limits

  • A floor, never a total. Reflection, dynamic dispatch, and the shell harnesses under tests/ are invisible to a static call graph. --test-gate reports script_gates_unmodelled= for exactly this reason. It narrows what you must think about; it does not replace thinking.
  • It cannot see non-code coupling. Two constants that must agree across two files, a Helm value a Python default mirrors, an API shape the SPA assumes — no call edge, no edge in the graph. That is precisely the class of bug in the second example above, and this skill would not have caught it either.
  • Green here is not green in CI. It reasons about the tree you have. Run kc-preflight.

Signals

GitHub stars
354
Forks
32
Last commit
Sep 2026
Advanced
Catalog kind
skill
Gateway key
kc-scope-pr
Source
github.com/imran31415/kube-coder