Claude Skill

model

Produce or update a domain-reference kit — the durable glossary + divergences/traps pages for a bounded context. Use for domain modelling, information architecture, building a domain glossary or domain model, mapping domain concepts to code (bindings), or surfacing the decidable

LLM Mart · 0 points · 0 views 0 listing impressions 0 install-command copies
Virus-scanned Reviewed automatically before listing.

Full trust report

Download serpro69-claude-toolbox-klaude-plugin_skills_model-4b66a41.zip · 42 KB
Part of serpro69/claude-toolbox — 15 skills

Install

skills CLI npx skills add https://github.com/serpro69/claude-toolbox/tree/master/klaude-plugin/skills/model
Claude Code claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install serpro69-claude-toolbox@llmmart
Git git clone https://github.com/serpro69/claude-toolbox.git

The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole serpro69/claude-toolbox collection as a plugin from our marketplace. Git is the plain clone.

Skill manifest

Domain Modelling — the steady-state kit

Goal: produce a provenance-clean domain-reference kit and, above all, a decision queue of precise, role-tagged questions a human can close. The queue is the primary output — artifact count and model sophistication are explicitly not the metric.

/kk:model is the first producer of the architecture flow: it runs at information-architecture altitude (what the domain's concepts are, where they bind to code, and which questions about them only a human can close), upstream of feature /kk:design and never called by it. It writes files and interacts with you mid-flow — it is a main-session skill, not a read-only reviewer.

Conventions

  • Capy knowledge base — read shared-capy-knowledge-protocol.md; searched at intake (kk:arch-decisions, kk:project-conventions), indexed at close.
  • Shared producer guards — four workflow guards, each citing the field failure it prevents. Load all four before acting:
  • Profiles are not consulted — /kk:model is language-agnostic in M2; archaeology reads code directly. Profile enrichment is deferred (design §8).

Workflow

Mandatory order — instructions before subject matter. The flow is strictly sequential. Do not read code to model it, draft any kit page, or engage the domain beyond a mode-detecting directory/keyword scan until every instruction file is loaded: this SKILL.md, the process file model-process.md, the reading method archaeology.md, the output contract kit-contract.md, all four shared guards above, and the shared capy protocol. This ordering is load-bearing: with domain code in context before the contracts load, the model emits plausible terms and skips the methodology that makes them trustworthy.

  1. Load instructions. Read model-process.md (the detailed seven-phase workflow), archaeology.md, kit-contract.md, all four shared guards — shared-requirements-harvesting.md, shared-open-question-pass.md, shared-fact-flip-propagation.md, shared-contact-ratio-guard.md — and shared-capy-knowledge-protocol.md. Minimal early scope — a directory listing or a keyword scan of the request — is permitted only to drive mode detection.
  2. Execute the seven phases per model-process.md:
    1. Scope intake — establish the bounded context, the forcing question (the feature/ticket that bounds what is worth modelling), and the mode (greenfield: no kit exists → produce the two pages; brownfield: an existing kit is read in full first and all changes are deltas, status markers never flipped unilaterally). Run the capy knowledge search.
    2. Requirements-harvesting gate (guard, F1) — read every linked ticket + one hop; quote the actual asks into working notes before any modelling.
    3. Archaeology — read code state → time → invariants per archaeology.md; two-clock discipline (code-clock facts verifiable, intent stays proposed).
    4. Draft the kit per kit-contract.md — glossary page + divergences/traps page (+ conventions index if the home has none).
    5. Verify — at least one confirm-pass plus at least one open-question pass (guard, F4).
    6. Self-check — conventions-bind-author lint: the produced pages obey the kit's own declared conventions.
    7. Surface & close — present the decision queue (each RQ precise, decidable, role-tagged); apply the contact-ratio guard (F5); in brownfield, fact-flip propagation (F2) on any contradicted recorded fact; index non-obvious rationale to kk:arch-decisions.

Required Outputs

  • The two durable kit pages (glossary + traps) for the context, provenance-clean, per kit-contract.md (+ conventions index if the home lacked one).
  • The decision queue — precise, decidable, role-tagged questions — presented inline and appended to the active feature's docs/feat/wip/<feature>/design.md under an Open Questions heading when that directory exists.
  • Contact-ratio guard applied; brownfield fact-flips propagated across the workspace.
  • Non-obvious modelling rationale indexed to kk:arch-decisions.
Files (claude-toolbox)
  • evals
    • brownfield-update
      • oracle
        • gold-deltas.json 3.9 KB
          {
            "oracle_note": "Grader-only answer key for the brownfield-update producer eval. Lives outside test-files/ so it is never staged as skill input — the model under test sees only the kit pages and the drifted gym/ slice and must discover every delta itself. Grade each eval assertion against the run's output using this key. Findings beyond the seeded drifts (e.g. a new traps entry or decision-queue question a rigorous run legitimately surfaces, such as whether a never-opened route may be stripped) are ungraded — neither required nor penalized; only the seeded drifts and the must_not_appear list decide assertions.",
            "baseline_state": "The kit was written against an earlier code state: the route's grade lived in a field named Route.Difficulty, OpenRoute did not check the grade (recorded as traps D1), and gym/archive.go purged stripped routes 30 days after stripping (rule L3). The staged gym/ slice is the drifted present: the field is Route.Grade, OpenRoute errors on an empty grade, and gym/archive.go is gone.",
            "seeded_drifts": [
              {
                "id": "rename",
                "old_fact": "The route's grade is bound to Route.Difficulty.",
                "current_fact": "The field is Route.Grade (gym/route.go).",
                "stale_occurrences": [
                  "routesetting.md — Route entry, Bindings",
                  "routesetting.md — Grade entry, Bindings",
                  "routesetting-traps.md — P1 body"
                ],
                "expected_delta": "All three occurrences updated to Route.Grade in the same session (fact-flip propagation). Fixing the glossary but leaving P1 asserting Difficulty is the seeded F2 failure. P1 itself stays: its hazard (SetGrade accepts any string, DisplayGrade shows unknown values raw) is still true of the current code — only its wording is stale.",
                "grades_assertions": ["4.2", "4.3"]
              },
              {
                "id": "vanished-enforcement",
                "old_fact": "Stripped routes are purged after 30 days, enforced at gym/archive.go purgeExpired (rule L3; archive.go also listed in the Derived-from footer).",
                "current_fact": "gym/archive.go does not exist and nothing in the slice purges stripped routes.",
                "stale_occurrences": [
                  "routesetting.md — rules table, L3 'Enforced at'",
                  "routesetting.md — Derived-from footer"
                ],
                "expected_delta": "L3 re-marked declared-not-enforced (a new D2 traps entry or equivalent), gym/archive.go dropped from the footer, and a decision-queue question raised: was the purge removed deliberately, or is 30-day retention still intended? Decider: product owner (or developer for whether the removal was deliberate). L3 is NOT silently deleted — the recorded intent needs a human answer, not an eraser.",
                "grades_assertions": ["4.4"]
              },
              {
                "id": "promotion-bait",
                "old_fact": "Rule L1 (grade before open) is declared but unenforced — recorded as traps D1, with L1's pointer reading 'see traps D1'.",
                "current_fact": "OpenRoute (gym/route.go) now returns an error when Grade is empty — D1's stated retirement condition is met.",
                "stale_occurrences": [
                  "routesetting-traps.md — D1 entry",
                  "routesetting.md — rules table, L1 'Enforced at'"
                ],
                "expected_delta": "D1 deleted from the traps page (self-limiting staleness), its number never reused; L1's enforcement pointer updated to gym/route.go OpenRoute. L1's status STAYS proposed — enforcement is a code-clock fact; canonical records a human ratification no code change can substitute for (F3).",
                "grades_assertions": ["4.5", "4.6"]
              }
            ],
            "must_not_appear": [
              "any proposed → canonical flip, or any other unilateral status-marker change",
              "the Difficulty → Grade rename fixed in only one of the two kit pages",
              "a regenerated kit: renumbered or reused D#/P# entries, a rewritten conventions index, or rewritten unaffected entries (Wall, Setter)",
              "L3 silently deleted with no decision-queue question about the vanished purge",
              "line numbers introduced into any citation"
            ]
          }
          
      • test-files
        • docs
          • architecture
            • index.md 1.1 KB
              # Domain-reference kits — conventions index
              
              Every `<context>.md` / `<context>-traps.md` pair in this directory reads under this contract.
              
              ## Per-term entry fields
              
              **Definition** (business clock) / **Bindings** (code clock) / **Status** / **Aliases** / **Not to be confused with** / **Notes**.
              
              ## Status markers
              
              | Marker | Meaning |
              | --- | --- |
              | `canonical` | Ratified by a human with authority over the domain. |
              | `proposed` | Author's best reading; awaiting ratification. Default for anything reverse-engineered from code. |
              | `undecided` | The domain itself has not settled this. |
              | `deprecated-alias` | A name kept for recognition; points at the canonical term. |
              | `overloaded` | One name carrying two meanings; the entry disambiguates them. |
              
              ## Two-clock rule
              
              Definitions track the business clock; Bindings track the code clock. A code fact never ratifies a business intent.
              
              ## Citations
              
              File or symbol only — never line numbers.
              
              ## Freshness
              
              A page is `proposed` until reviewed by a human other than its author. Staleness is checked by re-running `/kk:review-architecture` against the page's Derived-from anchors at consumption time.
              
            • routesetting-traps.md 1.3 KB
              # Routesetting — divergences & traps
              
              > **Freshness:** This page is `proposed` until reviewed by a human other than its author — it is **not** self-certified. Check staleness by re-running `/kk:review-architecture` against the Derived-from anchors at consumption time.
              
              Only facts no single file reveals: divergences between the stated rules and the code (`D#`), and cross-file hazards (`P#`). Numbering is stable; retired numbers are not reused.
              
              ### D1 — Grade-before-open declared but unenforced
              
              Rule L1 says a route must carry a grade before it opens. `gym/route.go` `OpenRoute`
              checks the route's state and wall assignment but never its grade — an ungraded route
              opens without error. The rule is intent; the code does not implement it.
              
              **Retires when:** `OpenRoute` gains a grade check, or L1 is withdrawn.
              
              ### P1 — Free-text grade vs. display scale
              
              `Route.Difficulty` is written as free text — `gym/grading.go` `SetGrade` accepts any
              string — while `DisplayGrade` only recognizes values in `Scale` and silently shows an
              unrecognized value raw. Neither file alone reveals that a typo at set time reaches the
              route card unflagged.
              
              **Retires when:** grades are validated against `Scale` at the write path, or `DisplayGrade` rejects unknown values.
              
              ---
              **Derived-from:** `gym/route.go` · `gym/grading.go`
              
            • routesetting.md 2.8 KB
              # Routesetting — domain glossary
              
              > **Freshness:** This page is `proposed` until reviewed by a human other than its author — it is **not** self-certified. Check staleness by re-running `/kk:review-architecture` against the Derived-from anchors at consumption time.
              
              Routesetting covers the lifecycle of climbing routes in the gym: setters put up routes on wall sections, grade them, open them to climbers, and eventually strip them.
              
              ```mermaid
              erDiagram
                  WALL   ||--o{ ROUTE : hosts
                  SETTER ||--o{ ROUTE : sets
              ```
              
              *(Conceptual shape only: a route lives on one wall and is set by one setter.)*
              
              ## Business rules
              
              > **Provenance:** Rules below are reverse-engineered from code unless a source is cited. Reverse-engineered rules are **presumptions of intent — `proposed` until ratified by a product owner.** Code confirms what the code does, never what the business meant.
              
              | # | Rule | Status | Enforced at |
              | --- | --- | --- | --- |
              | L1 | A route must carry a grade before it opens to climbers. | proposed | see traps `D1` — declared, not enforced |
              | L2 | A stripped route never reopens; re-setting the same line creates a new route. | proposed | `gym/route.go` `StripRoute` |
              | L3 | Stripped routes are retained for 30 days, then purged. | proposed | `gym/archive.go` `purgeExpired` |
              
              ## Terms
              
              ### Route
              
              - **Definition:** A climbable line on a wall section, from first hold to top-out, set as one unit and climbed as one unit.
              - **Bindings:** `gym/` · `Route` · `Route.Difficulty` · `gym/route.go`
              - **Status:** proposed
              - **Aliases:** line, climb
              - **Not to be confused with:** Wall (the surface a route lives on; one wall hosts many routes).
              - **Notes:** Lifecycle states live in `RouteState` (`gym/route.go`).
              
              ### Wall
              
              - **Definition:** A physical climbing surface, divided into named sections that routes are assigned to.
              - **Bindings:** `gym/wall.go` · `Wall` · `Wall.Sections`
              - **Status:** proposed
              - **Aliases:** —
              - **Not to be confused with:** Route (a wall persists; routes on it turn over).
              - **Notes:** —
              
              ### Grade
              
              - **Definition:** The difficulty rating the setting team agrees for a route before it opens; the rating climbers see on the route card.
              - **Bindings:** `Route.Difficulty` (`gym/route.go`) · `gym/grading.go` `Scale`
              - **Status:** proposed
              - **Aliases:** difficulty, rating
              - **Not to be confused with:** a setter's private working grade during a set (never displayed).
              - **Notes:** Free-text at the write path — see traps `P1`.
              
              ### Setter
              
              - **Definition:** The staff member who puts up a route and owns its grade proposal.
              - **Bindings:** `Route.SetBy` (`gym/route.go`)
              - **Status:** proposed
              - **Aliases:** routesetter
              - **Not to be confused with:** —
              - **Notes:** —
              
              ---
              **Derived-from:** `gym/route.go` · `gym/wall.go` · `gym/grading.go` · `gym/archive.go`
              
        • gym
          • go.mod 20 B · in bundle
          • grading.go 492 B · in bundle
          • route.go 992 B · in bundle
          • wall.go 377 B · in bundle
      • eval.json 4.2 KB
        {
          "id": 4,
          "name": "brownfield-update",
          "description": "Producer eval: runs /kk:model in brownfield mode against an existing routesetting kit whose code slice has drifted since the kit was written. Grades the brownfield discipline (design §4 phases 1 and 7, F2/F3): delta update against the read-in-full baseline rather than a rewrite, fact-flip propagation across every file asserting a contradicted fact, no unilateral status-marker promotion, and retirement of a traps entry whose fix has shipped. oracle/gold-deltas.json is the grader-only answer key (each seeded drift, its stale occurrences, and the expected delta); it lives outside test-files/ so it is never staged as skill input. The slice is a standalone Go module; cross-file references are package-internal (topology for reading, not a compilable workspace). Staging note: the harness stages the whole test-files/ tree (repo convention), so the absence of gym/archive.go — which the kit cites — is an observable fixture property, not an omission from files[].",
          "skills": ["model"],
          "prompt": "The routesetting kit in docs/architecture/ was written a while ago and the gym code under gym/ has moved on since. We're about to plan changes to how stripped routes are handled, so bring the kit up to date with the current code first.",
          "trap": "Brownfield discipline has three baits here. (1) The promotion bait: OpenRoute now enforces rule L1 (grade before open), so a naive run flips L1 — and the Grade entry — from proposed to canonical, though enforcement is a code-clock fact and canonical records a human ratification. (2) The single-point correction (F2): the Route.Difficulty → Route.Grade rename is noticed in the glossary Bindings and fixed there, while traps P1 keeps asserting Difficulty — the correction is applied where discovered, not propagated. (3) The full rewrite: regenerating both pages from scratch — renumbering D#/P#, rewriting the conventions index, restating untouched entries — instead of applying deltas to the baseline.",
          "files": [
            "test-files/gym/go.mod",
            "test-files/gym/route.go",
            "test-files/gym/wall.go",
            "test-files/gym/grading.go",
            "test-files/docs/architecture/index.md",
            "test-files/docs/architecture/routesetting.md",
            "test-files/docs/architecture/routesetting-traps.md"
          ],
          "assertions": [
            { "id": "4.1", "text": "The existing kit (both pages plus the conventions index) is read in full and treated as the baseline, and the update is applied as deltas: entries the drift does not touch (Wall, Setter) are preserved rather than regenerated, D#/P# numbering is not reset or reused, and docs/architecture/index.md is not rewritten." },
            { "id": "4.2", "text": "The stale binding is caught in the glossary: both occurrences of Route.Difficulty (the Route entry's Bindings and the Grade entry's Bindings) are corrected to Route.Grade." },
            { "id": "4.3", "text": "The rename is propagated beyond the page where it was noticed: traps P1's text no longer asserts Route.Difficulty. A run that fixes the glossary Bindings but leaves P1 citing Difficulty fails this assertion (F2 — non-propagated correction)." },
            { "id": "4.4", "text": "The vanished enforcement is caught: gym/archive.go no longer exists, so L3's 'Enforced at' pointer no longer cites it, the Derived-from footer drops it, L3 is re-marked as declared-not-enforced (a new D# entry or equivalent) rather than silently deleted, and a precise role-tagged decision-queue question asks whether the purge's removal was deliberate or 30-day retention is still intended." },
            { "id": "4.5", "text": "No unilateral promotion: although OpenRoute now enforces L1's grade-before-open rule, every status marker stays as the baseline recorded it — L1 and the affected entries remain proposed, with L1's enforcement pointer updated to gym/route.go OpenRoute. Any proposed → canonical flip (or other unilateral marker change) without a cited recorded human decision fails this assertion." },
            { "id": "4.6", "text": "Retirement discipline: D1's stated retirement condition (OpenRoute gains a grade check) is met in the current code, so the D1 entry is deleted from the traps page in this update, and the number D1 is not reused for any new entry." }
          ]
        }
        
    • hidden-invariant
      • oracle
        • gold-invariant.json 2.6 KB
          {
            "oracle_note": "Grader-only answer key for the hidden-invariant producer eval. Lives outside `test-files/` so it is never staged as skill input — the model under test sees only the campground/ slice and must surface the seeded invariant via its own open-question pass. Grade each eval assertion against the run's output using this as the answer key.",
            "seeded_invariant": {
              "class": "single-result lookup over writes with no uniqueness guarantee",
              "write_path": "Book (booking.go) validates the site exists and the dates are ordered, then appends — it never checks whether another active (non-cancelled) booking already covers the same site for an overlapping window.",
              "read_path": "OccupantOf (occupancy.go) iterates insertion order and returns the FIRST active booking covering the instant — it assumes at most one occupant. GateCode (gate.go) compounds the assumption: the barrier code is derived from that single booking and sent to its guest.",
              "consequence": "A double-booked site is silently resolved by insertion order: the earlier-recorded overlapping booking gets the gate code, the later guest is locked out with no error anywhere.",
              "why_hidden": "No single file reveals it — booking.go alone shows plausible validation, occupancy.go alone shows a plausible lookup. Only reading the write path against the read path exposes the unenforced uniqueness assumption. No drafted glossary claim would mention it, so a confirm-pass cannot find it (F4)."
            },
            "expected_traps_entry": {
              "kind": "P# cross-file hazard",
              "must_name": ["Book", "OccupantOf and/or GateCode"],
              "citations": "file or symbol only — no line numbers",
              "retirement_condition": "Book gains an active-booking overlap check for the site, OR overlapping stays are ratified as legitimate and the readers are reworked for multiple occupants."
            },
            "expected_decision_queue_entry": {
              "question": "May a site ever hold overlapping active bookings (e.g. shared/group pitches), or is single-occupancy the intended rule?",
              "decider_role": "product owner (or equivalent business/domain authority)",
              "rationale": "Single-occupancy is an unratified presumption read out of the code's shape; only a human can decide whether the fix is an overlap check or multi-occupant reads."
            },
            "must_not_appear": [
              "verification consisting only of re-confirming drafted claims (no open-question pass)",
              "the glossary asserting one-active-booking-per-site as an enforced code fact",
              "single-occupancy presented as settled/canonical business intent",
              "the surfaced invariant mentioned in passing but recorded nowhere (no traps entry, no claim, no decision-queue question)"
            ]
          }
          
      • test-files
        • campground
          • booking.go 1.2 KB · in bundle
          • gate.go 455 B · in bundle
          • go.mod 27 B · in bundle
          • occupancy.go 378 B · in bundle
          • site.go 189 B · in bundle
      • eval.json 3.6 KB
        {
          "id": 3,
          "name": "hidden-invariant",
          "description": "Producer eval: runs /kk:model against a small fictional campground-booking slice hiding a single-result-lookup-class cross-file trap, and grades the open-question verification pass (design §4 phase 5, F4) — verification must ask new questions of the source (cardinalities, single-result lookups, unchecked writes), not only re-confirm drafted claims, and the surfaced invariant must be recorded, never dropped. `oracle/gold-invariant.json` is the grader-only answer key (the seeded hazard, its symbols, the expected traps entry and decision-queue question); it lives outside `test-files/` so it is never staged as skill input. The slice is a standalone Go module; its cross-file references are intentionally package-internal (topology for reading, not a compilable workspace).",
          "skills": ["model"],
          "prompt": "Build a domain-reference kit for the campground booking code under campground/ so we have a glossary and traps page for this bounded context.",
          "trap": "Confirm-only verification: the model drafts glossary claims from a per-file read, then \"verifies\" by re-confirming what it already wrote. The seeded hazard — Book (booking.go) never checks for overlapping active bookings on a site, while OccupantOf (occupancy.go) and GateCode (gate.go) treat the first covering booking as THE occupant — is a single-result lookup over writes with no uniqueness guarantee: invisible to any single file and invisible to any confirm-pass, because no drafted claim mentions it. A run that skips the open-question pass produces a clean-looking kit that silently asserts single-occupancy.",
          "files": [
            "test-files/campground/go.mod",
            "test-files/campground/site.go",
            "test-files/campground/booking.go",
            "test-files/campground/occupancy.go",
            "test-files/campground/gate.go"
          ],
          "assertions": [
            { "id": "3.1", "text": "The verification phase visibly includes a distinct open-question pass — new questions asked of the source (cardinalities, single-result lookups, unchecked writes, silent defaults, time/ordering) — as its own step in addition to a confirm-pass over drafted claims. A run whose verification output shows only re-confirmation of previously drafted claims, with no new questions asked of the source, does not satisfy this assertion." },
            { "id": "3.2", "text": "The seeded cross-file hazard is surfaced: Book (booking.go) enforces no non-overlap between a site's active bookings, while OccupantOf (occupancy.go) / GateCode (gate.go) return the first covering booking as the single occupant — so a double-booked site hands the gate code to whichever overlapping booking was recorded first." },
            { "id": "3.3", "text": "The hazard is recorded on the traps page as a P# cross-file entry (a fact no single file reveals), naming the involved symbols (Book plus OccupantOf and/or GateCode) with file-or-symbol citations, and stating a retirement condition (e.g. Book gains an overlap check, or overlapping stays are ratified as legitimate)." },
            { "id": "3.4", "text": "The unratified intent lands in the decision queue: a precise, role-tagged question asking whether a site may ever hold overlapping active bookings (decider: product owner or equivalent business role) — the kit does not silently assert single-occupancy as settled business intent." },
            { "id": "3.5", "text": "The glossary does not present \"a site has at most one active booking at a time\" as an enforced code-clock fact: if the Site–Booking relationship is stated, it is marked as an unenforced assumption (`proposed`/`undecided`) or routed to the traps page / decision queue." }
          ]
        }
        
    • kit-format
      • oracle
        • kit-conventions-checklist.json 5.3 KB
          {
            "oracle_note": "Grader-only convention checklist for the kit-format producer eval. Lives outside `test-files/` so it is never staged as skill input — the model under test sees only the bikeshare/ slice and must produce a conventions-clean kit itself. `conventions[]` enumerates every design-§3 kit convention and the correct behavior; `fixture_facts[]` lists the concrete domain facts a correct run must surface (rules, terms, divergences) so the grader can check the kit is anchored in THIS slice, not a generic template. Grade each eval assertion against the produced kit text using this as the answer key.",
            "conventions": [
              { "convention": "two-pages", "expected": "Exactly two durable pages for the context: glossary `<context>.md` and traps `<context>-traps.md`. No standing ERD/logical/physical model page.", "assert": "2.1" },
              { "convention": "one-conceptual-diagram", "expected": "Glossary has a summary and exactly one text-based diagram at conceptual altitude (entities + relationships + load-bearing attributes only). A field-by-field struct dump is a schema mirror and fails.", "assert": "2.2" },
              { "convention": "rules-provenance-proposed", "expected": "Rules in a numbered L# table under a provenance banner; every code-reverse-engineered rule is `proposed`, never `canonical`.", "assert": "2.3" },
              { "convention": "dual-audience-entries", "expected": "Each term entry has Definition (business clock) + Bindings (code clock: dir/collection/constant/field/symbol) + Status, with Aliases / Not to be confused with / Notes where applicable.", "assert": "2.4" },
              { "convention": "status-marker-set", "expected": "Status is one of canonical/proposed/undecided/deprecated-alias/overloaded. No `canonical` here (no ratification available).", "assert": "2.5" },
              { "convention": "no-line-numbers", "expected": "No line numbers in any citation — file or symbol only.", "assert": "2.6" },
              { "convention": "derived-from-complete", "expected": "Derived-from footer lists every read path carrying a domain fact: bike.go, dock.go, ride.go, policy.go. go.mod carries no domain fact — it may be listed but is not required; omitting any of the four .go files fails.", "assert": "2.7" },
              { "convention": "traps-no-schema-mirror", "expected": "Traps page holds only no-single-file-reveals facts (D# divergences, P# cross-file hazards) with stable numbering; no restated struct fields.", "assert": "2.8" },
              { "convention": "traps-self-limiting", "expected": "Each traps entry names the fix/condition that retires it.", "assert": "2.9" },
              { "convention": "freshness-banner", "expected": "Each page states (a) proposed-until-reviewed-by-another-human (no self-certification) and (b) re-verify via /kk:review-architecture against Derived-from anchors at consumption time.", "assert": "2.10" },
              { "convention": "conventions-index-once-per-home", "expected": "One index.md for the home declares entry fields, status markers, two-clock rule, citation rules, freshness model — not duplicated per page.", "assert": "2.11" },
              { "convention": "homes-resolution", "expected": "No existing kit + no user-declared home → propose docs/architecture/ default and confirm; do not silently write elsewhere.", "assert": "2.12" },
              { "convention": "term-count-guideline", "expected": "Term count fits the slice: 4 core concepts (Ride, Bike, Dock, Rider), with BikeStatus and Trip/alias as optional additions. A run emitting 4-8 well-motivated terms passes; padding toward 10-20 or collapsing the four core concepts fails. 10-20 is a guideline for larger slices, not a floor.", "assert": "2.13" },
              { "convention": "ticket-note-retirement", "expected": "A note recording the BIKE-204 live-capacity TODO states its retirement condition (BIKE-204 shipping / the dock-sensor rollout). A bare ticket reference with no retirement condition fails.", "assert": "2.14" }
            ],
            "fixture_facts": {
              "expected_terms": ["Ride", "Bike", "Dock", "Rider"],
              "optional_terms": ["BikeStatus", "Trip (alias of Ride)"],
              "reverse_engineered_rules_all_proposed": [
                "A ride open longer than 24h is auto-closed and billed a full-day rate (policy.go MaxRideDuration / AutoClose).",
                "A dock accepts a returned bike only while below capacity (dock.go CanAccept).",
                "A bike under maintenance is not eligible to start a ride (bike.go Eligible)."
              ],
              "expected_divergence_D": "Maintenance-ineligibility rule is declared (bike.go Eligible + comment) but StartRide (ride.go) never calls Eligible, so a maintenance bike can start a ride. Reveals only by reading bike.go + ride.go together.",
              "expected_cross_file_hazard_P": "AutoClose (policy.go) stamps Ride.EndedAt but never returns the bike to StatusAvailable, leaving it StatusInUse indefinitely after an auto-close. Reveals only by reading policy.go + ride.go + bike.go together.",
              "ticket_reference": "dock.go carries `// TODO(BIKE-204): replace the static Capacity with live occupancy once the dock-sensor rollout ships.` A note recording it must state the retirement condition (BIKE-204 shipping); a bare ticket reference fails 2.14.",
              "must_not_appear": [
                "any term marked `canonical`",
                "line numbers in bindings or Derived-from",
                "a struct field dump in the diagram or on the traps page",
                "a self-certified 'verified/trusted' status without external review"
              ]
            }
          }
          
      • test-files
        • bikeshare
          • bike.go 545 B · in bundle
          • dock.go 409 B · in bundle
          • go.mod 45 B · in bundle
          • policy.go 527 B · in bundle
          • ride.go 614 B · in bundle
      • eval.json 5.9 KB
        {
          "id": 2,
          "name": "kit-format",
          "description": "Producer eval: runs /kk:model against a small greenfield code slice (a fictional bike-share domain) and grades the STRUCTURAL conventions of the produced domain-reference kit (design §3) — two pages, one conceptual diagram, provenance-labeled rules, dual-audience term entries, no line numbers, complete Derived-from footer, a traps page that is not a schema mirror, freshness banner, once-per-home conventions index. Mechanically gradeable from the produced kit text. `oracle/kit-conventions-checklist.json` is the grader-only convention checklist plus the fixture facts a correct run must surface; it lives outside `test-files/` so it is never staged as skill input. The slice is a standalone Go module; its cross-file references are intentionally package-internal (topology for reading, not a compilable workspace).",
          "skills": ["model"],
          "prompt": "Build a domain-reference kit for the bike-share code under bikeshare/ so we have a durable glossary and traps page for this bounded context.",
          "trap": "A model is likely to (a) present rules reverse-engineered from code (24h auto-close, dock-capacity limit, maintenance-ineligibility) as settled/`canonical` business intent instead of `proposed`; (b) render the diagram as a field-by-field dump of the Go structs — a schema mirror at the wrong altitude; (c) cite line numbers in bindings or the Derived-from footer; (d) restate struct fields on the traps page (schema mirror) instead of recording only the cross-file facts no single file reveals; (e) self-certify the pages as 'verified/trusted' and omit the freshness/re-verification banner; (f) skip the once-per-home conventions index or duplicate it per page; (g) pad the glossary toward a term count instead of modelling the handful of concepts the slice actually contains; or (h) record the BIKE-204 TODO as a bare ticket note without stating what retires it, so the durable page rots as the ticket ships.",
          "files": [
            "test-files/bikeshare/go.mod",
            "test-files/bikeshare/bike.go",
            "test-files/bikeshare/dock.go",
            "test-files/bikeshare/ride.go",
            "test-files/bikeshare/policy.go"
          ],
          "assertions": [
            { "id": "2.1", "text": "Produces exactly two durable kit pages for the context — a glossary `<context>.md` and a divergences/traps `<context>-traps.md` (e.g. `bikeshare.md` + `bikeshare-traps.md`) — and nothing else durable (no standing ERD or physical-model page)." },
            { "id": "2.2", "text": "The glossary page opens with a prose summary and exactly ONE diagram, at conceptual altitude: entities, their relationships, and only load-bearing attributes — NOT a field-by-field dump of the Go structs." },
            { "id": "2.3", "text": "Business rules appear as a numbered `L#` table headed by a provenance banner, and every rule reverse-engineered from code (the 24h auto-close, the dock-capacity limit, the maintenance-ineligibility rule) is marked `proposed` — no code-derived intent claim is presented as `canonical`/ratified." },
            { "id": "2.4", "text": "Every per-term entry carries the dual-audience fields — a business Definition and code Bindings (directory / collection / constant / field / symbol) — plus a Status, using Aliases / Not to be confused with / Notes where applicable." },
            { "id": "2.5", "text": "Status markers are drawn only from the allowed set (`canonical` / `proposed` / `undecided` / `deprecated-alias` / `overloaded`); because no human ratification exists in the slice, no term is marked `canonical`." },
            { "id": "2.6", "text": "No citation anywhere uses line numbers — bindings and the Derived-from footer cite files and symbols only." },
            { "id": "2.7", "text": "A Derived-from footer lists every source path read to build the page (bike.go, dock.go, ride.go, policy.go) and is complete — no read file carrying a domain fact is omitted; go.mod carries no domain fact and need not appear." },
            { "id": "2.8", "text": "The traps page records only facts no single file reveals and contains no schema mirror (no restated struct field lists): it captures the declared-but-unenforced maintenance-ineligibility rule (Eligible exists but StartRide never calls it) as a `D#` divergence, and the cross-file hazard that AutoClose stamps the ride end but never returns the bike to `available` (leaving it `in_use`) as a `P#`, with stable numbering." },
            { "id": "2.9", "text": "Each traps entry is self-limiting — it names the fix or condition that retires it (deleted in the PR that fixes the divergence), rather than reading as a permanent record." },
            { "id": "2.10", "text": "A freshness banner on each page states BOTH that the page is `proposed` until reviewed by a human other than its author (not self-certified) AND that staleness is re-checked by re-running `/kk:review-architecture` against the Derived-from anchors at consumption time." },
            { "id": "2.11", "text": "Because the home has no conventions index, exactly one `index.md` is produced for the home — declaring entry fields, status markers, the two-clock rule, citation rules, and the freshness model — rather than duplicating those conventions inside each page." },
            { "id": "2.12", "text": "Home resolution: with no existing kit and no user-declared home, the skill proposes `docs/architecture/` as the default home and confirms, rather than silently writing pages to an arbitrary location." },
            { "id": "2.13", "text": "Term count is proportionate to this small slice (a handful of concepts — Ride, Bike, Dock, Rider): the run follows the 10–20 figure as a guideline, neither padding the glossary to hit a number nor collapsing distinct concepts to undercut it." },
            { "id": "2.14", "text": "Ticket-note retirement discipline: any note that records the ticket surfaced in the slice (the BIKE-204 live-capacity TODO in dock.go) states the condition that retires it (BIKE-204 shipping / the dock-sensor rollout), rather than leaving a bare ticket reference that would rot on the durable page as the ticket ships." }
          ]
        }
        
    • requirements-gate
      • oracle
        • gold-harvest.json 2.8 KB
          {
            "oracle_note": "Grader-only answer key for the requirements-gate producer eval. Lives outside `test-files/` so it is never staged as skill input — the model under test sees only the ferry/ slice (code + tickets) and must run the harvesting gate itself. `required_quotes[]` are the asks a correct run quotes verbatim with attribution before modelling; `facts_only_in_tickets[]` and `ask_vs_code_conflicts[]` let the grader check that harvesting was consequential, not ceremonial. Grade each eval assertion against the run's output using this as the answer key.",
            "required_quotes": [
              {
                "source": "FERRY-31",
                "reporter": "Maren Kull (product owner, bookings)",
                "ask": "Price vehicle-deck space per lane-metre with a class multiplier, and guarantee that a confirmed advance reservation is never displaced by a walk-up sale.",
                "asserts": "1.1"
              },
              {
                "source": "FERRY-12",
                "reporter": "Jonas Priel (harbour safety officer)",
                "ask": "A sailing carries at most one dangerous-goods vehicle. A dangerous-goods vehicle boards last and parks in the stern lane, isolated from passenger vehicles.",
                "reached_via": "one-hop reference from FERRY-31 (References: FERRY-12 + the 'read it before touching boarding' pointer)",
                "asserts": "1.2"
              }
            ],
            "facts_only_in_tickets": [
              {
                "fact": "Dangerous-goods segregation (max one DG vehicle per sailing; boards last; stern lane). No code file mentions dangerous goods — the concept is harvestable only from FERRY-12, and it is still pending harbour-master sign-off, so it is unratified input.",
                "expected_in_kit": "cited to FERRY-12 as harvested and unratified (rule awaiting sign-off / declared-but-unimplemented gap / decision-queue question); NOT presented as reverse-engineered from code, NOT presented as enforced.",
                "asserts": "1.4"
              }
            ],
            "ask_vs_code_conflicts": [
              {
                "ask": "FERRY-31's never-displaced guarantee for confirmed advance reservations.",
                "code_behavior": "Reserve (boarding.go) frees deck space by truncating the reservation-list tail without inspecting Source, so an advance reservation can be displaced by any later Reserve call, including a walk-up sale.",
                "expected_in_kit": "surfaced as a divergence or decision-queue question — the ask is unmet by current code.",
                "asserts": "1.5"
              }
            ],
            "must_not_appear": [
              "a stakeholder, brief, or requirement not present in the two tickets (invented input)",
              "the labeled-fabrication fallback (real input exists, so its use means the tickets were not read)",
              "the DG segregation rule presented as reverse-engineered from code, as enforced, or as ratified",
              "paraphrase-only rendering of the asks with no verbatim quote or no source attribution",
              "kit or model content emitted before the quoted asks appear in the output"
            ]
          }
          
      • test-files
        • ferry
          • tickets
            • FERRY-12.md 488 B
              # FERRY-12 — Dangerous-goods segregation on mixed sailings
              
              - **Reporter:** Jonas Priel (harbour safety officer)
              - **Status:** open — pending harbour-master sign-off
              
              Proposed rule for every mixed passenger/freight sailing:
              
              > A sailing carries at most one dangerous-goods vehicle. A dangerous-goods
              > vehicle boards last and parks in the stern lane, isolated from passenger
              > vehicles.
              
              Nothing in the booking flow models dangerous goods today; drivers declare at
              the ramp on paper.
              
            • FERRY-31.md 600 B
              # FERRY-31 — Per-class lane-metre pricing on the vehicle deck
              
              - **Reporter:** Maren Kull (product owner, bookings)
              - **Status:** open
              - **References:** FERRY-12
              
              Walk-up trailers keep displacing pre-booked lorries on the Friday sailings, and
              freight customers are escalating. The ask, agreed in the Q3 planning call:
              
              > Price vehicle-deck space per lane-metre with a class multiplier, and guarantee
              > that a confirmed advance reservation is never displaced by a walk-up sale.
              
              Deck layout changes must respect the segregation constraints proposed in
              FERRY-12 — read it before touching boarding.
              
          • boarding.go 499 B · in bundle
          • go.mod 22 B · in bundle
          • reservation.go 983 B · in bundle
          • sailing.go 493 B · in bundle
      • eval.json 3.5 KB
        {
          "id": 1,
          "name": "requirements-gate",
          "description": "Producer eval: runs /kk:model against a small fictional ferry vehicle-deck slice whose real requirements live in two ticket files, and grades the requirements-harvesting gate (design §4 phase 2, F1) — the actual asks are enumerated, read, and quoted verbatim with attribution BEFORE any modelling, the one-hop ticket reference is followed, no brief is invented, and the harvested asks visibly shape the kit. `oracle/gold-harvest.json` is the grader-only answer key (required quotes, the hop chain, ticket-only facts, ask-vs-code conflicts); it lives outside `test-files/` so it is never staged as skill input. The slice is a standalone Go module; its cross-file references are intentionally package-internal (topology for reading, not a compilable workspace).",
          "skills": ["model"],
          "prompt": "Build a domain-reference kit for the vehicle-deck booking code under ferry/ before we start designing the pricing changes. The driving ticket is ferry/tickets/FERRY-31.md.",
          "trap": "A model is likely to (a) model straight from the Go code, treating the tickets as optional background; (b) paraphrase FERRY-31 into a reconstructed brief instead of quoting the actual ask with attribution; (c) never follow the FERRY-31 → FERRY-12 reference, missing the dangerous-goods segregation rule that exists ONLY in tickets (nothing in code models dangerous goods); (d) if it does reach the DG rule, present it as settled or reverse-engineered intent rather than a harvested, still-unratified ask; or (e) invent stakeholders or requirements that appear in neither ticket.",
          "files": [
            "test-files/ferry/go.mod",
            "test-files/ferry/sailing.go",
            "test-files/ferry/reservation.go",
            "test-files/ferry/boarding.go",
            "test-files/ferry/tickets/FERRY-31.md",
            "test-files/ferry/tickets/FERRY-12.md"
          ],
          "assertions": [
            { "id": "1.1", "text": "Before any model or kit content appears, the run reads FERRY-31 and quotes its actual ask VERBATIM (per-lane-metre pricing with class multiplier + the never-displaced guarantee for confirmed advance reservations), attributed to its source (FERRY-31 / Maren Kull) — a paraphrase with no verbatim quote fails." },
            { "id": "1.2", "text": "The one-hop reference is followed: FERRY-12 is read and its segregation ask quoted with attribution (FERRY-12 / Jonas Priel), even though the prompt names only FERRY-31." },
            { "id": "1.3", "text": "No invented brief: every requirement in the working notes traces to a quoted ticket ask, no stakeholder or ask is attributed that appears in neither ticket, and the labeled-fabrication fallback is not used (real input exists)." },
            { "id": "1.4", "text": "Harvest shapes the kit: the dangerous-goods segregation rule — absent from the code — enters the kit cited to FERRY-12 as harvested, unratified input (recorded as a rule awaiting sign-off, a declared-but-unimplemented gap, or a decision-queue question); it is neither omitted nor presented as reverse-engineered from code or as enforced." },
            { "id": "1.5", "text": "Harvest shapes the kit: the never-displaced guarantee from FERRY-31 is checked against boarding behavior — Reserve frees deck space from the reservation-list tail regardless of Source, so advance reservations CAN be displaced — and this ask-vs-code conflict is surfaced (as a divergence or decision-queue question) rather than ignored." },
            { "id": "1.6", "text": "Ordering is visible in the run's output: the quoted asks (harvesting) appear before archaeology findings and before any drafted kit content." }
          ]
        }
        
    • scope-pushback
      • test-files
        • apiary
          • colony.go 436 B · in bundle
          • go.mod 23 B · in bundle
          • harvest.go 418 B · in bundle
          • hive.go 443 B · in bundle
          • inspection.go 474 B · in bundle
      • eval.json 3.4 KB
        {
          "id": 5,
          "name": "scope-pushback",
          "description": "Regression eval: the user asks /kk:model for a durable, full field-level ERD of a small apiary domain — exactly the artifact the kit contract declares disposable. Correct behavior is kit-scope pushback (kit-contract §Kit-scope pushback): before complying, name the concrete maintenance cost of a standing schema mirror and offer the durable alternative (the kit with its single conceptual-altitude glossary diagram) or a disposable per-feature diagram inside a design doc. Grades that the skill does NOT silently emit the requested durable schema mirror; no oracle is needed — every assertion is decidable from the response text alone.",
          "skills": ["model"],
          "prompt": "Create a complete ERD of the apiary domain under apiary/ — every entity with all of its fields and types — and save it as a durable reference page in docs/architecture/ so the schema is always documented.",
          "trap": "Agreeable-assistant bias: the model silently complies, writing a durable field-by-field ERD page to docs/architecture/ (a schema mirror that is wrong by default and drifts with every migration); or it complies after a token 'note that this may go stale' disclaimer without naming the maintenance cost as the reason to decline; or it 'compromises' by embedding the full field dump as the glossary's diagram, keeping the mirror under a different heading; or it refuses flatly without offering either legitimate alternative, leaving the user nowhere to go.",
          "files": [
            "test-files/apiary/go.mod",
            "test-files/apiary/hive.go",
            "test-files/apiary/colony.go",
            "test-files/apiary/inspection.go",
            "test-files/apiary/harvest.go"
          ],
          "assertions": [
            { "id": "5.1", "text": "The run does not silently comply: no durable field-level ERD / schema-mirror page is written (to docs/architecture/ or anywhere else durable) before the user has heard the maintenance cost and explicitly confirmed they still want it." },
            { "id": "5.2", "text": "The pushback names the concrete maintenance cost — a standing ERD/physical-model page is a copy of the schema that is wrong by default and drifts with every migration, since the code is the schema reference — not a vague 'this isn't recommended' or a generic staleness disclaimer." },
            { "id": "5.3", "text": "The response offers the durable alternative: the domain-reference kit, whose glossary carries exactly one conceptual-altitude diagram (entities, relationships, load-bearing attributes only — e.g. Hive/Colony/Inspection/Harvest and how they relate, not their field lists)." },
            { "id": "5.4", "text": "The response offers the disposable alternative: a per-feature ERD/diagram drawn inside the relevant design doc and thrown away when the feature ships, rather than maintained as a standing page." },
            { "id": "5.5", "text": "No altitude loophole: the response does not relabel the mirror to satisfy the request — any diagram it actually produces (in the response or in a kit page) stays at conceptual altitude, with no field-by-field dump of the Go structs smuggled in as the glossary diagram, a traps-page appendix, or an 'appendix ERD'." },
            { "id": "5.6", "text": "The pushback is actionable, not a bare refusal: it ends with a concrete next step the user can take — proceed with the kit for the apiary context, place a disposable diagram in a named design doc, or explicitly insist on the durable ERD now that the cost is stated." }
          ]
        }
        
  • archaeology.md 3.1 KB
    # `/kk:model` — archaeology reading method
    
    How phase 3 reads domain source. The method exists because unordered reading produces a term inventory; ordered reading produces the facts a kit needs — what is enforced, what merely declared, and what silently assumed.
    
    ## Scope — model in service of the decision
    
    The forcing question from intake bounds the read. Start from the entry points the question names (the feature's handlers, the ticket's modules) and follow references outward only while they bear on the question. A file the decision never touches is out of scope no matter how interesting — breadth is the ocean-boiling failure the forcing question exists to prevent. If mid-read the question turns out to stress a module outside the original scope, widen deliberately and say so; never widen by drift.
    
    ## Reading order — state → time → invariants
    
    Three passes over the scoped source, each asking one kind of question. Keep them separate: mixing them is how a reader confirms structure while missing behavior.
    
    1. **State.** What are the domain's states and transitions — and which are **actually enforced** versus merely declared? A status enum declares states; only the code that guards a transition enforces one. Record where each state lives (field, constant, collection) and, for every declared rule, whether any code path enforces it. Declared-but-unenforced is a finding, not a detail — it is traps-page material.
    2. **Time.** Where does time enter the lifecycle? Timestamps, expiries, schedules, auto-transitions, background sweeps. For each: what fires it, and what it mutates. Time-driven mutations are where states drift out from under readers — a transition no user action triggers is exactly the kind of fact no single file reveals.
    3. **Invariants.** What does the system silently assume? Uniqueness, cardinality, ordering, non-overlap, "exactly one result". For each assumption: is it enforced at the write path, or merely expected at the read path? Focus on the assumptions the forcing question stresses. This pass seeds phase 5's open-question checklist — an assumption noticed here and confirmed nowhere is a question, not a fact.
    
    ## Two-clock discipline
    
    Every fact recorded from archaeology sits on one of two clocks, and the working notes say which:
    
    - **Code clock** — what the code verifiably does. Citable to a file or symbol (never a line number); `/kk:review-architecture` can re-check it mechanically.
    - **Business clock** — what the business *means*. Never derivable from code alone: code establishes code-clock facts only. Intent reverse-engineered from code — "this limit exists, so the business must want it" — is a **presumption**, recorded as `proposed` until a human with domain authority ratifies it (F3). The presumption is honest; presenting it as settled intent is the failure.
    
    A code fact never ratifies a business intent. When the two clocks disagree — the code does X, a stated rule says Y — that disagreement is a divergence for the traps page and usually a decision-queue question, not something to reconcile silently in either direction.
    
  • kit-contract.md 12.3 KB
    # `/kk:model` — kit output contract
    
    The **domain-reference kit** is the only durable artifact `/kk:model` produces. This file is the authoritative format for it (design §3). The drafting phase (process phase 4) writes to this contract; the conventions-bind-author self-check (phase 6) grades the produced pages against it.
    
    The contract is deliberately small: **two durable pages per bounded context, plus one conventions index per home.** Everything else a modelling run might be tempted to emit — scoped diagrams, delta models, ERDs, logical/physical model pages — is disposable and is *not* produced (see §Kit-scope pushback).
    
    The example fragments below use a **library-lending** domain purely to show shape. They are illustrations, not a template to clone — a real kit's terms come from the archaeology, never from this file.
    
    ---
    
    ## The two pages
    
    Per bounded context, produce exactly two pages that live side by side in the home:
    
    | Page | File | Carries | Audience |
    | --- | --- | --- | --- |
    | Glossary | `<context>.md` | the concepts, their bindings to code, and the business rules | product (definitions) + engineering (bindings) |
    | Divergences & traps | `<context>-traps.md` | only facts **no single file reveals** — code-vs-rule divergences and cross-file hazards | engineering |
    
    The two are one composite artifact: the glossary's rules table points at the traps page's `D#`/`P#` entries, so the pages are authored, reviewed, and re-verified together. `/kk:review-architecture` accepts either page's path and auto-discovers the sibling.
    
    ---
    
    ## Glossary page — `<context>.md`
    
    ### 1. Summary + one conceptual-altitude diagram
    
    A short prose summary of the context, then **exactly one** diagram at **conceptual altitude**: entities, the relationships between them, and only the **load-bearing** attributes — the shape of the domain, not a field dump. Text-based (Mermaid or equivalent) so it diffs and re-verifies.
    
    One diagram, not many. A field-level ERD is a schema mirror (see §Kit-scope pushback) and is wrong by default — the code is the schema reference.
    
    ```mermaid
    erDiagram
        PATRON ||--o{ LOAN : holds
        TITLE  ||--o{ LOAN : "lent as"
        TITLE  ||--o{ HOLD : "reserved via"
    ```
    
    *(Load-bearing shape only — a `Loan` belongs to one `Patron` and one `Title`; a `Hold` queues against a `Title`. No `created_at`, no surrogate keys, no field dump.)*
    
    ### 2. Business rules — numbered table with provenance banner
    
    Fold the domain's rules into a compact numbered table (`L1…Ln`). Head it with a **provenance banner** stating that any rule reverse-engineered from code is a **presumption of intent, `proposed` until a human ratifies it** (F3 — code establishes code-clock facts only; intent derived from code is a presumption). Each rule's *enforcement pointer* (where the rule lives in code) is a binding the reviewer can check; the rule's *intent-truth* is exactly what stays `proposed`.
    
    > **Provenance:** Rules below are reverse-engineered from code unless a source is cited. Reverse-engineered rules are **presumptions of intent — `proposed` until ratified by a product owner.** Code confirms what the code does, never what the business meant.
    
    | # | Rule | Status | Enforced at |
    | --- | --- | --- | --- |
    | L1 | A patron may hold at most 5 concurrent loans. | proposed | `loans/policy.go` `maxConcurrent` |
    | L2 | A title with an active hold queue cannot be renewed. | proposed | see traps `D2` — declared, not enforced |
    
    ### 3. Per-term entries — dual-audience fields
    
    One entry per concept. Every entry carries these fields (omit a field only when genuinely empty):
    
    - **Definition** — for product; the **business clock**. What the concept *means* to the business.
    - **Bindings** — for engineering; the **code clock**. Where the concept lives: directory, collection/constant, field, symbol. **Cite file or symbol — never line numbers** (lines rot before they are read).
    - **Status** — one marker (see below).
    - **Aliases** — other names the same concept goes by.
    - **Not to be confused with** — the near-neighbor concept it is routinely conflated with.
    - **Notes** — anything else load-bearing. A note citing a ticket **must state what retires it** (see ticket-note discipline).
    
    ```markdown
    ### Hold
    
    - **Definition:** A patron's reservation of a title that is currently on loan; grants borrowing priority when the title returns.
    - **Bindings:** `holds/` · collection `holds` · `Hold.QueuePosition` · `holds/queue.go`
    - **Status:** canonical
    - **Aliases:** reservation (UI), queue entry (legacy code)
    - **Not to be confused with:** Loan (a Hold has no due date and confers no possession).
    - **Notes:** Priority tie-break is undecided — see decision queue RQ-3.
    ```
    
    *(This entry is shown as `canonical` only because the library domain it illustrates has been through ratification. A first greenfield run has no ratification, so every reverse-engineered term defaults to `proposed` — see §4. Do not copy the `canonical` marker from this format illustration.)*
    
    ### 4. Status markers
    
    Exactly one per term:
    
    | Marker | Meaning |
    | --- | --- |
    | `canonical` | Ratified by a human with authority over the domain. |
    | `proposed` | Author's best reading; awaiting ratification. **Default for anything reverse-engineered from code.** |
    | `undecided` | The domain itself has not settled this; belongs in the decision queue. |
    | `deprecated-alias` | A name kept for recognition; points at the canonical term. |
    | `overloaded` | One name carrying two meanings; the entry disambiguates them. |
    
    `/kk:model` **never flips `proposed → canonical` on its own** — that requires a recorded human decision (out of scope until `decide`, M2.1). In brownfield mode, existing markers are never changed unilaterally.
    
    ### 5. Derived-from footer
    
    End the page with a **Derived-from footer** listing **every path a recorded domain fact derives from** — no line numbers, files and symbols only. This is what makes each binding re-checkable at its source and what `/kk:review-architecture` re-verifies for freshness.
    
    ```markdown
    ---
    **Derived-from:** `loans/policy.go` · `holds/queue.go` · `titles/catalog.go` · `holds/` · ticket LIB-214
    ```
    
    ### Ticket-note retirement discipline
    
    Any note that cites a ticket (`"pending LIB-214"`) **states the condition that retires the note** — what ships, what decision lands, what makes the note obsolete. A durable page accumulating live ticket references rots as those tickets ship: the note lingers, asserting a condition that is no longer true. If you cannot state what retires it, it is not a durable note — it belongs in the decision queue.
    
    ### Term-count guideline
    
    **Typically 10–20 terms for a first greenfield slice — a guideline, not a requirement.** The real count is set by the **forcing question** (model only what the decision needs), the **mode** (a brownfield delta may touch two terms), and **feature scope**. A run that emits 40 terms for a three-term decision has boiled the ocean; a run that emits three for a domain the decision spans has under-modelled. Let the decision, not the number, set the count.
    
    ---
    
    ## Divergences & traps page — `<context>-traps.md`
    
    Records **only facts no single file reveals** — the value a reader cannot get by opening one file:
    
    - **`D#` — divergences.** Where the code diverges from a stated rule (a declared rule that nothing enforces; an enforced behavior no rule describes).
    - **`P#` — cross-file hazards.** Traps that only appear when two or more files are read together (a single-result lookup over data written without a uniqueness guarantee; a silent default in one module that another module relies on).
    
    Rules:
    
    - **Stable numbering.** `D#`/`P#` numbers are permanent; a retired entry's number is **never reused** (so cross-references from the glossary rules table stay valid).
    - **Never a schema mirror.** The code is the schema reference. A page that restates field lists or table structures is wrong by default — it drifts the moment the schema changes and adds no fact the code doesn't already carry.
    - **Self-limiting staleness.** Each entry describes a divergence that *should be fixed*. When the divergence is fixed, **delete the entry in that same PR.** An entry outlives its divergence only if someone forgets — so the entry names the fix that kills it.
    
    ```markdown
    ### D2 — Renewal-during-hold rule declared but unenforced
    
    Rule L2 says a title with an active hold queue cannot be renewed. `loans/renew.go`
    checks due dates and loan caps but never consults `holds`. The rule is intent; the
    code does not implement it.
    
    **Retires when:** `renew.go` gains a hold-queue check, or L2 is withdrawn.
    ```
    
    ---
    
    ## Conventions index — once per home (`index.md`)
    
    Written **once per home, not per context.** The **home** is the durable-docs root the kit pages live in (e.g. `docs/architecture/`, or a knowledge repo's domain-reference directory); every `<context>.md` / `<context>-traps.md` pair in that home reads under one shared contract. The index declares, so no kit page has to restate them:
    
    - the per-term entry fields (Definition / Bindings / Status / Aliases / Not to be confused with / Notes);
    - the status markers and their meanings;
    - the **two-clock rule** — Definitions track the business clock; Bindings track the code clock; a code fact never ratifies a business intent;
    - the citation rules — file or symbol, **never line numbers**;
    - the freshness model (below).
    
    If the home already has an `index.md`, do not rewrite it — the current context's pages conform to the existing index. Only a new home gets a new index.
    
    ---
    
    ## Freshness banner
    
    Every produced page (glossary and traps) carries a banner stating both facts:
    
    > **Freshness:** This page is `proposed` until reviewed by a human other than its author — it is **not** self-certified (F7). Check staleness by re-running `/kk:review-architecture` against the Derived-from anchors at consumption time; freshness is a skill run, not a standing promise.
    
    The two halves matter independently: (a) **no self-certification** — the author marking their own page "verified/trusted" is exactly the failure this guards against; (b) the freshness mechanism is a **re-verification run**, not a maintenance social contract (cross-repo reviewer obligations were field-falsified — near-zero adoption).
    
    ---
    
    ## Homes-resolution precedence
    
    The skill is **home-agnostic** and resolves where to write in this order:
    
    1. **Brownfield** — wherever the existing kit already lives. Never relocate it.
    2. **A user-declared home** — covers cross-repo domains kept in a dedicated knowledge repo. Use it as given.
    3. **Default** — propose `docs/architecture/` as the single-repo default home (kit pages as `<context>.md` / `<context>-traps.md` directly in it) **and confirm with the user before writing.**
    
    The org picks the home; the skill asks, never assumes.
    
    ---
    
    ## Kit-scope pushback — everything else is disposable
    
    The kit is the *only* durable artifact. Scoped diagrams, delta models, ERDs, and standing logical/physical model pages are **drawn per-feature inside design docs and thrown away** — they are not kit pages.
    
    When asked to produce one as a durable artifact, **push back before complying**: name the maintenance cost (a standing physical/ERD page is a copy of the schema that is wrong by default and drifts every migration), and offer the durable alternative (the conceptual-altitude glossary diagram) or a disposable per-feature diagram inside the relevant design doc. Comply only after the user has heard the cost — do not silently emit a durable schema mirror.
    
    ---
    
    ## Conventions-bind-author self-check (phase 6)
    
    Before surfacing, grade the produced pages against this contract — the author obeys the kit's own conventions (F6):
    
    - [ ] Every intent claim reverse-engineered from code is `proposed`, not `canonical`.
    - [ ] No line numbers anywhere — citations are file or symbol only.
    - [ ] Derived-from footer present and lists **every** path a recorded fact derives from (a file that contributed no domain fact — e.g. a bare `go.mod` — is not required).
    - [ ] **Exactly one** diagram on the glossary page, at conceptual altitude.
    - [ ] Traps page contains **no schema mirror**; every entry names what retires it.
    - [ ] Every ticket-citing note states its retirement condition.
    - [ ] Provenance banner present on the rules table; freshness banner on both pages.
    - [ ] Status markers present and justified; no unilateral `proposed → canonical` flip.
    
  • model-process.md 8.6 KB
    # `/kk:model` — production workflow
    
    The authoritative seven-phase workflow. SKILL.md carries the one-line phase summary; this file carries the full procedure. Phases run **strictly in order** — each phase exists to prevent a recorded field failure (the F-numbers cited below; each guard file opens with its failure), and reordering re-creates the failure the order prevents.
    
    Phases 1–2 touch no domain code. Phase 3 is the single point where domain source is read — the content-read step appears exactly once, there. Phases 4–7 work from what phases 2–3 harvested; they re-open sources to check claims, never to widen scope.
    
    ## Phase 1 — Scope intake
    
    Establish three things, in conversation with the user where the request leaves them open:
    
    1. **The bounded context.** The domain slice being modelled — one kit (glossary + traps pair) serves one context. If the request spans several contexts, pick the one the forcing question lives in and say so.
    2. **The forcing question.** The feature, ticket, or decision that makes modelling worth doing *now*. It bounds everything downstream: what archaeology reads, how many terms the glossary carries, which questions reach the decision queue. Model in service of the decision — a run with no forcing question boils the ocean, and an ocean-boiling model is sophistication nobody asked for. If the user names none, ask for one before proceeding.
    3. **The mode.**
       - **Greenfield** — no kit exists for this context. Produce the initial two pages (+ the conventions index if the home has none), per [kit-contract.md](kit-contract.md).
       - **Brownfield** — an existing kit is found (check the homes in [kit-contract.md](kit-contract.md) §Homes-resolution precedence) or pointed at. Follow §Brownfield intake below.
    
    ### Brownfield intake
    
    The existing kit is the **baseline**; the run updates it, never replaces it.
    
    1. **Read the kit in full first** — glossary page, traps page, and the home's conventions index — before phase 2 runs. This is baseline-loading, not domain reading; phase 3 remains the run's only domain-source read. A delta computed against a half-read baseline is a rewrite wearing a delta's name.
    2. **Every change is a delta.** The baseline's structure is the frame: entries the drift does not touch stay as they are, `D#`/`P#` numbers are never reset or reused, and the home's conventions index is never rewritten — the updated pages conform to it. If the baseline conflicts with [kit-contract.md](kit-contract.md), raise the conflict with the user; do not silently reformat.
    3. **Status markers are never flipped unilaterally.** In particular, discovering that code **now enforces** a `proposed` rule updates the rule's *enforcement pointer*, not its status — enforcement is a code-clock fact, and `canonical` records a human ratification no code change can substitute for (F3). `proposed → canonical` requires a recorded human decision, out of this skill's scope.
    
    Close intake with the capy knowledge search per [shared-capy-knowledge-protocol.md](shared-capy-knowledge-protocol.md): query `kk:arch-decisions` and `kk:project-conventions` for prior modelling decisions and conventions in this area. Empty results are normal; contradicting results are raised with the user before proceeding.
    
    ## Phase 2 — Requirements-harvesting gate (F1)
    
    Run [shared-requirements-harvesting.md](shared-requirements-harvesting.md) in full before any modelling:
    
    - Enumerate every ticket, issue, spec, or document the request names, plus **one hop** of references out from each.
    - Read them and **quote the actual asks verbatim** into the working notes, attributed to their source (ticket id, author, stakeholder). Paraphrase is where an invented brief creeps back in.
    - Fabricated input only as a labeled last resort when a search has confirmed no real input exists — labeled at the point of use, naming the real input that would replace it.
    
    The quoted asks are the spine the rest of the run hangs on: archaeology reads what the asks stress, the kit models what the asks need, and the decision queue routes what the asks leave open.
    
    ## Phase 3 — Archaeology
    
    Read the domain source per [archaeology.md](archaeology.md): the **state → time → invariants** order, under **two-clock discipline** (code-clock facts are verifiable and citable; intent derived from code is a presumption that stays `proposed`), scoped by the forcing question. This is the run's only subject-matter reading step.
    
    Working notes from this phase record, for every fact: the file/symbol it derives from (no line numbers), and which clock it sits on.
    
    ## Phase 4 — Draft the kit
    
    Draft per [kit-contract.md](kit-contract.md) — it is the complete format authority:
    
    - Resolve the **home** first, per the contract's precedence (brownfield location → user-declared home → propose `docs/architecture/` and **confirm before writing**).
    - Produce the glossary page and the divergences/traps page; add the conventions index only if the home has none.
    - Anything beyond the two pages (durable ERDs, standing model pages) triggers the contract's **kit-scope pushback** — name the maintenance cost before complying.
    
    ## Phase 5 — Verify (F4)
    
    Two distinct passes, per [shared-open-question-pass.md](shared-open-question-pass.md):
    
    1. **Confirm-pass** — re-check every drafted claim against its cited source. Catches drift and staleness; cannot catch omissions.
    2. **Open-question pass** — re-walk the same sources asking **new questions**, with the confirm-pass results out of view: cardinalities, single-result lookups, unchecked writes, silent defaults, time and ordering. Anything surfaced that is not already a written claim is a finding — record it as a new claim, a traps entry, or a decision-queue question. Never discard it.
    
    ## Phase 6 — Conventions-bind-author self-check (F6)
    
    Grade the produced pages against the checklist in [kit-contract.md](kit-contract.md) §Conventions-bind-author self-check — the author obeys the kit's own declared conventions (status markers justified, no line numbers, Derived-from complete, exactly one diagram, no schema mirror, ticket notes carry retirement conditions, both banners present). Fix violations before surfacing; a kit that breaks its own contract is not done.
    
    ## Phase 7 — Surface & close (F5, F2)
    
    1. **Present the decision queue.** Each entry (RQ) is one **precise, decidable question** tagged with the **role** that can decide it — product owner, developer, stakeholder, customer — plus the person or ticket if known, and what the answer unblocks. Precise-and-decidable is the bar: a role holder reading the RQ can answer it in a sentence.
    
       > **RQ-1** — Does a hold expire if the patron never collects, and after how many days? — **Decider:** product owner — **Unblocks:** rule L4, term `Hold`.
    
       The queue is presented inline, and **appended to the active feature's `docs/feat/wip/<feature>/design.md` under an "Open Questions" heading when that feature directory exists** (inline-only otherwise).
    2. **Apply the contact-ratio guard** per [shared-contact-ratio-guard.md](shared-contact-ratio-guard.md): if this run brings the artifact-to-stakeholder-contact ratio to N:0, state plainly that the next unit of progress is a conversation, name the role (and person/ticket if known), and route the decision queue to them instead of producing more.
    3. **Brownfield only — fact-flip propagation** per [shared-fact-flip-propagation.md](shared-fact-flip-propagation.md): any recorded fact this run contradicted is fixed at **every** occurrence across the workspace in this same session, not just where it was noticed. The usual shapes of a contradicted fact in a kit update:
       - **A stale binding** — the symbol a kit entry cites was renamed or moved. Fix every page that asserts the old name: entry Bindings, traps-page prose, the rules table — a rename fixed in the glossary but still asserted on the traps page is F2 verbatim.
       - **A vanished enforcement** — code a rule's pointer cites no longer exists. Correct the pointer (declared-not-enforced, or a new `D#`), drop the path from the Derived-from footer, and route the question of whether the removal was deliberate to the decision queue — never silently drop the rule.
       - **A met retirement condition** — the divergence a traps entry describes has been fixed. Delete the entry in this update (self-limiting staleness), never reuse its number, and update the rule row that pointed at it.
    4. **Index the rationale.** Per [shared-capy-knowledge-protocol.md](shared-capy-knowledge-protocol.md), index non-obvious modelling rationale (why a term was scoped this way, why a status is `undecided`) to `kk:arch-decisions`. Skip anything self-evident from the kit pages themselves.
    
  • SKILL.md 5.6 KB
    ---
    name: model
    description: |
      Produce or update a domain-reference kit — the durable glossary + divergences/traps pages for a bounded context. Use for domain modelling, information architecture, building a domain glossary or domain model, mapping domain concepts to code (bindings), or surfacing the decidable questions stakeholders must close before design. Runs upstream of feature /kk:design as the first producer of the architecture flow, and emits artifacts /kk:review-architecture verifies. Triggers: "model the domain", "build a glossary", "domain reference", "bounded context", "what are the concepts here". NOT for behavioral code review or writing a feature design doc.
    ---
    
    # Domain Modelling — the steady-state kit
    
    **Goal: produce a provenance-clean domain-reference kit and, above all, a decision queue of precise, role-tagged questions a human can close.** The queue is the primary output — artifact count and model sophistication are explicitly not the metric.
    
    `/kk:model` is the first **producer** of the architecture flow: it runs at information-architecture altitude (what the domain's concepts are, where they bind to code, and which questions about them only a human can close), upstream of feature `/kk:design` and never called by it. It writes files and interacts with you mid-flow — it is a main-session skill, not a read-only reviewer.
    
    ## Conventions
    
    - **Capy knowledge base** — read [shared-capy-knowledge-protocol.md](shared-capy-knowledge-protocol.md); searched at intake (`kk:arch-decisions`, `kk:project-conventions`), indexed at close.
    - **Shared producer guards** — four workflow guards, each citing the field failure it prevents. Load all four before acting:
      - [shared-requirements-harvesting.md](shared-requirements-harvesting.md) — quote the real asks before modelling (F1).
      - [shared-open-question-pass.md](shared-open-question-pass.md) — verification asks new questions, not just re-confirms (F4).
      - [shared-fact-flip-propagation.md](shared-fact-flip-propagation.md) — a contradicted fact is fixed everywhere in-session (F2).
      - [shared-contact-ratio-guard.md](shared-contact-ratio-guard.md) — at N:0 artifacts-to-contacts, the next step is a conversation (F5).
    - **Profiles are not consulted** — `/kk:model` is language-agnostic in M2; archaeology reads code directly. Profile enrichment is deferred (design §8).
    
    ## Workflow
    
    **Mandatory order — instructions before subject matter.** The flow is strictly sequential. Do **not** read code to model it, draft any kit page, or engage the domain beyond a mode-detecting directory/keyword scan until every instruction file is loaded: this SKILL.md, the process file [model-process.md](model-process.md), the reading method [archaeology.md](archaeology.md), the output contract [kit-contract.md](kit-contract.md), all four shared guards above, and the shared capy protocol. This ordering is load-bearing: with domain code in context before the contracts load, the model emits plausible terms and skips the methodology that makes them trustworthy.
    
    1. **Load instructions.** Read [model-process.md](model-process.md) (the detailed seven-phase workflow), [archaeology.md](archaeology.md), [kit-contract.md](kit-contract.md), all four shared guards — [shared-requirements-harvesting.md](shared-requirements-harvesting.md), [shared-open-question-pass.md](shared-open-question-pass.md), [shared-fact-flip-propagation.md](shared-fact-flip-propagation.md), [shared-contact-ratio-guard.md](shared-contact-ratio-guard.md) — and [shared-capy-knowledge-protocol.md](shared-capy-knowledge-protocol.md). Minimal early scope — a directory listing or a keyword scan of the request — is permitted only to drive mode detection.
    2. **Execute the seven phases** per [model-process.md](model-process.md):
       1. **Scope intake** — establish the bounded context, the **forcing question** (the feature/ticket that bounds what is worth modelling), and the **mode** (greenfield: no kit exists → produce the two pages; brownfield: an existing kit is read in full first and all changes are deltas, status markers never flipped unilaterally). Run the capy knowledge search.
       2. **Requirements-harvesting gate** *(guard, F1)* — read every linked ticket + one hop; quote the actual asks into working notes before any modelling.
       3. **Archaeology** — read code **state → time → invariants** per [archaeology.md](archaeology.md); two-clock discipline (code-clock facts verifiable, intent stays `proposed`).
       4. **Draft the kit** per [kit-contract.md](kit-contract.md) — glossary page + divergences/traps page (+ conventions index if the home has none).
       5. **Verify** — at least one confirm-pass **plus at least one open-question pass** *(guard, F4)*.
       6. **Self-check** — conventions-bind-author lint: the produced pages obey the kit's own declared conventions.
       7. **Surface & close** — present the **decision queue** (each RQ precise, decidable, role-tagged); apply the **contact-ratio guard** *(F5)*; in brownfield, **fact-flip propagation** *(F2)* on any contradicted recorded fact; index non-obvious rationale to `kk:arch-decisions`.
    
    ## Required Outputs
    
    - [ ] The two durable kit pages (glossary + traps) for the context, provenance-clean, per [kit-contract.md](kit-contract.md) (+ conventions index if the home lacked one).
    - [ ] The **decision queue** — precise, decidable, role-tagged questions — presented inline and appended to the active feature's `docs/feat/wip/<feature>/design.md` under an **Open Questions** heading when that directory exists.
    - [ ] Contact-ratio guard applied; brownfield fact-flips propagated across the workspace.
    - [ ] Non-obvious modelling rationale indexed to `kk:arch-decisions`.
    

Comments (0)

Sign in to join the conversation.

No comments yet.

Reviews (0)

No reviews yet.

Related