Skip to content

feat(fabrika): the /adr skill and its derived CLI contract — wave-0 pilot (#4704) - #4724

Merged
usirin merged 7 commits into
mainfrom
umut/fabrika-adr-skill-4704
Aug 2, 2026
Merged

feat(fabrika): the /adr skill and its derived CLI contract — wave-0 pilot (#4704)#4724
usirin merged 7 commits into
mainfrom
umut/fabrika-adr-skill-4704

Conversation

@usirin

@usirin usirin commented Aug 2, 2026

Copy link
Copy Markdown
Member

Fixes #4704

The fabrika wave-0 pilot: /adr, authored through /skill-creator against the brief, plus the CLI contract its verbs are specified by, plus a graded eval set.

What landed

  • claude-plugins/fabrika/skills/adr/SKILL.md113 lines, inside the brief's 80–120 target, against v1's 182. Six steps, six fences, each exactly one plain-literal invocation.
  • claude-plugins/fabrika/skills/adr/contract.mdsix verbs, fully specified. It also claims the seed package (packages/fabrika-cli/), which #4648 Resolved question 2 defers to the first derived contract.
  • claude-plugins/fabrika/skills/adr/evals/ — five graded cases with fixtures.
  • Three fabrika docs updated to carry the isolation rule (below).

No verbs are implemented here — building them is #4725. No v1 script is ported and no clause defers to one (#4638): grep for kampus-pipeline, .sh or scripts/ in either file returns nothing.

fabrika calls pipeline-cli nowhere

Founder ruling in-session, recorded as ADR 0238 in companion PR #4728. The deletion test decides it: a fabrika that calls v1 can never be the thing that replaces it, because every call keeps the old tree alive.

For this skill that means six verbs, not seven. adr sweep is a native implementation — v1's adr-sweep is cited as a list of mistakes already made (it exits 1 on its own informative case; its --json goes to stderr, #4723), never as something to call. adr classify was dropped rather than duplicated: cp-classify decides control-plane membership at the merge gate and that gate is the authority, so a fabrika copy of the guard vocabulary could contradict it on a merge-gating question. #4386 and #3416 were the gate misclassifying, so an author-side predictor would not have caught them anyway.

Encoded for the sessions that follow: rule 6 of the CLI interface convention, the README's absent-list, and field 4 of the authoring-brief contract — which becomes prior-art-to-read rather than verbs-to-call. The 18 unfired briefs (#4705#4722) were amended to match.

The derivation the brief did not pre-specify

adr resolve. The brief grouped #4296, #4338 and #4163 as one class — ADR state resolved against a tree that was not current, with the wrong answer indistinguishable from a right one. One verb answers all three, and absorbs v1's "never guess a slug from a title" rule as a fourth.

Its live / landed split separates presence from authority. 36 of the 233 ADRs on main are landed but proposed, superseded or retired — ADR 0164 is landed and proposed. "Cite only landed" would not have closed #4338; "cite only live" does.

Gates run before this PR

skill-reviewer (runbook step 5.5) ran pre-PR and returned Needs Major Revision with 28 findings; all blocking ones are fixed. Three of its claims I verified myself before acting, because they changed the architecture — all three held. One claim of mine did not: I asserted the template's **Banned.** labels trip the §CP probe. Tested in isolation they do not — the trigger is gate/guard in ordinary prose.

review-skill + review-code then FAILed the first submission for real cause: the adr sweep block still carried delegation language after the isolation rule was adopted, so a coder building from that paragraph alone would have written a pipeline-cli wrapper. Fixed in a1a8ab4a, along with the missing --json payload shape.

Deviation from the pre-derived carry-list

The brief's pre-derived material said to keep a trimmed ADR template in the wrapper. I cut it entirely — it is now the specified output of adr new, so it has one home. The brief instructs flagging rather than following when it pre-decides the split, so: flagged. skill-reviewer agreed on the principle (~90%) while catching three seam defects the removal created; all fixed.

Evals

Iteration 1: 95% with the skill, 40% without, 18 assertions over 4 cases. The sharpest result is eval 2 — the baseline shipped an ADR stamped 0237, a number open PR #4703 already holds; the skill's arm refused to claim one at all.

Iteration 2 re-ran the three cases still valid after the rewrite: 12/13. The one regression was mine — dropping the 12-word title cap invited an em-dash aside, fixed so the contrast sits inside the clause.

Caveats stated rather than buried: n=1 per cell, so a one-assertion swing is noise. Both graders found defects in the eval design itself (one vacuous assertion, one unreachable branch); both are fixed and a fifth case now covers the indeterminate branch. Evals 3 and 5 cannot execute until fabrika-cli exists.

Filed along the way

#4723 · #4725 · #4726 · #4727, plus folded findings on #3779 (the live allocator collision) and #2617 (the §CP probe's false-positive rate, measured for the first time at 84%).

🤖 Generated with Claude Code

The fabrika wave-0 pilot, authored via /skill-creator against brief #4704.
v1 is reference only: no script is ported and no clause defers to one.

SKILL.md is 119 lines, inside the brief's 80-120 target, against v1's 182.
It carries only judgment; every deterministic step is a specified verb.

contract.md specifies seven verbs and claims the seed package
(packages/fabrika-cli/), which #4648 Resolved question 2 defers to the first
derived contract. adr sweep and adr classify delegate to pipeline-cli and
normalise two exit contracts a caller reliably misreads: adr-sweep exits 1
whenever it HAS a shortlist, and guard-content-probe exits 0 on the CP hold
and 3 on proven-ordinary. Delegating rather than reimplementing keeps one
adjacency ranker in the repo; wrapping rather than calling directly is forced
by cli-invocation-guard, whose own remedy uses the variable expansion the
fabrika conventions ban.

adr resolve is the derivation the brief did not pre-specify: it collapses
#4296, #4338 and #4163 (ADR state resolved against a stale tree) plus v1's
never-guess-a-slug rule into one verb, and its live/landed split separates
presence from authority - 36 of 234 ADRs on main are landed but proposed,
superseded or retired.

evals/ carries five graded cases with fixtures. Iteration 1 measured 95% with
the skill against 40% without, over 18 assertions.

Fixes #4704
@github-actions

github-actions Bot commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

No preview deploy

  • No preview deploy for this PR — its diff touches no deploy-relevant path, so no preview stack was minted and e2e is not applicable. (e3efe5f)
  • web — Stage pr-4724 torn down.

… settled

Two corrections, both surfaced by the skill's own eval runs.

The corpus count was 234; 233 records match NNNN-slug.md. The 234th file is
0034a-live-fan-out-options-considered.md, which the four-digit pattern does
not match. The 36 landed-but-not-live figure is unchanged.

The skill cited ADR 0164 as settled law while telling authors to cite only
live ADRs - 0164 is status: proposed. The behaviour it describes is live
regardless, because cp-classify and guard-content-probe enforce it and stamp
(§CP, ADR 0164) into their own output, so both files now cite the enforcement
and name 0164's status rather than leaning on it. The live/landed rule binds
the artifact that states it.
usirin added 2 commits August 1, 2026 17:31
The previous fix traded one drift for another. It hardcoded "still proposed
in ADR 0164" into the skill, which is a claim about a mutable field in a
record this artifact does not own - stale the moment #4388's pending ruling
lands, and the same rot the live/landed rule exists to prevent.

The skill now names only what binds: cp-classify enforces §CP-by-content on
the merge path. The contract's grounding carries the fuller picture - the
enforcement is live while 0164's status field has read proposed throughout,
tracked as #4388 - and states that a caller learns a record's current status
from adr resolve rather than from a claim written down elsewhere.
… two assertions

Iteration 2 caught a side effect of the title fix. Dropping the 12-word cap
and asking for "long enough to carry the discriminating half" invited an
em-dash aside - the run produced "Sozluk pages stay client-rendered, never
server-rendered - the live SSE view already owns the data path", a decision
clause plus a second clause with its own subject and verb, which fails the
skill's own one-clause rule. The rule now says where the contrast belongs
rather than only how long the title may be.

Two eval assertions also could not discriminate. Eval 1 rested three of four
assertions on report.md, which the harness blocks subagents from writing;
that one now also binds to the artifact. Eval 4's glossary-routing assertion
passed equally for saying and doing under a read-only run; it now requires
the row text and its insertion point.
Full isolation, ruled in-session. A fabrika that calls pipeline-cli can never
be the thing that replaces it - every call is a tether that keeps the old tree
alive. Duplication is the accepted cost.

For /adr this drops the two wrapper verbs. adr sweep becomes a native
implementation: the ranking is fabrika's own, and v1's adr-sweep is now cited
as a list of mistakes already made (it exits non-zero on its own informative
case; its --json goes to stderr, #4723) rather than as an implementation to
call.

adr classify is dropped entirely rather than duplicated. cp-classify decides
control-plane membership at the merge gate and that gate is the authority; a
fabrika copy of the guard vocabulary could tell an author "ordinary" while the
gate says "control-plane" - two answers to a merge-gating question, worse than
either a tether or a drifted ranking. #4386 and #3416 were the gate
misclassifying, so an author-side predictor would not have caught them. The
skill now states the expectation and never predicts the verdict.

Encoded for the sessions that follow: CLI interface convention rule 6, the
README's absent-list, and the authoring-brief contract's field 4, which
becomes prior-art-to-read rather than verbs-to-call. The 18 unfired briefs
(#4705-#4722) are amended to match - runbook step 7 anticipated exactly this.
notusirin
notusirin previously approved these changes Aug 2, 2026
@usirin

usirin commented Aug 2, 2026

Copy link
Copy Markdown
Member Author

review-skill: FAIL @ 5f38c5d — changes-requested

Reviewed-head: @ 5f38c5d

Verified PR #4724 against #4704's acceptance criteria + the skill-rigor checklist. Class: non-blocking (cp-classifynot-control-plane [path-clear-no-content-source]; no path matches the live CONTROL_PLANE_RE, and no .decisions/** file is present). All artifacts were read at the head SHA above, never from a working copy.

Required namespaces for this diff (class-probe classify --namespaces): review-code, review-skill — the three fabrika non-skill files ride the §CLASS no-class fail-closed rule into has-code. The review-code verdict is posted as its own comment.

Acceptance criteria

  • [PASS] SKILL.md within 80–120 lines + the five first-submission criteria — 113 lines (additions=113, newline-terminated). (1) No Rules section; every invariant sits at its use site. (2) Six fenced blocks, each exactly one plain-literal fabrika-cli invocation; no variable expansion, command substitution or ../ climb anywhere in the file; no shell arithmetic in prose. (3) Both fail-closed lines present (next row). (4) The description carries the four trigger phrases and a checkable Done clause ("Done when the file exists, the sweep landed on hits-resolved or read-by-hand, every ADR reference in it resolves as live, and the vocabulary impact is a named term or an explicit none"). (5) Both forced-outcome gates survive as one-liners (next row).
  • [PASS] The two fail-closed safety statements survive — SKILL.md:20-21 "A non-zero exit is UNKNOWN, never "nothing reserved."" (with Nothing catches a cross-PR ADR number collision — two concurrent lanes both minted ADR 0198 #3779); SKILL.md:56-58 "no-overlap — nothing mechanically adjacent was left to open, never that there is no contradiction … Read the domain by hand." The non-zero rule recurs at SKILL.md:78 for adr resolve ("never absent", A stale working tree fails toward "does not exist" — recurrence of #308 across 4 seats #4163) — a different verb, a different wrong answer, a different incident, so this is co-location at a second use site rather than a restated invariant.
  • [PASS] Both forced-outcome gates — contradiction sweep: SKILL.md:52 "None of its three outcomes is a clearance", with each of shortlist / no-overlap / indeterminate forced to an action. Vocabulary binary: SKILL.md:92 "Land on exactly one outcome; the explicit "none" separates considered it from forgot to", with its two branches at :94-96.
  • [PASS] Pilot verdict on the brief format posted on the issue — Authoring brief: /adr — the fabrika wave-0 pilot skill #4704 comment of 2026-08-02T00:11:03Z: "Keep the format. Three amendments, none blocking — fire the remaining 18."
  • [PASS] A fresh session boots from the issue + repo alone — evidenced by that same verdict ("zero clarifying questions … All six fields were usable as written"). This is author-recorded, and the recorded verdict is the evidence form the brief itself commissions; nothing in the diff contradicts it.
  • [PASS] skill-reviewer ran pre-PR, findings addressed, PR records the pass — the body carries the pass plus a finding/resolution table, and the substantive fixes verify in the artifact: F2 live/landed split (SKILL.md:75-79, contract.md:293-316), F5 max-of-union-plus-one with an example chosen to discriminate it from first-free (contract.md:86-90), F6 --title default (contract.md:187), F7 ## Records deliberately unscaffolded (contract.md:224-226), F8 sweep forced outcome (SKILL.md:52).
  • [PASS] One PR carries SKILL.md + contract.md with Fixes #4704 — both added; Fixes #4704 is line 1 of the body.
  • [FAIL] The contract spec is implementable from it alone — five of the six verbs clear Part 2's completeness test comfortably. adr sweep does not, on two of the six criteria:
    • Output shape (test 2). --json is declared at contract.md:499 but its payload shape is never given — no key list, no example. Every other verb names its keys (next :83, new :191, resolve :312, supersede/amend-in-part :408), and Shared conventions :54 promises "one JSON object with the named keys given per verb". Sweep gives none, so an implementer has to invent the payload.
    • Exit-status semantics (test 3). Exit 3's trigger reads "the underlying sweep could not run" (:515) and its error message is "adr sweep: the underlying sweep failed" (:523) — but :484 states the verb is "Implemented in fabrika-cli, calling nothing — the lexical/rarity ranking is fabrika's own." With no underlying tool, the condition that produces exit 3 is unspecified.
    • Root cause. :505-507 still carries the superseded delegation framing: "Upstream exits 1 on a shortlist … relaying that status … the outcome token is upstream's, verbatim." That contradicts :484 and the isolation rule this same PR lands as cli-interface-convention.md §6 ("No fabrika skill and no fabrika verb invokes pipeline-cli"). §6 was adopted after the pre-PR skill-reviewer pass, so this block has not yet been re-read against it. It also trips Part 2 test 6 (no clause defers to a v1 script): a token required to be "upstream's, verbatim" cannot be produced without calling upstream.
    • Remedy (small and local). Rewrite :505-507 to state fabrika's own outcome contract with no relay framing; restate exit 3's trigger as a failure of fabrika's own scan/rank; and give --json a key list plus one literal example, as the other four verbs do.
  • [PASS] No verbs implemented, no v1 script ported — no packages/fabrika-cli/** in the diff; SKILL.md has zero matches for pipeline-cli, kampus-pipeline, .sh or scripts/. contract.md's v1 mentions are explicitly reference-only (:309-310, :553-557).
  • [PASS] All six brief fields usable as written — recorded in the brief-format verdict; Amendment 1 (field 4 "assumable verbs" → "prior art to read, not to call") lands in this PR's authoring-brief-contract.md.

Skill rigor

  • [PASS] Behavioral correctness — the six steps trace as a coherent executable procedure: claim → write → sweep → resolve + status-edit → vocabulary → re-check. Step 6's re-check of the author's own id (SKILL.md:101-105) closes for the caller exactly the residual allocation race contract.md:162-165 admits the verb cannot. No unreachable branch, no guard that cannot fire.
  • [PASS] Trigger / description quality — it names the artifact, four trigger phrases, the unprompted-reach case ("whenever a technical preference, convention, or invariant gets settled in conversation … even when nobody asks"), and a checkable Done clause. Observation, not a finding: a second skill named adr exists at claude-plugins/kampus-pipeline/skills/adr/. There is no live shadowing today — fabrika carries no marketplace entry (README.md:52-53, Split the plugin distribution channel: pin marketplace consumers to a known-good version during the pipeline rewrite #4643) — but the collision becomes real the moment fabrika is loadable, and deserves an explicit cutover note then.
  • [FAIL] Cross-skill conflict / contradicts a shared contract — the same root finding as the AC row above, not a second defect: contract.md:505-507 contradicts cli-interface-convention.md §6, which this PR adds in the same diff. Recorded here because the axis is contract-consistency, not only spec completeness.
  • [PASS] Gate-invariant preservation — no pipeline gate invariant is in this diff's reach: nothing under claude-plugins/kampus-pipeline/**, .claude/** or .github/**, and cp-classify returns proven-ordinary. The skill strengthens the §CP posture rather than weakening it — SKILL.md:107-111 instructs "That gate is the authority; do not predict it and never reword the ADR to change its verdict", and names the asymmetry (a false §CP costs one approval, a false ordinary reaches main with none — §CP-by-content (ADR 0164) has no platform enforcement — only §CP-by-path is hard-gated #4386, Guard-touching ADRs mis-classified NON-§CP by path-regex alone — ADR 0164 content clause not applied at review gate or driver #3416).
  • [PASS] deviation-disclosure (§DEV) — the departure from the brief's pre-derived carry-list (the ADR template cut from the wrapper) is disclosed in the body with its reasoning, and the ADR 0074 allocation divergence is disclosed as needing an amending ADR rather than quietly outvoted (contract.md:150-160) — §DEV class 2 handled correctly. Nit: the heading reads ## Deviation from the pre-derived carry-list rather than the canonical ## Deviations.

Factual spot-checks — all four asserted numbers verify

Claim Site Measured
233 ADRs on main SKILL.md:76 233 NNNN-slug.md files at main — exact
36 landed-but-not-live SKILL.md:75, contract.md:303-305 36 — 234 compact-index rows − 182 accepted − 15 amended-in-part − 1 extended-in-part; the residue is 20 superseded, 9 proposed, 2 superseded-in-part, 2 retired, moot, §3 superseded, reference — exact
corpus median 14 words SKILL.md:33-34 14 — ranks 117 and 118 of 234 titles are both 14 — exact
84% classify guard-touching SKILL.md:108 197/233 = 84.5%, measured with guard-content-probe classify over the full corpus — the PR body's "196 of 233" is off by one; the skill's "84%" is right

PR-body accuracy — not artifact defects, but the body is what a merger reads

The body describes an earlier design, and its arithmetic has drifted from the head:

  • "119 lines … seven fences" → the file is 113 lines with six fences.
  • "seven verbs", and "adr sweep and adr classify delegate to pipeline-cli … founder-ruled" → the head specifies six verbs and delegates nothing; adr classify is explicitly not derived (contract.md:21-27), and §6 supersedes the delegation posture outright.
  • "36 of the 234 ADRs on main" → 233, as SKILL.md itself correctly states.
  • The skill-reviewer table's F1 and F3 resolutions ("fixed via the wrapper verbs", "normalised inside adr classify") describe fixes that no longer exist — the head resolves both by removing the delegation entirely.

Worth refreshing the body alongside the adr sweep fix, so the durable record matches what merges.

Assessment. This is a strong pilot. The fence discipline is exact, every load-bearing number verifies against the repo, both fail-closed statements and both forced-outcome gates survive as one-liners, no invariant is restated, and SKILL.md holds the ADR-0238 line with zero pipeline-cli reach. The single blocking defect is narrow and local: one paragraph of superseded relay framing left in the normative half of adr sweep's block, plus that verb's unspecified --json payload. It is precisely the residue that survives an adopt-a-new-rule turn — §6 landed after the pre-PR review, so nothing had yet re-read that block against it.

Failing items above must be addressed before this PR can merge. The PR stays open and unmerged; #4704 stays open and assigned. Re-request review once they're satisfied.

Verdict-written: 2026-08-02T01:39:11Z

@usirin

usirin commented Aug 2, 2026

Copy link
Copy Markdown
Member Author

review-code: FAIL @ 5f38c5d — changes-requested

Reviewed-head: @ 5f38c5d

Verified PR #4724 against #4704's acceptance criteria. Class: non-blocking (cp-classifynot-control-plane [path-clear-no-content-source]). All artifacts read at the head SHA above, never from a working copy.

Why this namespace is required. class-probe classify --namespaces returns review-code and review-skill for this diff. Three changed files — claude-plugins/fabrika/README.md, claude-plugins/fabrika/docs/authoring-brief-contract.md, claude-plugins/fabrika/docs/cli-interface-convention.md — match no §CLASS class (they sit under claude-plugins/ but outside skills/|agents/, so HAS_SKILLS_RE misses them and HAS_DOCS_EXCLUDE_RE carves them out of has-docs). They therefore ride the §CLASS no-class fail-closed rule into has-code. This verdict covers those three files; the review-skill comment covers skills/adr/** and carries the full evidence.

The three files in this namespace — all clean

  • [PASS] README.md:52-56 — replaces "No skills yet / No CLI … pipeline-cli stays the v1-era substrate fabrika may call but never grows into" with "No dependency on v1. fabrika calls pipeline-cli nowhere — not from a skill, not from a verb. Its own verbs live in packages/fabrika-cli/." Consistent with the §6 rule this PR adds and with the seed-package claim in skills/adr/contract.md:5-10. No stale "may call" language survives.
  • [PASS] docs/cli-interface-convention.md — adds §6 "fabrika calls nothing outside fabrika" (+29/−0), sourced to the in-session founder ruling, with the deletion-test rationale and two named consequences. It supersedes the earlier "may call but never grows into it" posture explicitly rather than silently, and records adr classify as dropped-because-already-enforced. Part 1's rule numbering stays contiguous and the Enforcement section below it is untouched.
  • [PASS] docs/authoring-brief-contract.md — renames field 4 "Assumable verbs" → "Prior art — to read and not to call", rewrites the field body and its bootability check row 4, and updates the worked example. This is Amendment 1 of the pilot's own brief-format verdict (posted on Authoring brief: /adr — the fabrika wave-0 pilot skill #4704), landing in the same PR that motivated it. The three doc changes are mutually consistent: all three now say the same thing about v1.
  • [PASS] No user-local, absolute, or sibling-repo paths introduced in any of the three; all links are repo-relative and resolve.

Acceptance criteria (shared checklist — the same boxes both gates verify)

Nine of the ten boxes PASS; the full per-box evidence is in the review-skill comment on this PR and is not duplicated here. One box fails, and it is conjunctive across the checklist, so this namespace fails with it:

  • [FAIL] "The contract spec is readable without the authoring transcript: a downstream coder can implement the verbs from it alone (… output shape, exit-status semantics …)"skills/adr/contract.md's adr sweep block misses two of Part 2's six completeness criteria: --json (:499) has no declared payload shape at all, and exit 3's trigger names "the underlying sweep" (:515, :523) while :484 states the verb is "Implemented in fabrika-cli, calling nothing". Root cause is superseded delegation framing left at :505-507 ("Upstream exits 1relaying that status … the outcome token is upstream's, verbatim"), which contradicts §6 — the rule this same PR adds in cli-interface-convention.md. Full finding and remedy in the review-skill comment.

Note. The failing artifact belongs to the skill class, not to this namespace's three files, which are clean on their own terms. This namespace fails because the acceptance-criteria checklist is shared and conjunctive — not because of a defect in README.md or either docs/ file. Fixing the adr sweep block clears both namespaces.

Failing item above must be addressed before this PR can merge. The PR stays open and unmerged; #4704 stays open and assigned. Re-request review once it is satisfied.

Verdict-written: 2026-08-02T01:40:06Z

review-skill FAIL on #4724. The isolation rule (ADR 0238) was adopted after
the adr sweep block was written, and nobody re-read the block against it, so
its normative half still described a wrapper: the outcome token was "upstream's,
verbatim", exit 3 meant "the underlying sweep could not run", and its error
message named a component the spec says does not exist. A coder building from
that paragraph alone would have written a pipeline-cli wrapper - re-tethering
fabrika to v1 through the document meant to prevent it.

The outcome is now stated as this verb's own verdict, with v1's exit-1-on-a-
shortlist named as the mistake it avoids rather than a status it relays. Exit 3
becomes "the corpus could not be read".

adr sweep --json was also the only --json in the contract with no declared
payload shape, failing completeness test 2. Its keys are now named.
@usirin

usirin commented Aug 2, 2026

Copy link
Copy Markdown
Member Author

review-skill: PASS @ a1a8ab4 — merge-ready

Reviewed-head: @ a1a8ab4

Re-review of the repair round (prior FAIL at 5f38c5d5). Class: non-blocking (cp-classifynot-control-plane [path-clear-no-content-source]). Every artifact read at the head SHA above via the contents API at ?ref=<head>, never from a working copy.

Required namespaces (class-probe classify --namespaces): review-code and review-skill — the three fabrika non-skill files match no §CLASS class and ride the no-class fail-closed rule into has-code. The review-code verdict is a separate comment and it FAILs on a finding in its own file set, so nothing merges yet; this marker discharges the skill class only.

Prior blocking finding — verified repaired

One root cause, three surfaces, all in contract.md's adr sweep block. All three fixed:

  • Delegation framing gone. :505-507 previously read "Upstream exits 1 … relaying that status … the outcome token is upstream's, verbatim". It now reads "All three outcomes are answers, and all three exit 0. The outcome is this verb's own verdict, and a caller must never read its own shortlist as a failed run — which is precisely the mistake v1's adr-sweep makes by exiting 1 on the one case it was asked to produce." v1 is a contrast, not a callee.
  • Exit 3 is now self-contained. :5193 = "the corpus could not be read, so the outcome is UNKNOWN"; error :527 names <dir>, not a component the spec says does not exist.
  • --json names its payload. :509-511outcome, entries (array of {id, score, file, title}, empty unless shortlist), reason (string for no-overlap/indeterminate, else null), scanned, inScope, cited. Same bar the four sibling verbs were passed on at 5f38c5d5.

Residual-language sweep. grep -ni 'upstream|relay|wrapper|delegat|pass-through|passthrough' over the whole of contract.md returns zero matches. Its only two pipeline-cli occurrences (:12, :17) are the statement of the isolation rule itself. The verb is stated self-contained at :483-484 and its algorithm specified at :562-565.

Load-bearing claims re-measured at the new head

  • 113 lines, inside 80–120.
  • Exactly 6 fenced blocks, each exactly one line, each a plain-literal fabrika-cli invocation (adr next · adr new 0240 only-landed-adrs-may-be-cited · adr sweep --new 0240 · adr resolve 0164 0023 0126 · adr supersede 0126 --by 0240 · adr resolve 0240). No variable expansion, no command substitution, no parent-dir climb.
  • ADR 0238 isolation clean — a grep of SKILL.md for pipeline-cli, kampus-pipeline, .sh, scripts/, $ and the parent-dir climb exits 1: zero matches. (:108 names cp-classify as the gate that will judge the ADR PR, explicitly not as something the skill calls.)
  • Both fail-closed statements survive:20-21 "a non-zero exit is UNKNOWN, never 'nothing reserved'" (Nothing catches a cross-PR ADR number collision — two concurrent lanes both minted ADR 0198 #3779); :56-58 "no-overlapnever that there is no contradiction … Read the domain by hand." The non-zero rule recurs at :78 for adr resolve ("never absent", A stale working tree fails toward "does not exist" — recurrence of #308 across 4 seats #4163): different verb, different wrong answer, different incident — co-location, not restatement.
  • Both forced-outcome gates survive:52 "None of its three outcomes is a clearance"; :92 "Land on exactly one outcome".
  • No invariant stated twice, no Rules section — headings are # adr then ## 1## 6; every invariant sits at its use site.

Acceptance criteria

  • [PASS] 80–120 lines + the five first-submission criteria — 113 lines; no Rules section; six one-invocation fences; both fail-closed lines; the description carries the trigger phrases, the unprompted-reach case and a checkable Done clause; both forced-outcome gates as one-liners.
  • [PASS] The two fail-closed statements survive — evidence above.
  • [PASS] Pilot verdict on the brief format posted on Authoring brief: /adr — the fabrika wave-0 pilot skill #4704 (2026-08-02T00:11:03Z): "Keep the format. Three amendments, none blocking — fire the remaining 18."
  • [PASS] Fresh session boots from issue + repo alone — recorded in that verdict ("zero clarifying questions … All six fields were usable as written"); nothing in the diff contradicts it.
  • [PASS] skill-reviewer ran pre-PR, findings addressed, PR records the pass — substantive fixes verify at this head: live/landed split (SKILL.md:75-79, contract.md:293-316), max-of-union-plus-one with a discriminating example (contract.md:86-90), --title default (:187), ## Records deliberately unscaffolded (:224-226), sweep forced outcome (SKILL.md:52).
  • [PASS] One PR carries both files with Fixes #4704 — both added; Fixes #4704 is line 1 of the body.
  • [PASS] Contract implementable from it alone — the prior FAIL row, cleared. All six verbs clear Part 2's completeness test: every flag typed with a default (:75-80, :180-188, :285-291, :400-405, :494-499); every line-grammar shape shown by a literal example, all four resolve states included; every non-zero exit enumerated with its condition; every error names message, stream and code; each judging verb states scope + zero-scope (:112-125, :338-340, :531-534) and each non-judging verb says so (:246, :448). Test 6 holds — v1 at :309-310 and :557-561 is semantics-to-check and scars-to-avoid, never an implementation to call.
  • [PASS] No verbs implemented, no v1 script ported — no packages/fabrika-cli/** in the diff (Implement packages/fabrika-cli — the six adr verbs from the wave-0 pilot's derived contract #4725 is the implementation ticket); zero v1 reach in SKILL.md.
  • [PASS] All six brief fields usable — recorded on Authoring brief: /adr — the fabrika wave-0 pilot skill #4704; Amendment 1 lands in this PR's authoring-brief-contract.md.

Skill rigor

PR body — rewritten and now matching the artifact: 113 lines (measured 113), six fences (measured 6), six verbs (contract.md:31-38 lists exactly six), and the two wrapper verbs it used to describe are gone. No residual drift found.

Non-blocking observations — recorded, none gating, none a regression from the prior head:

  1. adr resolve --json over several ids is serialization-underdetermined: :312 says "one object per id" while Shared conventions :54 promises "one JSON object", so an implementer must choose array vs JSON-lines. Nothing in SKILL.md consumes --json, so pin it in Implement packages/fabrika-cli — the six adr verbs from the wave-0 pilot's derived contract #4725.
  2. Four verbs name --json keys without showing the bytes; only adr next (:135-137) shows a literal example. Same bar those four were passed on at 5f38c5d5 — sweep now sits at parity. Raising it for all five belongs to a convention follow-up.
  3. adr new's invocation line (:175) omits [--json] while its Output paragraph specifies --json keys.
  4. evals.json eval 3 assertion 4 ("Does not treat the sweep's non-zero exit status as a failed run") encodes v1's exit-1-on-shortlist defect as expected behavior, which the repaired contract designs out (contract.md:505). Latent — evals 3 and 5 cannot execute until the verbs exist, and eval mechanics are out of this brief's scope (fabrika eval layer: the execution harness, the incident corpus, and the ruled bar #4649).
  5. The fabrika-cli verbs do not exist yet: by design, Implement packages/fabrika-cli — the six adr verbs from the wave-0 pilot's derived contract #4725 owns them. Not flagged.

Assessment. The repair is exactly what was asked for and it is complete. Re-measured from scratch, every load-bearing claim holds. The contract spec is buildable cold for all six verbs.

The skill class is merge-ready. review-skill does not mergeship-it is the authorized merge step and it requires a current-head PASS in every present namespace; review-code FAILs at this head on claude-plugins/fabrika/README.md, so this PR does not merge until that is cleared too. Merging will auto-close #4704 via Fixes #4704.

Verdict-written: 2026-08-02T02:02:49Z

@usirin

usirin commented Aug 2, 2026

Copy link
Copy Markdown
Member Author

review-code: FAIL @ a1a8ab4 — changes-requested

Reviewed-head: @ a1a8ab4

Re-review of the repair round (prior FAIL at 5f38c5d5). Class: non-blocking (cp-classifynot-control-plane [path-clear-no-content-source]). Every file read at the head SHA above via the contents API at ?ref=<head>, never from a working copy.

Why this namespace is required. class-probe classify --namespaces returns review-code and review-skill. Three changed files — claude-plugins/fabrika/README.md, claude-plugins/fabrika/docs/authoring-brief-contract.md, claude-plugins/fabrika/docs/cli-interface-convention.md — match no §CLASS class (they sit under claude-plugins/ but outside skills/|agents/, so HAS_SKILLS_RE misses them and HAS_DOCS_EXCLUDE_RE carves them out of has-docs), so they ride the no-class fail-closed rule into has-code. This verdict covers those three files. The review-skill comment covers skills/adr/** and PASSes — the prior round's adr sweep finding is fully repaired and the shared acceptance-criteria checklist is now all-PASS. This namespace fails on a defect in its own file set.

The prior round's finding — repaired

The 5f38c5d5 review-code FAIL was a referral: the failing artifact was skills/adr/contract.md, not these three files. That is fixed (see the review-skill comment for the per-surface evidence), and the shared AC checklist now passes in full — including the box this namespace failed on, "a downstream coder can implement the verbs from it alone."

New finding in this namespace — README.md contradicts the tree this PR creates

  • [FAIL] claude-plugins/fabrika/README.md states three times that skills/ is empty, and this PR is the change that makes that false. The diff edits this file (:53-57) and correctly deletes the absent-list bullet "No skills yet. They arrive one authoring session at a time through /skill-creator" — so the fact was tracked — but three sibling claims elsewhere in the same file were left stale:

    • :33 — "This posture is the whole reason skills/ is empty right now. An empty directory is the correct state until the first authoring session lands its skill through the door." This PR is that first session; the sentence describes a state it ends.
    • :44, inside the Layout tree — "└── skills/ one dir per skill, each authored by /skill-creator — **empty today**". Flatly false at this head: contents/claude-plugins/fabrika/skills?ref=a1a8ab4a returns .gitkeep and adr.
    • :47 — "skills/ holds a .gitkeep so the directory survives a clone while it is empty." The rationale is spent; the .gitkeep is now vestigial.

    Why this blocks rather than rides as a nit. README.md:42 declares this file's own job — "the mission, the only-door posture, the layout" — so it is fabrika's front door and the orientation document for the 18 sibling authoring briefs (Authoring brief: /report — fabrika skill (wave 0) #4705Authoring brief: /doctor — fabrika skill (wave 3) #4722) that this wave-0 pilot unblocks. Every one of those sessions is a cold boot, which is precisely the reader a false layout claim misleads. It is also self-inflicted by this diff and confined to it: no other file is wrong, and no design question is open. CLAUDE.md's doc-surface rule applies directly — when the docs and the tree disagree, the tree is authoritative and the doc gets fixed.

    Remedy — three lines, entirely local. Reword :33 from "is empty right now" to the post-pilot state (the door is proven, skills/adr/ is the first artifact through it); change :44's trailing note from "empty today" to name adr/; and either drop :47's "while it is empty" clause or drop the .gitkeep with it. Nothing else in the file needs to move.

    No follow-up issue covers this — adr-sweep shortlist --json writes its payload to stderr, not stdout #4723 / Implement packages/fabrika-cli — the six adr verbs from the wave-0 pilot's derived contract #4725 / Database.ts cites ADR 0040 as live authority — 0040 is superseded #4726 / Glossary control-plane row defines §CP by the retired hand-merge model #4727, the four filed by this session, are all about other surfaces — so it is not a deliberate deferral.

The other two files in this namespace — clean

  • [PASS] docs/cli-interface-convention.md (+29/−0) — adds §6 "fabrika calls nothing outside fabrika", sourced to the in-session founder ruling, with the deletion-test rationale and two named consequences. It supersedes the earlier "may call but never grows into it" posture explicitly rather than silently, and records adr classify as dropped-because-already-enforced-at-the-merge-gate. Part 1's rule numbering stays contiguous (1–6) and the Enforcement section below it is untouched and still correct (no conformance guard yet, deliberately, because zero verbs means zero scope — ADR 0092). The words "wrapper" / "relaying an upstream answer" / "pass-throughs" appear here only inside the description of the superseded posture this rule retires, which is the rule's own rationale, not residual delegation language.
  • [PASS] docs/authoring-brief-contract.md — renames field 4 "Assumable verbs" → "Prior art — to read and not to call", rewrites the field body, updates bootability check row 4 ("Every prior-art verb is named, with what it computes and — where known — what it gets wrong") and the worked example. This is Amendment 1 of the pilot's own brief-format verdict posted on Authoring brief: /adr — the fabrika wave-0 pilot skill #4704, landing in the same PR that produced it.
  • [PASS] No user-local, absolute, or sibling-repo paths introduced in any of the three; all links are repo-relative and resolve.

Acceptance criteria — the shared checklist

All ten boxes PASS at this head. The per-box evidence is in the review-skill comment on this PR and is not duplicated here; the box this namespace failed on at 5f38c5d5"the contract spec is readable without the authoring transcript" — is cleared, with all six verbs (next, new, resolve, supersede, amend-in-part, sweep) now clearing Part 2's six completeness criteria.

This namespace therefore fails on the README finding alone, not on the acceptance criteria. That is the whole remaining distance: three lines in one file, no artifact under skills/adr/** needs to change, and the review-skill PASS at this head stands unless the branch moves.

Failing item above must be addressed before this PR can merge. The PR stays open and unmerged; #4704 stays open and assigned. Re-request review once it is satisfied.

Verdict-written: 2026-08-02T02:03:32Z

…lls it

review-code FAIL on #4724. The previous commit deleted the "No skills yet"
bullet but left three other statements that this same PR falsifies: the
only-door paragraph's "the whole reason skills/ is empty right now", the
layout tree's "empty today", and the .gitkeep line's "while it is empty".
That file declares itself fabrika's front door and is the orientation doc for
the 18 sibling briefs, all of which are cold boots - so a false claim there is
read by every one of them.

Also folded in three non-blocking review notes while the branch was open:
adr resolve --json over several ids is now pinned as a JSON array rather than
left array-vs-JSON-lines underdetermined; adr new's invocation line names its
--json flag; and eval 3's fourth assertion no longer encodes v1's
exit-1-on-a-shortlist as expected behaviour, which the repaired contract
designs out.
@usirin

usirin commented Aug 2, 2026

Copy link
Copy Markdown
Member Author

review-code: PASS @ e3efe5f — merge-ready

Reviewed-head: @ e3efe5f

Third round. Prior: FAIL at 5f38c5d5, FAIL at a1a8ab4a. Class: non-blocking (cp-classifynot-control-plane [path-clear-no-content-source], re-run at this head — no path matches the live CONTROL_PLANE_RE and no .decisions/** file is present). Every file read at the head SHA above via the contents API at ?ref=<head>, never from a working copy.

Required namespaces (class-probe classify --namespaces): review-code and review-skill, unchanged. The three fabrika non-skill files — README.md, docs/authoring-brief-contract.md, docs/cli-interface-convention.md — match no §CLASS class (under claude-plugins/ but outside skills/|agents/, so HAS_SKILLS_RE misses them and HAS_DOCS_EXCLUDE_RE carves them out of has-docs) and ride the no-class fail-closed rule into has-code. This verdict covers those three files; skills/adr/** is the review-skill comment's.

The blocking finding — repaired

The a1a8ab4a FAIL was one finding with three surfaces: README.md asserted three times that skills/ is empty, and this PR is the change that makes that false. All three are gone, and the replacements are true rather than merely vaguer:

  • :33 — was "This posture is the whole reason skills/ is empty right now. An empty directory is the correct state until the first authoring session lands its skill through the door." Now: "This posture is why skills/ fills one authoring session at a time rather than by porting." The claim moves from a state assertion this PR ends to a mechanism assertion that stays true after it, which is the durable fix rather than a re-stamp that goes stale on skill web: phoenix-relay-idiom — every page on @connection + idiomatic Relay #2.
  • :43 — the layout tree's └── skills/ … — empty today no longer carries the trailing clause.
  • :46-48 — was "skills/ holds a .gitkeep so the directory survives a clone while it is empty." Now: "A .gitkeep remains from when the directory was empty; it is harmless and can go with any later change." Correctly reframed as a leftover from a past state, with its own disposal noted.

Whole-file re-read — every remaining claim tested against the tree at this head

Read README.md end to end rather than the diff, per the standing instruction, and checked each falsifiable claim against contents/…?ref=e3efe5fb:

  • [PASS] Layout tree :39-44 — lists exactly the four entries the fabrika root actually holds at this ref: .claude-plugin/, README.md, docs/, skills/. It does not expand skills/, which is consistent with its treatment of docs/ (also unexpanded, four files), so it makes no depth claim that adr/ could falsify. The round-2 remedy suggested naming adr/; dropping the false clause instead is an equally complete fix at this tree's granularity.
  • [PASS] :40 "no version — ADR 0110"claude-plugins/fabrika/.claude-plugin/plugin.json at this ref carries no version key.
  • [PASS] :52-53 "not listed in the root marketplace manifest"grep -i fabrika over .claude-plugin/marketplace.json at this ref returns nothing.
  • [PASS] :54-56 "fabrika calls pipeline-cli nowhere — not from a skill, not from a verb." This PR adds the first skill, so the claim is testable against real content for the first time, and it holds: zero pipeline-cli in SKILL.md, zero in evals.json, and contract.md's only two occurrences (:12, :17) are the isolation rule's own statement of itself. The claim got stronger, not staler, under this diff.
  • [PASS] :27-31 the only-door claim — the PR body records the skill was authored through /skill-creator against the brief, with skill-reviewer at runbook step 5.5. Nothing entered skills/ by a second door. docs/skill-conventions.md resolves at this ref.
  • [PASS] :11-15 "v1 … stays frozen and untouched" — no path under claude-plugins/kampus-pipeline/ appears in the changed-file set. ../kampus-pipeline/ resolves.
  • [PASS] No user-local, absolute, or sibling-repo path anywhere in the three files. The ../../../ links in cli-interface-convention.md are repo-relative climbs from claude-plugins/fabrika/docs/ to the repo root and resolve at this ref (spot-checked .patterns/skill-script-io-contract.md, .decisions/0092-…).

The other two files — unchanged since the PASSed round

docs/authoring-brief-contract.md and docs/cli-interface-convention.md are byte-identical to a1a8ab4a, where both already passed; the incremental compare shows the only changed paths since then are README.md, contract.md and evals.json. Their verdicts carry: §6 "fabrika calls nothing outside fabrika" supersedes the earlier posture explicitly, keeps Part 1's numbering contiguous, and states the no-conformance-guard absence as deliberate under ADR 0092 (zero verbs is zero scope). The words wrapper / relaying an upstream answer / pass-throughs appear there only inside the description of the superseded posture §6 retires — the rule's own rationale, not residual delegation language.

Acceptance criteria

All nine boxes on #4704 PASS at this head. Per-box evidence is in the review-skill comment and not duplicated; the box this namespace failed on at 5f38c5d5 (the contract spec is readable without the authoring transcript) cleared at a1a8ab4a and re-verified at this head.

Non-blocking — recorded, not gating

  1. :46's first clause, "skills/ carries no README and no loose files", reads descriptive while the sentence that follows it discloses the one loose file (.gitkeep). It self-corrects within two sentences and misleads no cold reader — the paragraph as a whole states the law, then its single tracked exception — but the clause would be exactly true rather than true-with-an-immediate-caveat if it were phrased as the law it is ("carries no README and no loose files by layout law"). Free to fold into whichever change removes the .gitkeep.

Assessment. The one blocking finding is fully repaired, and the whole-file re-read found no second claim this PR falsifies — including the two claims that only became testable once a real skill landed, both of which hold. This namespace is merge-ready.

review-code does not merge. ship-it is the authorized merge step and requires a current-head PASS in every present namespace; see the review-skill verdict at this same head. Merging auto-closes #4704 via Fixes #4704.

Verdict-written: 2026-08-02T02:17:12Z

@usirin

usirin commented Aug 2, 2026

Copy link
Copy Markdown
Member Author

review-skill: PASS @ e3efe5f — merge-ready

Reviewed-head: @ e3efe5f

Third round; re-binding a PASS to a moved head. Prior: FAIL at 5f38c5d5, PASS at a1a8ab4a. Class: non-blocking (cp-classifynot-control-plane [path-clear-no-content-source], re-run at this head). Every artifact read at the head SHA above via the contents API at ?ref=<head>, never from a working copy.

Required namespaces (class-probe classify --namespaces): review-code and review-skill. This marker discharges the skill class — SKILL.md, contract.md, evals/**; the three fabrika non-skill files ride the no-class fail-closed rule into has-code and are covered by the separate review-code comment at this head.

A PASS binds to content, not to a prior verdict, so every load-bearing claim below was re-measured at e3efe5fb rather than carried forward.

What moved in this file set

a1a8ab4a…e3efe5fb touches this namespace in two files, +5/-3 total, both repairs of this namespace's own non-blocking observations. SKILL.md is byte-identical.

  • [PASS] Observation 1 discharged — adr resolve --json is pinned. contract.md:312-314 was "one object per id", which left array-vs-JSON-lines for the implementer to invent. Now: "a JSON array — one object per id, in argument order, with keys id, state, file, detail, baseRef, baseSha. An array rather than JSON-lines, so a single id and many ids parse identically and a caller never has to branch on the count." The shape is named and the reason is stated, which is what Implement packages/fabrika-cli — the six adr verbs from the wave-0 pilot's derived contract #4725 needed and what the observation asked for.
  • [PASS] Observation 3 discharged — adr new names its flag. :175 now reads ... [--tags <a,b>] [--json], so the invocation line and the Output paragraph (:190, keys path, id, slug) agree.
  • [PASS] Observation 4 discharged — the eval no longer encodes a defect as expected behavior. evals.json eval 3 assertion 4 was "Does not treat the sweep's non-zero exit status as a failed run", which presumed the exit-1-on-a-shortlist that the repaired contract designs out. Now: "Treats a shortlist as the sweep working, not as a failed run." That is coherent with contract.md:507-509 ("All three outcomes are answers, and all three exit 0") and with :519 (0 = an outcome token was produced), and it tests the skill's reading rather than a status that will not exist. evals.json parses as valid JSON at this head.

Standing bars — re-measured at this head

  • [PASS] SKILL.md is 113 lines, inside 80-120.
  • [PASS] Exactly six fenced blocks, each exactly one line, each a plain-literal fabrika-cli invocation: adr next (:14), adr new 0240 only-landed-adrs-may-be-cited (:26), adr sweep --new 0240 (:49), adr resolve 0164 0023 0126 (:69), adr supersede 0126 --by 0240 (:82), adr resolve 0240 (:101). No variable expansion, no command substitution, no parent-dir climb. (adr amend-in-part at :85 is inline prose, not a seventh fence.) Note the [--json] added to contract.md:175 correctly did not propagate into the adr new fence — the skill consumes the line grammar, and a fence carrying an unused flag would violate the one-plain-literal rule for no gain.
  • [PASS] ADR 0238 isolation clean — a grep of SKILL.md for pipeline-cli, kampus-pipeline, .sh, scripts/, the dollar sign and the parent-dir climb exits 1: zero matches. (:108 names cp-classify as the gate that will judge the ADR PR, explicitly not as something the skill calls.)
  • [PASS] Both fail-closed statements survive:20-21 "A non-zero exit is UNKNOWN, never 'nothing reserved.'" (Nothing catches a cross-PR ADR number collision — two concurrent lanes both minted ADR 0198 #3779); :56-58 "no-overlap ... never that there is no contradiction ... Read the domain by hand."
  • [PASS] Both forced-outcome gates survive:52 "None of its three outcomes is a clearance"; :92 "Land on exactly one outcome".
  • [PASS] No invariant stated twice, no Rules section. Headings are the H1 then ## 1 ... ## 6. The second non-zero-exit line at :78 is a different verb, a different wrong answer (absent, not "nothing reserved") and a different incident (A stale working tree fails toward "does not exist" — recurrence of #308 across 4 seats #4163, not Nothing catches a cross-PR ADR number collision — two concurrent lanes both minted ADR 0198 #3779) — co-location at the use site, which is the fabrika convention, not restatement.
  • [PASS] Residual-language sweep — a case-insensitive grep of the whole of contract.md for upstream, relay, wrapper, delegat, pass-through and passthrough returns zero matches. Its only two pipeline-cli occurrences (:12, :17) are the isolation rule stating itself; adr sweep is specified native at :485-486 and :564-567, with v1 cited at :559-563 as "a list of mistakes already made, not ... an implementation to copy."

contract.md against Part 2 of the CLI convention — all six verbs

Re-ran the completeness test at this head; thinness here is a real defect because #4725 builds from this file.

  • [PASS] Required sections, all six blocks. adr next, adr new, adr resolve, adr supersede/adr amend-in-part, adr sweep each carry Invocation, Inputs, Output, Exit status, Errors, Scope, Examples, Grounding, in that order, plus the header and the verb-inventory table with a split test per row.
  • [PASS] 1 — every flag typed with a default (:73-80, :180-188, :285-291, :400-407, :496-501).
  • [PASS] 2 — every stdout shape shown by an example, not only described: the line grammars all have literal byte-for-byte examples, including all four resolve states (:346-360) and both the shortlist and indeterminate sweep outcomes (:540-554).
  • [PASS] 3 — every non-zero exit enumerated with its condition (:92-100, :228-235, :320-328, :426-436, :515-523).
  • [PASS] 4 — every error names message, stream and code (:102-110, :237-244, :330-338, :438-448, :525-531).
  • [PASS] 5 — every judging verb states its scope and zero scope (:112-125, :340-342, :533-536, all reddening on zero per ADR 0092); the two non-judging verbs say so explicitly (:246-247, :450).
  • [PASS] 6 — no clause defers to a v1 script, another skill's prose, or the session. v1 appears at :309-310 and :559-563 as semantics-to-check and scars-to-avoid. The one deferral in the file points the other way and is correct: :9-10 defers to cli-interface-convention.md where the two disagree, which is the convention's own precedence rule.
  • [PASS] Internal coherence spot-check: the indeterminate example at :550 runs against the small-corpus fixture, which holds 3 records against the rarity floor of 10 stated at :565-567. The example is consistent with the rule it illustrates.

Acceptance criteria — #4704, all nine

  • [PASS] 80-120 lines plus the five first-submission criteria — 113 lines; no Rules section; six one-invocation fences; both fail-closed lines; the description (:3) carries the trigger phrases, the unprompted-reach case ("even when nobody asks for an ADR") and a checkable Done clause; both forced-outcome gates as one-liners.
  • [PASS] The two fail-closed statements survive — evidence above.
  • [PASS] Pilot verdict on the brief format posted on Authoring brief: /adr — the fabrika wave-0 pilot skill #4704 (2026-08-02T00:11:03Z): "Keep the format. Three amendments, none blocking — fire the remaining 18."
  • [PASS] Fresh session boots from issue and repo alone — recorded in that verdict; nothing in this diff contradicts it.
  • [PASS] skill-reviewer ran pre-PR, findings addressed, PR records the pass — the body's "Gates run before this PR" section; substantive fixes verify at this head (live/landed split, max-of-union-plus-one, --title default, ## Records deliberately unscaffolded at :224-226, sweep forced outcome).
  • [PASS] One PR carries both files with Fixes #4704 — both added; Fixes #4704 is line 1 of the body.
  • [PASS] Contract implementable from it alone — the Part 2 run above, all six verbs.
  • [PASS] No verbs implemented, no v1 script ported — no packages/fabrika-cli/** in the changed-file set (Implement packages/fabrika-cli — the six adr verbs from the wave-0 pilot's derived contract #4725 owns it); zero v1 reach in SKILL.md.
  • [PASS] All six brief fields usable — recorded on Authoring brief: /adr — the fabrika wave-0 pilot skill #4704; Amendment 1 lands in this PR's authoring-brief-contract.md.

Skill rigor

Non-blocking — recorded, not gating

  1. The --json shared generalization now has one documented exception. Shared conventions :54 still says "--json swaps the line grammar for one JSON object with the named keys given per verb" under a section that opens "Every verb below obeys these" — and adr resolve is now emphatically an array. This is not the underdetermination the prior round flagged: that was an implementer with two readings and no way to choose, and it is gone. What remains is a general clause with a specific, bolded, reasoned exception, which resolves the standard way (the verb block wins) and cannot mislead Implement packages/fabrika-cli — the six adr verbs from the wave-0 pilot's derived contract #4725. Worth tightening :54 to "one JSON value — an object unless the verb's block says otherwise" on any later pass.
  2. adr new names [--json] in its invocation but carries no --json row in its Inputs table, where the other four blocks with the flag do (:80, :291, :407, :501). Defensible under :46's "stated once rather than repeated per block" framing, and :190 gives the payload keys, so nothing is underdetermined — but the asymmetry is now visible where it was not before the flag was named. One table row.
  3. Carried, unchanged grade: four verbs name --json keys without showing the bytes; only adr next (:135-137) shows a literal --json example. Criterion 2 is satisfied for the line grammars; raising the bar to JSON payloads belongs to a convention follow-up, not to this PR.
  4. The fabrika-cli verbs do not exist yet — by design, Implement packages/fabrika-cli — the six adr verbs from the wave-0 pilot's derived contract #4725 owns them. Not flagged.

Assessment. Three repairs, three discharged, nothing regressed. Every standing bar re-measured from scratch at this head holds, and the contract is buildable cold for all six verbs. The two new residues are both one-line doc-precision items in a spec that is otherwise complete.

The skill class is merge-ready at this head. review-skill does not mergeship-it is the authorized merge step and requires a current-head PASS in every present namespace; the review-code verdict at this same head is the other one. Merging auto-closes #4704 via Fixes #4704.

Verdict-written: 2026-08-02T02:19:28Z

usirin added a commit that referenced this pull request Aug 2, 2026
#4520, #4730)

Two ends of one too-small required-review set, on the merge-authorization path.

`verdict gate --require` was a single-valued `Flag.string`, so a repeated flag kept
only the first occurrence and dropped the rest without a word: `--require review-code
--require review-doc` cleared PR #4724 as enqueueable while `--require
review-code,review-doc` refused on an absent `review-doc` — the same required set,
opposite answers, decided by spelling. The `parseRequired` guard one layer below
already refuses to shrink the conjunction; it never saw occurrence 2..n, so it was
born dead rather than drifted. The flag is now `Flag.atLeast(1)` and every occurrence
unions in, which also routes a later occurrence's bogus token back into that guard.

Beside it, a coverage assertion: an affirmative gate answer must cover as many
distinct namespaces as argv asked about. That is the general form — it refuses any
future path that answers about fewer things than it was asked, which is the shape of
this whole class (a check that runs, exits clean, and returns a plausible value that
is simply smaller). Its operands come from two origins on purpose: the CLI's parse of
argv against the decision returned over the service boundary.

ship-it Step 0 re-derived the artifact-class set instead of delegating to
`class-probe`, and its copy could only ever answer with a SUBSET: a file matching none
of the three predicates produced silence, and silence subtracts a class. On PR #4724's
list it printed `has-skills` alone where the probe printed `has-code, has-skills` —
the plugin-docs-beside-skills shape any plugin home reproduces. The #2765 no-class
rule lived there as five comment lines and zero executable ones. Step 0 now prints
`class-probe`'s answer, which is what #2765's own commit said it was always meant to
do, and the no-class rule lands as an executable fail-closed branch keyed on the
§CPREAD file count against the probe's stdout.

Scope note: the executed gate was not weakened by the Step-0 half alone — Step 2
re-derives the set from the CLI and no executable consumer of `step0-classify` exists.
The exposure was the prose contract telling an agent to carry Step 0's set forward,
and turning it live took a second deviation, which is the `--require` defect. Neither
half demonstrates an un-gated merge on its own; the pair is the urgency.

In-place edit to the frozen v1 `claude-plugins/kampus-pipeline/` corpus under the
founder's #4650 No-go exception, scoped to this defect only (recorded on #4730).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants