Repository navigation
docs: describe loopwright by its principles, not its stack (#13) - #17
Merged
SamuelDenani merged 9 commits intoOct 7, 2026
Merged
Conversation
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…les doc (#13) Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ries (#13) Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…13) The preamble said "The engine that enforces them lives in `.loopwright/scripts/`", attributing enforcement of all twelve opinions to that directory one line after citing the doc that denies it: `docs/loopwright/principles.md:175-176` states the engine has zero coupling to Claude, agents, skills or sessions. Six of the twelve `enforced by:` pointers live under `.claude/`, so an agent following this line to find what enforces test-first would find nothing there. "Its engine lives in" drops the false attribution and also resolves the sentence's double "them" (the opinions, then the tests). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The old lead's "a CI quality gate ... plus the loop that feeds it" was its
only statement that the product has two halves, and roughly half the README
is about the loop half. Dropping it left `README.md:131` ("The gate is the
enforcement half. The other half is how work reaches it:") introducing that
duality cold.
Sentence 2 now carries the category fact, so sentence 1 stays the opinion and
the lead still carries the committed baseline, the earned-vs-bought question,
and the verdict as a comment an agent can act on.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
✅ Quality gate passedcommit
|
| Check | Baseline | Now | Verdict | |
|---|---|---|---|---|
| TypeScript errors | — | n/a | collector not configured — see docs/loopwright/quality-gate.md | |
| High advisories | 0 | 2 | regressed 2 (tolerance 0) |
High advisories
brace-expansion— high: brace-expansion: Quadratic-time expansion of the{a},b}rewrite causes CPU denial of service · fix available — upgrade itjs-yaml— high: js-yaml: maxTotalMergeKeys does not limit CPU use for empty merge sources · fix available — upgrade it
📊 All metrics
| Check | Baseline | Now | Verdict | |
|---|---|---|---|---|
| ✅ | Failing tests | 0 | 0 | holding |
| ✅ | Failing test suites | 0 | 0 | holding |
| TypeScript errors | — | n/a | collector not configured — see docs/loopwright/quality-gate.md | |
| ✅ | Lint errors | 0 | 0 | holding |
| ✅ | Lint warnings | 0 | 0 | holding |
| ✅ | Critical advisories | 0 | 0 | holding |
| High advisories | 0 | 2 | regressed 2 (tolerance 0) | |
| ✅ | Suppressed advisories | 0 | 0 | holding |
| 📈 | Line coverage | 84.67% | 85.01% | improved 0.34% |
| 📈 | Branch coverage | 78.93% | 79.44% | improved 0.51% |
| 📈 | Function coverage | 89.65% | 89.71% | improved 0.06% |
| 📈 | Statement coverage | 85.01% | 85.41% | improved 0.40% |
| 📈 | Duplicated code | 0.90% | 0.88% | improved 0.02% |
| ✅ | Highest function complexity | 14 | 14 | holding |
| 📈 | Average function complexity | 1.81 | 1.80 | improved 0.01 |
| ✅ | Oversized files | 0 | 0 | holding |
| ✅ | Skipped tests | 0 | 0 | holding |
| ✅ | Focused tests (.only) | 0 | 0 | holding |
| ✅ | Tests with no assertion | 0 | 0 | holding |
| ✅ | Coverage-ignore hints | 1 | 1 | holding |
| ✅ | Type suppressions (@ts-ignore etc.) | 2 | 2 | holding |
| ✅ | Inline lint suppressions | 2 | 2 | holding |
| ✅ | Empty catch blocks | 0 | 0 | holding |
📈 This PR improves 6 metric(s). Run
node .loopwright/scripts/quality-gate.mjs --update-baselineand commit.loopwright/baseline.jsonto lock the gain in.
Generated by .loopwright/scripts/quality-gate.mjs · reproduce locally with node .loopwright/scripts/run-report.mjs --all && node .loopwright/scripts/quality-gate.mjs · full reports are in the workflow artifacts.
SamuelDenani
marked this pull request as ready for review
October 7, 2026 23:39
Code reviewNo issues found. Checked for bugs and CLAUDE.md compliance. |
This was referenced Oct 7, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What and why
loopwright described itself through its stack and its directory layout in the four
places that carry its identity. This makes the process opinion lead and the stack
follow, so the source repo and every repo that adopts it tell the same story that
docs/loopwright/principles.md(landed in #11) tells.The most consequential of the four is
.loopwright/claude-md-section.md.install.sh:30syncs it into every host repo andinstall.sh:53-63splices it intothat repo's
CLAUDE.mdbetween the marker comments — it is how loopwright introducesitself to everyone who adopts it, and it overwrites each adopter's marker region on
their next install run. This repo's own
CLAUDE.mdmarker region is that block(verified byte-identical), so that edit is one text applied twice and guarded by a
byte-identity sync check.
Part of #13
Spec:
docs/specs/issue-13.mdThe one line whose truth value changed
Everything else here is reframing.
README.md:142-143was an actual correction:P8 makes the merge half a default that a host can opt out of, so the absolute claim
was wrong. It now reads:
P8's opt-in knob does not exist in code yet (RFC #5 records this in its Risks), so
the text states the rule without naming a config key, and says plainly that no opt-in
ships today. "Nothing in the harness merges" was verified against the code, not just
the doc: no
gh pr merge, auto-merge ormerge_methodcall exists under.claude/,.github/,.loopwright/scripts/,install.shorsetup.sh, and.claude/skills/babysit-pr/SKILL.md:56reads "Merging is the user's decision — nevermerge."
The second site of that absolute rule is
docs/loopwright/loop-harness.md:66, whichbelongs to #12, not to this PR. A reader who greps for the old phrasing will still
find it there until #12 lands — this branch is not half-finished.
Nothing factual was removed, with that one exception
Every requirement fact survives; it just stops being the identity:
package.jsonis requiredREADME.md:181README.md:117,:183.loopwright/scripts/, tests at.loopwright/tests/CLAUDE.md:6cd .loopwright && npx vitest runruns themCLAUDE.md:7(verbatim).loopwright/.loopwright/claude-md-section.md:6.loopwright/claude-md-section.md:7How "leads with the process opinion" was made checkable
So this was not a matter of taste, each rewritten lead had to pass a literal test: the
first sentence names a concrete opinion, and does not contain the stack/mechanism
words for that site before the opinion appears.
docs/loopwright/quality-gate.md:3-5was the tone to match. All three leads scored FAIL before and PASS after.
Plan recap, with per-step commits
## Your toolchain is a detail, the:91clause, the:173parentheticalc01c0eeprinciples.mdrow added first in "How it's wired"be9571f,ab9ee43da0bf75CLAUDE.md:1-6preamble — a separate site, above the marker27edb2bpackage.jsondescriptiononlyabf29b0c60d8d4,611bc5fCLAUDE.mdholds two independent texts and only one is shared, which is why steps3 and 4 are separate:
:1-6is the preamble above<!-- loopwright:start -->, uniqueto this repo and shared with nothing; the marker region is the injected block. An
earlier review missed the preamble, so it got its own step.
Rulings I made
Recorded here because this is the only place they reach a human.
README.md:141-144restates P1 and I left it. The paragraph "State lives inartifacts — the refined RFC on the issue, a committed spec in
docs/specs/, onecommit per plan step, the PR conversation…" duplicates P1's second clause. Task: Strip opinions from loop-harness.md, leaving mechanics #12's
orchestrator found it; it is in my file but outside my acceptance criteria. My plan
was already accepted and committed and steps were running when it surfaced, so I
declined to re-scope mid-execution. Follow-up issue wanted. It is also stricter
than the harness actually is —
/grill-rfckeeps its task spine and sub-issuedrafts session-scoped and uncommitted, with no carve-out stated.
If wrong: one duplicated statement of P1 survives after both Task: Strip opinions from loop-harness.md, leaving mechanics #12 and Task: Describe loopwright by its principles, not its stack #13 merge,
and a reader may believe the harness commits more state than it does. The fix is a
~4-line follow-up in a file no other task owns; re-scoping mid-run risked a
plan/spec mismatch across five remaining steps.
The spec's propagation command was denied by a permission classifier; I accepted a
verified equivalent.
awk … > CLAUDE.md.tmp && mv CLAUDE.md.tmp CLAUDE.mdwasrefused as irreversible local destruction. The coder did not request a permission
rule, re-issue it through another tool, or delegate it — it ran the installer's awk
verbatim to a temp file, applied that content, and proved byte-identity. I
re-verified independently: running
install.sh's own splice to a scratchpad fileand diffing gives zero difference, so
CLAUDE.mdis exactly what the installerproduces. I did not run the blocked command myself.
If wrong: an adopter's next install could produce a different
CLAUDE.mdthan thisrepo ships. Mitigated by running the installer's actual awk program, with its actual
marker literals, against the real section file.
I treated a dropped "today" as a failed verification, not a deferrable minor.
The spec mandates "ships no such opt-in today" and the first Step 2 text omitted
it. Bare present tense reads as a standing commitment never to automate merging —
the inverse of P8. Sent back for one fix round (
ab9ee43).If wrong: one round-trip spent on a single word. Had I deferred it, the README
would have asserted the opposite of the principle this RFC exists to state.
CLAUDE.md:5was fixed because it contradicted the doc it cites. "The enginethat enforces them lives in
.loopwright/scripts/" attributed all twelveopinions to that directory, but
principles.md:175-176says "nothing under.loopwright/scripts/depends on Claude, agents, skills or sessions" — P1, P6, P8,P9, P10 and P11 are enforced under
.claude/or not yet at all. The clause was newin this branch, so not inherited. Now reads "Its engine lives in …" (
c60d8d4).If wrong: an agent asking what enforces test-first is sent to the wrong directory,
in the first file every agent in this repo reads.
I left four minors the final review voted to leave. See below.
No native task list exists in this background session, so the ledger plus this PR
body are the whole record of progress.
If wrong: the user loses a live task-list view mid-run; the delivered diff is
unaffected.
Deferred minors, consciously left
README.md:93-94— "loopwright fixes the metric vocabulary and the verdict, neverwhich tool measures each metric" is universally quantified, but 3 of 5 collectors ship
exactly one adapter (
tsc,npm-audit,jscpd); real choice exists only forlintand
tests. Accurate as a P12 boundary claim, and the adapter table immediately belowis the disclosure.
README.md:146-147— the gate half compresses P2 to its first sentence and omits"and review findings resolved". Not a regression (the old text had the identical gap),
and the sentence signposts the compression by pointing at P2 and P8 in full.
README.md:149— "the harness" is not defined inREADME.md, whose own word is"the loop". Vocabulary preference; "harness" is what
principles.md:110-113uses.package.json:4— the old description's explicit "a CI quality gate that agentscannot cheat" is now implied by "green must be earned" rather than stated. Not on
the spec's must-survive list, and
package.jsonis"private": true, so this stringis never published.
Two further items were examined and ruled not defects: the shared block's
.loopwright/location claim is loose (the loop ships in.claude/, CI in.github/)but is byte-preserved from the pre-change text and is a fact the spec protects; and
"a committed baseline" is briefly untrue between
install.shandsetup.sh, before ahost records one.
Verification
confirming no metric moved. Both warnings are pre-existing and not from this branch:
typecheckcollector unconfigured, andaudit.high= 2 (brace-expansion,js-yaml). Noaudit.ignoreentry was added — both have upstream fixes andCLAUDE.mdforbids ignoring an advisory that does..loopwright/baseline.jsonand.loopwright/config.jsonare untouched.IN-SYNC, andCLAUDE.mdis byte-identical toinstall.sh's own awkoutput.
README.md,CLAUDE.md,.loopwright/claude-md-section.md,package.json,docs/specs/issue-13.md.docs/loopwright/loop-harness.mddoes not appear; Task: Strip opinions from loop-harness.md, leaving mechanics #12 owns it and was executingagainst it in parallel, and the no-overlap guarantee is what made that safe.
package.jsonchanged onlydescription(structural compare: key order preserved,no other field differs).
.loopwright/config.jsonscopessources.rootsto.mjsunder
.loopwright/scriptsand.loopwright/tests, so markdown and one JSON stringmove no metric; a vitest case asserting on prose would itself be a defect. Each step
substituted a runnable check with recorded before/after output instead.
🤖 Generated with Claude Code