diff --git a/.claude/skills/pair-capability-assess-architecture/SKILL.md b/.claude/skills/pair-capability-assess-architecture/SKILL.md index 0fa65262..1ecfcf5c 100644 --- a/.claude/skills/pair-capability-assess-architecture/SKILL.md +++ b/.claude/skills/pair-capability-assess-architecture/SKILL.md @@ -1,7 +1,7 @@ --- name: pair-capability-assess-architecture description: "Evaluates and recommends an architecture pattern (layered, hexagonal, microservices, modular monolith, etc.) when the choice is open. Output-only: emits a proposal + target for /pair-capability-record-decision to persist." -version: 0.5.0 +version: 0.6.0 author: Foomakers --- @@ -42,6 +42,7 @@ Read [resolution cascade](../../../.pair/knowledge/guidelines/technical-standard - [Architecture README](../../../.pair/knowledge/guidelines/architecture/README.md) — decision tree, complexity matrix, selection criteria - [Architectural Patterns](../../../.pair/knowledge/guidelines/architecture/architectural-patterns/README.md) — pattern descriptions and trade-offs - [Project Constraints](../../../.pair/knowledge/guidelines/architecture/project-constraints/README.md) — team, platform, deployment constraints + - [Coupling Balance](../../../.pair/knowledge/guidelines/architecture/design-patterns/coupling-balance.md) — the three-dimensional coupling model (integration strength × distance × volatility + balance rule); its criteria inform pattern scoring in Step 3 (a pattern that lowers strength or aligns distance to volatility scores higher for a volatile, tightly-coupled domain) 2. **Act**: If PRD exists, read [adoption/product/PRD.md](../../../.pair/adoption/product/PRD.md) for project context (team size, scale, compliance). 3. **Verify**: Every file listed in 1-2 above has been read; any that's missing follows [Graceful Degradation](#graceful-degradation) (ask the developer directly) instead of silently proceeding to Step 3. diff --git a/.claude/skills/pair-capability-assess-coupling/SKILL.md b/.claude/skills/pair-capability-assess-coupling/SKILL.md new file mode 100644 index 00000000..f12a5249 --- /dev/null +++ b/.claude/skills/pair-capability-assess-coupling/SKILL.md @@ -0,0 +1,193 @@ +--- +name: pair-capability-assess-coupling +description: "Assesses architecture coupling against the three-dimensional model (integration strength x socio-technical distance x volatility + balance rule): `$scope: diff` — composed by /pair-process-review, emits a 1-line Architecture verdict + collapsed findings (D22), critical findings flagged for the merge decision; `$scope: full` — one-shot codebase audit written to .pair/working/reports/architecture/, handing every unbalanced integration (volatile as critical/significant, stable as tolerable) to the caller for tech-debt promotion. Reads real integration points, never structure alone; never a single-dimension decouple. Output-only; the model lives in one guideline (D37)." +version: 0.1.0 +author: Foomakers +--- + +# /pair-capability-assess-coupling — Coupling Balance Assessment + +Assess whether the coupling relationships in a change (or a whole codebase) are +**balanced**, in two scopes — `diff` (per-PR, composed by `/pair-process-review`) and `full` +(one-shot audit, standalone) — against the model resolved from the +[coupling-balance guideline](../../../.pair/knowledge/guidelines/architecture/design-patterns/coupling-balance.md): +the three dimensions (**integration strength**, **socio-technical distance**, +**volatility**), the **balance rule**, the **severity** criteria, the DDD mapping, +and the test implications. The model lives **only** in that guideline (D37); this +skill applies it and never restates it. + +**Every finding is three-dimensional.** A coupling verdict is computed on all three +dimensions or it is not emitted — a finding grounded in fewer than three (e.g. a +structural dependency count alone) is invalid by construction (guideline "The Three +Dimensions"). The assessment **reads the actual code** — imports, calls, shared data +structures, data access — never the dependency graph's shape alone. + +## Arguments + +| Argument | Required | Description | +| --------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------ | +| `$scope` | No | `diff` — assess only the integration points the PR touches. `full` — audit the whole codebase. Auto-detected: called by `/pair-process-review` → `diff`; otherwise → `full`. | +| `$area` | No | Full scope only. Package/area to narrow the audit (default: whole codebase). | +| `$output` | No | Full scope only. Directory the audit report is written to. Default: `.pair/working/reports/architecture/` (D14 — report path override). | + +## Model Source (both scopes read this) + +The model is resolved through the standard **Adoption > KB default** layering; the +KB guideline is the sole home of the criteria (D37): + +1. **KB default** — [coupling-balance.md](../../../.pair/knowledge/guidelines/architecture/design-patterns/coupling-balance.md): strength levels (intrusive > functional > model > contract), the distance axes, essential-vs-accidental volatility, the balance rule, severity, DDD mapping, test implications. +2. **Volatility inputs (adoption)** — [adoption/product/subdomain/](../../../.pair/adoption/product/subdomain/) (subdomain classification → essential volatility: core = high, supporting = medium, generic = low) and [adoption/tech/boundedcontext/](../../../.pair/adoption/tech/boundedcontext/) (context boundaries → distance). Read when present; **asked or estimated** when absent (no-DDD degradation, never HALT — consistent with #246). +3. **Project delta (adoption)** — `tech/risk-matrix.md` `## Overrides` may tune severity thresholds; absent ⇒ KB defaults apply completely (D21). + +A missing/malformed adoption file is treated as absent: warn and fall back (never HALT on adoption absence). + +## Algorithm + +### Step 0: Detect Scope + +1. **Check**: Is `$scope` provided? +2. **Skip**: If provided, use it. Proceed to Step 1. +3. **Act**: Auto-detect: invoked with a PR/diff in context (i.e. by `/pair-process-review`) → `diff`; otherwise → `full`. +4. **Verify**: Scope is set. + +### Step 1: Load the Model + +1. **Act**: Read [coupling-balance.md](../../../.pair/knowledge/guidelines/architecture/design-patterns/coupling-balance.md) (the criteria) and the volatility inputs (Model Source layers 2-3), skipping any adoption file that doesn't exist. +2. **Act**: If the guideline is **missing** (KB not installed), follow [Graceful Degradation](#graceful-degradation) — assess against the three dimensions from first principles and note the reduced basis; do not invent a different model. +3. **Verify**: Model + available volatility inputs loaded. Adoption absence is logged as "volatility asked/estimated", not an error. + +### Step 2: Resolve Integration Points (read the real code) + +1. **Act**: Identify the coupling relationships in the surface: + - `diff` — only the integration points the diff **touches**: new/changed imports, cross-module calls, shared types/DTOs, direct data access across a boundary, duplicated business rules. Never the whole codebase (huge-diff edge case). + - `full` — map integrations between components across `$area` (default: whole codebase). +2. **Act**: For each relationship, read the actual code at both ends — what knowledge is shared, which symbols cross the boundary — never the dependency graph shape alone. +3. **Verify**: Every relationship in scope has its real shared-knowledge surface identified. **Single-module project / no cross-component integration** → no relationships: emit verdict "balanced / not applicable", no noise findings (edge case). + +### Step 3: Score the Three Dimensions + +For each relationship, assign **all three** per the guideline: + +1. **Integration strength** — intrusive / functional / model / contract, from what actually crosses the boundary (private access and duplicated rules are intrusive/functional even when they look incidental). +2. **Socio-technical distance** — code-structure + team + runtime distance, relative to the abstraction level under analysis (fractal: a cross-module imbalance counts even inside one deployable). +3. **Volatility** — essential from subdomain classification (core→high, supporting→medium, generic→low); accidental (provider/fashion-dependent implementation) flagged as such. **Never from commit frequency alone.** No DDD artifact → ask the developer or estimate from the code's business role, and **label the value "estimated"** in the output. + +**Verify**: no relationship carries a partial (< 3 dimensions) score. A partial score is dropped, not emitted. + +### Step 4: Apply the Balance Rule and Severity + +1. **Act**: Apply the **balance rule** exactly as the guideline defines it — resolve the criteria from [The Balance Rule](../../../.pair/knowledge/guidelines/architecture/design-patterns/coupling-balance.md#the-balance-rule) (combine strength and distance; volatility is the multiplier). Do not restate the rule here. +2. **Act**: Assign severity from the guideline's [Severity](../../../.pair/knowledge/guidelines/architecture/design-patterns/coupling-balance.md#severity) table (critical / significant / tolerable) — the sole home of the criteria (D37); this skill applies it, never restates the conditions. +3. **Act**: Rank the findings — unbalanced **and** volatile (critical/significant), plus significant implicit-knowledge findings, earn *attention* and feed the merge decision. An unbalanced-but-low-volatility relationship is **retained as a tolerable finding** for tech-debt promotion — never dropped, never blocking. Only a **balanced** relationship (or a partial <3-dimension score) is **not** a finding ("few critical beat many minor"). +4. **Verify**: every emitted finding is unbalanced on the rule and carries a severity backed by all three dimensions. + +### Step 5: Attach a Rebalancing Proposal (two-dimensional, never "decouple") + +1. **Act**: For each finding, propose a move that names the dimension it changes (guideline "Rebalancing"): **reduce strength** (introduce a contract / ACL / published event) or **reduce distance** (co-locate). Never a bare single-dimension "decouple". +2. **Act**: Decomposition raises distance — only suggest splitting when strength is already low enough to keep the split balanced; on a high-strength relationship, reduce strength first. +3. **Act**: Where relevant, name the test implication (contract-coupled → integration contract test + boundary/encapsulation test). +4. **Verify**: every finding has a grounded, multi-dimensional proposal. + +### Step 6: Route by Scope + +- `$scope = diff` → Step 7 (emit review verdict, write nothing). +- `$scope = full` → Step 8 (write audit report, hand off tech-debt promotion). + +## Diff Scope (per-PR) + +### Step 7: Emit Review Verdict + +1. **Act**: Compute the overall verdict = highest severity among the diff's findings (a balanced diff → "balanced"). Render the 1-line verdict + collapsed `
` findings per Output Format — **output-only, no files written**. The caller (`/pair-process-review`) embeds it as the **Architecture** verdict-first row (1 line at top, details collapsed, D22). +2. **Act**: If any finding is **critical** → flag it explicitly for the caller: this is the signal `/pair-process-review` factors into its major/critical severity flow (the merge decision stays `/pair-process-review`'s — this skill never blocks). A **significant/tolerable** finding in a low-volatility area is reported for **tech-debt promotion**, not blocking (AC2). +3. **Verify**: Verdict emitted; critical findings flagged; nothing written. + +## Full Scope (one-shot audit) + +### Step 8: Write Audit Report + Hand Off Tech-Debt + +1. **Act**: Render the report — the mapped integrations and, flagged, **every unbalanced** one: unbalanced+volatile as critical/significant (attention), unbalanced+low-volatility as **tolerable** (retained, surfaced as tech-debt, never dropped), each with its three-dimensional score, severity, real integration point (file/symbol), and rebalancing proposal. Estimated volatility (no-DDD) is labelled as estimated. +2. **Act**: Create `$output` (default `.pair/working/reports/architecture/`) if absent; write `$output/-coupling-audit.md`. This is a direct write — reports are operational artifacts (D14), the same exception `/pair-capability-assess-security` audit and `/pair-capability-design-manual-tests` use; this skill writes **no adoption content**. +3. **Act**: Assemble a tech-debt promotion tuple **per finding** for the caller to persist via `/pair-capability-write-issue` (topical label `tech-debt`, the #224 pipeline): title, the three-dimensional rationale, severity, rebalancing proposal. This skill **creates no issues itself** — it hands the tuples to the caller. +4. **Verify**: report written at the resolved path; tech-debt tuples assembled for handoff. + +## Output Format + +### Diff Scope + +```text +COUPLING ASSESSMENT (composed by /pair-process-review — no files written): +├── Scope: Diff +├── Verdict: [balanced | tolerable | significant | critical] — [1-line summary] +├── Findings: [N total — N critical, N significant, N tolerable] +├── Basis: [KB model | + subdomain/boundedcontext adoption | volatility estimated (no DDD)] +└── Feeds: Architecture row of the review report (D22) — critical flags the review decision, never blocks here +``` + +
+N coupling findings + +1. [severity] [component A] ↔ [component B] — strength: [intrusive|functional|model|contract], distance: [low|moderate|high], volatility: [high|medium|low (est?)] — [unbalanced: cascading | low-cohesion] — proposal: [reduce strength: … | reduce distance: …] — test: [contract+boundary | …] +... + +
+ +### Full Scope + +```text +COUPLING AUDIT COMPLETE: +├── Scope: [whole codebase | $area] +├── Mapped: [N integrations] +├── Flagged: [N unbalanced — N critical, N significant, N tolerable] +├── Report: [.pair/working/reports/architecture/ — written] +├── Tech-debt: [N tuples handed to caller for /pair-capability-write-issue (tech-debt label, #224)] +└── Basis: [KB model | + subdomain/boundedcontext adoption | volatility estimated (no DDD)] +``` + +A single-module / no-cross-component surface renders as `Verdict: balanced — not applicable (no cross-component integration)` with no findings. + +## Composition Interface + +When composed by `/pair-process-review` (review-time Architecture dimension, step 2.3): + +- **Input**: `/pair-process-review` invokes `/pair-capability-assess-coupling` with `$scope: diff` against the PR diff. +- **Output**: returns the verdict + collapsed findings (Diff Scope output). `/pair-process-review` embeds it as the **Architecture** verdict-first row (D22) and, if any finding is critical, factors it into its own major/critical severity flow. **Capability absent** → `/pair-process-review` renders the row as **"not assessed"** and proceeds (standard graceful degradation) — this skill states the contract; the row/degradation rendering is `/pair-process-review`'s. +- **Persistence**: none — diff scope writes nothing. + +When composed for full-audit tech-debt promotion: + +- The caller persists each handed-off finding as a tech-debt item via `/pair-capability-write-issue` (topical `tech-debt` label — the #224 pipeline). This skill assembles the tuples; it creates no issues itself. + +When read by `/pair-capability-assess-architecture`: + +- The coupling-balance guideline is a reading input to `/pair-capability-assess-architecture`'s evaluation step — the coupling criteria inform pattern scoring. `/pair-capability-assess-coupling` and `/pair-capability-assess-architecture` share the guideline, not each other's logic. + +When invoked **independently** (`/pair-capability-assess-coupling` on a branch, or `$scope: full`): full one-shot flow; the report (full) or verdict (diff) is returned to the developer. + +> Review-side wiring (listing `/pair-capability-assess-coupling` as a Composed Skill in `/pair-process-review` step 2.3 and the Architecture row in the review template) is delivered separately (#228). This skill is authored ready-to-compose; nothing here depends on that wiring existing yet. + +## Edge Cases + +- **Huge diff**: assess only the changed integration points, never the whole codebase in diff scope (Step 2.1). +- **No DDD artifacts** (no subdomain/boundedcontext): ask or estimate volatility, label it "estimated", complete the assessment — **never HALT** (consistent with #246 degradation). +- **Capability absent in review**: `/pair-process-review` renders "not assessed" and proceeds (graceful degradation) — this skill has no say once uninstalled. +- **Single-module project**: no cross-component integrations → verdict "balanced / not applicable", no noise findings. +- **Unbalanced but stable** (low volatility): reported as **tolerable** → tech-debt, never blocks (AC2). +- **Structure-only signal** (a dependency count with no readable shared-knowledge surface): not a finding — a verdict on fewer than three dimensions is invalid (Step 3 verify). + +## Graceful Degradation + +See [graceful degradation](../../../.pair/knowledge/guidelines/technical-standards/ai-development/skill-conventions/graceful-degradation.md) (guideline missing → minimal assessment, ask directly; adoption file missing → run against KB defaults; PM tool unreachable → n/a) for the standard scenarios. Additional cases: + +- **coupling-balance guideline absent** (KB partially installed): assess the three dimensions from first principles and note the reduced basis in the output rather than HALTing — never substitute a different model. +- **`/pair-capability-map-subdomains` / `/pair-capability-map-contexts` not available**: infer volatility from the code's business role and label it estimated; infer boundaries from package structure — do not HALT. +- **`/pair-capability-write-issue` not installed** (full scope): the report (Step 8.2) is still written — it's this skill's own direct write; the tech-debt tuples stand in the report with no persistence path; note this explicitly. + +## Notes + +- **Writes exactly one kind of file itself**: the full-scope audit report under `.pair/working/reports/architecture/` (Step 8.2) — the same D14 exception `/pair-capability-assess-security` audit uses. Adoption content is never self-written; tech-debt items always go through the caller's `/pair-capability-write-issue` composition. +- **Never blocks** — no merge authority; a critical finding is a signal for `/pair-process-review`, not a gate this skill enforces. +- **Model lives in one guideline** (D37): [coupling-balance.md](../../../.pair/knowledge/guidelines/architecture/design-patterns/coupling-balance.md). This skill references it and never duplicates the strength levels, balance rule, or severity criteria — searching the KB for the model finds it only there. +- **Three dimensions, always**: a finding grounded in fewer than three is invalid; structure alone is never a finding. +- **Never blanket-decouple**: decomposition raises distance, so a split is proposed only when strength is already low enough to keep it balanced. +- **Idempotent** — see [idempotency convention](../../../.pair/knowledge/guidelines/technical-standards/ai-development/skill-conventions/idempotency.md): a fresh verdict is computed every run against the current diff/codebase by design. +- **D22** (1-line verdict + collapsed details): a project-level rendering decision the caller honors; this skill emits in that shape. diff --git a/.claude/skills/pair-next/SKILL.md b/.claude/skills/pair-next/SKILL.md index f96282c5..00a9f752 100644 --- a/.claude/skills/pair-next/SKILL.md +++ b/.claude/skills/pair-next/SKILL.md @@ -7,7 +7,7 @@ author: Foomakers # /pair-next — Project Navigator -Analyze project state and recommend the single most relevant next skill to invoke. Covers the full 39-skill catalog across all lifecycle phases. +Analyze project state and recommend the single most relevant next skill to invoke. Covers the full 40-skill catalog across all lifecycle phases. ## Arguments (optional) @@ -37,9 +37,9 @@ Keep only candidate issues that carry the given label. `--filter` takes a **sing The scope is **stateless across steps**. Every run — and every step of a multi-step run — re-queries the PM tool and **re-evaluates** `--root` and `--filter` against the **current** board state. If an issue's tags change between steps (e.g. a review raises `risk:yellow` → `risk:red`), the next step's selection reflects the change immediately. `/pair-next` never reuses a selection computed in a previous step. -## Skill Catalog (39 skills) +## Skill Catalog (40 skills) -The catalog is **derived from the installed corpus**: every skill directory under `.skills/` must appear here — 9 process + 29 capability + `/pair-next` itself = 39. If an installed skill is missing from these tables (or a row names a skill that is not installed), the catalog has drifted: update the tables, the stated counts, and the cascade rows together. +The catalog is **derived from the installed corpus**: every skill directory under `.skills/` must appear here — 9 process + 30 capability + `/pair-next` itself = 40. If an installed skill is missing from these tables (or a row names a skill that is not installed), the catalog has drifted: update the tables, the stated counts, and the cascade rows together. ### Process Skills (9) @@ -55,7 +55,7 @@ The catalog is **derived from the installed corpus**: every skill directory unde | `/pair-process-implement` | Sprint Execution | Implement story tasks with TDD | | `/pair-process-review` | Sprint Execution | Review PR through structured phases | -### Capability Skills (29) +### Capability Skills (30) | Skill | Category | Description | | ------------------------ | --------------- | ---------------------------------------------------------------------------- | @@ -81,6 +81,7 @@ The catalog is **derived from the installed corpus**: every skill directory unde | `/pair-capability-assess-observability` | Assessment | Assess observability strategy | | `/pair-capability-assess-security` | Assessment | Assess security posture (review verdict + one-shot audit) | | `/pair-capability-assess-cost` | Assessment | Classify cost exposure (green/yellow/orange/red) at review — output-only | +| `/pair-capability-assess-coupling` | Assessment | Assess coupling balance (strength × distance × volatility) — diff verdict + full audit | | `/pair-capability-analyze-debt` | Analysis | Analyze technical debt with prioritization | | `/pair-capability-analyze-code-quality` | Analysis | Analyze code quality with metrics | | `/pair-capability-estimate` | Planning | Estimate story using adopted methodology | @@ -218,4 +219,4 @@ See [graceful degradation](../../../.pair/knowledge/guidelines/technical-standar - This skill is read-only: it inspects state but never modifies files or PM tool data. - Row order encodes the tie-break (delivery proximity) — see the **Tie-break** note under the Step 3 table. - Re-run `/pair-next` after completing any skill to get an updated recommendation. -- **Full catalog coverage**: nearly all of the 39 skills can be suggested — process skills via the cascading checks (Steps 2-3), capability skills via targeted checks (row 7 `/pair-capability-checkpoint`, rows 12-16 including `/pair-capability-grill`) or process-skill composition. `/pair-capability-publish-pr` will be reachable via `/pair-process-implement` once wired (not yet composed), so `/pair-next` cannot surface it today. +- **Full catalog coverage**: nearly all of the 40 skills can be suggested — process skills via the cascading checks (Steps 2-3), capability skills via targeted checks (row 7 `/pair-capability-checkpoint`, rows 12-16 including `/pair-capability-grill`) or process-skill composition. `/pair-capability-publish-pr` will be reachable via `/pair-process-implement` once wired (not yet composed), so `/pair-next` cannot surface it today. diff --git a/.pair/adoption/decision-log/2026-07-25-ul-borrowed-terms-and-docs-site-dissemination-ownership.md b/.pair/adoption/decision-log/2026-07-25-ul-borrowed-terms-and-docs-site-dissemination-ownership.md new file mode 100644 index 00000000..b205f4e9 --- /dev/null +++ b/.pair/adoption/decision-log/2026-07-25-ul-borrowed-terms-and-docs-site-dissemination-ownership.md @@ -0,0 +1,45 @@ +# DDR: Borrowed-term marking in UL tables + the docs site as a dissemination channel + +## Status + +Accepted + +## Date + +2026-07-25 + +## Context + +Two attribution defects surfaced while analysing PR #381 (story #263, coupling-balance guideline + `assess-coupling`). Both are boundary-documentation defects in `adoption/tech/boundedcontext/`, not code: + +1. **Duplicate owned term.** `development-collaboration.md` declared `Adoption` in its own Ubiquitous Language table ("a recorded decision about which practice, tool, or pattern the project follows"), while `adoption/product/context-map.md` assigns `Adoption` to the **Adoption & Guidelines** subdomain and `knowledge-standards.md` owns `Adoption file`. The same term appeared as *owned* in two bounded contexts with two definitions — the classic ubiquitous-language collision. Development Collaboration does legitimately touch adoptions (skills read them), so deleting the row would lose real information. +2. **Unattributed deployable.** `apps/website/**` maps to no registered subdomain, and the existing "ownership splits by concern, not by path" rule was scoped explicitly to `packages/knowledge-hub/dataset/.pair/knowledge/**` — it said nothing about the site. Every PR touching the docs site therefore had to re-invent an attribution. The same PR's `$scope: full` dogfood independently found *website ↔ knowledge-hub dataset* to be the repo's single **CRITICAL** coupling: skill-catalog rows and `N skills` counts hand-copied across ~10 `.mdx` files. The missing ownership rule and the CRITICAL coupling are the same defect seen from two sides — nothing declared the site's facts to be derived rather than authored. + +**Hard to reverse / surprising without context:** ownership rules are cited by every subsequent PR's bounded-context analysis and by `/pair-capability-assess-coupling`; changing them later invalidates prior attributions. + +**Real trade-off considered:** the rejected alternative for (2) was to register a new subdomain (e.g. "Documentation & Dissemination"). Rejected — the site produces no knowledge of its own, it renders facts other subdomains author; a new subdomain would legitimise the duplication instead of forbidding it, and the catalog's stated philosophy favours fewer contexts for a two-person team. + +## Decision + +1. **Borrowed-term convention.** A term a context consumes but does not own is marked *(consumed)* in its UL table and names its owning context, reusing the owner's definition in substance. A term is *owned* in exactly one bounded context; an unmarked duplicate across two UL tables is a boundary defect, not a synonym. Applied: `development-collaboration.md` now lists `Adoption *(consumed)* — owned by Knowledge & Standards (Adoption & Guidelines)`. +2. **The docs site is a dissemination channel, and "splits by concern" extends to it.** `apps/website/**` is owned by **Integration & Process Standardization** as a distribution channel (build/deploy pipeline, routing/IA, the `docs-staleness` gate) and maps to no business subdomain. The facts it renders — catalog rows, skill/capability counts, guideline prose — are *authored-by* the content contexts (Knowledge & Standards for guidelines/how-to, Development Collaboration for skills/workflows) and only *disseminated-by* Integration. +3. **Load-bearing corollary.** Those facts MUST be derived from the dataset, never hand-copied into `.mdx`. The derivation checks in `apps/website/lib/docs-staleness-check.ts` are the contract test of that derivation; hand-maintained duplication of dataset facts in the site is a CRITICAL coupling defect. This makes the rebalance already shipped in PR #381 (Check 2c — catalog row *content* single-sourced from dataset SKILL.md frontmatter) the enforced norm rather than a one-off cleanup. + +## Consequences + +### Benefits + +- Bounded-context attribution for a docs-site PR is now deterministic — no per-PR re-derivation, no silent double-attribution. +- UL collisions become detectable by inspection: an unmarked duplicate term is, by definition, a defect. +- The CRITICAL coupling cannot silently regress: the rule names the derivation contract that forbids re-introducing hand-copied dataset facts. + +### Trade-offs and Limitations + +- The convention is prose-enforced, not gate-enforced: no test asserts that `(consumed)` markers stay accurate or that a new `.mdx` fact is derived. Nothing reads `boundedcontext/*.md` programmatically today; adding a conformance check is a candidate follow-up if drift appears. +- Integration & Process Standardization grows broader still (integration + process + KB distribution + site dissemination). Same limitation already recorded in DDR `2026-07-19-merge-kb-management-into-integration.md`; if dissemination grows its own concern it may warrant re-splitting, superseding both DDRs. + +## Context Map Impact + +- No change to `adoption/product/context-map.md` — it indexes the five registered subdomains, and no subdomain is added or removed. +- `adoption/tech/boundedcontext/development-collaboration.md`: `Adoption` re-marked as a consumed term + borrowed-term convention stated under the UL table. +- `adoption/tech/boundedcontext/integration-process-standardization.md`: Data Ownership gains the docs-site dissemination bullet and the derivation corollary. diff --git a/.pair/adoption/tech/boundedcontext/development-collaboration.md b/.pair/adoption/tech/boundedcontext/development-collaboration.md index eb6fae1f..9b0f924a 100644 --- a/.pair/adoption/tech/boundedcontext/development-collaboration.md +++ b/.pair/adoption/tech/boundedcontext/development-collaboration.md @@ -35,8 +35,10 @@ This context orchestrates the collaboration between developers and AI assistants | Term | Definition | | ---- | ---------- | | Workflow | A sequence of collaborative phases (requirements → design → implementation → review) between developer and AI assistant | -| Adoption | A recorded decision about which practice, tool, or pattern the project follows | | Skill | An atomic, invocable unit of operational knowledge that an AI assistant executes | +| Adoption *(consumed)* | A project's committed choice of a practice, tool, or process, recorded as a delta over KB defaults. **Owned by Knowledge & Standards** (subdomain Adoption & Guidelines); workflows and skills here *read* adoptions, they do not define or own them. | + +**Borrowed-term convention.** A term this context consumes but does not own is marked *(consumed)* and names its owning context, reusing that context's definition verbatim in substance. A term appears as owned in exactly one bounded context — an unmarked duplicate across two UL tables is a boundary defect, not a synonym. ## Quality Attributes diff --git a/.pair/adoption/tech/boundedcontext/integration-process-standardization.md b/.pair/adoption/tech/boundedcontext/integration-process-standardization.md index 637bf57f..1ccd876e 100644 --- a/.pair/adoption/tech/boundedcontext/integration-process-standardization.md +++ b/.pair/adoption/tech/boundedcontext/integration-process-standardization.md @@ -29,6 +29,7 @@ This context manages all integration logic and process standardization for the p - Owns integration configurations, process definitions, and automation scripts. - Owns the KB dataset, its distribution artifacts/metadata, and the local KB cache. - **Ownership splits by concern, not by path.** This context owns the *packaging & distribution* of KB content — the dataset as a release artifact, the flatten/prefix/symlink transform, the `pair update` mirror, and the cache. It does **not** own the content's *authoring*: guidelines and conventions are authored and owned by **Knowledge & Standards**, skills and workflows by **Development Collaboration**. A file under `packages/knowledge-hub/dataset/.pair/knowledge/**` is therefore *authored-by* its content subdomain and *distributed-by* this context — its co-location in the dataset directory is packaging, not content ownership. (Resolves the recurring "same edit lands in two bounded contexts" attribution ambiguity.) +- **The docs site is dissemination, and the same split applies.** `apps/website/**` is a separate deployable owned by this context as a *distribution channel*: its build/deploy pipeline, its routing/IA, and the `docs-staleness` gate. It maps to no business subdomain of its own. The **facts** it renders — skill catalog rows, `N skills` / `N capabilities` counts, guideline prose — are *authored-by* the content contexts (**Knowledge & Standards** for guidelines/how-to, **Development Collaboration** for skills/workflows) and only *disseminated-by* this context. Corollary, load-bearing: those facts MUST be derived from the dataset (single source of truth), never hand-copied into `.mdx`; the derivation checks in `apps/website/lib/docs-staleness-check.ts` are the contract test of that derivation. Hand-maintained duplication of dataset facts in the site is a CRITICAL coupling defect (see the `$scope: full` dogfood triage in story #263). ## Team Alignment diff --git a/.pair/knowledge/getting-started.md b/.pair/knowledge/getting-started.md index 7195715f..afcf4f27 100644 --- a/.pair/knowledge/getting-started.md +++ b/.pair/knowledge/getting-started.md @@ -79,7 +79,7 @@ Welcome to the AI-Human pairing repository template! This guide provides essenti - **`way-of-working.md`**: Main process documentation – the starting point to understand the full workflow - **`getting-started.md`**: This guide – essential information to get started with the framework -- **`skills-guide.md`**: Full catalog of 39 Agent Skills (9 process + 29 capability + 1 navigator) with composition patterns, adoption file mapping, and usage instructions +- **`skills-guide.md`**: Full catalog of 40 Agent Skills (9 process + 30 capability + 1 navigator) with composition patterns, adoption file mapping, and usage instructions - **`how-to/`**: Step-by-step guides for each development phase and LLM collaboration - Process guides (01-11): Operational documentation for each phase - **`assets/`**: Templates, checklists, and document examples (e.g., PRD, bootstrap checklist) diff --git a/.pair/knowledge/guidelines/architecture/design-patterns/README.md b/.pair/knowledge/guidelines/architecture/design-patterns/README.md index 506e08fa..fbf519c6 100644 --- a/.pair/knowledge/guidelines/architecture/design-patterns/README.md +++ b/.pair/knowledge/guidelines/architecture/design-patterns/README.md @@ -78,6 +78,11 @@ This folder contains guidelines for establishing solid architectural foundations - Lazy, human-approved subdomain context split convention - Loading and conflict-flag instructions for brainstorm/refine sessions +10. **Coupling Balance** (`coupling-balance.md`) + - Three-dimensional coupling model: integration strength × socio-technical distance × volatility + - The balance rule + severity criteria (critical/significant/tolerable) + - DDD-pattern mapping, fractal application, and test implications; criteria source for `assess-coupling` + ## 🔄 Decision Support ### Pattern Selection Decision Tree diff --git a/.pair/knowledge/guidelines/architecture/design-patterns/coupling-balance.md b/.pair/knowledge/guidelines/architecture/design-patterns/coupling-balance.md new file mode 100644 index 00000000..1c7cc706 --- /dev/null +++ b/.pair/knowledge/guidelines/architecture/design-patterns/coupling-balance.md @@ -0,0 +1,201 @@ +# Coupling Balance + +The single home of Pair's coupling model (D37): how to evaluate whether a +relationship between two components is *balanced*, on three dimensions, at every +level of abstraction. Skills reference this file; they never restate the model. + +## Purpose + +Coupling is not a defect to be minimized to zero — a system with no coupling does +nothing. The engineering question is never "is there coupling?" but "is this +coupling **balanced**?". This guideline defines the three dimensions used to answer +that, the balance rule that combines them, the severity a given imbalance carries, +and how the model maps onto the DDD patterns already in this knowledge base. It is +the criteria source for the `assess-coupling` skill (diff review + full audit) and a +reading input to `assess-architecture`. + +## The Three Dimensions + +Every coupling relationship is characterised on **all three** dimensions. A verdict +that rests on fewer than three is not a coupling verdict — it is a structural guess, +and this model rejects it. + +### 1. Integration Strength — how much two components must know about each other + +Strength measures the *amount of shared knowledge* a relationship carries: the more +one component must understand about the internals of the other to work with it, the +stronger the coupling. Four levels, from strongest to weakest: + +| Level | Shared knowledge | Example | +| --- | --- | --- | +| **Intrusive** (strongest) | Private internals: reaching past the public surface into implementation detail | reading another module's database tables directly; depending on a private field or an undocumented side effect | +| **Functional** | Shared behavioural expectations: a caller relies on *how* the other fulfils a responsibility, not only *what* it exposes | duplicated business rules kept in sync by hand; a consumer that re-implements the producer's validation | +| **Model** | A shared data model / shared types: both sides bind to the same representation of a concept | a common DTO or schema imported by both; a shared entity passed across a boundary | +| **Contract** (weakest) | Only a published contract: a stable interface, event shape, or protocol, with internals hidden on both sides | calling a versioned API; consuming a documented event; depending on an interface, not an implementation | + +Stronger integration means a change on one side is more likely to force a change on +the other. Strength is the dimension a rebalancing usually targets: introducing a +contract *reduces* strength without moving the components. + +### 2. Socio-technical Distance — the cost of co-evolving the two components + +Distance measures how expensive it is to change both sides **together**. It is +socio-technical because the cost is not only in the code: + +- **Code-structure distance** — same function / same module / same package / same + deployable / separate deployables. The further apart in the structure, the more + coordination a joint change needs. +- **Team distance** — same author / same team / different teams / different + organisations. Crossing a team boundary turns a code change into a negotiation. +- **Runtime distance** — in-process call / same process boundary / network hop / + asynchronous exchange. The further apart at runtime, the harder atomic change and + the more failure modes a joint change must survive. + +Distance is the dimension a rebalancing targets when it *co-locates*: moving the two +sides closer (same module, same team) lowers the cost of the changes they force on +each other. Decomposition does the opposite — it **raises** distance. + +### 3. Volatility — how likely the relationship is to change + +Volatility is the probability that the coupled behaviour will actually change. It is +evaluated **from the business domain, never from commit history alone** — a file +that churned last month is not thereby volatile, and a quiet file in a core +subdomain is not thereby stable. Two kinds: + +- **Essential volatility** — inherent to the domain: core, differentiating + capabilities change as the business learns. Sourced from subdomain classification + (see [strategic-subdomain-definition.md](strategic-subdomain-definition.md)): + **core → high**, **supporting → medium**, **generic → low**. +- **Accidental volatility** — a generic capability whose *implementation* is + provider- or fashion-dependent (a payment SDK, a UI framework) can be volatile even + though the capability is generic. Flag it explicitly as accidental so the + rebalancing targets the implementation seam, not the capability. + +Commit frequency is at most a weak corroborating signal and is never, on its own, +evidence of volatility. + +## The Balance Rule + +Combine strength and distance first, then let volatility set the stakes. + +- **Balanced**: strength and distance move together in *opposite* directions — high + strength with low distance (tightly-related things kept close), or low strength + with high distance (loosely-related things kept apart). Both are healthy. +- **Unbalanced — high strength + high distance**: the pathological case. + Tightly-coupled components that are expensive to change together produce + **cascading, expensive changes**: every modification ripples across the boundary + that was meant to contain it. This is the imbalance that hurts most. +- **Unbalanced — low strength + low distance**: **low cohesion**. Things that barely + relate are crammed together, so the module has no reason to exist as a unit and + changes for unrelated reasons. + +**Volatility is the multiplier.** An imbalance in a **stable** relationship is +tolerable — it will rarely be paid for, so rebalancing may cost more than it saves. +The same imbalance in a **volatile** relationship is where change actually lands, and +is where the model raises the alarm. **Low volatility neutralises an imbalance;** +high volatility sharpens it. + +## Severity + +Severity is a function of the imbalance *and* its volatility — never of structure +alone: + +| Severity | Condition | +| --- | --- | +| **Critical** | Unbalanced **and** high volatility — the imbalance sits exactly where change lands. | +| **Significant** | Unbalanced and moderate volatility; **or** implicit shared knowledge regardless of stated volatility — duplicated business rules, access to another component's private interface/tables (intrusive/functional strength that hides as if it were a contract). | +| **Tolerable** | Unbalanced and low volatility — recorded as architectural debt, **never blocks** a merge. | + +The guiding heuristic is **few critical findings beat many minor ones**: a report +that flags everything flags nothing. Only unbalanced-and-volatile relationships earn +*attention* — the critical/significant findings that feed the merge decision. An +imbalance neutralised by low volatility does **not** vanish: it is **retained as a +tolerable finding** and surfaced as architectural debt — never dropped, never +blocking. What is genuinely *not a finding* is a **balanced** relationship, or any +score resting on fewer than three dimensions. + +## Rebalancing — always two-dimensional + +A rebalancing proposal names the dimension it moves and why. There is **no valid +single-word "decouple" recommendation**: + +- **Reduce strength** — introduce a contract (interface, published event, API + version, anti-corruption layer) so the two sides stop sharing internals. This is + the default move when the components genuinely belong apart. +- **Reduce distance** — co-locate: move the two sides into the same module / team / + process so a joint change is cheap. The right move when the coupling is essential + and the split was accidental. + +**Decomposition is not free: splitting components raises distance.** Recommending +"decouple" (i.e. split) is only sound when strength is already low enough that the +higher distance stays balanced. Proposing a split on a high-strength relationship +just converts a *cascading-change* imbalance into a *distributed cascading-change* +imbalance — strictly worse. When strength is high, reduce strength first. + +## Fractal Application + +The model applies at **every level of abstraction**, and distance is always relative +to the level under analysis: + +- functions within a module, +- modules within a package, +- packages within a deployable, +- deployables within a system. + +A cross-module imbalance counts even inside a single deployable: "it all ships +together" does not make two tightly-coupled, distant-in-structure modules balanced. +Evaluate the relationship at the level where the change actually crosses a boundary. + +## Mapping to DDD Patterns + +The strategic DDD patterns already in this knowledge base are *instances* of +rebalancing moves — this model is the why behind them: + +- **[Bounded contexts](bounded-contexts.md)** partition the model so a change stays + inside one context: a distance boundary drawn where volatility differs. +- **Anticorruption layer** is a strength reducer: the downstream context refuses the + upstream model and translates at the seam, turning model/functional coupling into + contract coupling. +- **Open-host service / published language** lowers strength for *many* downstream + consumers at once — one stable contract instead of N model bindings. +- **Aggregates** keep high-strength, high-volatility invariants inside a single + consistency boundary — low distance where strength must stay high. +- **Conformist / shared kernel** are the deliberately-accepted high-strength + relationships; the model says they are only safe when distance is low (same team, + minimal shared surface) and are re-examined the moment volatility rises. + +See [integration-patterns.md](integration-patterns.md) for the communication +mechanics and [context-map-maintenance.md](context-map-maintenance.md) for keeping +the relationship assessment current. + +## Test Implications + +The strength level of a relationship dictates what must be tested at its boundary: + +- **Contract-coupled** relationships imply **integration contract tests** — proof the + published contract is honoured by both sides (the consumer's expectations and the + provider's guarantees stay in agreement) — **and boundary tests** proving + encapsulation holds: nothing beyond the contract leaks across the seam. A leak + silently upgrades the relationship from contract to model/intrusive strength + without anyone deciding to. +- **Model/functional-coupled** relationships need tests that pin the shared model or + duplicated rule, so a drift on one side breaks a test rather than production. +- **Intrusive** coupling is, by definition, untestable at a stable boundary — there + is no boundary — which is itself the finding. + +## Bibliographic Reference + +The three-dimensional framing of coupling as *integration strength × distance × +volatility*, and the balance rule that combines them, is informed by the coupling +model articulated at [coupling.dev](https://coupling.dev). The content of this +guideline — definitions, levels, severity criteria, DDD mapping, and examples — is +Pair's own formulation. + +## Related Documents + +- [Design Patterns README](README.md) — pattern index +- [Strategic Subdomain Definition](strategic-subdomain-definition.md) — subdomain + classification, the source of essential volatility +- [Bounded Contexts](bounded-contexts.md) · [Integration Patterns](integration-patterns.md) + · [Context Map Maintenance](context-map-maintenance.md) — the DDD patterns this + model explains diff --git a/.pair/knowledge/skills-guide.md b/.pair/knowledge/skills-guide.md index ceef1aba..774889e3 100644 --- a/.pair/knowledge/skills-guide.md +++ b/.pair/knowledge/skills-guide.md @@ -15,9 +15,9 @@ Run `/pair-next` at the start of every session. It reads project adoption files | Type | Count | Purpose | |------|-------|---------| | **Process** | 9 | Lifecycle phases — orchestrate capability skills | -| **Capability** | 29 | Atomic units — perform a single focused operation | +| **Capability** | 30 | Atomic units — perform a single focused operation | -Process skills compose capability skills. Capability skills are independently invocable. Total: 39 (9 process + 29 capability + 1 navigator). +Process skills compose capability skills. Capability skills are independently invocable. Total: 40 (9 process + 30 capability + 1 navigator). ## Full Catalog @@ -37,7 +37,7 @@ Process skills compose capability skills. Capability skills are independently in > How-to guides 04 and 05 (subdomain/bounded-context definition) were removed — domain modeling is referenced inline by each real caller's own how-to (02, 03, 06, 09; 08 planned — #242). See [Domain Modeling Skills](#domain-modeling-skills-2) below and [Migration Notes](#migration-notes). -### Capability Skills (29) +### Capability Skills (30) #### Domain Modeling Skills (2) @@ -48,7 +48,7 @@ Process skills compose capability skills. Capability skills are independently in Reclassified from process to capability (D24) — see [Callers Matrix](#callers-matrix-scoped-capabilities) and [Migration Notes](#migration-notes). -#### Assessment Skills (10) +#### Assessment Skills (11) | Skill | Scope | |-------|-------| @@ -62,6 +62,7 @@ Reclassified from process to capability (D24) — see [Callers Matrix](#callers- | `/pair-capability-assess-ai` | AI development tools evaluation | | `/pair-capability-assess-security` | Security posture — review verdict (`$mode: review`, composed by `/pair-process-review`) + one-shot OWASP Top 10 audit (`$mode: audit`). Unlike the 8 above, not purely output-only — writes its own audit report (D14 exception); never scans for secrets, that's the deterministic CI layer `/pair-capability-setup-gates` provisions (D24) | | `/pair-capability-assess-cost` | Cost exposure — chromatic class (`cost:green\|yellow\|orange\|red`) from the diff/story against the [cost-signal catalog](guidelines/quality-assurance/cost-assessment.md) (general + AWS-first, other providers via adoption links). Output-only: feeds `/pair-capability-classify`'s cost dimension, writes nothing, blocks nothing; report/monitoring mode is a separate slice | +| `/pair-capability-assess-coupling` | Coupling balance — three-dimensional model (integration strength × socio-technical distance × volatility + balance rule) from the [coupling-balance guideline](guidelines/architecture/design-patterns/coupling-balance.md). `$scope: diff` feeds the review Architecture verdict (never blocks); `$scope: full` audits the codebase, flags only unbalanced+volatile integrations, writes a report and hands findings to `/pair-capability-write-issue` for tech-debt. Reads real integration points, never structure alone | #### Classification Skills (1) diff --git a/.pair/knowledge/way-of-working.md b/.pair/knowledge/way-of-working.md index 3cecd041..f01363c4 100644 --- a/.pair/knowledge/way-of-working.md +++ b/.pair/knowledge/way-of-working.md @@ -78,4 +78,4 @@ The process is designed to: 2. **🤖🤝👨‍💻 Code Review** (`/pair-process-review`) → Structured review with adoption compliance, merge flow, and parent cascade 3. **🤖⚡ Status Update** → Automatic story/epic/initiative tracking update (handled by `/pair-process-implement` and `/pair-process-review`) -> **Skill-enabled workflow**: Run `/pair-next` at session start to determine the most relevant skill. See [skills-guide.md](skills-guide.md) for the full catalog of 39 skills. +> **Skill-enabled workflow**: Run `/pair-next` at session start to determine the most relevant skill. See [skills-guide.md](skills-guide.md) for the full catalog of 40 skills. diff --git a/CLAUDE.md b/CLAUDE.md index 4022fba2..86c37745 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -144,4 +144,3 @@ function isLocalPath(str: string): boolean { - **Regression prevention**: Test stays in codebase to catch future breaks - **Clarity**: Test documents expected behavior - **Confidence**: Linting + tests pass before committing - diff --git a/apps/website/content/docs/contributing/writing-skills.mdx b/apps/website/content/docs/contributing/writing-skills.mdx index 485fbfbc..9208eca9 100644 --- a/apps/website/content/docs/contributing/writing-skills.mdx +++ b/apps/website/content/docs/contributing/writing-skills.mdx @@ -285,5 +285,5 @@ Three distinct verbs, kept separate — don't overload one across branches: **`v - [Agent Skills specification](https://agentskills.io) — The open standard, including frontmatter fields and size limits. - [`writing-great-skills`](https://github.com/mattpocock/skills) — The reference model behind the effectiveness standard (predictability, information hierarchy, leading words, pruning). -- [Skills Catalog](/docs/reference/skills-catalog) — Full list of all 39 pair skills. +- [Skills Catalog](/docs/reference/skills-catalog) — Full list of all 40 pair skills. - [Skills concept](/docs/concepts/skills) — How skills fit into the pair ecosystem. diff --git a/apps/website/content/docs/developer-journey/execution.mdx b/apps/website/content/docs/developer-journey/execution.mdx index dbd22435..118fb4bc 100644 --- a/apps/website/content/docs/developer-journey/execution.mdx +++ b/apps/website/content/docs/developer-journey/execution.mdx @@ -123,6 +123,6 @@ This loop repeats for every story. `/pair-next` always knows what comes next. ## Reference -- [Skills Catalog](/docs/reference/skills-catalog) — all 39 skills with commands and composition +- [Skills Catalog](/docs/reference/skills-catalog) — all 40 skills with commands and composition - [Guidelines & How-To Catalog](/docs/reference/guidelines-catalog) — all 9 guideline categories and 9 how-to guides - [Adopt a Knowledge Base](/docs/customization/adopt) — set up pair if you haven't already diff --git a/apps/website/content/docs/developer-journey/index.mdx b/apps/website/content/docs/developer-journey/index.mdx index 7cfd95fc..1b802505 100644 --- a/apps/website/content/docs/developer-journey/index.mdx +++ b/apps/website/content/docs/developer-journey/index.mdx @@ -40,7 +40,7 @@ Level 4: Execution (per story) You can follow this flow in two ways: -1. **Process Skills (recommended)** — invoke a slash command and the AI handles the structured process for you. See the [Skills Catalog](/docs/reference/skills-catalog) for all 39 skills. +1. **Process Skills (recommended)** — invoke a slash command and the AI handles the structured process for you. See the [Skills Catalog](/docs/reference/skills-catalog) for all 40 skills. 2. **How-to Guides** — follow the manual step-by-step instructions from the Knowledge Base. See the [Guidelines & How-To Catalog](/docs/reference/guidelines-catalog) for all 9 how-to guides. Skills compose capability skills internally, enforce adoption compliance, and update your PM tool automatically. The how-to guides give you the same process with full manual control. @@ -117,5 +117,5 @@ Feeling lost? Check the [FAQ](/docs/support/general-faq) — it answers common q ## Reference -- [Skills Catalog](/docs/reference/skills-catalog) — all 39 skills with commands and composition +- [Skills Catalog](/docs/reference/skills-catalog) — all 40 skills with commands and composition - [Guidelines & How-To Catalog](/docs/reference/guidelines-catalog) — all 9 guideline categories and 9 how-to guides diff --git a/apps/website/content/docs/getting-started/index.mdx b/apps/website/content/docs/getting-started/index.mdx index fc49a125..d4a77910 100644 --- a/apps/website/content/docs/getting-started/index.mdx +++ b/apps/website/content/docs/getting-started/index.mdx @@ -15,7 +15,7 @@ A structured set of documents — guidelines, how-tos, architecture decisions, t ## Skills -Structured instructions that AI assistants discover and execute, following the [Agent Skills](https://agentskills.io) open standard. Skills automate the full product lifecycle — from PRD creation to code review — with 39 composable skills covering process and capability concerns. +Structured instructions that AI assistants discover and execute, following the [Agent Skills](https://agentskills.io) open standard. Skills automate the full product lifecycle — from PRD creation to code review — with 40 composable skills covering process and capability concerns. [Learn more about Skills](/docs/concepts/skills) diff --git a/apps/website/content/docs/integrations/claude-code.mdx b/apps/website/content/docs/integrations/claude-code.mdx index 932aea3a..0128b710 100644 --- a/apps/website/content/docs/integrations/claude-code.mdx +++ b/apps/website/content/docs/integrations/claude-code.mdx @@ -25,7 +25,7 @@ your-project/ │ ├── pair-next/ │ ├── pair-process-implement/ │ ├── pair-capability-verify-quality/ -│ └── ... ← 39 skills +│ └── ... ← 40 skills ├── .pair/ │ ├── knowledge/ ← upstream guidelines (don't edit) │ └── adoption/ ← your project decisions diff --git a/apps/website/content/docs/reference/coupling-model.mdx b/apps/website/content/docs/reference/coupling-model.mdx new file mode 100644 index 00000000..4748008f --- /dev/null +++ b/apps/website/content/docs/reference/coupling-model.mdx @@ -0,0 +1,46 @@ +--- +title: Coupling Model +description: The three-dimensional coupling model behind the classification matrix's coupling-balance dimension — integration strength, socio-technical distance, volatility, and the balance rule. +--- + +Coupling is not a defect to minimise to zero — a system with no coupling does nothing. The engineering question is never "is there coupling?" but "is this coupling **balanced**?". This model answers that on three dimensions, at every level of abstraction, and is the criteria source for the `/pair-capability-assess-coupling` skill and a reading input to `/pair-capability-assess-architecture`. Source: [`coupling-balance.md`](https://github.com/foomakers/pair/blob/main/packages/knowledge-hub/dataset/.pair/knowledge/guidelines/architecture/design-patterns/coupling-balance.md). + +> This page orients. The scoring levels, the severity conditions and the mapping onto the DDD patterns live in the guideline linked above — the single source of truth. Nothing here restates them. + +## Three dimensions, all three required + +| Dimension | Asks | Rebalanced by | +| --- | --- | --- | +| **Integration strength** | How much must each side know about the other — private internals, shared behaviour, a shared model, or only a published contract? | Introducing a contract: lowers strength without moving anything | +| **Socio-technical distance** | What does it cost to change both sides *together* — across code structure, team boundaries, and runtime? | Co-locating (lowers) or decomposing (raises) | +| **Volatility** | How likely is the coupled behaviour to actually change, judged from the business domain — not from commit history? | Not a lever: it is the multiplier on the other two | + +A verdict resting on fewer than three dimensions is not a coupling verdict — the model rejects it as a structural guess. + +## The balance rule + +Strength and distance must move in **opposite** directions. Both healthy shapes follow from that: high strength with low distance (tightly-related things kept close), or low strength with high distance (loosely-related things kept apart). + +The two imbalances are the failure modes: + +- **High strength + high distance** — the pathological case. Tightly-coupled components that are expensive to change together produce cascading, expensive changes: every modification ripples across the boundary that was meant to contain it. +- **Low strength + low distance** — low cohesion. Things that barely relate are crammed together, so the unit has no reason to exist and changes for unrelated reasons. + +**Volatility sets the stakes.** An imbalance in a stable relationship is tolerable — it will rarely be paid for, so rebalancing may cost more than it saves. The same imbalance where change actually lands is where the model raises the alarm. Low volatility neutralises an imbalance; high volatility sharpens it. Severity therefore follows from imbalance *and* volatility, never from structure alone, and a low-volatility imbalance is recorded as architectural debt rather than blocking a merge. + +The guiding heuristic is **few critical findings beat many minor ones**: a report that flags everything flags nothing. + +## Where the verdict lands + +`/pair-capability-assess-coupling` applies the model in two modes: + +- **`$scope: diff`** — verdict on the integrations a change touches, feeding the **coupling-balance dimension** of the classification matrix (see [Quality Model](/docs/reference/quality-model)). Like every other dimension, it can only raise the risk tier, never lower one already raised. +- **`$scope: full`** — audit of the whole codebase, producing a prioritised triage plus a tech-debt handoff for the imbalances worth paying down. + +Coupling balance is computed as part of classification; it is projected as its own tag only if a project chooses to expose it — `risk:*` is the sole tag family enabled by default. + +## Related + +- [Quality Model](/docs/reference/quality-model) — how the coupling-balance dimension composes with the other classification dimensions, tiers, and tags +- [Skills Catalog](/docs/reference/skills-catalog) — `assess-coupling` and `assess-architecture` commands and composition +- [Guidelines & How-To Catalog](/docs/reference/guidelines-catalog) — the Design Patterns category this model belongs to diff --git a/apps/website/content/docs/reference/guidelines-catalog.mdx b/apps/website/content/docs/reference/guidelines-catalog.mdx index 6299780b..53299c84 100644 --- a/apps/website/content/docs/reference/guidelines-catalog.mdx +++ b/apps/website/content/docs/reference/guidelines-catalog.mdx @@ -43,7 +43,7 @@ Patterns, decisions, and constraints for system design. | --- | --- | | **Architectural Patterns** | Clean architecture, hexagonal, CQRS, event sourcing, layered, CRUD, transaction script | | **Decision Frameworks** | ADR process, decision tracking | -| **Design Patterns** | DDD patterns, bounded contexts, aggregates, context map inline-maintenance | +| **Design Patterns** | DDD patterns, bounded contexts, aggregates, context map inline-maintenance, [coupling balance](/docs/reference/coupling-model) | | **Deployment Architectures** | Service topologies, scaling patterns | | **LLM Integration** | AI/LLM integration patterns | | **Project Constraints** | Budget, timeline, compliance constraints | @@ -158,7 +158,7 @@ Design systems, research, and content strategy. ## Related - [Quality Model](/docs/reference/quality-model) — the single source of default quality rules (classification, tiers, tags) -- [Skills Catalog](/docs/reference/skills-catalog) — all 39 pair skills with commands and composition +- [Skills Catalog](/docs/reference/skills-catalog) — all 40 pair skills with commands and composition - [Process Lifecycle](/docs/developer-journey) — step-by-step walkthrough of the full process - [KB Structure](/docs/reference/kb-structure) — directory layout and file purposes - [Customize for Your Team](/docs/customization/team) — override guidelines via adoption files diff --git a/apps/website/content/docs/reference/index.mdx b/apps/website/content/docs/reference/index.mdx index 1a04f4e2..ec5354bf 100644 --- a/apps/website/content/docs/reference/index.mdx +++ b/apps/website/content/docs/reference/index.mdx @@ -20,6 +20,7 @@ Look-up material: complete, factual, no narrative. Come here when you know what - [KB Structure](/docs/reference/kb-structure) — Directory layout and file purposes of `.pair/` - [Configuration](/docs/reference/configuration) — `config.json` options - [Quality Model](/docs/reference/quality-model) — Default quality rules, tiers, and tags +- [Coupling Model](/docs/reference/coupling-model) — The three dimensions and the balance rule behind the coupling dimension - [Skill Management](/docs/reference/skill-management) — How skills are resolved, transformed, and installed ## Specs diff --git a/apps/website/content/docs/reference/kb-structure.mdx b/apps/website/content/docs/reference/kb-structure.mdx index fbb280dc..0e41c6b6 100644 --- a/apps/website/content/docs/reference/kb-structure.mdx +++ b/apps/website/content/docs/reference/kb-structure.mdx @@ -121,7 +121,7 @@ Neither subdirectory is scaffolded by `pair install` — a skill creates them on - [Customize the Knowledge Base](/docs/customization/team) — How to override guidelines - [Configuration Reference](/docs/reference/configuration) — config.json options -- [Skills Catalog](/docs/reference/skills-catalog) — All 39 pair skills +- [Skills Catalog](/docs/reference/skills-catalog) — All 40 pair skills - [llms.txt](/docs/concepts/llms-txt) — How pair makes docs and project context consumable by AI assistants - [knowledge-hub README](https://github.com/foomakers/pair/blob/main/packages/knowledge-hub/README.md) — KB package operations, scripts, and maintainer guide - [content-ops README](https://github.com/foomakers/pair/blob/main/packages/content-ops/README.md) — File operations API, copy behaviors, and transform configuration diff --git a/apps/website/content/docs/reference/meta.json b/apps/website/content/docs/reference/meta.json index ca2234dc..b759f4c5 100644 --- a/apps/website/content/docs/reference/meta.json +++ b/apps/website/content/docs/reference/meta.json @@ -7,6 +7,7 @@ "pair-next", "guidelines-catalog", "quality-model", + "coupling-model", "skill-management", "kb-structure", "configuration" diff --git a/apps/website/content/docs/reference/quality-model.mdx b/apps/website/content/docs/reference/quality-model.mdx index 12d73062..3db2d7f6 100644 --- a/apps/website/content/docs/reference/quality-model.mdx +++ b/apps/website/content/docs/reference/quality-model.mdx @@ -29,7 +29,7 @@ Every quality theme nests under one of these three pillars, pointing at its exis ## Classification & Tiers -The compiled matrix has one row per dimension: service/domain criticality, change/diff risk, business impact, security relevance, and coupling balance. Each resolves to green/yellow/red; the **risk tier is the max across assessed dimensions** and is never lowered once raised by review. Cost is tracked separately as its own class, always computed and written to the matrix — it's projected as the `cost:green|yellow|orange|red` tag only if a project chooses to expose it (see Tag Projection below). +The compiled matrix has one row per dimension: service/domain criticality, change/diff risk, business impact, security relevance, and [coupling balance](/docs/reference/coupling-model). Each resolves to green/yellow/red; the **risk tier is the max across assessed dimensions** and is never lowered once raised by review. Cost is tracked separately as its own class, always computed and written to the matrix — it's projected as the `cost:green|yellow|orange|red` tag only if a project chooses to expose it (see Tag Projection below). | Tier | Merge | Reviewers | SLA | Approval | | --- | --- | --- | --- | --- | diff --git a/apps/website/content/docs/reference/skill-management.mdx b/apps/website/content/docs/reference/skill-management.mdx index eacddd57..96512743 100644 --- a/apps/website/content/docs/reference/skill-management.mdx +++ b/apps/website/content/docs/reference/skill-management.mdx @@ -267,6 +267,6 @@ No code change is required in `apps/pair-cli` — the `skills` registry (`config ## Related -- [Skills Catalog](/docs/reference/skills-catalog) — All 39 pair skills +- [Skills Catalog](/docs/reference/skills-catalog) — All 40 pair skills - [Configuration Reference](/docs/reference/configuration) — config.json registry settings - [KB Structure Reference](/docs/reference/kb-structure) — Directory layout diff --git a/apps/website/content/docs/reference/skills-catalog.mdx b/apps/website/content/docs/reference/skills-catalog.mdx index ed35472e..d51eac6a 100644 --- a/apps/website/content/docs/reference/skills-catalog.mdx +++ b/apps/website/content/docs/reference/skills-catalog.mdx @@ -1,17 +1,17 @@ --- title: Skills Catalog -description: Complete catalog of all 39 pair skills organized by type — process, capability, and meta. +description: Complete catalog of all 40 pair skills organized by type — process, capability, and meta. --- -pair ships with 39 skills organized into three types: **process** (workflow orchestration), **capability** (atomic operations), and **meta** (navigation). Each skill is a `SKILL.md` file invoked as a slash command by your AI coding assistant. +pair ships with 40 skills organized into three types: **process** (workflow orchestration), **capability** (atomic operations), and **meta** (navigation). Each skill is a `SKILL.md` file invoked as a slash command by your AI coding assistant. -> **Last updated:** 2026-07-19. Source: `packages/knowledge-hub/dataset/.skills/` +> **Last updated:** 2026-07-24. Source: `packages/knowledge-hub/dataset/.skills/` ## Meta Skills | Skill | Command | Description | | ----- | ------- | ----------- | -| **next** | `/pair-next` | Determines the most relevant next action by reading adoption files and PM tool state. Suggests which skill to invoke. | +| **next** | `/pair-next` | Determines the most relevant next action for your project by reading adoption files and PM tool state. | ## Process Skills @@ -20,14 +20,14 @@ Process skills orchestrate multi-step workflows by composing capability skills. | Skill | Command | Description | Composes | | ----- | ------- | ----------- | -------- | | **specify-prd** | `/pair-process-specify-prd` | Creates or updates a Product Requirements Document through structured template analysis and iterative review — drafting a new PRD, or filling in a missing/outdated section. | — | -| **bootstrap** | `/pair-process-bootstrap` | Orchestrates full project setup — PRD verification, categorization, checklist, standards, quality gates, PM tool — for a brand-new project, end to end. | `/pair-process-specify-prd`, `/pair-capability-setup-pm`, `/pair-capability-record-decision`, assess-* (optional) | +| **bootstrap** | `/pair-process-bootstrap` | Orchestrates full project setup — PRD verification, project categorization, checklist, standards, quality gates, PM tool — for a brand-new project, end to end. | `/pair-process-specify-prd`, `/pair-capability-setup-pm`, `/pair-capability-record-decision`, assess-* (optional) | | **plan-initiatives** | `/pair-process-plan-initiatives` | Turns a PRD into prioritized (P0/P1/P2) strategic initiatives through structured analysis and validation. | `/pair-capability-write-issue` | -| **plan-epics** | `/pair-process-plan-epics` | Breaks a strategic initiative into epics — each delivering end-to-end value in 2-4 sprints. Not for filing a single epic issue from text you already wrote (that's write-issue directly). | `/pair-capability-write-issue` | +| **plan-epics** | `/pair-process-plan-epics` | Breaks a strategic initiative into epics — each delivering end-to-end value in 2-4 sprints — through structured analysis and validation. | `/pair-capability-write-issue` | | **plan-stories** | `/pair-process-plan-stories` | Slices an epic into user stories via vertical slicing and INVEST validation, each sized for one sprint. | `/pair-capability-write-issue` | -| **refine-story** | `/pair-process-refine-story` | Refines a user story from Draft to Ready — the single Draft→Ready path (D24): phase 0 grill(sync), Given-When-Then acceptance criteria, map-subdomains/map-contexts scoped analysis, classify matrix, sprint readiness. Not for sizing an already-refined story (use estimate). | `/pair-capability-grill`, `/pair-capability-write-issue`; `/pair-capability-map-subdomains`, `/pair-capability-map-contexts`, `/pair-capability-classify` (optional) | -| **plan-tasks** | `/pair-process-plan-tasks` | Breaks a refined user story into implementation tasks — checklist, dependency graph, AC-coverage table — added to the story body; no separate task issues. | `/pair-capability-write-issue` | -| **implement** | `/pair-process-implement` | Implements a refined user story task-by-task via a 5-step cycle per task (context, branch, implementation, quality, commit); at the closing phase it writes a checkpoint and publishes one PR through a handoff-only subagent, resuming from the checkpoint when re-invoked on an interrupted story. | `/pair-capability-verify-quality`, `/pair-capability-record-decision`, `/pair-capability-checkpoint`, `/pair-capability-publish-pr` | -| **review** | `/pair-process-review` | Reviews a pull request through 6 sequential phases (5 review + optional merge with parent cascade) to decide whether it merges. Not a quick build/test sanity check (use verify-quality). | `/pair-capability-classify`, `/pair-capability-verify-quality`, `/pair-capability-verify-done`, `/pair-capability-record-decision`, `/pair-capability-analyze-debt`, `/pair-capability-assess-security` (required); `/pair-capability-verify-adoption`, `/pair-capability-assess-stack`, `/pair-capability-execute-manual-tests` (optional) | +| **refine-story** | `/pair-process-refine-story` | Refines a user story from Draft to Ready — the single Draft→Ready path (D24): phase 0 grill(sync), Given-When-Then acceptance criteria, map-subdomains/map-contexts scoped analysis, classify matrix, sprint readiness. | `/pair-capability-grill`, `/pair-capability-write-issue`; `/pair-capability-map-subdomains`, `/pair-capability-map-contexts`, `/pair-capability-classify` (optional) | +| **plan-tasks** | `/pair-process-plan-tasks` | Breaks a refined user story into implementation tasks — checklist, dependency graph, AC-coverage table — added to the story body; no separate task issues are created. | `/pair-capability-write-issue` | +| **implement** | `/pair-process-implement` | Implements a refined user story task-by-task, via a 5-step cycle per task (context, branch, implementation, quality, commit). | `/pair-capability-verify-quality`, `/pair-capability-record-decision`, `/pair-capability-checkpoint`, `/pair-capability-publish-pr` | +| **review** | `/pair-process-review` | Reviews a pull request through 6 sequential phases (5 review + optional merge with parent cascade) — validation, technical review, adoption compliance, completeness, decision — to decide whether it merges. | `/pair-capability-classify`, `/pair-capability-verify-quality`, `/pair-capability-verify-done`, `/pair-capability-record-decision`, `/pair-capability-analyze-debt`, `/pair-capability-assess-security` (required); `/pair-capability-verify-adoption`, `/pair-capability-assess-stack`, `/pair-capability-execute-manual-tests` (optional) | ## Capability Skills @@ -37,8 +37,8 @@ Capability skills are atomic operations invoked independently or composed by pro | Skill | Command | Description | | ----- | ------- | ----------- | -| **map-subdomains** | `/pair-capability-map-subdomains` | Classifies business capabilities into DDD subdomains (core, supporting, generic) with a volatility rating, scoped to items just touched. Composed by `/pair-process-refine-story`, `/pair-process-plan-initiatives`, `/pair-process-plan-epics`; full-scope re-mapping only via `/pair-process-bootstrap`. | -| **map-contexts** | `/pair-capability-map-contexts` | Maps subdomains to DDD bounded contexts and derives the integration pattern between them (integration strength, socio-technical distance, volatility), scoped to items just touched. Composed by `/pair-process-refine-story`, `/pair-process-plan-tasks`; full-scope re-mapping only via `/pair-process-bootstrap`. | +| **map-subdomains** | `/pair-capability-map-subdomains` | Classifies business capabilities into DDD subdomains (core, supporting, generic) with a volatility rating, scoped to items just touched. | +| **map-contexts** | `/pair-capability-map-contexts` | Maps subdomains to DDD bounded contexts and derives the integration pattern between them (integration strength, socio-technical distance, volatility), scoped to items just touched. | Reclassified from process skills — see [Migration Notes](/docs/reference/skill-management#migration-notes). @@ -48,16 +48,17 @@ All `assess-*` skills are **output-only**: they produce a proposal (rendered ado | Skill | Command | Description | | ----- | ------- | ----------- | -| **assess-ai** | `/pair-capability-assess-ai` | Evaluates and recommends AI development tools — coding assistants, agent frameworks, MCP integrations, models — when the choice is open. Output-only; caller persists via `/pair-capability-record-decision`. | -| **assess-architecture** | `/pair-capability-assess-architecture` | Evaluates and recommends an architecture pattern (layered, hexagonal, microservices, etc.) when the choice is open. Output-only; caller persists via `/pair-capability-record-decision`. | -| **assess-cost** | `/pair-capability-assess-cost` | Assesses cost class (green/yellow/orange/red) against the multi-provider cost-signal catalog — composed by `/pair-process-review` to feed the classification matrix's cost dimension. Output-only, never blocks. | -| **assess-infrastructure** | `/pair-capability-assess-infrastructure` | Evaluates and recommends infrastructure strategy — cloud, CI/CD, deployment, IaC, environments — when the choice is open. Output-only; caller persists via `/pair-capability-record-decision`. | -| **assess-methodology** | `/pair-capability-assess-methodology` | Evaluates and recommends the development methodology (Scrum, Kanban, Lean, etc.) — iterations, ceremonies, flow — when the choice is open. Output-only; caller persists via `/pair-capability-record-decision`. | -| **assess-observability** | `/pair-capability-assess-observability` | Evaluates and recommends the observability strategy — monitoring, logging, tracing, alerting, telemetry — when the choice is open. Output-only; caller persists via `/pair-capability-record-decision`. | -| **assess-pm** | `/pair-capability-assess-pm` | Evaluates and recommends which PM tool fits, when the choice is still open — proposes, doesn't configure. `/pair-capability-setup-pm` configures the tool once picked; otherwise the caller persists via `/pair-capability-record-decision`. | -| **assess-stack** | `/pair-capability-assess-stack` | Evaluates and recommends the tech stack when the choice is open: full evaluation at bootstrap, or a single new dependency during implementation. Doesn't audit code already written (that's verify-adoption). Output-only; caller persists via `/pair-capability-record-decision`. | -| **assess-testing** | `/pair-capability-assess-testing` | Evaluates and recommends the testing strategy — framework, pyramid distribution, coverage targets — when the choice is open. Doesn't write tests itself. Output-only; caller persists via `/pair-capability-record-decision`. | -| **assess-security** | `/pair-capability-assess-security` | Assesses security posture against the KB/adoption rule cascade — `$mode: review` composed by `/pair-process-review` (1-line verdict + collapsed findings feeding the security dimension, D22); `$mode: audit` — one-shot OWASP Top 10 scan, writes a report to `.pair/working/reports/security/`. The one exception to output-only in this table: it writes that report file itself; adoption content still goes through `/pair-capability-record-decision`. Never scans for committed secrets — that's the deterministic CI layer `/pair-capability-setup-gates` provisions (D24). | +| **assess-ai** | `/pair-capability-assess-ai` | Evaluates and recommends AI development tools — coding assistants (Copilot, Claude Code, Cursor), agent frameworks, MCP integrations, models — when the choice is open. | +| **assess-architecture** | `/pair-capability-assess-architecture` | Evaluates and recommends an architecture pattern (layered, hexagonal, microservices, modular monolith, etc.) when the choice is open. | +| **assess-cost** | `/pair-capability-assess-cost` | Classifies the financial exposure of a change as a chromatic cost class (green/yellow/orange/red) at review or on demand, by scanning the diff/story for cost signals against the KB cost-signal catalog resolved through the project's stack/architecture/infrastructure adoption. | +| **assess-coupling** | `/pair-capability-assess-coupling` | Assesses architecture coupling against the three-dimensional model (integration strength x socio-technical distance x volatility + balance rule). | +| **assess-infrastructure** | `/pair-capability-assess-infrastructure` | Evaluates and recommends infrastructure strategy — cloud provider, CI/CD pipeline, deployment pattern, IaC, environments — when the choice is open. | +| **assess-methodology** | `/pair-capability-assess-methodology` | Evaluates and recommends the development methodology (Scrum, Kanban, Lean, SAFe, hybrid) — iterations, ceremonies, flow — when the choice is open. | +| **assess-observability** | `/pair-capability-assess-observability` | Evaluates and recommends the observability strategy — monitoring, logging, tracing, alerting, telemetry — when the choice is open. | +| **assess-pm** | `/pair-capability-assess-pm` | Evaluates and recommends which project management tool fits this project (Jira, Linear, GitHub Projects, etc.) when the choice is still open — proposes a choice, doesn't configure anything. | +| **assess-stack** | `/pair-capability-assess-stack` | Evaluates and recommends the tech stack — languages, frameworks, database, libraries, versions — when the choice is open: full evaluation at bootstrap, a single new dependency during implementation ('should we add Redis', 'is this new dependency consistent with our stack'), or composed by `/pair-process-review` when it finds an unlisted dependency in code. | +| **assess-testing** | `/pair-capability-assess-testing` | Evaluates and recommends the testing strategy — framework, pyramid distribution, coverage targets, TDD approach — when the choice is open. | +| **assess-security** | `/pair-capability-assess-security` | Assesses security posture against resolved rules (KB global + per-service + per-web-app + adoption project rules). | ### Classification Capabilities @@ -65,7 +66,7 @@ All `assess-*` skills are **output-only**: they produce a proposal (rendered ado | Skill | Command | Description | | ----- | ------- | ----------- | -| **classify** | `/pair-capability-classify` | Builds the classification matrix (risk + cost dimensions) by applying the quality model — from the story context in refinement, from the code/diff in review (confirm-or-raise, never lower, D17). Writes the matrix to the card/PR body as 1 line + `
` (D22) and emits chromatic tags (`risk:*`, opt-in `cost:*`) only when `tech/risk-matrix.md` declares the `## Tag Projection`. Deterministic (same input → same matrix). Composed by `/pair-process-refine-story` (`$context: refinement`) and `/pair-process-review` (`$context: review`). | +| **classify** | `/pair-capability-classify` | Builds the classification matrix by applying the quality model (KB default + `tech/risk-matrix.md` adoption delta) — from the story context in refinement, from the code/diff in review (confirm-or-raise, never lower). | ### Analysis Capabilities @@ -73,52 +74,52 @@ All `analyze-*` skills are **output-only report producers**: they analyze and re | Skill | Command | Description | | ----- | ------- | ----------- | -| **analyze-code-quality** | `/pair-capability-analyze-code-quality` | Produces an objective code quality report (complexity, size, coverage, duplication, maintainability). Composed by `/pair-process-review`; invoke directly for a report on demand. Output-only, never blocks. | -| **analyze-debt** | `/pair-capability-analyze-debt` | Produces a technical debt report (code, design, test, documentation, infrastructure), prioritized by impact x effort. Composed by `/pair-process-review`; invoke directly to catalog debt. Output-only, never blocks a PR. | +| **analyze-code-quality** | `/pair-capability-analyze-code-quality` | Produces an objective code quality report — complexity, size, coverage, duplication, maintainability score — for a repo or package, with actionable recommendations. | +| **analyze-debt** | `/pair-capability-analyze-debt` | Produces a technical debt report — categorized items (code, design, test, documentation, infrastructure), prioritized by impact x effort. | ### Verification Capabilities | Skill | Command | Description | | ----- | ------- | ----------- | -| **verify-adoption** | `/pair-capability-verify-adoption` | Detects conformity/non-conformity of already-written code against the project's adopted decisions, for a given scope — a compliance audit, not a new-choice evaluation (that's assess-stack and siblings). Detection-only. | -| **verify-done** | `/pair-capability-verify-done` | Checks a PR or work item against Definition of Done criteria, skipping already-passing criteria. Composed by `/pair-process-review`; invoke directly on demand. | -| **verify-quality** | `/pair-capability-verify-quality` | Checks whether the codebase currently passes its quality gates (lint, tests, type-check, coverage), skipping gates already passing. Composed by `/pair-process-implement`, `/pair-process-review`. | +| **verify-adoption** | `/pair-capability-verify-adoption` | Detects conformity/non-conformity of already-written code and configuration against the project's adopted decisions (architecture, tech-stack, infrastructure, etc.), for a given scope — a compliance audit, not a new-choice evaluation (that's `/pair-capability-assess-stack` and siblings). | +| **verify-done** | `/pair-capability-verify-done` | Checks a PR or work item against Definition of Done criteria (universal + project-specific), skipping already-passing criteria. | +| **verify-quality** | `/pair-capability-verify-quality` | Checks whether the codebase currently passes its quality gates (lint, tests, type-check, coverage) — pass/fail per gate, skipping gates already passing. | ### Setup and Management Capabilities | Skill | Command | Description | | ----- | ------- | ----------- | -| **setup-pm** | `/pair-capability-setup-pm` | Configures the PM tool — creates/wires it up, applies its implementation guide, updates way-of-working — whether already chosen or picked here. Composed by `/pair-process-bootstrap`; delegated to by assess-pm. | -| **setup-gates** | `/pair-capability-setup-gates` | Configures CI/CD quality gates — pipeline config, lint/format packages, husky hooks — for the adopted tech stack. Idempotent. | -| **manage-flags** | `/pair-capability-manage-flags` | Manages a feature flag's lifecycle: creation, activation, deactivation, cleanup. | +| **setup-pm** | `/pair-capability-setup-pm` | Configures the project management tool — creates/wires it up, applies its implementation guide, updates way-of-working, records the decision — whether the tool was already chosen or picked here. | +| **setup-gates** | `/pair-capability-setup-gates` | Configures CI/CD quality gates — pipeline config, shared lint/format packages, husky hooks, the required deterministic secret-scanning job (gitleaks by default, R6.5/D24) — for the adopted tech stack. | +| **manage-flags** | `/pair-capability-manage-flags` | Manages a feature flag's lifecycle — creation, activation, deactivation, cleanup — per the feature-flags guidelines. | ### Quality Assurance Capabilities | Skill | Command | Description | | ----- | ------- | ----------- | -| **design-manual-tests** | `/pair-capability-design-manual-tests` | Designs a manual test suite — critical path files + suite README — for post-release validation. Not for planning the automated-testing approach (use assess-testing). | -| **execute-manual-tests** | `/pair-capability-execute-manual-tests` | Executes a project's manual test suite against released/deployed artifacts, producing a structured PASS/FAIL report per critical path. Not for running the automated suite (use verify-quality). If no suite exists, halts with guidance to run `/pair-capability-design-manual-tests` first. | +| **design-manual-tests** | `/pair-capability-design-manual-tests` | Designs a manual test suite — critical path files + suite README — for post-release validation, by analyzing released artifacts, architecture, and deployment targets. | +| **execute-manual-tests** | `/pair-capability-execute-manual-tests` | Executes a project's manual test suite against released or deployed artifacts, producing a structured PASS/FAIL report per critical path. | ### Recording and Writing Capabilities | Skill | Command | Description | | ----- | ------- | ----------- | -| **record-decision** | `/pair-capability-record-decision` | Records a decision — ADR (architectural), ADL (non-architectural), or DDR (domain) — or an analysis-log entry (`$type: analysis`, written as `Category: Analysis`) for a completed technical analysis, and is the **sole writer** of adoption/context-map files. Invoke directly to record or backfill a decision already made. Composed by `/pair-process-implement`, `/pair-process-review`. | -| **write-issue** | `/pair-capability-write-issue` | Creates or updates an issue in the adopted PM tool from a type-specific template. Supports topical labels (e.g. `tech-debt`) for deliberate backlog promotion. | -| **estimate** | `/pair-capability-estimate` | Estimates story points for a refined user story using the adopted estimation methodology; confirms rather than re-estimating if already sized. | +| **record-decision** | `/pair-capability-record-decision` | Records a decision — ADR (architectural), ADL (non-architectural), DDR (domain, 3-criteria gate), or an analysis-log entry ($type: analysis, written as Category: Analysis, decision-log/) — and is the sole writer of adoption/context-map files. | +| **write-issue** | `/pair-capability-write-issue` | Creates or updates an issue in the adopted PM tool from a type-specific template (bug, story, epic, etc.), including topical labels (e.g. tech-debt) for deliberate promotion. | +| **estimate** | `/pair-capability-estimate` | Estimates story points for a refined user story using the project's adopted estimation methodology; confirms rather than re-estimating if already sized. | ### Discovery Capabilities | Skill | Command | Description | | ----- | ------- | ----------- | -| **grill** | `/pair-capability-grill` | Interviews one question at a time, always with a recommendation, after exploring the KB/codebase first; `sync` mode drives systematic AI-human alignment on a story until shared understanding. Invoke directly to interview on any topic. Write-free — returns the synthesis to the caller. | +| **grill** | `/pair-capability-grill` | Interviews one question at a time, always with a recommendation, after exploring the KB/codebase first; sync mode drives systematic AI-human alignment on a story until shared understanding is confirmed. | ### State and Handoff Capabilities | Skill | Command | Description | | ----- | ------- | ----------- | -| **checkpoint** | `/pair-capability-checkpoint` | Writes and resumes a self-contained progress checkpoint (story, branch, tasks done, decisions, remaining todos) in `.pair/working/checkpoints/`, so work survives a context reset. Invoke directly to save or resume progress. | -| **publish-pr** | `/pair-capability-publish-pr` | Publishes a completed story branch as a pull request: runs the quality gate (HALTs on red), creates or updates ONE PR from the pr-template with conditional sections (Services to Release, Screenshots) filled only when pertinent, copies the story's classification tags, marks it ready-for-review, and updates the board state. Standalone — driven by a handoff/checkpoint; reads the WoW `git-workflow` (base-branch, squash) and `code-host`. Composed by the closing phase of `/pair-process-implement` (invoked in a handoff-only subagent so the PR is built on a clean context); reused by hotfix and automation loops. Never merges. | +| **checkpoint** | `/pair-capability-checkpoint` | Writes and resumes a self-contained progress checkpoint (story, branch, tasks done, decisions, remaining todos) so work survives a context reset. | +| **publish-pr** | `/pair-capability-publish-pr` | Publishes a completed story branch as a pull request: runs the quality gate, creates or updates ONE PR from the pr-template (conditional sections filled only when pertinent), copies the story's classification tags, marks it ready-for-review, and updates the board state. | ## Skill Properties diff --git a/apps/website/lib/docs-staleness-check.test.ts b/apps/website/lib/docs-staleness-check.test.ts index 8966462e..74816347 100644 --- a/apps/website/lib/docs-staleness-check.test.ts +++ b/apps/website/lib/docs-staleness-check.test.ts @@ -10,7 +10,16 @@ import { countHowToGuides, buildValidRoutes, runAllChecks, + deriveSkillCommand, + extractFirstSentence, + transformCommandTokens, + readSkillDescription, + parseCatalogRow, + checkCatalogContent, + generateCatalogRows, } from './docs-staleness-check' +import { join } from 'node:path' +import { readFileSync } from 'node:fs' // White-box unit tests for the docs-staleness gate LOGIC. Exported functions are // tested directly — no spawning of any CLI/script. The thin `tsx` CLI wrapper is @@ -169,9 +178,112 @@ describe('buildValidRoutes', () => { }) describe('runAllChecks (in-process, real docs tree)', () => { - it('reports zero drift and 39 skills against the actual repo', () => { + it('reports zero drift and 40 skills against the actual repo', () => { const { errors, skillCount } = runAllChecks(REPO_ROOT) expect(errors, errors.join('\n')).toHaveLength(0) - expect(skillCount).toBe(39) + expect(skillCount).toBe(40) + }) +}) + +// Check 2c — catalog ROW CONTENT single-sourced from the dataset SKILL.md frontmatter. +describe('deriveSkillCommand', () => { + it('non-meta skill → /pair--', () => { + expect(deriveSkillCommand('process', 'review')).toBe('/pair-process-review') + expect(deriveSkillCommand('capability', 'classify')).toBe('/pair-capability-classify') + }) + it('meta skill (name === category) → /pair-', () => { + expect(deriveSkillCommand('next', 'next')).toBe('/pair-next') + }) +}) + +describe('readSkillDescription', () => { + it('extracts the quoted description scalar from frontmatter', () => { + expect(readSkillDescription('---\nname: x\ndescription: "Hello world."\n---\n# x\n')).toBe( + 'Hello world.', + ) + }) + it('returns empty string when absent', () => { + expect(readSkillDescription('---\nname: x\n---\n')).toBe('') + }) +}) + +describe('extractFirstSentence', () => { + it('cuts at the first sentence-terminating period', () => { + expect(extractFirstSentence('First sentence. Second one.')).toBe('First sentence.') + }) + it('does not cut on known abbreviations (e.g.)', () => { + expect(extractFirstSentence('Uses e.g. this and that. Next.')).toBe('Uses e.g. this and that.') + }) + it('cuts before a $scope/$mode enumeration and ensures a closing period', () => { + expect(extractFirstSentence('Does a thing: `$scope: full` here.')).toBe('Does a thing.') + }) +}) + +describe('transformCommandTokens', () => { + const cmds = new Map([['classify', '/pair-capability-classify']]) + it('backticks + qualifies a bare /command at a word boundary', () => { + expect(transformCommandTokens('Composes /classify here.', cmds)).toBe( + 'Composes `/pair-capability-classify` here.', + ) + }) + it('leaves slash-joined prose (map-a/map-b) intact', () => { + expect(transformCommandTokens('see map-a/map-b flow', cmds)).toBe('see map-a/map-b flow') + }) +}) + +describe('parseCatalogRow', () => { + const catalog = '| **classify** | `/pair-capability-classify` | Applies the model. | — |' + it('parses the command + description cells of a row', () => { + expect(parseCatalogRow(catalog, 'classify')).toEqual({ + command: '/pair-capability-classify', + description: 'Applies the model.', + }) + }) + it('returns null when the skill has no row', () => { + expect(parseCatalogRow(catalog, 'ghost')).toBeNull() + }) +}) + +describe('checkCatalogContent (Check 2c)', () => { + const catalog = '| **classify** | `/pair-capability-classify` | Applies the model. | — |' + it('passes when the row matches the generated truth', () => { + const expected = new Map([ + ['classify', { command: '/pair-capability-classify', description: 'Applies the model.' }], + ]) + expect(checkCatalogContent(expected, catalog)).toEqual([]) + }) + it('flags command drift, naming the skill', () => { + const expected = new Map([ + ['classify', { command: '/pair-capability-classify-X', description: 'Applies the model.' }], + ]) + const errs = checkCatalogContent(expected, catalog) + expect(errs.some(e => e.includes('command drift') && e.includes('classify'))).toBe(true) + }) + it('flags description drift, naming the skill', () => { + const expected = new Map([ + ['classify', { command: '/pair-capability-classify', description: 'Something else.' }], + ]) + const errs = checkCatalogContent(expected, catalog) + expect(errs.some(e => e.includes('description drift') && e.includes('classify'))).toBe(true) + }) + it('skips a skill with no catalog row (checkCatalogSync owns presence)', () => { + const expected = new Map([['ghost', { command: '/pair-ghost', description: 'X.' }]]) + expect(checkCatalogContent(expected, catalog)).toEqual([]) + }) +}) + +describe('generateCatalogRows + committed catalog parity (Check 2c integration)', () => { + const SKILLS_DIR = join(REPO_ROOT, 'packages/knowledge-hub/dataset/.skills') + const CATALOG = join(REPO_ROOT, 'apps/website/content/docs/reference/skills-catalog.mdx') + it('derives a command + non-empty description for every dataset skill', () => { + const rows = generateCatalogRows(SKILLS_DIR) + expect(rows.size).toBe(40) + expect(rows.get('next')?.command).toBe('/pair-next') + for (const [, row] of rows) expect(row.description.length).toBeGreaterThan(0) + }) + it('the committed skills-catalog rows match the dataset-derived truth (no drift)', () => { + const rows = generateCatalogRows(SKILLS_DIR) + const errors = checkCatalogContent(rows, readFileSync(CATALOG, 'utf-8')) + expect(errors, errors.join('\n')).toHaveLength(0) }) }) diff --git a/apps/website/lib/docs-staleness-check.ts b/apps/website/lib/docs-staleness-check.ts index c2889c85..2ca5881e 100644 --- a/apps/website/lib/docs-staleness-check.ts +++ b/apps/website/lib/docs-staleness-check.ts @@ -129,6 +129,164 @@ export function findDeadLinks(content: string, rel: string, validRoutes: Set`; + * every other skill becomes `/pair--`. + */ +export function deriveSkillCommand(category: string, name: string): string { + return name === category ? `/pair-${name}` : `/pair-${category}-${name}` +} + +/** Enumerate every dataset skill as {category, name} (categories × getSkillNames). */ +export function collectSkillEntries(skillsDir: string): SkillEntry[] { + const categories = readdirSync(skillsDir, { withFileTypes: true }).filter(d => d.isDirectory()) + const out: SkillEntry[] = [] + for (const cat of categories) { + for (const name of getSkillNames(join(skillsDir, cat.name))) { + out.push({ category: cat.name, name }) + } + } + return out +} + +/** Absolute path to a skill's SKILL.md (a meta skill lives at the category root). */ +export function skillMdPath(skillsDir: string, entry: SkillEntry): string { + return entry.name === entry.category + ? join(skillsDir, entry.category, 'SKILL.md') + : join(skillsDir, entry.category, entry.name, 'SKILL.md') +} + +/** The quoted `description:` scalar from a SKILL.md's YAML frontmatter (empty if absent). */ +export function readSkillDescription(skillMdContent: string): string { + const m = skillMdContent.match(/^description:\s*"([\s\S]*?)"\s*$/m) + return m?.[1] ?? '' +} + +// Abbreviations whose trailing period does NOT end a sentence ("e.g.", "etc."). +const SENTENCE_ABBREVIATIONS = /(?:e\.g|i\.e|etc|vs|approx)$/i + +/** + * The lead sentence of a frontmatter description, as the catalog renders it. Ends at + * the first sentence-terminating period (one followed by whitespace/EOS, skipping + * known abbreviations and mid-token dots like `.pair/…`), OR — for skills whose lead + * is followed by a `$scope`/`$mode` enumeration ("… rule): `$scope: diff` …") — at + * the `:` that introduces it. A closing period is always ensured. + */ +export function extractFirstSentence(description: string): string { + let cut = description.length + const mode = /:\s(?=`\$)/.exec(description) + if (mode && mode.index + 1 < cut) cut = mode.index + 1 + const period = /\.(?=\s|$)/g + let m: RegExpExecArray | null + while ((m = period.exec(description)) !== null) { + if (SENTENCE_ABBREVIATIONS.test(description.slice(0, m.index))) continue + if (m.index + 1 < cut) cut = m.index + 1 + break + } + const lead = description.slice(0, cut).replace(/:\s*$/, '').trim() + return /[.!?]$/.test(lead) ? lead : `${lead}.` +} + +/** + * Render bare `/short-name` command references as the catalog does — backticked, + * fully-qualified `` `/pair-…` ``. A `/` only starts a command token at a word + * boundary (not after a letter/backtick), so slash-joined prose like + * "map-subdomains/map-contexts" is left intact. + */ +export function transformCommandTokens(text: string, commandByName: Map): string { + return text.replace(/(^|[^\w`])\/([a-z][a-z0-9-]*)/g, (full, pre: string, name: string) => { + const cmd = commandByName.get(name) + return cmd ? `${pre}\`${cmd}\`` : full + }) +} + +/** The catalog Description a skill should have: its frontmatter lead, catalog-rendered. */ +export function deriveCatalogDescription( + frontmatterDescription: string, + commandByName: Map, +): string { + return transformCommandTokens(extractFirstSentence(frontmatterDescription), commandByName) +} + +/** Derive the expected Command + Description for every dataset skill (name → row). */ +export function generateCatalogRows(skillsDir: string): Map { + const entries = collectSkillEntries(skillsDir) + const commandByName = new Map(entries.map(e => [e.name, deriveSkillCommand(e.category, e.name)])) + const rows = new Map() + for (const e of entries) { + const desc = readSkillDescription(readFileSync(skillMdPath(skillsDir, e), 'utf-8')) + rows.set(e.name, { + command: deriveSkillCommand(e.category, e.name), + description: deriveCatalogDescription(desc, commandByName), + }) + } + return rows +} + +/** Parse a skill's Command + Description cells from its catalog table row (null if absent). */ +export function parseCatalogRow( + catalog: string, + skill: string, +): { command: string; description: string } | null { + for (const line of catalog.split('\n')) { + const m = line.match(/^\|\s*\*\*([a-z0-9-]+)\*\*\s*\|/) + if (!m || m[1] !== skill) continue + // `| **skill** | `/cmd` | description | (composes) |` → ['', '**skill**', '`/cmd`', 'desc', …] + const cells = line.split('|').map(c => c.trim()) + return { + command: (cells[2] ?? '').replace(/^`|`$/g, ''), + description: cells[3] ?? '', + } + } + return null +} + +/** + * Check 2c: every catalog row's Command + Description MATCH the dataset-derived truth. + * Presence/absence of rows is checkCatalogSync's job — a skill with no row is skipped + * here (checkCatalogSync already flags it) rather than double-reported. + */ +export function checkCatalogContent(expected: Map, catalog: string): string[] { + const errors: string[] = [] + for (const [skill, exp] of expected) { + const row = parseCatalogRow(catalog, skill) + if (row === null) continue + if (row.command !== exp.command) { + errors.push( + `Catalog command drift for "${skill}": expected \`${exp.command}\` but catalog has \`${row.command}\``, + ) + } + if (row.description !== exp.description) { + errors.push( + `Catalog description drift for "${skill}": expected "${exp.description}" but catalog has "${row.description}"`, + ) + } + } + return errors +} + /** Check 2: catalog lists every skill dir, and no catalog row lacks a dir (both directions). */ export function checkCatalogSync(allSkills: string[], catalog: string): string[] { const errors: string[] = [] @@ -252,7 +410,11 @@ export function runAllChecks(root: string): RunResult { } // Check 2: catalog sync (both directions) - errors.push(...checkCatalogSync(allSkills, readFileSync(CATALOG_FILE, 'utf-8'))) + const catalog = readFileSync(CATALOG_FILE, 'utf-8') + errors.push(...checkCatalogSync(allSkills, catalog)) + + // Check 2c: catalog row CONTENT (Command + Description) single-sourced from the dataset + errors.push(...checkCatalogContent(generateCatalogRows(SKILLS_DIR), catalog)) // Checks 3 & 4: CLI command anchors + tutorial references const cli = checkCliCommands(COMMANDS_DIR, COMMANDS_FILE, TUTORIALS_DIR) diff --git a/packages/knowledge-hub/dataset/.pair/knowledge/getting-started.md b/packages/knowledge-hub/dataset/.pair/knowledge/getting-started.md index 309bd8e7..3646c41f 100644 --- a/packages/knowledge-hub/dataset/.pair/knowledge/getting-started.md +++ b/packages/knowledge-hub/dataset/.pair/knowledge/getting-started.md @@ -79,7 +79,7 @@ Welcome to the AI-Human pairing repository template! This guide provides essenti - **`way-of-working.md`**: Main process documentation – the starting point to understand the full workflow - **`getting-started.md`**: This guide – essential information to get started with the framework -- **`skills-guide.md`**: Full catalog of 39 Agent Skills (9 process + 29 capability + 1 navigator) with composition patterns, adoption file mapping, and usage instructions +- **`skills-guide.md`**: Full catalog of 40 Agent Skills (9 process + 30 capability + 1 navigator) with composition patterns, adoption file mapping, and usage instructions - **`how-to/`**: Step-by-step guides for each development phase and LLM collaboration - Process guides (01-11): Operational documentation for each phase - **`assets/`**: Templates, checklists, and document examples (e.g., PRD, bootstrap checklist) diff --git a/packages/knowledge-hub/dataset/.pair/knowledge/guidelines/architecture/design-patterns/README.md b/packages/knowledge-hub/dataset/.pair/knowledge/guidelines/architecture/design-patterns/README.md index 506e08fa..fbf519c6 100644 --- a/packages/knowledge-hub/dataset/.pair/knowledge/guidelines/architecture/design-patterns/README.md +++ b/packages/knowledge-hub/dataset/.pair/knowledge/guidelines/architecture/design-patterns/README.md @@ -78,6 +78,11 @@ This folder contains guidelines for establishing solid architectural foundations - Lazy, human-approved subdomain context split convention - Loading and conflict-flag instructions for brainstorm/refine sessions +10. **Coupling Balance** (`coupling-balance.md`) + - Three-dimensional coupling model: integration strength × socio-technical distance × volatility + - The balance rule + severity criteria (critical/significant/tolerable) + - DDD-pattern mapping, fractal application, and test implications; criteria source for `assess-coupling` + ## 🔄 Decision Support ### Pattern Selection Decision Tree diff --git a/packages/knowledge-hub/dataset/.pair/knowledge/guidelines/architecture/design-patterns/coupling-balance.md b/packages/knowledge-hub/dataset/.pair/knowledge/guidelines/architecture/design-patterns/coupling-balance.md new file mode 100644 index 00000000..1c7cc706 --- /dev/null +++ b/packages/knowledge-hub/dataset/.pair/knowledge/guidelines/architecture/design-patterns/coupling-balance.md @@ -0,0 +1,201 @@ +# Coupling Balance + +The single home of Pair's coupling model (D37): how to evaluate whether a +relationship between two components is *balanced*, on three dimensions, at every +level of abstraction. Skills reference this file; they never restate the model. + +## Purpose + +Coupling is not a defect to be minimized to zero — a system with no coupling does +nothing. The engineering question is never "is there coupling?" but "is this +coupling **balanced**?". This guideline defines the three dimensions used to answer +that, the balance rule that combines them, the severity a given imbalance carries, +and how the model maps onto the DDD patterns already in this knowledge base. It is +the criteria source for the `assess-coupling` skill (diff review + full audit) and a +reading input to `assess-architecture`. + +## The Three Dimensions + +Every coupling relationship is characterised on **all three** dimensions. A verdict +that rests on fewer than three is not a coupling verdict — it is a structural guess, +and this model rejects it. + +### 1. Integration Strength — how much two components must know about each other + +Strength measures the *amount of shared knowledge* a relationship carries: the more +one component must understand about the internals of the other to work with it, the +stronger the coupling. Four levels, from strongest to weakest: + +| Level | Shared knowledge | Example | +| --- | --- | --- | +| **Intrusive** (strongest) | Private internals: reaching past the public surface into implementation detail | reading another module's database tables directly; depending on a private field or an undocumented side effect | +| **Functional** | Shared behavioural expectations: a caller relies on *how* the other fulfils a responsibility, not only *what* it exposes | duplicated business rules kept in sync by hand; a consumer that re-implements the producer's validation | +| **Model** | A shared data model / shared types: both sides bind to the same representation of a concept | a common DTO or schema imported by both; a shared entity passed across a boundary | +| **Contract** (weakest) | Only a published contract: a stable interface, event shape, or protocol, with internals hidden on both sides | calling a versioned API; consuming a documented event; depending on an interface, not an implementation | + +Stronger integration means a change on one side is more likely to force a change on +the other. Strength is the dimension a rebalancing usually targets: introducing a +contract *reduces* strength without moving the components. + +### 2. Socio-technical Distance — the cost of co-evolving the two components + +Distance measures how expensive it is to change both sides **together**. It is +socio-technical because the cost is not only in the code: + +- **Code-structure distance** — same function / same module / same package / same + deployable / separate deployables. The further apart in the structure, the more + coordination a joint change needs. +- **Team distance** — same author / same team / different teams / different + organisations. Crossing a team boundary turns a code change into a negotiation. +- **Runtime distance** — in-process call / same process boundary / network hop / + asynchronous exchange. The further apart at runtime, the harder atomic change and + the more failure modes a joint change must survive. + +Distance is the dimension a rebalancing targets when it *co-locates*: moving the two +sides closer (same module, same team) lowers the cost of the changes they force on +each other. Decomposition does the opposite — it **raises** distance. + +### 3. Volatility — how likely the relationship is to change + +Volatility is the probability that the coupled behaviour will actually change. It is +evaluated **from the business domain, never from commit history alone** — a file +that churned last month is not thereby volatile, and a quiet file in a core +subdomain is not thereby stable. Two kinds: + +- **Essential volatility** — inherent to the domain: core, differentiating + capabilities change as the business learns. Sourced from subdomain classification + (see [strategic-subdomain-definition.md](strategic-subdomain-definition.md)): + **core → high**, **supporting → medium**, **generic → low**. +- **Accidental volatility** — a generic capability whose *implementation* is + provider- or fashion-dependent (a payment SDK, a UI framework) can be volatile even + though the capability is generic. Flag it explicitly as accidental so the + rebalancing targets the implementation seam, not the capability. + +Commit frequency is at most a weak corroborating signal and is never, on its own, +evidence of volatility. + +## The Balance Rule + +Combine strength and distance first, then let volatility set the stakes. + +- **Balanced**: strength and distance move together in *opposite* directions — high + strength with low distance (tightly-related things kept close), or low strength + with high distance (loosely-related things kept apart). Both are healthy. +- **Unbalanced — high strength + high distance**: the pathological case. + Tightly-coupled components that are expensive to change together produce + **cascading, expensive changes**: every modification ripples across the boundary + that was meant to contain it. This is the imbalance that hurts most. +- **Unbalanced — low strength + low distance**: **low cohesion**. Things that barely + relate are crammed together, so the module has no reason to exist as a unit and + changes for unrelated reasons. + +**Volatility is the multiplier.** An imbalance in a **stable** relationship is +tolerable — it will rarely be paid for, so rebalancing may cost more than it saves. +The same imbalance in a **volatile** relationship is where change actually lands, and +is where the model raises the alarm. **Low volatility neutralises an imbalance;** +high volatility sharpens it. + +## Severity + +Severity is a function of the imbalance *and* its volatility — never of structure +alone: + +| Severity | Condition | +| --- | --- | +| **Critical** | Unbalanced **and** high volatility — the imbalance sits exactly where change lands. | +| **Significant** | Unbalanced and moderate volatility; **or** implicit shared knowledge regardless of stated volatility — duplicated business rules, access to another component's private interface/tables (intrusive/functional strength that hides as if it were a contract). | +| **Tolerable** | Unbalanced and low volatility — recorded as architectural debt, **never blocks** a merge. | + +The guiding heuristic is **few critical findings beat many minor ones**: a report +that flags everything flags nothing. Only unbalanced-and-volatile relationships earn +*attention* — the critical/significant findings that feed the merge decision. An +imbalance neutralised by low volatility does **not** vanish: it is **retained as a +tolerable finding** and surfaced as architectural debt — never dropped, never +blocking. What is genuinely *not a finding* is a **balanced** relationship, or any +score resting on fewer than three dimensions. + +## Rebalancing — always two-dimensional + +A rebalancing proposal names the dimension it moves and why. There is **no valid +single-word "decouple" recommendation**: + +- **Reduce strength** — introduce a contract (interface, published event, API + version, anti-corruption layer) so the two sides stop sharing internals. This is + the default move when the components genuinely belong apart. +- **Reduce distance** — co-locate: move the two sides into the same module / team / + process so a joint change is cheap. The right move when the coupling is essential + and the split was accidental. + +**Decomposition is not free: splitting components raises distance.** Recommending +"decouple" (i.e. split) is only sound when strength is already low enough that the +higher distance stays balanced. Proposing a split on a high-strength relationship +just converts a *cascading-change* imbalance into a *distributed cascading-change* +imbalance — strictly worse. When strength is high, reduce strength first. + +## Fractal Application + +The model applies at **every level of abstraction**, and distance is always relative +to the level under analysis: + +- functions within a module, +- modules within a package, +- packages within a deployable, +- deployables within a system. + +A cross-module imbalance counts even inside a single deployable: "it all ships +together" does not make two tightly-coupled, distant-in-structure modules balanced. +Evaluate the relationship at the level where the change actually crosses a boundary. + +## Mapping to DDD Patterns + +The strategic DDD patterns already in this knowledge base are *instances* of +rebalancing moves — this model is the why behind them: + +- **[Bounded contexts](bounded-contexts.md)** partition the model so a change stays + inside one context: a distance boundary drawn where volatility differs. +- **Anticorruption layer** is a strength reducer: the downstream context refuses the + upstream model and translates at the seam, turning model/functional coupling into + contract coupling. +- **Open-host service / published language** lowers strength for *many* downstream + consumers at once — one stable contract instead of N model bindings. +- **Aggregates** keep high-strength, high-volatility invariants inside a single + consistency boundary — low distance where strength must stay high. +- **Conformist / shared kernel** are the deliberately-accepted high-strength + relationships; the model says they are only safe when distance is low (same team, + minimal shared surface) and are re-examined the moment volatility rises. + +See [integration-patterns.md](integration-patterns.md) for the communication +mechanics and [context-map-maintenance.md](context-map-maintenance.md) for keeping +the relationship assessment current. + +## Test Implications + +The strength level of a relationship dictates what must be tested at its boundary: + +- **Contract-coupled** relationships imply **integration contract tests** — proof the + published contract is honoured by both sides (the consumer's expectations and the + provider's guarantees stay in agreement) — **and boundary tests** proving + encapsulation holds: nothing beyond the contract leaks across the seam. A leak + silently upgrades the relationship from contract to model/intrusive strength + without anyone deciding to. +- **Model/functional-coupled** relationships need tests that pin the shared model or + duplicated rule, so a drift on one side breaks a test rather than production. +- **Intrusive** coupling is, by definition, untestable at a stable boundary — there + is no boundary — which is itself the finding. + +## Bibliographic Reference + +The three-dimensional framing of coupling as *integration strength × distance × +volatility*, and the balance rule that combines them, is informed by the coupling +model articulated at [coupling.dev](https://coupling.dev). The content of this +guideline — definitions, levels, severity criteria, DDD mapping, and examples — is +Pair's own formulation. + +## Related Documents + +- [Design Patterns README](README.md) — pattern index +- [Strategic Subdomain Definition](strategic-subdomain-definition.md) — subdomain + classification, the source of essential volatility +- [Bounded Contexts](bounded-contexts.md) · [Integration Patterns](integration-patterns.md) + · [Context Map Maintenance](context-map-maintenance.md) — the DDD patterns this + model explains diff --git a/packages/knowledge-hub/dataset/.pair/knowledge/skills-guide.md b/packages/knowledge-hub/dataset/.pair/knowledge/skills-guide.md index 7974b47a..ce475e99 100644 --- a/packages/knowledge-hub/dataset/.pair/knowledge/skills-guide.md +++ b/packages/knowledge-hub/dataset/.pair/knowledge/skills-guide.md @@ -15,9 +15,9 @@ Run `/next` at the start of every session. It reads project adoption files and P | Type | Count | Purpose | |------|-------|---------| | **Process** | 9 | Lifecycle phases — orchestrate capability skills | -| **Capability** | 29 | Atomic units — perform a single focused operation | +| **Capability** | 30 | Atomic units — perform a single focused operation | -Process skills compose capability skills. Capability skills are independently invocable. Total: 39 (9 process + 29 capability + 1 navigator). +Process skills compose capability skills. Capability skills are independently invocable. Total: 40 (9 process + 30 capability + 1 navigator). ## Full Catalog @@ -37,7 +37,7 @@ Process skills compose capability skills. Capability skills are independently in > How-to guides 04 and 05 (subdomain/bounded-context definition) were removed — domain modeling is referenced inline by each real caller's own how-to (02, 03, 06, 09; 08 planned — #242). See [Domain Modeling Skills](#domain-modeling-skills-2) below and [Migration Notes](#migration-notes). -### Capability Skills (29) +### Capability Skills (30) #### Domain Modeling Skills (2) @@ -48,7 +48,7 @@ Process skills compose capability skills. Capability skills are independently in Reclassified from process to capability (D24) — see [Callers Matrix](#callers-matrix-scoped-capabilities) and [Migration Notes](#migration-notes). -#### Assessment Skills (10) +#### Assessment Skills (11) | Skill | Scope | |-------|-------| @@ -62,6 +62,7 @@ Reclassified from process to capability (D24) — see [Callers Matrix](#callers- | `/assess-ai` | AI development tools evaluation | | `/assess-security` | Security posture — review verdict (`$mode: review`, composed by `/review`) + one-shot OWASP Top 10 audit (`$mode: audit`). Unlike the 8 above, not purely output-only — writes its own audit report (D14 exception); never scans for secrets, that's the deterministic CI layer `/setup-gates` provisions (D24) | | `/assess-cost` | Cost exposure — chromatic class (`cost:green\|yellow\|orange\|red`) from the diff/story against the [cost-signal catalog](guidelines/quality-assurance/cost-assessment.md) (general + AWS-first, other providers via adoption links). Output-only: feeds `/classify`'s cost dimension, writes nothing, blocks nothing; report/monitoring mode is a separate slice | +| `/assess-coupling` | Coupling balance — three-dimensional model (integration strength × socio-technical distance × volatility + balance rule) from the [coupling-balance guideline](guidelines/architecture/design-patterns/coupling-balance.md). `$scope: diff` feeds the review Architecture verdict (never blocks); `$scope: full` audits the codebase, flags only unbalanced+volatile integrations, writes a report and hands findings to `/write-issue` for tech-debt. Reads real integration points, never structure alone | #### Classification Skills (1) diff --git a/packages/knowledge-hub/dataset/.pair/knowledge/way-of-working.md b/packages/knowledge-hub/dataset/.pair/knowledge/way-of-working.md index 4a23e1c4..2b5336b3 100644 --- a/packages/knowledge-hub/dataset/.pair/knowledge/way-of-working.md +++ b/packages/knowledge-hub/dataset/.pair/knowledge/way-of-working.md @@ -78,4 +78,4 @@ The process is designed to: 2. **🤖🤝👨‍💻 Code Review** (`/review`) → Structured review with adoption compliance, merge flow, and parent cascade 3. **🤖⚡ Status Update** → Automatic story/epic/initiative tracking update (handled by `/implement` and `/review`) -> **Skill-enabled workflow**: Run `/next` at session start to determine the most relevant skill. See [skills-guide.md](skills-guide.md) for the full catalog of 39 skills. +> **Skill-enabled workflow**: Run `/next` at session start to determine the most relevant skill. See [skills-guide.md](skills-guide.md) for the full catalog of 40 skills. diff --git a/packages/knowledge-hub/dataset/.skills/capability/assess-architecture/SKILL.md b/packages/knowledge-hub/dataset/.skills/capability/assess-architecture/SKILL.md index 57f121d2..e67c57d4 100644 --- a/packages/knowledge-hub/dataset/.skills/capability/assess-architecture/SKILL.md +++ b/packages/knowledge-hub/dataset/.skills/capability/assess-architecture/SKILL.md @@ -1,7 +1,7 @@ --- name: assess-architecture description: "Evaluates and recommends an architecture pattern (layered, hexagonal, microservices, modular monolith, etc.) when the choice is open. Output-only: emits a proposal + target for /record-decision to persist." -version: 0.5.0 +version: 0.6.0 author: Foomakers --- @@ -42,6 +42,7 @@ Read [resolution cascade](../../../.pair/knowledge/guidelines/technical-standard - [Architecture README](../../../.pair/knowledge/guidelines/architecture/README.md) — decision tree, complexity matrix, selection criteria - [Architectural Patterns](../../../.pair/knowledge/guidelines/architecture/architectural-patterns/README.md) — pattern descriptions and trade-offs - [Project Constraints](../../../.pair/knowledge/guidelines/architecture/project-constraints/README.md) — team, platform, deployment constraints + - [Coupling Balance](../../../.pair/knowledge/guidelines/architecture/design-patterns/coupling-balance.md) — the three-dimensional coupling model (integration strength × distance × volatility + balance rule); its criteria inform pattern scoring in Step 3 (a pattern that lowers strength or aligns distance to volatility scores higher for a volatile, tightly-coupled domain) 2. **Act**: If PRD exists, read [adoption/product/PRD.md](../../../.pair/adoption/product/PRD.md) for project context (team size, scale, compliance). 3. **Verify**: Every file listed in 1-2 above has been read; any that's missing follows [Graceful Degradation](#graceful-degradation) (ask the developer directly) instead of silently proceeding to Step 3. diff --git a/packages/knowledge-hub/dataset/.skills/capability/assess-coupling/SKILL.md b/packages/knowledge-hub/dataset/.skills/capability/assess-coupling/SKILL.md new file mode 100644 index 00000000..3014282a --- /dev/null +++ b/packages/knowledge-hub/dataset/.skills/capability/assess-coupling/SKILL.md @@ -0,0 +1,193 @@ +--- +name: assess-coupling +description: "Assesses architecture coupling against the three-dimensional model (integration strength x socio-technical distance x volatility + balance rule): `$scope: diff` — composed by /review, emits a 1-line Architecture verdict + collapsed findings (D22), critical findings flagged for the merge decision; `$scope: full` — one-shot codebase audit written to .pair/working/reports/architecture/, handing every unbalanced integration (volatile as critical/significant, stable as tolerable) to the caller for tech-debt promotion. Reads real integration points, never structure alone; never a single-dimension decouple. Output-only; the model lives in one guideline (D37)." +version: 0.1.0 +author: Foomakers +--- + +# /assess-coupling — Coupling Balance Assessment + +Assess whether the coupling relationships in a change (or a whole codebase) are +**balanced**, in two scopes — `diff` (per-PR, composed by `/review`) and `full` +(one-shot audit, standalone) — against the model resolved from the +[coupling-balance guideline](../../../.pair/knowledge/guidelines/architecture/design-patterns/coupling-balance.md): +the three dimensions (**integration strength**, **socio-technical distance**, +**volatility**), the **balance rule**, the **severity** criteria, the DDD mapping, +and the test implications. The model lives **only** in that guideline (D37); this +skill applies it and never restates it. + +**Every finding is three-dimensional.** A coupling verdict is computed on all three +dimensions or it is not emitted — a finding grounded in fewer than three (e.g. a +structural dependency count alone) is invalid by construction (guideline "The Three +Dimensions"). The assessment **reads the actual code** — imports, calls, shared data +structures, data access — never the dependency graph's shape alone. + +## Arguments + +| Argument | Required | Description | +| --------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------ | +| `$scope` | No | `diff` — assess only the integration points the PR touches. `full` — audit the whole codebase. Auto-detected: called by `/review` → `diff`; otherwise → `full`. | +| `$area` | No | Full scope only. Package/area to narrow the audit (default: whole codebase). | +| `$output` | No | Full scope only. Directory the audit report is written to. Default: `.pair/working/reports/architecture/` (D14 — report path override). | + +## Model Source (both scopes read this) + +The model is resolved through the standard **Adoption > KB default** layering; the +KB guideline is the sole home of the criteria (D37): + +1. **KB default** — [coupling-balance.md](../../../.pair/knowledge/guidelines/architecture/design-patterns/coupling-balance.md): strength levels (intrusive > functional > model > contract), the distance axes, essential-vs-accidental volatility, the balance rule, severity, DDD mapping, test implications. +2. **Volatility inputs (adoption)** — [adoption/product/subdomain/](../../../.pair/adoption/product/subdomain/) (subdomain classification → essential volatility: core = high, supporting = medium, generic = low) and [adoption/tech/boundedcontext/](../../../.pair/adoption/tech/boundedcontext/) (context boundaries → distance). Read when present; **asked or estimated** when absent (no-DDD degradation, never HALT — consistent with #246). +3. **Project delta (adoption)** — `tech/risk-matrix.md` `## Overrides` may tune severity thresholds; absent ⇒ KB defaults apply completely (D21). + +A missing/malformed adoption file is treated as absent: warn and fall back (never HALT on adoption absence). + +## Algorithm + +### Step 0: Detect Scope + +1. **Check**: Is `$scope` provided? +2. **Skip**: If provided, use it. Proceed to Step 1. +3. **Act**: Auto-detect: invoked with a PR/diff in context (i.e. by `/review`) → `diff`; otherwise → `full`. +4. **Verify**: Scope is set. + +### Step 1: Load the Model + +1. **Act**: Read [coupling-balance.md](../../../.pair/knowledge/guidelines/architecture/design-patterns/coupling-balance.md) (the criteria) and the volatility inputs (Model Source layers 2-3), skipping any adoption file that doesn't exist. +2. **Act**: If the guideline is **missing** (KB not installed), follow [Graceful Degradation](#graceful-degradation) — assess against the three dimensions from first principles and note the reduced basis; do not invent a different model. +3. **Verify**: Model + available volatility inputs loaded. Adoption absence is logged as "volatility asked/estimated", not an error. + +### Step 2: Resolve Integration Points (read the real code) + +1. **Act**: Identify the coupling relationships in the surface: + - `diff` — only the integration points the diff **touches**: new/changed imports, cross-module calls, shared types/DTOs, direct data access across a boundary, duplicated business rules. Never the whole codebase (huge-diff edge case). + - `full` — map integrations between components across `$area` (default: whole codebase). +2. **Act**: For each relationship, read the actual code at both ends — what knowledge is shared, which symbols cross the boundary — never the dependency graph shape alone. +3. **Verify**: Every relationship in scope has its real shared-knowledge surface identified. **Single-module project / no cross-component integration** → no relationships: emit verdict "balanced / not applicable", no noise findings (edge case). + +### Step 3: Score the Three Dimensions + +For each relationship, assign **all three** per the guideline: + +1. **Integration strength** — intrusive / functional / model / contract, from what actually crosses the boundary (private access and duplicated rules are intrusive/functional even when they look incidental). +2. **Socio-technical distance** — code-structure + team + runtime distance, relative to the abstraction level under analysis (fractal: a cross-module imbalance counts even inside one deployable). +3. **Volatility** — essential from subdomain classification (core→high, supporting→medium, generic→low); accidental (provider/fashion-dependent implementation) flagged as such. **Never from commit frequency alone.** No DDD artifact → ask the developer or estimate from the code's business role, and **label the value "estimated"** in the output. + +**Verify**: no relationship carries a partial (< 3 dimensions) score. A partial score is dropped, not emitted. + +### Step 4: Apply the Balance Rule and Severity + +1. **Act**: Apply the **balance rule** exactly as the guideline defines it — resolve the criteria from [The Balance Rule](../../../.pair/knowledge/guidelines/architecture/design-patterns/coupling-balance.md#the-balance-rule) (combine strength and distance; volatility is the multiplier). Do not restate the rule here. +2. **Act**: Assign severity from the guideline's [Severity](../../../.pair/knowledge/guidelines/architecture/design-patterns/coupling-balance.md#severity) table (critical / significant / tolerable) — the sole home of the criteria (D37); this skill applies it, never restates the conditions. +3. **Act**: Rank the findings — unbalanced **and** volatile (critical/significant), plus significant implicit-knowledge findings, earn *attention* and feed the merge decision. An unbalanced-but-low-volatility relationship is **retained as a tolerable finding** for tech-debt promotion — never dropped, never blocking. Only a **balanced** relationship (or a partial <3-dimension score) is **not** a finding ("few critical beat many minor"). +4. **Verify**: every emitted finding is unbalanced on the rule and carries a severity backed by all three dimensions. + +### Step 5: Attach a Rebalancing Proposal (two-dimensional, never "decouple") + +1. **Act**: For each finding, propose a move that names the dimension it changes (guideline "Rebalancing"): **reduce strength** (introduce a contract / ACL / published event) or **reduce distance** (co-locate). Never a bare single-dimension "decouple". +2. **Act**: Decomposition raises distance — only suggest splitting when strength is already low enough to keep the split balanced; on a high-strength relationship, reduce strength first. +3. **Act**: Where relevant, name the test implication (contract-coupled → integration contract test + boundary/encapsulation test). +4. **Verify**: every finding has a grounded, multi-dimensional proposal. + +### Step 6: Route by Scope + +- `$scope = diff` → Step 7 (emit review verdict, write nothing). +- `$scope = full` → Step 8 (write audit report, hand off tech-debt promotion). + +## Diff Scope (per-PR) + +### Step 7: Emit Review Verdict + +1. **Act**: Compute the overall verdict = highest severity among the diff's findings (a balanced diff → "balanced"). Render the 1-line verdict + collapsed `
` findings per Output Format — **output-only, no files written**. The caller (`/review`) embeds it as the **Architecture** verdict-first row (1 line at top, details collapsed, D22). +2. **Act**: If any finding is **critical** → flag it explicitly for the caller: this is the signal `/review` factors into its major/critical severity flow (the merge decision stays `/review`'s — this skill never blocks). A **significant/tolerable** finding in a low-volatility area is reported for **tech-debt promotion**, not blocking (AC2). +3. **Verify**: Verdict emitted; critical findings flagged; nothing written. + +## Full Scope (one-shot audit) + +### Step 8: Write Audit Report + Hand Off Tech-Debt + +1. **Act**: Render the report — the mapped integrations and, flagged, **every unbalanced** one: unbalanced+volatile as critical/significant (attention), unbalanced+low-volatility as **tolerable** (retained, surfaced as tech-debt, never dropped), each with its three-dimensional score, severity, real integration point (file/symbol), and rebalancing proposal. Estimated volatility (no-DDD) is labelled as estimated. +2. **Act**: Create `$output` (default `.pair/working/reports/architecture/`) if absent; write `$output/-coupling-audit.md`. This is a direct write — reports are operational artifacts (D14), the same exception `/assess-security` audit and `/design-manual-tests` use; this skill writes **no adoption content**. +3. **Act**: Assemble a tech-debt promotion tuple **per finding** for the caller to persist via `/write-issue` (topical label `tech-debt`, the #224 pipeline): title, the three-dimensional rationale, severity, rebalancing proposal. This skill **creates no issues itself** — it hands the tuples to the caller. +4. **Verify**: report written at the resolved path; tech-debt tuples assembled for handoff. + +## Output Format + +### Diff Scope + +```text +COUPLING ASSESSMENT (composed by /review — no files written): +├── Scope: Diff +├── Verdict: [balanced | tolerable | significant | critical] — [1-line summary] +├── Findings: [N total — N critical, N significant, N tolerable] +├── Basis: [KB model | + subdomain/boundedcontext adoption | volatility estimated (no DDD)] +└── Feeds: Architecture row of the review report (D22) — critical flags the review decision, never blocks here +``` + +
+N coupling findings + +1. [severity] [component A] ↔ [component B] — strength: [intrusive|functional|model|contract], distance: [low|moderate|high], volatility: [high|medium|low (est?)] — [unbalanced: cascading | low-cohesion] — proposal: [reduce strength: … | reduce distance: …] — test: [contract+boundary | …] +... + +
+ +### Full Scope + +```text +COUPLING AUDIT COMPLETE: +├── Scope: [whole codebase | $area] +├── Mapped: [N integrations] +├── Flagged: [N unbalanced+volatile — N critical, N significant, N tolerable] +├── Report: [.pair/working/reports/architecture/ — written] +├── Tech-debt: [N tuples handed to caller for /write-issue (tech-debt label, #224)] +└── Basis: [KB model | + subdomain/boundedcontext adoption | volatility estimated (no DDD)] +``` + +A single-module / no-cross-component surface renders as `Verdict: balanced — not applicable (no cross-component integration)` with no findings. + +## Composition Interface + +When composed by `/review` (review-time Architecture dimension, step 2.3): + +- **Input**: `/review` invokes `/assess-coupling` with `$scope: diff` against the PR diff. +- **Output**: returns the verdict + collapsed findings (Diff Scope output). `/review` embeds it as the **Architecture** verdict-first row (D22) and, if any finding is critical, factors it into its own major/critical severity flow. **Capability absent** → `/review` renders the row as **"not assessed"** and proceeds (standard graceful degradation) — this skill states the contract; the row/degradation rendering is `/review`'s. +- **Persistence**: none — diff scope writes nothing. + +When composed for full-audit tech-debt promotion: + +- The caller persists each handed-off finding as a tech-debt item via `/write-issue` (topical `tech-debt` label — the #224 pipeline). This skill assembles the tuples; it creates no issues itself. + +When read by `/assess-architecture`: + +- The coupling-balance guideline is a reading input to `/assess-architecture`'s evaluation step — the coupling criteria inform pattern scoring. `/assess-coupling` and `/assess-architecture` share the guideline, not each other's logic. + +When invoked **independently** (`/assess-coupling` on a branch, or `$scope: full`): full one-shot flow; the report (full) or verdict (diff) is returned to the developer. + +> Review-side wiring (listing `/assess-coupling` as a Composed Skill in `/review` step 2.3 and the Architecture row in the review template) is delivered separately (#228). This skill is authored ready-to-compose; nothing here depends on that wiring existing yet. + +## Edge Cases + +- **Huge diff**: assess only the changed integration points, never the whole codebase in diff scope (Step 2.1). +- **No DDD artifacts** (no subdomain/boundedcontext): ask or estimate volatility, label it "estimated", complete the assessment — **never HALT** (consistent with #246 degradation). +- **Capability absent in review**: `/review` renders "not assessed" and proceeds (graceful degradation) — this skill has no say once uninstalled. +- **Single-module project**: no cross-component integrations → verdict "balanced / not applicable", no noise findings. +- **Unbalanced but stable** (low volatility): reported as **tolerable** → tech-debt, never blocks (AC2). +- **Structure-only signal** (a dependency count with no readable shared-knowledge surface): not a finding — a verdict on fewer than three dimensions is invalid (Step 3 verify). + +## Graceful Degradation + +See [graceful degradation](../../../.pair/knowledge/guidelines/technical-standards/ai-development/skill-conventions/graceful-degradation.md) (guideline missing → minimal assessment, ask directly; adoption file missing → run against KB defaults; PM tool unreachable → n/a) for the standard scenarios. Additional cases: + +- **coupling-balance guideline absent** (KB partially installed): assess the three dimensions from first principles and note the reduced basis in the output rather than HALTing — never substitute a different model. +- **`/map-subdomains` / `/map-contexts` not available**: infer volatility from the code's business role and label it estimated; infer boundaries from package structure — do not HALT. +- **`/write-issue` not installed** (full scope): the report (Step 8.2) is still written — it's this skill's own direct write; the tech-debt tuples stand in the report with no persistence path; note this explicitly. + +## Notes + +- **Writes exactly one kind of file itself**: the full-scope audit report under `.pair/working/reports/architecture/` (Step 8.2) — the same D14 exception `/assess-security` audit uses. Adoption content is never self-written; tech-debt items always go through the caller's `/write-issue` composition. +- **Never blocks** — no merge authority; a critical finding is a signal for `/review`, not a gate this skill enforces. +- **Model lives in one guideline** (D37): [coupling-balance.md](../../../.pair/knowledge/guidelines/architecture/design-patterns/coupling-balance.md). This skill references it and never duplicates the strength levels, balance rule, or severity criteria — searching the KB for the model finds it only there. +- **Three dimensions, always**: a finding grounded in fewer than three is invalid; structure alone is never a finding. +- **Never blanket-decouple**: decomposition raises distance, so a split is proposed only when strength is already low enough to keep it balanced. +- **Idempotent** — see [idempotency convention](../../../.pair/knowledge/guidelines/technical-standards/ai-development/skill-conventions/idempotency.md): a fresh verdict is computed every run against the current diff/codebase by design. +- **D22** (1-line verdict + collapsed details): a project-level rendering decision the caller honors; this skill emits in that shape. diff --git a/packages/knowledge-hub/dataset/.skills/next/SKILL.md b/packages/knowledge-hub/dataset/.skills/next/SKILL.md index 18f72ea5..b1a20906 100644 --- a/packages/knowledge-hub/dataset/.skills/next/SKILL.md +++ b/packages/knowledge-hub/dataset/.skills/next/SKILL.md @@ -7,7 +7,7 @@ author: Foomakers # /next — Project Navigator -Analyze project state and recommend the single most relevant next skill to invoke. Covers the full 39-skill catalog across all lifecycle phases. +Analyze project state and recommend the single most relevant next skill to invoke. Covers the full 40-skill catalog across all lifecycle phases. ## Arguments (optional) @@ -37,9 +37,9 @@ Keep only candidate issues that carry the given label. `--filter` takes a **sing The scope is **stateless across steps**. Every run — and every step of a multi-step run — re-queries the PM tool and **re-evaluates** `--root` and `--filter` against the **current** board state. If an issue's tags change between steps (e.g. a review raises `risk:yellow` → `risk:red`), the next step's selection reflects the change immediately. `/next` never reuses a selection computed in a previous step. -## Skill Catalog (39 skills) +## Skill Catalog (40 skills) -The catalog is **derived from the installed corpus**: every skill directory under `.skills/` must appear here — 9 process + 29 capability + `/next` itself = 39. If an installed skill is missing from these tables (or a row names a skill that is not installed), the catalog has drifted: update the tables, the stated counts, and the cascade rows together. +The catalog is **derived from the installed corpus**: every skill directory under `.skills/` must appear here — 9 process + 30 capability + `/next` itself = 40. If an installed skill is missing from these tables (or a row names a skill that is not installed), the catalog has drifted: update the tables, the stated counts, and the cascade rows together. ### Process Skills (9) @@ -55,7 +55,7 @@ The catalog is **derived from the installed corpus**: every skill directory unde | `/implement` | Sprint Execution | Implement story tasks with TDD | | `/review` | Sprint Execution | Review PR through structured phases | -### Capability Skills (29) +### Capability Skills (30) | Skill | Category | Description | | ------------------------ | --------------- | ---------------------------------------------------------------------------- | @@ -81,6 +81,7 @@ The catalog is **derived from the installed corpus**: every skill directory unde | `/assess-observability` | Assessment | Assess observability strategy | | `/assess-security` | Assessment | Assess security posture (review verdict + one-shot audit) | | `/assess-cost` | Assessment | Classify cost exposure (green/yellow/orange/red) at review — output-only | +| `/assess-coupling` | Assessment | Assess coupling balance (strength × distance × volatility) — diff verdict + full audit | | `/analyze-debt` | Analysis | Analyze technical debt with prioritization | | `/analyze-code-quality` | Analysis | Analyze code quality with metrics | | `/estimate` | Planning | Estimate story using adopted methodology | @@ -218,4 +219,4 @@ See [graceful degradation](../../.pair/knowledge/guidelines/technical-standards/ - This skill is read-only: it inspects state but never modifies files or PM tool data. - Row order encodes the tie-break (delivery proximity) — see the **Tie-break** note under the Step 3 table. - Re-run `/next` after completing any skill to get an updated recommendation. -- **Full catalog coverage**: nearly all of the 39 skills can be suggested — process skills via the cascading checks (Steps 2-3), capability skills via targeted checks (row 7 `/checkpoint`, rows 12-16 including `/grill`) or process-skill composition. `/publish-pr` will be reachable via `/implement` once wired (not yet composed), so `/next` cannot surface it today. +- **Full catalog coverage**: nearly all of the 40 skills can be suggested — process skills via the cascading checks (Steps 2-3), capability skills via targeted checks (row 7 `/checkpoint`, rows 12-16 including `/grill`) or process-skill composition. `/publish-pr` will be reachable via `/implement` once wired (not yet composed), so `/next` cannot surface it today. diff --git a/packages/knowledge-hub/src/conformance/assess-cost.test.ts b/packages/knowledge-hub/src/conformance/assess-cost.test.ts index 76c31cfd..6e247ff4 100644 --- a/packages/knowledge-hub/src/conformance/assess-cost.test.ts +++ b/packages/knowledge-hub/src/conformance/assess-cost.test.ts @@ -115,15 +115,15 @@ describe('assess-cost catalog registration (#226)', () => { ['dataset', NEXT_DATASET, SKILLS_GUIDE_DATASET], ['mirror', NEXT_MIRROR, SKILLS_GUIDE_MIRROR], ] as const) { - it(`${label} next catalog lists assess-cost and states 29 capability / 39 total`, () => { + it(`${label} next catalog lists assess-cost and states 30 capability / 40 total`, () => { expect(next).toMatch(/assess-cost/) - expect(next).toContain('29 capability') - expect(next).toContain('39 skills') + expect(next).toContain('30 capability') + expect(next).toContain('40 skills') }) - it(`${label} skills-guide lists assess-cost and states 29 capability / 39 total`, () => { + it(`${label} skills-guide lists assess-cost and states 30 capability / 40 total`, () => { expect(guide).toMatch(/assess-cost/) - expect(guide).toContain('29 capability') + expect(guide).toContain('30 capability') }) } }) diff --git a/packages/knowledge-hub/src/conformance/assess-coupling.test.ts b/packages/knowledge-hub/src/conformance/assess-coupling.test.ts new file mode 100644 index 00000000..f17b917b --- /dev/null +++ b/packages/knowledge-hub/src/conformance/assess-coupling.test.ts @@ -0,0 +1,175 @@ +import { describe, it, expect } from 'vitest' +import { readFileSync, existsSync } from 'fs' +import { join } from 'path' + +// Conformance guard for story #263: pair-capability-assess-coupling assesses +// architecture coupling against the THREE-DIMENSIONAL model (integration strength × +// socio-technical distance × volatility + balance rule). Two scopes: `diff` (composed +// by /review, output-only, 1-line Architecture verdict + collapsed findings, D22, +// never blocks) and `full` (codebase audit — flags only unbalanced+volatile +// integrations, writes a report under .pair/working/reports/architecture/, hands +// findings to /write-issue for tech-debt, #224). The model lives ONLY in the KB +// guideline coupling-balance.md (D37); the skill references it, never restates it. +// Review-side wiring (compose into /review step 2.3 + the Architecture row in the +// review template) lands separately (#228) and is deliberately NOT asserted here. + +const DATASET_SKILLS = join(__dirname, '../../dataset/.skills') +const MIRROR_SKILLS = join(__dirname, '../../../../.claude/skills') +const DATASET_KB = join(__dirname, '../../dataset/.pair/knowledge') +const MIRROR_KB = join(__dirname, '../../../../.pair/knowledge') + +const GUIDELINE_REL = 'guidelines/architecture/design-patterns/coupling-balance.md' + +const SKILL_DATASET = readFileSync( + join(DATASET_SKILLS, 'capability/assess-coupling/SKILL.md'), + 'utf-8', +) +const SKILL_MIRROR = readFileSync( + join(MIRROR_SKILLS, 'pair-capability-assess-coupling/SKILL.md'), + 'utf-8', +) +const GUIDELINE_DATASET = readFileSync(join(DATASET_KB, GUIDELINE_REL), 'utf-8') +const GUIDELINE_MIRROR = readFileSync(join(MIRROR_KB, GUIDELINE_REL), 'utf-8') +const NEXT_DATASET = readFileSync(join(DATASET_SKILLS, 'next/SKILL.md'), 'utf-8') +const NEXT_MIRROR = readFileSync(join(MIRROR_SKILLS, 'pair-next/SKILL.md'), 'utf-8') +const GUIDE_DATASET = readFileSync(join(DATASET_KB, 'skills-guide.md'), 'utf-8') +const GUIDE_MIRROR = readFileSync(join(MIRROR_KB, 'skills-guide.md'), 'utf-8') + +describe('assess-coupling — skill structure (#263)', () => { + for (const [label, content] of [ + ['dataset', SKILL_DATASET], + ['mirror', SKILL_MIRROR], + ] as const) { + it(`${label} declares the $scope: diff | full contract`, () => { + expect(content).toMatch(/\$scope/) + expect(content.toLowerCase()).toContain('diff') + expect(content.toLowerCase()).toContain('full') + }) + + it(`${label} evaluates all three dimensions (a <3 finding is invalid)`, () => { + expect(content.toLowerCase()).toContain('integration strength') + expect(content.toLowerCase()).toContain('distance') + expect(content.toLowerCase()).toContain('volatility') + expect(content.toLowerCase()).toMatch(/fewer than three|all three/) + }) + + it(`${label} keeps the model in the guideline, never in the skill (D37)`, () => { + expect(content).toContain('coupling-balance.md') + expect(content).toContain('D37') + }) + + it(`${label} sources volatility from subdomain classification, never commit history alone`, () => { + expect(content.toLowerCase()).toContain('subdomain') + expect(content.toLowerCase()).toMatch(/commit (frequency|history)/) + }) + + it(`${label} uses the critical/significant/tolerable severity scale; tolerable never blocks`, () => { + expect(content.toLowerCase()).toContain('critical') + expect(content.toLowerCase()).toContain('significant') + expect(content.toLowerCase()).toContain('tolerable') + expect(content.toLowerCase()).toMatch(/never block/) + }) + + it(`${label} never recommends a single-dimension "decouple"`, () => { + expect(content.toLowerCase()).toMatch(/never.*decouple|no.*single-dimension|reduce strength/) + expect(content.toLowerCase()).toContain('decomposition raises distance') + }) + + it(`${label} emits a 1-line verdict + collapsed details (D22) and degrades to "not assessed"`, () => { + expect(content).toContain('D22') + expect(content.toLowerCase()).toContain('
') + expect(content.toLowerCase()).toContain('not assessed') + }) + + it(`${label} degrades on no-DDD (estimate volatility) and never HALTs on adoption absence`, () => { + expect(content.toLowerCase()).toMatch(/estimate/) + expect(content.toLowerCase()).toMatch(/never halt/) + }) + + it(`${label} full scope writes the architecture report + hands off tech-debt via write-issue (#224)`, () => { + expect(content).toContain('.pair/working/reports/architecture/') + expect(content).toContain('write-issue') + expect(content).toContain('#224') + }) + + it(`${label} reads real integration points, never structure alone`, () => { + expect(content.toLowerCase()).toMatch(/never structure alone|structure alone/) + expect(content.toLowerCase()).toContain('imports') + }) + + it(`${label} handles the single-module edge case as balanced / not applicable`, () => { + expect(content.toLowerCase()).toContain('not applicable') + }) + } +}) + +describe('coupling-balance.md — guideline (#263 T1)', () => { + for (const [label, content] of [ + ['dataset', GUIDELINE_DATASET], + ['mirror', GUIDELINE_MIRROR], + ] as const) { + it(`${label} defines the four integration-strength levels`, () => { + for (const level of ['intrusive', 'functional', 'model', 'contract']) { + expect(content.toLowerCase()).toContain(level) + } + }) + + it(`${label} defines socio-technical distance and essential/accidental volatility`, () => { + expect(content.toLowerCase()).toContain('socio-technical distance') + expect(content.toLowerCase()).toContain('essential') + expect(content.toLowerCase()).toContain('accidental') + }) + + it(`${label} states the balance rule (both-high cascading / both-low low-cohesion; volatility neutralises)`, () => { + expect(content.toLowerCase()).toContain('balance rule') + expect(content.toLowerCase()).toMatch(/cascading/) + expect(content.toLowerCase()).toMatch(/low cohesion/) + expect(content.toLowerCase()).toMatch(/neutralis/) + }) + + it(`${label} defines the severity criteria`, () => { + for (const sev of ['critical', 'significant', 'tolerable']) { + expect(content.toLowerCase()).toContain(sev) + } + }) + + it(`${label} maps to DDD patterns (bounded contexts, ACL, open-host, aggregates)`, () => { + expect(content.toLowerCase()).toContain('bounded context') + expect(content.toLowerCase()).toMatch(/anticorruption|anti-corruption/) + expect(content.toLowerCase()).toContain('open-host') + expect(content.toLowerCase()).toContain('aggregate') + }) + + it(`${label} applies fractally and states the test implications (contract + boundary)`, () => { + expect(content.toLowerCase()).toContain('fractal') + expect(content.toLowerCase()).toContain('contract test') + expect(content.toLowerCase()).toMatch(/boundary test|encapsulation/) + }) + + it(`${label} includes the coupling.dev bibliographic reference`, () => { + expect(content.toLowerCase()).toContain('coupling.dev') + }) + } +}) + +describe('assess-coupling catalog registration (#263)', () => { + it('dataset skill directory exists', () => { + expect(existsSync(join(DATASET_SKILLS, 'capability/assess-coupling/SKILL.md'))).toBe(true) + }) + + for (const [label, next, guide] of [ + ['dataset', NEXT_DATASET, GUIDE_DATASET], + ['mirror', NEXT_MIRROR, GUIDE_MIRROR], + ] as const) { + it(`${label} next catalog lists assess-coupling and states 30 capability / 40 total`, () => { + expect(next).toMatch(/assess-coupling/) + expect(next).toContain('30 capability') + expect(next).toContain('40 skills') + }) + + it(`${label} skills-guide lists assess-coupling and states 30 capability / 40 total`, () => { + expect(guide).toMatch(/assess-coupling/) + expect(guide).toContain('30 capability') + }) + } +})