Skip to content

docs(decisions): 0248 — the authoring session mints a contract's implementation ticket at handoff (#4749) - #5235

Merged
usirin merged 1 commit into
mainfrom
umut/4749-contract-implementation-ticket-handoff
Aug 10, 2026
Merged

docs(decisions): 0248 — the authoring session mints a contract's implementation ticket at handoff (#4749)#5235
usirin merged 1 commit into
mainfrom
umut/4749-contract-implementation-ticket-handoff

Conversation

@usirin

@usirin usirin commented Aug 10, 2026

Copy link
Copy Markdown
Member

Fixes #4749

Records the founder ruling on the spec-to-build seam (issue comment 2026-08-10T00:12:17Z, which supersedes the earlier 2026-08-02 comment's CI-guard shape) and writes it into the two in-repo surfaces that carry it.

The decision

The authoring session mints a fabrika contract's implementation ticket, as part of its handoff, and review-skill checks it exists.

  • Actor + moment — the authoring session, at handoff. The handoff is not complete until the ticket exists and names its number. The session is the filer because it just derived the verb inventory and ran the split test.
  • The check — a listed review-skill rigor criterion, scoped to a PR that adds or changes a claude-plugins/fabrika/skills/*/contract.md: the ticket must exist, be open, be named in the PR body or handoff, and route to these verbs. Fixes #<brief> does not satisfy it — that closes the brief, which is a done-signal, not the hand-off.
  • Zero scope (ADR 0092) — a diff with no fabrika contract.md is out of scope and records PASS with that evidence; an unreadable file list is UNKNOWN and fails, never "no contract touched."
  • Nothing auto-mints. A machine-minted ticket is un-triaged work entering the build pool — the second door Decision (founder-decision-fork): what 'done' means for v2, and the eval bar #4637-C closed. The mechanism demands the ticket, it never authors one.

Rejected on the record: minting implementation children on the epic up front (amends #4650's ruled briefs-only plan, and drops unassigned children into the coder pool), and leaving it to ambient noticing (the gap itself).

Why the teeth are a gate criterion, not a new CI job

A grep-shaped CI guard answers "does the body contain an issue number" — satisfiable by the brief's own Fixes #<brief> line. The question that matters is "does an open ticket route to these verbs", which is a semantic read. review-skill already opens the PR, its linked issues and the contract text, and already did exactly this informally on the front-door PR (#5216). One listed criterion beats a second job that re-derives a weaker answer and drifts.

Acceptance criteria

  • The choice is recorded as an ADR — .decisions/0248-authoring-session-mints-the-implementation-ticket.md (actor, moment, and what enforces it)
  • The brief contract's field 6 states the hand-off's filing half explicitly — a new "Who files the implementation ticket: this session, at handoff" clause under "Where the session's job ends", plus the completeness-test row and the worked example
  • The decision states whether enforcement is a guard, a documented obligation, or both — both: the documented obligation in the brief contract, the teeth as a conjunctive gate criterion; the ADR says why a CI guard was not the shape
  • Zero-scope behaviour stated (ADR 0092) — out-of-scope PASS with evidence, unreadable file list fails
  • Whether the 17 open briefs need changing — no. A brief points at the contract doc rather than paraphrasing it, so every session boots against the live doc
  • The two landed instances reconciled — adr (Implement packages/fabrika-cli — the six adr verbs from the wave-0 pilot's derived contract #4725) and report (Implement the three /report fabrika verbs — the merged contract has no implementation ticket #4748) are both closed; the rule is retroactively satisfied and applies at authoring time only
  • Nothing files an implementation ticket automatically without triage

Files

File What changed
.decisions/0248-authoring-session-mints-the-implementation-ticket.md new ADR
claude-plugins/fabrika/docs/authoring-brief-contract.md field 6 gains the filing half; completeness test row 6; worked example
claude-plugins/kampus-pipeline/skills/review-skill/SKILL.md rigor check 5 (scoped) + the two PASS verdict templates + count phrasing
claude-plugins/kampus-pipeline/skills/author-skill/SKILL.md authoring-side mirror of check 5 + count phrasing
claude-plugins/kampus-pipeline/skills/write-code/SKILL.md one count phrase ("four rigor checks" → "rigor checks")

Three of the five are under claude-plugins/kampus-pipeline/skills/, so this PR is §CP and needs a @kamp-us/control-plane approval at head before ship-it can enqueue it. No CODEOWNERS row was added or widened, and nothing under claude-plugins/fabrika/skills/ was touched.

Checks run locally

…ementation ticket at handoff (#4749)

The spec-to-build seam had no owner: a landed fabrika contract.md specifies
verbs nobody has built, and an open issue is the only route into the build
pool, so both early instances (#4725, #4748) got a ticket only because an
agent happened to look.

Records the founder ruling: the authoring session files the implementation
ticket as part of its handoff, the handoff names its number, and review-skill
lists it as a gate criterion scoped to fabrika contract PRs (out of scope =
PASS with evidence, unreadable file list = fail, ADR 0092). Nothing mints a
ticket by machine.

Fixes #4749
@usirin
usirin requested a review from a team as a code owner August 10, 2026 00:51
@github-actions

github-actions Bot commented Aug 10, 2026

Copy link
Copy Markdown

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. (f8d56d6)
  • web — Stage pr-5235 torn down.

@usirin

usirin commented Aug 10, 2026

Copy link
Copy Markdown
Member Author

review-skill: advisory — blocking-set PR (§CP — approval-gated)

Reviewed-head: @ f8d56d6

Verified PR #5235 against #4749's acceptance criteria + the skill-rigor checklist. Graded against the newest ruling on #4749 (2026-08-10T00:12:17Z — authoring session mints at handoff, review-skill lists the check), which supersedes the 2026-08-02 CI-guard ruling. Skill text sourced read-only from f8d56d6 via a per-run ref (refs/pr/5235-gate), never a checkout.

Skill-class files under review (3): claude-plugins/kampus-pipeline/skills/{review-skill,author-skill,write-code}/SKILL.md

Acceptance criteria

  • [PASS] Choice recorded as an ADR — .decisions/0248-…md, §1 names actor (the authoring session) + moment (its handoff, "not complete until the ticket exists and the handoff names its number"); §2 names the check
  • [PASS] Enforcement stated explicitly (guard / obligation / both) — the "Why the teeth are a gate criterion and not a CI guard" section rules both halves, with teeth placed on the gate: "Teeth were not declined; they were placed at the only surface that can judge the ticket rather than count a number"
  • [PASS] Zero-scope behaviour stated (ADR 0092) — §2: out-of-scope diff = PASS with evidence; unreadable file list = UNKNOWN and fails, "never 'no contract touched'"
  • [PASS] The 17 open briefs need no change — Consequences bullet 1, with its reason (a brief points at the live doc rather than paraphrasing it)
  • [PASS] Nothing auto-files a ticket without triage — §3, and check 5's closing clause: "You never file the ticket yourself… Your job is to demand it"

Skill rigor

  • [PASS] Behavioral correctness — check 5 is executable as written: it names its selector (the PR's changed-file list), its scope pattern (claude-plugins/fabrika/skills/*/contract.md), the assertion (ticket exists + open + named + routes to these verbs), and the two negative cases a grader would otherwise get wrong (Fixes #<brief> is a done-signal, not the hand-off; a bare number tracking something else). All three branches — in-scope / out-of-scope / unreadable — have a stated disposition, so no input leaves the check undefined.
  • [PASS] Trigger / description quality — the review-skill frontmatter description gains the check-5 clause; trigger phrases are byte-identical, so routing is unchanged. author-skill's description drops only the word "four".
  • [PASS] Cross-skill conflict / shadowing — the scoped path is reachable by construction. §CLASS HAS_SKILLS_RE = ^claude-plugins/[^/]+/(skills|agents)/, which matches claude-plugins/fabrika/skills/*/contract.md, so review-skill is guaranteed dispatched on exactly the PRs check 5 scopes to — the criterion is not a phantom gate. No collision with the fabrika review rubric: ADR 0248's last Consequences bullet rules the criterion belongs to "whichever skill is the live skill-class gate… not a second, parallel check".
  • [PASS] Gate-invariant preservation — the edit tightens this gate; it weakens nothing. See the walk below.
  • [PASS] Contract implementation ticket (the new check 5, applied to itself) — out of scope: the diff carries no claude-plugins/fabrika/skills/*/contract.md (5 files, changed-file list read from the API). The check ran and had nothing to assert.

The self-gating question: does the review-skill edit loosen its own gate?

This PR edits the very rubric grading it, so I walked every removed and changed line in review-skill/SKILL.md.

Finding: it TIGHTENS. Net one new conjunctive obligation; zero weakening.

Invariant State after the diff
"a rigor FAIL fails the gate… conjunctive across both lists" Untouched — not in the diff. Check 5 inherits it, so a check-5 FAIL fails the gate.
Rigor checks 1–4 bodies Byte-identical. Zero - lines fall inside checks 1–4; the only deletion in that region is the list-header sentence.
Zero-scope disposition Fail-closed, correct. Unreadable file list = UNKNOWN = fails (ADR 0092), with the anti-pattern named explicitly. Out-of-scope PASS is evidence-bearing, not silent.
Marker contract (@ <sha>, namespace, upsert key, never-merges, advisory arm) Untouched — the description's marker sentence and §VERDICT are unchanged.
ADR 0073's four behavioral failures Preserved as four, correctly. Line 518 still reads "the four behavioral failures ADR 0073 enumerated" — that is the 0073 failure taxonomy, a different list from the now-five checks. The coder did not over-apply the count edit here, which is the right call.

All 7 deletions in this file are count phrasing ("the four rigor checks" → "the rigor checks") or the two sentences the new clause extends. Nothing normative was softened: author-skill's "Write to satisfy all four up front" → "Write to satisfy them up front" now binds five, not four.

The one place a count survives that I checked closely — line 21, "You exist to check those four" — is accurate: it refers to the four ADR 0073 concerns enumerated in the sentence immediately above it, not to the rigor-check count.

Residual nit (non-blocking, no repair asked). In the brief-contract's field 6, the new clause says "review-skill lists this as a criterion" three paragraphs after the same field says "nothing waits on fabrika's own /review-skill". Two different things share a name there. ADR 0248's "whichever skill is the live skill-class gate" bullet resolves it, so a reader who follows the link is not misled.


Two claims I verified rather than accepted

Scope claim — check 5 is genuinely scoped, not a fifth universal check. Confirmed in the text: "Scope this check off the PR's changed-file list", with an explicit Out of scope branch. Confirmed too that leaving packages/fabrika-cli/src/eval/corpus.ts untouched was correct, not an omission: its SKILL_RIGOR_CHECKS closed vocabulary is keyed to a different rubric (claude-plugins/fabrika/skills/review/rubrics/skill.md) whose fourth member is fabrika-conventions, not gate-invariant-preservation, and whose docblock already excludes a fifth candidate on purpose per ADR 0243 §1a. Editing it would have been the defect.

ADR number 0248 is unclaimed. origin/main tops out at 0246. I enumerated the .decisions/ files of every open PR: #52300247, #47030237, #46140235; #5233, #5231, #4833, #3941 add none. No collision.

Advisory only — three files sit under /claude-plugins/kampus-pipeline/skills/, owned by @kamp-us/control-plane in live CODEOWNERS. This authorizes nothing on its first line; a control-plane approval at head is what merges it.

@usirin

usirin commented Aug 10, 2026

Copy link
Copy Markdown
Member Author

review-doc: advisory — blocking-set PR (§CP — approval-gated)

Reviewed-head: @ f8d56d6

Verified PR #5235's prose surface against #4749's acceptance criteria + doc hygiene. Doc text sourced read-only from f8d56d6 via a per-run ref, never a checkout. Graded against the newest ruling on #4749 (2026-08-10T00:12:17Z), which supersedes the 2026-08-02 CI-guard ruling.

Doc-class file under review (1): .decisions/0248-authoring-session-mints-the-implementation-ticket.md (added, +131) — matches HAS_DOCS_RE via ^\.decisions/, outside the ^claude-plugins/ carve-out.

Acceptance criteria

Doc hygiene

  • [PASS] Relative links resolve — ../claude-plugins/fabrika/docs/authoring-brief-contract.md and 0092-gates-fail-closed-on-zero-scope.md both resolve from .decisions/; .decisions/0092, 0073, 0243 all exist at head.
  • [PASS] Standard markdown links, no Obsidian [[wikilinks]] — scanned the added lines; none.
  • [PASS] No home / local / absolute / sibling-repo paths — grepped every added line for /Users/, ~/, /home/, file://: none. All paths repo-relative or full GitHub URLs.
  • [PASS] Surface discipline — the why + history lands in .decisions/, the operating rule in the fabrika doc, the check in the gate skill. No ADR content duplicated into README/DEVELOPMENT.md.
  • [PASS] Falsifiable claims grounded in source, not intuition — the load-bearing mechanism claim ("the only route into the build pool is an open issue") cites write-code/scripts/step1-candidate-pool.sh. I read that script at head and confirmed the predicate matches: state=open&labels=status:triaged,$P with select(.assignee == null and (.pull_request | not)), p0→p1→p2. The claim is accurate, not asserted.
  • [PASS] No committed ADR index touched (ADR 0126 — discovery is by filename + frontmatter, there is no index to update).

ADR number 0248 is unclaimedorigin/main tops out at 0246; across every open PR, #5230 holds 0247, #4703 holds 0237, #4614 holds 0235, and #5233/#5231/#4833/#3941 add no ADR. No duplicate.

Closing keywords — the body's closing set is exactly {#4749}: one match for (fix|close|resolve)[a-z]*:? +(#N | issue URL), namely Fixes #4749. The four other lines carrying a closing verb are safe — two are the `Fixes #<brief>` placeholder (no number), and two put "closed" after the number ("the second door #4637-C closed", "(#4748) are both closed"), which GitHub does not parse as a closing reference.

Advisory only — this PR is §CP (three files under /claude-plugins/kampus-pipeline/skills/, owned by @kamp-us/control-plane). This authorizes nothing on its first line.

@usirin

usirin commented Aug 10, 2026

Copy link
Copy Markdown
Member Author

review-code: advisory — blocking-set PR (§CP — approval-gated)

Reviewed-head: @ f8d56d6

Verified PR #5235 against #4749's acceptance criteria. Files sourced read-only from f8d56d6 via a per-run ref, never a checkout. Graded against the newest ruling on #4749 (2026-08-10T00:12:17Z), which supersedes the 2026-08-02 CI-guard ruling.

Why this namespace is required — the no-class fail-closed rule (#2765). I ran pipeline-cli class-probe classify --namespaces over the PR's changed-file list; it returned three namespaces: review-code, review-doc, review-skill. review-code is not here because the diff touches apps//packages//infra//.glossary/no file matches HAS_CODE_RE. It is here because claude-plugins/fabrika/docs/authoring-brief-contract.md matches no class: it is excluded from review-doc by HAS_DOCS_EXCLUDE_RE's ^claude-plugins/ branch, and it is not under skills/|agents/ so it misses HAS_SKILLS_RE. Per §CLASS's no-class fail-closed rule that file rides has-code, so this gate runs on it rather than leaving it ungated.

review-design is correctly not required: live UI_RE = ^apps/web/src/, and no changed path matches.

File under review (1): claude-plugins/fabrika/docs/authoring-brief-contract.md (+23/−2)

Acceptance criteria

  • [PASS] Field 6 states the hand-off's filing half explicitly — the actor and the moment — so a session booting from the doc alone reads it there. Verified by placement, not just presence: the new block sits inside ### 6. Output contract — one PR, linked back, directly under the existing "Where the session's job ends." paragraph. It names the actor ("this session"), the moment ("at handoff… not complete until the implementation ticket exists and the handoff names its number"), and the ticket's minimum payload (skill served, repo-relative contract.md path, verb inventory, sequencing dependency).
  • [PASS] Nothing files a ticket automatically without triage — "Nothing mints it by machine… It goes through triage like any other issue; the session files it and stops."
  • [PASS] The obligation is stated as checked, not merely asked for — the "It is checked, not merely asked for." paragraph names review-skill as the checker and rules out Fixes #<brief> as satisfying it.

Correctness / hygiene

  • [PASS] Relative link resolves — ../../../.decisions/0248-…md from claude-plugins/fabrika/docs/ walks up three to the repo root and hits the ADR added by this same PR. Correct depth, and the target exists at head.
  • [PASS] No home / local / absolute / sibling-repo paths in any added line (grepped /Users/, ~/, /home/, file://, [[): none.
  • [PASS] Founder-owned fences untouched — nothing under claude-plugins/fabrika/skills/{wayfinding,prototyping,graduate,handoff}/ or plan-epic/** is in the diff. Only claude-plugins/fabrika/docs/ is touched, and no contract.md is added or changed anywhere.
  • [PASS] No CODEOWNERS row added or widened — .github/CODEOWNERS is not in the diff.
  • [PASS] Single source, no drift — the doc links ADR 0248 rather than restating its reasoning, matching the ADR's own "cites this decision rather than restating the rule, so the two cannot drift".

The 16 deleted lines — confirmed line-level rewrites, nothing load-bearing dropped. I enumerated every - line across all five files and they account exactly: review-skill 7, author-skill 6, write-code 1, this doc 2 = 16.

  • 13 are the count phrasing "four rigor checks" → "the rigor checks" (plus the two frontmatter description rewrites, which change only that count and keep every trigger phrase byte-identical).
  • 2 are this file's sentences that the new clause extends, not replaces: completeness-test row 6 keeps "The output contract is stated in the brief, not assumed" verbatim and appends the filing half; the worked example keeps "…implemented downstream by write-code, against that spec" and "No skill enters fabrika by any other path (Decision (founder-decision-fork): what 'done' means for v2, and the eval bar #4637-C)" verbatim, appending the filing sentence between them.
  • 1 is the review-skill rigor-list header, replaced by a two-line version that adds the check-5 scoping note.

No rule, no fence, no invariant and no cross-reference was removed. Diff shape matches independently: 5 files, +197/−16, 1 added / 4 modified, no file deletions.

Closing keywords — closing set is exactly {#4749} (Fixes #4749); the other closing-verb lines are `Fixes #<brief>` placeholders or put the verb after the number, neither of which GitHub parses.

Advisory only — this PR is §CP (three files under /claude-plugins/kampus-pipeline/skills/, owned by @kamp-us/control-plane in live CODEOWNERS). This authorizes nothing on its first line; a control-plane approval at head is what merges it.

@usirin usirin added the status:cp-banked Control-plane PR banked on the board, awaiting a control-plane approval label Aug 10, 2026
@usirin
usirin requested a review from notusirin August 10, 2026 01:05
@usirin
usirin added this pull request to the merge queue Aug 10, 2026
Merged via the queue into main with commit 2f13d04 Aug 10, 2026
46 checks passed
@usirin
usirin deleted the umut/4749-contract-implementation-ticket-handoff branch August 10, 2026 01:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

status:cp-banked Control-plane PR banked on the board, awaiting a control-plane approval

Projects

None yet

Development

Successfully merging this pull request may close these issues.

A landed fabrika contract mints no implementation ticket — the spec-to-build seam is manual

2 participants