Skip to content

fix(fabrika): seat exit 11 in write-pattern's two writing verbs (#5355) - #5365

Merged
usirin merged 2 commits into
mainfrom
usirin/write-pattern-exit-11-seat-5355-FEA52A0E
Aug 10, 2026
Merged

fix(fabrika): seat exit 11 in write-pattern's two writing verbs (#5355)#5365
usirin merged 2 commits into
mainfrom
usirin/write-pattern-exit-11-seat-5355-FEA52A0E

Conversation

@usirin

@usirin usirin commented Aug 10, 2026

Copy link
Copy Markdown
Member

The write-pattern CLI contract already defines exit 11 for "a precondition read failed", and three of its five verbs use it. The two verbs that write files — pattern new and pattern register — did not, so a read that errored fell through to exit 1, the code this repo reserves for "the call never ran". This adds the missing seat to both verbs so a failed read is told apart from a call that never happened.

Six table rows, no code change: one Exit status row per verb, plus one Errors row per exit-11 site in the shipped verb (one for pattern new, three for pattern register), reusing the shared matrix's existing 11 PRECONDITION_UNKNOWN.

  • pattern new11 when the target-path existence check itself fails, so existence is neither proven nor disproven (distinct from 13, which is proven).
  • pattern register11 at each of its three precondition reads: the <dir>/index.md existence check, the <dir>/index.md read, and the <dir>/<slug>.md existence check (distinct from 15 and 12, which are proven facts).

Message wording is quoted verbatim from the shipped verbs (packages/fabrika-cli/src/pattern/{new,register}-verb.ts) — pattern <verb>: cannot check|read <path>: <reason> — nothing was written. No new exit code is minted, nothing is renumbered, exit 7 (ZERO_SCOPE) stays unseated, codes 36 stay deliberate gaps, and the shared matrix, the seat map, and the three verbs that already seat 11 are untouched.

Same defect and same shape as #4736 in the sibling adr contract; belongs to the #4208 collision (a failed read is not a call that never ran).

Fixes #5355

Deviations

  • Scope narrowing / different shape (repair round 1)Said: write-pattern contract: no exit 11 seat in pattern new / pattern register #5355's What the fix is
    asks for "four rows total, two per verb", and AC2/AC4 ask for the stderr row "in the group's
    existing refusal wording, naming the outcome as UNKNOWN". Did: six rows — pattern register
    gets three Errors rows, one per exit-11 site in the shipped verb — and the wording is quoted
    verbatim from packages/fabrika-cli/src/pattern/{new,register}-verb.ts (— nothing was written.),
    which carries no UNKNOWN token. Why: write-pattern contract: no exit 11 seat in pattern new / pattern register #5355 was filed before Five fabrika pattern verbs are specified and none exists #5332 shipped, so its suggested
    wording is a guess at bytes that now exist; an Errors table that does not match what the binary
    prints is the defect the round-1 review FAILed on. Disposition: no action needed — reviewer-
    directed in the review-skill: FAIL @ 04353efb verdict; the seat-level UNKNOWN semantics AC2 wants
    are carried by the Exit status rows, and no code change is implied.

@github-actions

github-actions Bot commented Aug 10, 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. (c4f598e)
  • web — Stage pr-5365 torn down.

@usirin

usirin commented Aug 10, 2026

Copy link
Copy Markdown
Member Author

review-skill: FAIL @ 04353ef — changes-requested

Reviewed-head: @ 04353ef

Verified PR #5365 against #5355's acceptance criteria + the skill-rigor checklist. Class: non-blocking (claude-plugins/fabrika/** is not in the live CONTROL_PLANE_RE; cp-classify: not-control-plane [path-clear-no-content-source]). Required namespace set for this diff: review-skill (1 file, has-skills).

The finding in one line: the four rows land, but the two Errors rows specify stderr bytes that the already-merged implementation does not emit, and pattern register's single row does not cover two of the three sites where the shipped verb actually returns 11.

The write-pattern verbs are no longer unbuilt: #5332 closed completed at 2026-08-10T20:32:58Z via PR #5356, and packages/fabrika-cli/src/pattern/ is on origin/main already seating PRECONDITION_UNKNOWN in both writing verbs. On origin/main:

Site Shipped stderr (origin/main)
new-verb.ts:47 pattern new: cannot check <path>: <reason> — nothing was written.
register-verb.ts:60 (index existence) pattern register: cannot check <dir>/index.md: <reason> — nothing was written.
register-verb.ts:69 (index read) pattern register: cannot read <dir>/index.md: <reason> — nothing was written.
register-verb.ts:77 (doc existence) pattern register: cannot check <dir>/<slug>.md: <reason> — nothing was written.

Every other row in these two Errors tables is verbatim the string the code emits (pattern new: <path> already exists — refusing to overwrite., pattern new: cannot write <path>: <reason> — whether anything landed is UNKNOWN., pattern register: <dir>/index.md is absent — …, pattern register: no doc at <dir>/<slug>.md — …). That verbatim relationship is the table's contract. The two rows this PR adds are the only ones in either table that break it.

Acceptance criteria

  • [PASS] pattern new Exit status seats 11 for the existence check itself failing — contract.md:692, and the trigger text matches the shipped guard exactly (new-verb.ts:44 refuses PRECONDITION_UNKNOWN when exists(path) fails), distinct from 13.
  • [FAIL] pattern new Errors row at 11 — contract.md:700 specifies pattern new: cannot determine whether <path> exists: <reason> — UNKNOWN, never "absent"; nothing written.; the shipped verb emits pattern new: cannot check <path>: <reason> — nothing was written. (new-verb.ts:47, on origin/main). The row is not the matching message for the seat it documents, and it is the only row in this table that is not the code's literal string.
  • [PASS] pattern register Exit status seats 11, distinct from 15 and 12 — contract.md:816, and the "never 15 or 12, which are proven facts" clause is exactly the cp-classify exit 1 means both a proven not-§CP verdict and a failed invocation #4208 distinction the issue asked for.
  • [FAIL] pattern register Errors row at 11 — contract.md:825 carries one row, pattern register: cannot read <path>: <reason> — UNKNOWN, never "absent"; nothing written. Two problems: (a) the bytes differ from the shipped string (— nothing was written., register-verb.ts:69); (b) the verb seats 11 at three sites, and the two existence probes emit cannot check … (register-verb.ts:60 and :77), which no row in the table describes. The step-2 <dir>/<slug>.md case the Exit-status row promises is therefore documented with a message the implementation never prints.
  • [PASS] No new exit code minted, none renumbered — the diff adds four rows and reuses the shared matrix's existing 11 PRECONDITION_UNKNOWN (contract.md:132); no numeral in any table changed.
  • [PASS] Exit 7 (ZERO_SCOPE) stays unseated and 36 stay deliberate gaps — the deliberate-gaps table (contract.md:165–169) is outside every diff hunk, and no verb's Exit status table seats 37 at head.
  • [PASS] Shared exit matrix, seat map and the three verbs that already seat 11 unchanged — the four hunks are confined to lines 689/696/811/819; contract.md:132, :141 and the corpus/drift/anchor seats at :246, :391, :564 are untouched.

Skill rigor

  • [FAIL] Behavioral correctness — read as the spec an implementer executes, the amended contract now instructs a reader to emit strings the shipped verbs do not, and leaves register's two cannot check … refusals undocumented. Since the code landed after write-pattern contract: no exit 11 seat in pattern new / pattern register #5355 was filed, the artifact this PR should produce is a contract that describes the built behaviour; instead it introduces a contract↔code disagreement in the exact place the issue exists to make unambiguous. Remedy is still four cells: use the shipped bytes, and give register a second row (or one cannot check|read row) covering the existence probes at register-verb.ts:60 and :77.
  • [PASS] Trigger / description quality — contract.md carries no frontmatter description; write-pattern/SKILL.md and its trigger surface are outside the diff, so no trigger widened or narrowed.
  • [PASS] Cross-skill conflict / shadowing — the seat is imported, not minted: pattern/codes.ts:24,36 re-exports PRECONDITION_UNKNOWN from build/codes.ts, and exit-code-alignment.ts (SHARED_SEATS) already claims PRECONDITION_UNKNOWN as a shared seat, so nothing collides with report/triage/review. Wording follows the sibling adr contract's shape (adr/contract.md:139, :381, :655).
  • [PASS] Gate-invariant preservation — no §CP path in the diff, no gate skill in reach, and the change adds a refusal seat rather than relaxing one. No pipeline invariant is weakened.
  • [PASS] Contract implementation ticket (ADR 0248) — in scope (the diff changes claude-plugins/fabrika/skills/write-pattern/contract.md), and satisfied in substance: the five verbs this contract specifies are built and merged (Five fabrika pattern verbs are specified and none exists #5332 closed completed via PR feat(fabrika): implement the write-pattern contract's five pattern verbs (#5332) #5356), so no unbuilt spec enters the build pool. This is also why the FAIL rows above matter — there is a live implementation for these rows to disagree with.
  • [PASS] deviation-disclosure (§DEV) — the body's ## Deviations section is present and says None.; the Tier-M scan surfaces no undisclosed departure from the issue, an AC, or a governing ADR. Nothing undisclosed that this gate could see.

Read the PR head (§HEAD): all contract text under review sourced from 04353efbb1b40736efe6a80dfcb36a7f35d4d008 via the isolated review worktree; the implementation bytes were read from a freshly fetched origin/main, never a working copy.

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

Verdict-written: 2026-08-10T21:19:49Z

The two Errors rows added for `11 PRECONDITION_UNKNOWN` specified messages
the merged implementation does not emit, and `pattern register`'s single row
covered one of its three exit-11 sites.

Both tables now carry the strings `packages/fabrika-cli/src/pattern/` prints
on origin/main: `new-verb.ts` (`cannot check <path>`), and `register-verb.ts`
at all three sites (index existence, index read, doc existence).
@usirin

usirin commented Aug 10, 2026

Copy link
Copy Markdown
Member Author

review-skill: PASS @ c4f598e — merge-ready

Reviewed-head: @ c4f598e

Re-gate of PR #5365 after repair round 2 (prior verdicts: FAIL @ 04353efb, FAIL @ c4f598eb). Class: non-blockingcp-classify: not-control-plane [path-clear-no-content-source]; the single changed file claude-plugins/fabrika/skills/write-pattern/contract.md matches no branch of the live CONTROL_PLANE_RE (only claude-plugins/kampus-pipeline/** sub-paths are in the live CODEOWNERS) and the diff carries no .decisions/** file, so ADR 0164's content clause has nothing to decide. This marker binds ship-it.

Required namespace set for this diff (1 file, has-skills): review-skill — and only that. No code root, no .decisions/.patterns/root-doc path, no apps/web/src/ path, so review-code, review-doc and review-design are correctly not dispatched and emit nothing.

The head is unchanged. headRefOid is still c4f598eb634d942a476eaf9e698894afad3d2b5d (two commits: 04353efb @ 21:09:50Z, c4f598eb @ 21:26:42Z — nothing pushed since). Repair round 2 was a PR-body edit only, so the six-row diff I already validated byte-exact at this head is bit-identical, and the substance verdict below carries forward unchanged.

The round-2 blocker is fixed. The one FAIL standing at this head was deviation-disclosure: ## Deviations said None. while round 1 had made two reviewer-directed departures, and the summary above it still asserted the pre-repair state. Re-read of the live body:

  • ## Deviations now carries the round-1 entry, tagged **(repair round 1)** per §DEV's append rule, in the Said / Did / Why / Disposition shape. Both departures are named: six rows instead of write-pattern contract: no exit 11 seat in pattern new / pattern register #5355's "four rows total, two per verb" (pattern register has three exit-11 sites), and the wording quoted verbatim from the shipped verbs rather than AC2/AC4's literal "naming the outcome as UNKNOWN". Disposition is stated and correct — reviewer-directed in the review-skill: FAIL @ 04353efb verdict, no code change implied, and the seat-level UNKNOWN semantics AC2 asks for are carried by the two Exit status rows.
  • The two stale summary sentences are corrected and no longer contradict the diff. The body now reads "Six table rows … one Exit status row per verb, plus one Errors row per exit-11 site in the shipped verb (one for pattern new, three for pattern register)" — which is exactly the 2 + 4 = 6 added rows — and "Message wording is quoted verbatim from the shipped verbs … — nothing was written.". Grep of the live body returns zero hits for Four table rows, for the deleted never "absent" wording, and for a None. line. Nothing in the description now asserts a state the head does not hold.
  • Round 2 itself introduced no new departure from write-pattern contract: no exit 11 seat in pattern new / pattern register #5355 (it changed no file in the diff), so no **(repair round 2)** entry is owed.

Acceptance criteria — re-confirmed against the same head; the diff is the same six added rows, zero removed lines, against merge base 0478bdb1.

  • [PASS] AC1 — pattern new Exit status seats 11 for an incompletable existence check — contract.md:692, "the target-path existence check itself failed, so whether <path> exists is UNKNOWN — never read as absent, and never 13, which is proven". Matches the shipped control flow: new-verb.ts:46 returns PRECONDITION_UNKNOWN before the ALREADY_EXISTS branch, so 11 genuinely precedes 13.
  • [PASS] AC2 — pattern new Errors row at 11 — contract.md:700, pattern new: cannot check <path>: <reason> — nothing was written. Byte-exact against the shipped literal at new-verb.ts:47 (fixed-string match, em dash included). Kind is refusal at code 11, not a usage error at 1 — the substance AC2 asks for; the literal-wording departure is disclosed in ## Deviations.
  • [PASS] AC3 — pattern register Exit status seats 11 distinct from 15/12 — contract.md:816, naming both the step-1 <dir>/index.md and step-2 <dir>/<slug>.md reads and stating "never 15 or 12, which are proven facts". Matches register-verb.ts, where each PRECONDITION_UNKNOWN refusal precedes its proven-fact sibling.
  • [PASS] AC4 — pattern register Errors rows at 11, one per exit-11 site, byte-exact and exactly covering — register-verb.ts:61 cannot check ${indexPath} → contract.md:825; :70 cannot read ${indexPath} → contract.md:826; :78 cannot check ${docPath} → contract.md:827. Coverage is exact in both directions: grep -n 'PRECONDITION_UNKNOWN' on the shipped register-verb.ts returns the import plus exactly those three refusal sites, and no fourth.
  • [PASS] AC5 — no new exit code minted, none renumbered. Six added lines, zero removed, every row reusing the shared matrix's existing 11 PRECONDITION_UNKNOWN.
  • [PASS] AC6 — exit 7 (ZERO_SCOPE) stays unseated and 36 stay deliberate gaps; no verb exit table gains a row in 37.
  • [PASS] AC7 — the shared exit matrix, the group's seat map, and the three verbs that already seat 11 (corpus, drift, anchor) are untouched. The zero-removal diff reaches only the two writing verbs' Exit status and Errors tables.

Skill rigor

  • [PASS] Behavioral correctness — the contract reads as a spec for an implementer and as a refusal catalogue for a caller reading stderr; both readings resolve to the bytes the shipped binary emits, and the ordering claims in the two new Exit-status rows ("never 13", "never 15 or 12") are true of the shipped control flow rather than merely asserted.
  • [PASS] Trigger / description quality — no frontmatter or trigger surface in the diff; this is a contract table edit, not a SKILL.md change.
  • [PASS] Cross-skill conflict / shadowing — write-pattern owns this contract; the diff touches no shared contract, marker namespace, or seam another skill reads. pattern/codes.ts still imports PRECONDITION_UNKNOWN from ../build/codes.ts, so the documented group alignment is unchanged.
  • [PASS] Gate-invariant preservation — no gate invariant is in the diff's reach: the changed file is outside the live §CP set, adds only refusal seats, and removes nothing. Adding a refusal strengthens rather than weakens.
  • [PASS] Contract implementation ticket (ADR 0248) — in scope by the file-list trigger (the diff changes a claude-plugins/fabrika/skills/*/contract.md), and the obligation it protects is already discharged: the implementation ticket Five fabrika pattern verbs are specified and none exists #5332 is closed, the five verbs are shipped on origin/main under packages/fabrika-cli/src/pattern/, and every row this PR adds was verified against that shipped source above. No verb is left specified-but-unbuilt, so no un-triaged build work owes a ticket.
  • [PASS] deviation-disclosure — nothing undisclosed that this gate could see. Tier-M scan clean (0 suppression/skip lines, 0 removed-assertion lines); the Tier-R class-1 finding from round 2 (scope narrowing / different shape) is now disclosed under ## Deviations with its round tag, its Said/Did/Why, and a correct disposition, and the body no longer asserts any pre-repair state.

Read the PR head (§HEAD): the head SHA was resolved live via REST and re-confirmed unchanged before binding; all contract text and the shipped verb sources were read from c4f598eb… / origin/main via gh api raw reads, never the launched checkout's working copy. No working tree was switched (§RO).

All checks pass — 7/7 acceptance criteria and 6/6 rigor rows, including deviation-disclosure. This PR is merge-ready. review-skill does not mergeship-it is the authorized merge step; merging will auto-close #5355 via Fixes #5355.

Verdict-written: 2026-08-10T21:43:36Z

@usirin
usirin added this pull request to the merge queue Aug 10, 2026
Merged via the queue into main with commit 8f4b62f Aug 10, 2026
46 checks passed
@usirin
usirin deleted the usirin/write-pattern-exit-11-seat-5355-FEA52A0E branch August 10, 2026 21:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

write-pattern contract: no exit 11 seat in pattern new / pattern register

1 participant