Skip to content

chore(skills): review PRs through angles and whole rounds - #1522

Merged
OmarAlJarrah merged 30 commits into
mainfrom
chore/review-skill-angles
Nov 5, 2026
Merged

OmarAlJarrah merged 30 commits into
mainfrom
chore/review-skill-angles

Conversation

@OmarAlJarrah

@OmarAlJarrah OmarAlJarrah commented Nov 5, 2026 •

Copy link
Copy Markdown
Member

Summary

Two changes to .claude/skills, plus the lines of CLAUDE.md, docs/ir/ir-version.md and a comment in ir/irversion_test.go they touch.

  1. The review skill becomes an orchestrator of review angles. Its first round finds every flaw and its second confirms the fixes.
  2. Every open skills: issue is fixed, each in the skill whose trigger fires when its lesson applies.

The review skill

The skill ran fixed passes out of one reference file already at its word cap. Each pass sampled what it checked, and nothing asked on its own about testing adequacy, performance, reuse or consistency. Fixes were written before they were weighed, and later rounds kept finding what the first should have.

SKILL.md is now a table of angles. Each angle is a reference under .claude/skills/morphic-reviewing-prs/references/ that says what it attacks, which skills it loads and the matrix its report fills, every cell with a run or a reason:

Angle Attacks
Correctness each altered output, against what a consumer should get and main
Fidelity each touched construct, at every position and spelling, for loss
Determinism each result in both declaration orders, at every limit, on every run
Robustness each limit, call into code the package does not own, and read, with hostile input
Contract what consumers read: the IR and IRVersion, diagnostic codes, the CLI, the Go API
Design the mechanism, against the simplest correct one that scales and extends
Reuse and maintainability each addition, against what the tree or a maintained library could own
Testing each changed function by input class, each test by planted defect
Performance new work's growth and cost against main, in time and memory
Developer experience names, placement, comments and messages
Consistency each construct and name, against the codebase's own
Claims and process every sentence the change writes, closed issues, and how it ships

references/rounds.md holds how a round runs:

  • a round runs every angle over the whole change, deep into its logic and broad over the code living with it;
  • every decision rests on the text of the vision it serves and on a run showing it holds;
  • a fix is designed before it is written;
  • the first round finds everything, and a fresh reader that the first round did not anchor runs the second;
  • a later finding is a miss, whose angle is sharpened.

Round 1 now runs before a branch's first push (morphic-shipping-prs), and CLAUDE.md's review line runs round 2 once the PR opens. morphic-verifying-changes defines done by round 1.

The old references/review-probes.md rules move into the angles they serve. Five are reworded for the new structure:

  • code-before-claims gives its mutation half to plant-beyond-the-listed-mutants;
  • fan-out-a-pass-to-a-reader becomes fan-out-an-angle-to-a-reader;
  • mechanism-exists widens to helpers, algorithms and libraries;
  • read-standing-reviews and review-own-fixes speak of angles.

The old skill's sentence on deliberate oddities becomes oddity-needs-a-comment.

The open skills issues

Each issue becomes a rule or the edit it asks for, cited from the review angle that applies it.

A review of the branch at 78c30a744 found five rules a closing issue named as lacking a lesson that never cited the new rule the lesson went into, and two asks in the issues' comments with no home. This PR now also:

A fresh reader's review of 29372a248 found six more nits and a trap in planting Python. This PR now also:

  • has the lint give a skill path git ignores its own reason when the repository lacks it too, which the fallback to the repository had reported as missing, and pins a port's colon, a one-word bare key and a script both the skill and the repository hold (skills: skills_lint reads a repository-root scripts/ path as the skill's own #1363);
  • has oddity-needs-a-comment accept a lint finding's .golangci.yml exclusion with its reason, where CLAUDE.md puts a suppression, and disprove-each-finding defer to it;
  • has the push checklist stop with a message when it finds no branch to push to, and review-own-fixes push through it;
  • writes out send-only-what-the-fetch-produced's gated command, and scopes own-commits-against-the-base's former-base exclusion to the subjects;
  • adds python-plant-without-bytecode: a planted Python file runs with -B from a copy holding no __pycache__, as CPython reuses a stale .pyc for a same-size plant written within one second;
  • restores to CLAUDE.md's review line the clause running the next round on a review's fixes, now until one finds no issue: or nit:.

A fresh reader's review of 3b4d18424 found one more defect, that golangci-lint caps a linter's findings at fifty as well as a text's at three, and five nits. This PR now also:

  • has lint-probe-lists-every-finding lift both caps, with --max-issues-per-linter=0 beside --max-same-issues=0;
  • has analysis-input-is-fixed's probe diff a result against one rooted at production's entries alone (skills: hold a whole-program analysis to one input set before counting over it #1506);
  • has ci-is-the-gate run the skills lint and the scripts' tests, which no CI runs, and moved-prose's probe skip a file's front matter;
  • says in python-plant-without-bytecode that -B needs a copy free of __pycache__, and names /usr/bin/time in count-stops-at-the-timed-process's heading, the count it measured;
  • corrects the generations comment in ir/irversion_test.go, which still said two claims on one version always conflict (skills: the version-collision rule names the wrong part as conflicting #1378);
  • holds subjects.py's two bases in both orders.

A fresh reader's review of b4795b61a found that subjects.py, given a --base, stopped reading against main, so a branch started on a main that had moved past its base, then stacked on it, counted main's newer commits as its own; and three nits. This PR now also:

  • has subjects.py read a branch's own commits against origin/main as well as every --base, with a test of that branch shape, and own-commits-against-the-base name both and leave merges out of its probe, which then matches the count subjects.py prints;
  • pins the lint's normalizing of a repository path, as in scripts/./fuzz.sh;
  • has python-plant-without-bytecode run the unplanted copy beside each plant, by mutation-controls, as a test reading files beyond a copied scripts/ fails in every copy.

A fresh reader's review of 6ba7470c9 found no defect that breaks anything, and three nits. This PR now also has the lint refuse a bare #key in prose and in a command, outside frontmatter and link targets (#1344), keeps #1266's var _ option in optional-interface-converted, refuses an origin/ base whose name a failed gh pr view left empty, and has Correctness load morphic-curating-skills for a change to .claude/skills.

Four items in the closing issues, left out of scope or deferred, named work no issue tracked. Each is now an issue, cited where its rule lives:

Open PRs editing the same files, for whichever lands second to lint on the merged tree:

Closes #1262
Closes #1263
Closes #1265
Closes #1266
Closes #1270
Closes #1285
Closes #1286
Closes #1294
Closes #1303
Closes #1306
Closes #1308
Closes #1317
Closes #1326
Closes #1328
Closes #1338
Closes #1341
Closes #1343
Closes #1344
Closes #1346
Closes #1347
Closes #1348
Closes #1352
Closes #1357
Closes #1358
Closes #1362
Closes #1363
Closes #1364
Closes #1374
Closes #1378
Closes #1380
Closes #1392
Closes #1427
Closes #1443
Closes #1444
Closes #1445
Closes #1454
Closes #1461
Closes #1462
Closes #1473
Closes #1476
Closes #1477
Closes #1493
Closes #1495
Closes #1503
Closes #1505
Closes #1506
Closes #1507
Closes #1510
Closes #1511
Closes #1520

Test plan

  • python3.14 .claude/skills/morphic-curating-skills/scripts/skills_lint.py → clean. python3.14 -m unittest discover -s .claude/skills/<skill>/scripts → OK for morphic-curating-skills, morphic-shipping-prs and morphic-verifying-changes, all on the tree merged with main at ab953d453.
  • Each script fix, reverted alone, fails its own test and only that test:
    • subjects.py reading origin/main alone fails the three --base tests, and reading the --base alone, without origin/main, fails test_mains_own_commits_are_never_the_branchs;
    • each of the three lint fixes fails its own new test, as does each half of the file:line:column fix;
    • the line-range grammar fails test_a_pattern_or_a_ref_in_a_span_names_no_path reverted, without ranges, or with the stripping and the not-a-path test reading two grammars;
    • removing subjects.py's empty-base check fails test_an_unknown_or_empty_base_exits_two;
    • the ignored-path reason, reverted or taken from the repository path, fails test_a_path_git_ignores_is_held_as_no_clone_has_it, and a line suffix read without its end or a bare key required to hold a hyphen each fails its own case.
  • In a scratch repository holding a merge commit with an attribution trailer, the artifact grep reading first-parent commits only finds no hit, and the grep the checklist now runs finds it.
  • The lint's path changes, over the final tree's skills and CLAUDE.md: main's lint, run there, reports no finding the branch's does not, and the line-range grammar reads each of 2,337 distinct span and code-block words as 78c30a744's lint did.
  • Each rule block of review-probes.md at 4ac3031d7, compared with its new home after mapping citation paths back: 27 of 36 are word for word. The five above differ for the new structure, and four for other changes on this branch: near-miss (skills: near-miss names only annotation keywords as a predicate's near misses #1507), price-common-path (skills: the common-path cost row sends a small claim to a reading too wide to show it #1308), disprove-each-finding, which now defers to oddity-needs-a-comment, and moved-prose, whose probe now skips front matter.
  • Every rule key this branch adds is cited from outside its own block, by an angle's steps, another rule or a SKILL.md.
  • Each command the new text prescribes was run from the root, among them:
    • the push checklist's reads, subjects.py --base and the push by name (--dry-run);
    • gh pr view <N> --json mergeable,statusCheckRollup;
    • the open-PR search for an issue's closing line;
    • go run ./cmd/morphic-harness on a sample spec;
    • make check-lint-version;
    • the version-repeat check (on main: only 0.3.0 and 0.4.0, which repeat by design);
    • replay-own-diff-onto-main in a scratch repository, whose merge then differs from main in the PR's own files alone, with main as its second parent;
    • pgrep -lf 'make gate' beside a shell running no gate, which it lists, and gh pr view 1459 --json state,mergedAt on a landed stacked base;
    • go test's PATH prefix and its cache keying on PATH, in a scratch module;
    • the artifact grep with pat unset, which stops with an error under bash and zsh alike, and the push with no branch, which does the same;
    • send-only-what-the-fetch-produced's command, which stops at the fetch for PR 0 and passes its gates for this PR;
    • the stale .pyc probe, which reads the first of two same-size writes twice without -B.
  • Each closing issue was read whole, comments included. None changed between the read and this body. Each out-of-scope item or deferred alternative names an open or merged item, says why no work is needed, or is one of the four issues filed.
  • Two second-round reads by a fresh reader. Each finding was confirmed before it was fixed.
  • A third review, of the final state at 78c30a744: 5 nits and 2 suggestions, fixed in 969ee8300 to 4a0a39b2a and in this body's count above, and the two comment asks above, fixed in cd7e51109; the checklist's grep guard followed in 29372a248. Each script fix was seen to fail its test reverted, and each commit passes the lint and the scripts' tests on its own.
  • A fourth review, by a fresh reader, of 29372a248: 6 nits and 2 suggestions, each reproduced before it was fixed, in b5d2f7a45 to 3b4d18424, with the loop clause above. Of the suggestions, showing a former base in the checklist's block is left out, as an optional [--base <tip>] there reads as a shell redirect when copied; the rule's scoped sentence carries the case.
  • A fifth review, by a fresh reader, of 3b4d18424: 1 issue and 5 nits, each reproduced before it was fixed, in dd99baa82 to b4795b61a, and a question on perf stat settled by naming /usr/bin/time in the heading. golangci-lint over sixty planted os.Remove calls gave 3, 50 and 60 findings by default, with --max-same-issues=0 and with both flags; the two-base test, with one base kept, fails in one order; and the front-matter probe passes the PR's files and flags a list line after prose.
  • A sixth review, by a fresh reader, of b4795b61a: 1 issue and 3 nits, each reproduced before it was fixed, in 64d3c9351 and 6ba7470c9. Each fix's planted defect fails its test beside an unplanted control, and git rev-list --count --first-parent --no-merges HEAD --not origin/main gives 25 on b4795b61a, the count subjects.py printed there.
  • A seventh review, by a fresh reader, of 6ba7470c9: no issue:, 3 nits and 2 suggestions, fixed in 85d3b1311 and 03acbbc24; each fix's planted defect fails its test beside an unplanted control.

The review skill ran fixed passes out of one reference file already at
its word cap, and nothing in it drove a review to finish in one round.
Passes sampled what they checked, fixes were written before they were
weighed, and later rounds kept finding what the first should have.

The skill is now an orchestrator of review angles. Each angle is a
reference saying what it attacks, which skills it loads and the matrix
its report fills: correctness, fidelity, determinism, robustness,
contract, design, reuse and maintainability, testing, performance,
developer experience, consistency, and claims and process. A round runs
every angle over the whole change, deep into its logic and broad over
the code living with it, however much it finds first.

rounds.md holds how a round runs: the setup, now also before a PR
exists and with no origin; CI's run as the gate; every decision resting
on the vision it serves and a run showing it holds; a fix designed
before it is written; and a first round that finds everything, with a
second, by a reader the first did not anchor, that confirms the fixes.

The existing rules move into the angle they serve, their text unchanged
bar the few the new structure rewords, and each new rule cites the work
that showed its failure. morphic-designing-code gains rules for sharing
one implementation and keeping domain-free code apart. The shipping
skill runs the first round before a branch's first push,
morphic-verifying-changes defines done by it, and CLAUDE.md's review
line runs the second round once the PR opens.
morphic-verifying-changes gains the rules its probes kept missing. A
mutant run owns its cache and stops before the disk fills, a kill counts
only from a test that reaches the plant, and a claim about what a check
leaves out is planted where only the excluded callers go. A full disk or
a removed cache reads as a failing build, a gate failure under load is
told from one the change caused, a test's go children never reach a go
wrapper on PATH, and a cache probe holds the whole environment fixed,
which replaces the rule naming GODEBUG alone.

A test raises a time limit's outcome through a seam, an absence is
asserted on the field that would hold it, a new gate target draws a
finding planted for it, a lint probe lists every finding, and a count
over a whole-program analysis takes a fixed input set.

The gate is answered by CI's run on the final head as well as by a local
run, in CLAUDE.md, morphic-verifying-changes and the styleguide
departures alike.
morphic-measuring-performance's readings misled in ways no rule named.
An instruction count stops at the timed process, so work in children
reads as free. A count holds only across two rounds and beside a control
build. A resident set read with the collector off is total allocation.
Statement counts per function find where a small difference comes from,
and an instruction count confirms each site. A loop that reruns a phase
until it settles is driven through many turns, at n and 2n, with its
budget sweep rerun past the first turn.

The common path is priced on a spec small enough to hold uncollected,
the golden spec answering only a claim of a large effect, in the skill's
claim table and in the review's price-common-path alike. A counting seam
is the one the code already has: a pure function's parameter, or a
type's field where a type does the work.
morphic-designing-code gains four rules from work its table let through.
A visitor of a type few nodes carry prunes the walk to them, with a test
on a carrier off the path and a counting seam, and the table sends a
document walk to it beside read-once-per-run. Each part of a bound's
charge is grown alone against the cost it stands for. A new recursion
under compilers/openapi joins the recursion pin with its bound. A
function one package hands another stays a function only for I/O, a
policy, a live query, a substituted seam or a callback, and otherwise
becomes the data the caller holds; the table gains its row.
The version-collision rule's heading and body read two ways, and it
named one part as conflicting where any of the constant, the row and the
entry can merge silently. It now says the PR merging second takes the
next version, and a check after each merge finds a repeated version, the
SKILL's bullet moving to merge time with it.

A new TypeID position is also read against the lists of references the
design documents give, a declaration's form reads only what an additive
change leaves alone, and a predicate over a property Unicode publishes
is swept over every code point beside its witnesses.
The push checklist read every commit back to origin/main, so a stacked
branch reported its base PR's subjects as its own, and one that had
left a stack read the stack's commits too. It now reads the branch's
first-parent line against the branch it targets, and subjects.py takes a
repeatable --base for the target and a former base, with tests. The
push names the PR's branch, so it runs from a detached review worktree,
and CI is read after it knowing a conflicting PR gets no run.

New rules read each issue a PR closes whole, comments and out-of-scope
items included, and again before saying it closes; send an edited body
only when its fetch produced it; count a cap two open PRs share at each
head; merge a landed stacked base's final head before main; replay a
branch's own diff onto main to leave a stack; and state that the
repository's no-attribution rule overrides a harness's reminder.
The review setup routed a review with no origin, and one before its PR
exists, only after the fetch it warns against, and called the pre-push
tree the author's own worktree. It now opens with those cases, a check
that no other checkout holds work on the PR's branch, and the route for
a stacked base that has landed; a mechanical conflict is resolved in the
throwaway tree rather than aborted. The gate rule says an unpushed
branch has no run yet, and the first round keeps its probes in a script
for the second.

The sentence on deliberate oddities, lost when the skill was split,
becomes a rule: only a comment at the line excuses one. A restructured
document accounts for every sentence it held. Claims and process runs
each command an edited rule prescribes, reads closed issues by the
shipping rule, and checks a choice resting on an open issue against
the open PRs settling it. Correctness simulates the runs a CI or cache
change claims, robustness re-measures a budget's stated margin when its
charge widens, and a near miss is taken from each class of keyword a
predicate tells apart.

The styleguide skill's trigger names the angles that load it, and a
misquoted name, a first-person phrase and unwrapped lines are fixed.
skills_lint held a grep pattern holding a slash, a git ref and a refspec
to the tree as missing paths, so probes were weakened to pass it. A word
holding a pattern's |, ^ or \, or a colon other than a :line suffix, now
names no path, and a span starting refs/ is a git ref. Over the current
skills no word the lint held as a path changes.

A rule cited by its key alone passed whatever key it named; the lint
now refuses that form and names the full one. A scripts/ or references/
path is held to the skill's own directory first and then to the
repository, which keeps a scripts/ of its own. Each fix has a test that
fails when the fix is reverted.
morphic-checking-style listed a chapter's rules by heading and sent a
reader to a rule's body only where a line already looked like a breach,
so a breach the heading does not suggest passed. Each listed rule is now
read to its Enforcement line before lines are held to it.

The departure exempting an unexported type from a compliance assertion
now holds only where a call's parameter is the interface; an optional
interface, found by a run-time assertion, gets a departure of its own,
converting the type where it is passed.

morphic-openapi-compiler gains a rule for a change to how a JSON Schema
dialect reads: count the committed corpus for the construct, then
measure on standalone schemas of the dialect and the test suite's
groups for it, each reached through a 3.1 wrapper, reading the type a
$ref lands on as well as the diagnostics.
Each rule added for the open skills issues is now cited from the review
angle that applies it, so a review, and an author's first round before
a push, reach it by name: mutation and plant rules from Testing,
measurement rules from Performance, a charge's parts from Robustness,
and a shared cap and a fetched body from Claims and process.

Reading the closed issues whole showed three out-of-scope items naming
work no issue tracked; each is now an issue of its own and named where
its rule lives. closing-issue-read-whole carries only the items naming
work still to do. A stale local linter's export-data failure gets the
toolchain rule its readers kept rediscovering.
The push checklist's artifact grep had been narrowed to the branch's
first-parent commits, which drops a merge commit's body and anything
merged from another branch, though a default squash pastes each one. It
now reads every commit the base and main lack; the subject check keeps
the narrower reading. A push from a detached tree with no PR stops on
an empty branch name.

A contract step had kept the version-collision reading the rule had
just settled, the rule's probe named history headings the file does not
have, and a departure's probe used \w, which git grep -E does not take
here, so it missed a second site. Whys that rested on open PRs cite the
issues recording the same evidence, the landed-base rule carries the
resolution its issue's comments record for main's later conflicts, and
the attribution rule gains its probe.

skills_lint holds a file:line:column span to its file, which main read
as a missing path and the pattern fix had stopped holding at all. The
IR version document no longer says the second branch always meets a
conflict. The angle intros are rewrapped to the width the rest keeps.
closing-issue-read-whole carried only an issue's out-of-scope items to
an open issue, while #1473 deferred a configuration change in its
Direction instead, which a second review round found unrecorded. A
deferred alternative naming work still to do now goes to an open issue
the same way.
Six issues this branch closes named an existing rule as lacking a
lesson, and each lesson went into a new rule beside it that the named
rule never cited: instructions-not-wall-clock (#1294, #1362),
count-on-one-thread (#1495), bound-the-product (#1461),
edit-pr-body-from-live-copy (#1326) and read-once-per-run (#1348). A
reader sent to the named rule met none of them, so each issue's title
still described its rule. Each named rule now cites the new one, inside
its 150 words.

The curating skill's rule format now says a rule split in two cites the
second from the first, and closing-issue-met-at-its-site has a review
hold each closing issue's title against the site it names on the head,
and each step of its Direction against the line meeting it.
gate-failure-under-load reran each failed package alone but never the
gate steps after the failure, which make gate never reached, so a load
failure left their verdict unknown while the reruns read as clean. #1347
asked for those steps to run after the reruns; the rule now says so.
The lint read a colon before anything but :line or :line:column as no
path, so a span citing a range such as file.go:12-20 went unchecked,
and a renamed file cited that way would pass. A path's line suffix is
now one grammar, a line, a line and column or a range, which both the
stripping and the not-a-path test read, so the two cannot drift. The
pattern's own :( alternative, which the colon rule already covers, is
gone.

subjects.py refuses an empty --base before git runs, but git refuses
one too with the same exit status, so the test passed with the check
removed. It now asserts the check's message.
Three paragraphs this branch edited were left unwrapped, one of them at
148 columns in docs/ir/ir-version.md, and are rewrapped to the file's
width.

interface-assertions-stay-narrow cited optional-interface-converted
right after "since the call fails the build", which read as support for
that sentence; it is the case the build cannot hold, and the rule now
says so where it cites it.
Two asks in the closing issues' comments had no home. #1347's: gates
that keep failing under load run one at a time from one queue, never
after a pgrep check, which matches any command line holding the words
and races another start. queue-gates-one-at-a-time says so, cited from
gate-failure-under-load, which is at its word cap.

#1427's: a review learns its stacked base has landed from the base PR's
state and mergedAt, as a baseRefName read before the retarget still
names the deleted branch. The review setup now says so beside the
landed-base rule it sends to.
The push checklist's artifact greps read $pat. Run in one chain whose
earlier step failed, as a fetch on a dropped connection does, pat was
never set and grep -niE "" matched every line of the log and the diff,
so a hundred kilobytes of hits hid any real one, and the push after it
still ran. It happened twice, on #1435 and on this branch. The greps
now read ${pat:?}, which stops them with an error naming pat.
The lint's fallback from a skill's own references/ or scripts/ to the
repository's reported a skill path git ignores as one that does not
exist, where main said no clone holds it. When neither holds the path,
the reason given is now the skill's own.

Three readings had no case to fail on: a colon before a port, as in
localhost:8080/v1, which the line-suffix grammar must read whole rather
than as a :line, a bare #key of one word, and a script both the skill and
the repository hold, which #1363 asked for. Each now has one.
disprove-each-finding had a review clear a finding by a decision in
.golangci.yml's exclusions or the tracker, while the oddity-needs-a-comment
rule it cites said only a comment at the line excuses one. The oddity
rule now accepts a lint finding's exclusion with its reason beside it,
where CLAUDE.md puts a suppression, still refuses the tracker alone, and
disprove-each-finding defers to it.

The push checklist ended in `[ -n "$h" ] && git push`, which ended the
chain with exit 1 and no message when it found no branch to push to, as
in a detached worktree before the PR opens. It now pushes to
${h:?name the branch}, which stops with that message, and
review-own-fixes points at the checklist rather than spelling the push
another way.

own-commits-against-the-base now scopes a former base's exclusion to
the subjects, as the artifact grep keeps those commits' messages, and
send-only-what-the-fetch-produced writes out the gated command its
probe runs.
CLAUDE.md's line on reviewing a new PR lost, in this branch's rewrite,
the clause sending a review back over its own fixes. It now runs the
next round on them until one finds no issue or nit, as
first-round-finds-everything already says.

python-plant-without-bytecode: a planted Python file runs with -B from a
copy holding no __pycache__, as CPython reuses a cached .pyc while the
source's size and modification second match, so a plant of the same
size written within that second is never read and reports the last
plant's verdict. The review's Testing angle cites it.
lint-probe-lists-every-finding had a probe pass --max-same-issues=0 to
see every finding, but golangci-lint also stops at fifty findings of
one linter by default, and says nothing of the rest: sixty planted
os.Remove calls drew three errcheck findings by default, fifty with
that flag and sixty with --max-issues-per-linter=0 beside it. The probe
now lifts both caps.

analysis-input-is-fixed's probe also diffs a result against one rooted
at production's entries alone, as #1506's comment asked.
The comment over generations said that whichever of two changes
claiming one version merges second meets the other's row in a
conflict. Two branches claiming 0.30.0 merged clean into two rows of it
(#1378), as docs/ir/ir-version.md now says, so the comment says the
same: whichever merges second checks for a repeated version.
ci-is-the-gate limited a review's local runs to probes, mutants,
differentials and measurements, while no CI runs the skills lint or the
scripts' tests, so a review of a skill change had no rule running them.
It now names both.

moved-prose's awk probe flagged every SKILL.md's closing front-matter
line as markup opening after prose. It now skips the front matter, and
still flags a list line after a paragraph.
python-plant-without-bytecode credited -B with a fix a copy free of
__pycache__ also needs, as -B writes no bytecode but still reads stale
bytecode left behind; its Why and Probe now say both. The heading of
count-stops-at-the-timed-process names /usr/bin/time, whose count the
rule measured, rather than every instruction count.

subjects.py's test of a former base passed its two bases in one order
only, so keeping the last base alone passed every test; it now runs
both orders.
subjects.py read a branch's own commits against --base alone once one
was given, so a branch started on a main that had moved past its base,
then stacked on that base, counted main's newer commits as its own and
held their subjects to its PR, while the checklist's artifact grep
beside it excluded both. It now reads against origin/main as well as
every --base, as no commit main holds lands again, and a test holds
that branch shape.

own-commits-against-the-base names both, and its probe leaves merges
out, as the subjects do, so it matches the count subjects.py prints.
The lint's fallback to a repository path normalizes it, and no test
held that: a span such as scripts/./fuzz.sh passed with the call
removed only because nothing cited one. The repository-script test now
does.

python-plant-without-bytecode now runs the unplanted copy beside a
plant, by mutation-controls, as a test reading files beyond a copied
scripts/ fails in every copy and would read as each plant's kill.
The lint refused a rule cited by its #key alone only in a one-word
span, so `see #key` in a command or #key in prose passed, as #1344
reported of every bare citation. Both are now refused, outside a
SKILL.md's frontmatter, where # opens a YAML comment, and outside a
link's target. A test also cites a script through scripts/../, which
the skill-path normalizing now has a case for.

subjects.py refused an empty --base, but the checklist passes
origin/<base>, which a failed gh pr view leaves as origin/. That is
refused too, naming why.
optional-interface-converted dropped the `var _` that #1266 offered
beside a conversion, which archtest accepts; it names both again.
Correctness names morphic-curating-skills as the domain skill of a
change to .claude/skills, which no angle loaded, and a line orphaned by
an earlier edit to disprove-each-finding is rewrapped.
@OmarAlJarrah
OmarAlJarrah merged commit 0d09a96 into main Nov 5, 2026
3 checks passed
@OmarAlJarrah
OmarAlJarrah deleted the chore/review-skill-angles branch November 5, 2026 16:14
OmarAlJarrah added a commit that referenced this pull request Nov 6, 2026
The departure's Rule and widened-field-values' Probe each gained a line
past the 100 columns their files wrap at, where no code span forces it,
and both are rewrapped. The Why of later-rounds-read-what-moved read
#1522's figure of about 240,000 tokens as what a round spent, where it
is the context each reader ended holding. The Why argues where the
findings sat, so the figure goes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment