From d6de5a54f5460b29ee0603986bf4c1386e6828da Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 17 Aug 2026 03:55:10 +0000 Subject: [PATCH 1/3] feat(coupling): add coupling plugin with /coupling:reduce skill New maintenance-category plugin for iterative coupling reduction at four altitudes (docs, code, application, repository). The reduce skill scans for change-transmitting dependencies typed against a coupling model (structured-design strength ladder, connascence strength x degree x locality, volatility weighting from co-change history), reproduces every finding behind a hard verification gate, then splits lanes: mechanical behavior-preserving reductions are applied under a scope budget and verified against the project's own build and tests, while cross-file and architectural candidates are surfaced and routed to design lanes, never auto-applied. A repo-scoped ledger (topic-docs memory tier, constant-slug delta) makes successive runs resume instead of restarting. Grounded in melodic-software/standards review and engineering criteria at orientation time (consumer standards win; bundled model is the fallback). Remediation catalog carries an explicit over-abstraction counterweight per mechanism. Registered in the marketplace catalog, cheat sheet, topic-docs implementers table, and dogfooding enabledPlugins. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_016CWMh6HAsgWWi9tLw76hZR --- .claude-plugin/marketplace.json | 6 + .claude/settings.json | 1 + docs/CATALOG.md | 1 + docs/SKILL-CHEAT-SHEET.md | 1 + docs/conventions/topic-docs/README.md | 1 + plugins/coupling/.claude-plugin/plugin.json | 20 ++ plugins/coupling/CHANGELOG.md | 21 ++ plugins/coupling/README.md | 64 +++++++ plugins/coupling/reference/topic-docs.md | 38 ++++ plugins/coupling/skills/reduce/SKILL.md | 181 ++++++++++++++++++ .../coupling/skills/reduce/evals/evals.json | 41 ++++ .../skills/reduce/reference/coupling-model.md | 119 ++++++++++++ .../skills/reduce/reference/ledger.md | 63 ++++++ .../skills/reduce/reference/remediations.md | 89 +++++++++ 14 files changed, 646 insertions(+) create mode 100644 plugins/coupling/.claude-plugin/plugin.json create mode 100644 plugins/coupling/CHANGELOG.md create mode 100644 plugins/coupling/README.md create mode 100644 plugins/coupling/reference/topic-docs.md create mode 100644 plugins/coupling/skills/reduce/SKILL.md create mode 100644 plugins/coupling/skills/reduce/evals/evals.json create mode 100644 plugins/coupling/skills/reduce/reference/coupling-model.md create mode 100644 plugins/coupling/skills/reduce/reference/ledger.md create mode 100644 plugins/coupling/skills/reduce/reference/remediations.md diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index 67b371a73..0eba50b37 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -262,6 +262,12 @@ "category": "maintenance", "tags": ["tidy", "refactoring", "simplify", "boy-scout", "maintenance", "skill"] }, + { + "name": "coupling", + "source": "./plugins/coupling", + "category": "maintenance", + "tags": ["coupling", "cohesion", "decouple", "connascence", "dependency-injection", "refactoring", "skill"] + }, { "name": "session-flow", "source": "./plugins/session-flow", diff --git a/.claude/settings.json b/.claude/settings.json index 84abcd3d8..dc419a8f7 100644 --- a/.claude/settings.json +++ b/.claude/settings.json @@ -38,6 +38,7 @@ "computer-use@melodic-software": true, "context-guard@melodic-software": true, "context7@melodic-software": true, + "coupling@melodic-software": true, "debugging@melodic-software": true, "desktop-notification@melodic-software": true, "discipline@melodic-software": true, diff --git a/docs/CATALOG.md b/docs/CATALOG.md index d6483a250..5be5f708f 100644 --- a/docs/CATALOG.md +++ b/docs/CATALOG.md @@ -66,6 +66,7 @@ plugin manifests and kept in sync by CI — never hand-edit it; the category voc - [`debugging`](../plugins/debugging) — Debug observed failures via a disciplined six-phase loop: build a fast deterministic reproduction signal, reproduce, rank falsifiable hypotheses, instrument, fix with a regression test, then clean up and post-mortem. - [`docs-hygiene`](../plugins/docs-hygiene) — Documentation-hygiene toolkit: compress (flavor-trim markdown with a semantic-diff safety net), audit-noise (classify markdown noise), extract-ssot (deduplicate repeated content into a single source of truth), audit-encapsulation (detect citations into skill-private surfaces), rename-references (sweep stale references after renames), audit-derivability (classify whether a whole document earns its existence — could a fresh agent re-derive it from the code?), and audit-progressive-disclosure (grade instruction files against a load-tier model for split opportunities and hub/spoke disclosure defects). - [`code-tidying`](../plugins/code-tidying) — Code tidying and comment hygiene: /code-tidying:tidy proactively hunts a rotated, glob-scoped lane for Beck-style tidyings under a research-backed scope budget and ships one tight PR; /code-tidying:batch-simplify sweeps recently changed files through grouped, dependency-ordered simplification waves with a never-drop deferred-items contract; /code-tidying:audit-comment-residue is a read-only classifier that flags history, plan, conversational, and ticket/PR residue in code comments for author-applied deletion. Project-specific tidy lanes are scaffolded into a tracked .claude/tidy-lanes/ config folder by a re-runnable setup skill. +- [`coupling`](../plugins/coupling) — Iteratively reduces coupling in any repository at any altitude — documents, code modules, applications, or repositories: scans for change-transmitting dependencies typed against a coupling model (strength ladder, connascence, volatility weighting), verifies every finding, applies a budgeted batch of safe behavior-preserving reductions, and keeps a durable ledger so structural candidates route to design lanes and repeated runs continue where the last stopped. - [`repo-hygiene`](../plugins/repo-hygiene) — Repo hygiene action-router: /repo-hygiene:clean sweeps reclaimable caches, build artifacts, and stale git metadata, and can realign the working tree to a fresh-pull state — dry-run-first, with destructive tiers gated behind explicit confirmation and a session-scoped destructive-command guard. Ecosystem targets are detected at runtime; secrets, runtime dependencies, and skill data are preserved by default. - [`repo-fleet-hygiene`](../plugins/repo-fleet-hygiene) — Cross-repository Git/GitHub fleet discovery, evidence rollup, and a gated apply verb that executes a prior fleet action plan behind one confirmation. Audit stays read-only and confidence-tiered; apply mutates only with --apply plus interactive confirmation or --yes. - [`disk-hygiene`](../plugins/disk-hygiene) — Context-aware disk hygiene for arbitrary directory trees: inventories orphaned and temporary artifacts, classifies evidence into review tiers, and offers exact-path cleanup only after a fresh safety preview and explicit per-tier approval. The target is read-only by default; OS-managed paths, links and mount points, VCS-tracked content without the complete checkout evidence bundle, changed entries, and live-handle uncertainty fail closed. diff --git a/docs/SKILL-CHEAT-SHEET.md b/docs/SKILL-CHEAT-SHEET.md index 3c844520b..937251a85 100644 --- a/docs/SKILL-CHEAT-SHEET.md +++ b/docs/SKILL-CHEAT-SHEET.md @@ -155,6 +155,7 @@ owned by [docs/CATALOG-TAXONOMY.md](CATALOG-TAXONOMY.md). | [`/code-tidying:tidy`](../plugins/code-tidying/skills/tidy/SKILL.md) | `code-tidying` | Proactively hunt one lane for safe structural tidyings and ship a structure-only PR | | [`/codebase-health:audit`](../plugins/codebase-health/skills/audit/SKILL.md) | `codebase-health` | Audit for drift between docs, config, code, and architecture via verified findings | | [`/computer-use:diagnose`](../plugins/computer-use/skills/diagnose/SKILL.md) | `computer-use` | Resolve computer-use capture, input, and screenshot symptoms to a cause | +| [`/coupling:reduce`](../plugins/coupling/skills/reduce/SKILL.md) | `coupling` | Scan for change-transmitting coupling, apply safe reductions in a budgeted batch, route the rest | | [`/discipline:do-your-research`](../plugins/discipline/skills/do-your-research/SKILL.md) | `discipline` | Re-anchor research discipline, then audit and correct the current work | | [`/discipline:do-your-research-deep`](../plugins/discipline/skills/do-your-research-deep/SKILL.md) | `discipline` | Verify every session claim against primary sources in a heavy fan-out | | [`/discipline:follow-our-standards`](../plugins/discipline/skills/follow-our-standards/SKILL.md) | `discipline` | Re-anchor to org engineering standards and audit the work in flight | diff --git a/docs/conventions/topic-docs/README.md b/docs/conventions/topic-docs/README.md index 943914ee2..793a8ef6e 100644 --- a/docs/conventions/topic-docs/README.md +++ b/docs/conventions/topic-docs/README.md @@ -559,6 +559,7 @@ relationship to the contract is fully stated by their table row. | adhd | rendered decision-table HTML view | ephemeral | by reference — the ephemeral row's five rules are its entire relationship | | discovery | `EXPLORE.md`, `RESEARCH.md` | memory | delta doc | | architecture | `deepening-candidates-.md` (per-lens candidate ledgers); deepening HTML report | memory + ephemeral | delta doc | +| coupling | `coupling-ledger.md` (repo-scoped finding ledger, updated in place; constant-slug delta) | memory | delta doc | | planning | `PRD.md`, `PLAN.md` (Brief), `design/`, opt-in brainstorm persist; five optional rendered HTML views (dense-round decision table, PRD pitch, brainstorm reaction page, plan view, design topology) | contract + memory + ephemeral | delta doc | | implementation | `PLAN.md` (Plan/progress), `DEVIATIONS.md`, status summaries | contract + memory | delta doc | | verification | `verification/` manifest; baselines, raw captures | contract + memory | delta doc | diff --git a/plugins/coupling/.claude-plugin/plugin.json b/plugins/coupling/.claude-plugin/plugin.json new file mode 100644 index 000000000..c34f2d112 --- /dev/null +++ b/plugins/coupling/.claude-plugin/plugin.json @@ -0,0 +1,20 @@ +{ + "$schema": "https://json.schemastore.org/claude-code-plugin-manifest.json", + "name": "coupling", + "version": "0.1.0", + "description": "Iteratively reduces coupling in any repository at any altitude — documents, code modules, applications, or repositories: scans for change-transmitting dependencies typed against a coupling model (strength ladder, connascence, volatility weighting), verifies every finding, applies a budgeted batch of safe behavior-preserving reductions, and keeps a durable ledger so structural candidates route to design lanes and repeated runs continue where the last stopped.", + "author": { + "name": "Melodic Software", + "email": "info@melodicsoftware.com" + }, + "license": "MIT", + "keywords": [ + "coupling", + "cohesion", + "decouple", + "connascence", + "dependency-injection", + "refactoring", + "skill" + ] +} diff --git a/plugins/coupling/CHANGELOG.md b/plugins/coupling/CHANGELOG.md new file mode 100644 index 000000000..9340196a0 --- /dev/null +++ b/plugins/coupling/CHANGELOG.md @@ -0,0 +1,21 @@ +# Changelog + +All notable changes to the `coupling` plugin are documented here. Format follows +[Keep a Changelog](https://keepachangelog.com/en/1.1.0/); this plugin uses semantic versioning. + +## [0.1.0] + +### Added + +- `reduce` skill: iterative coupling reduction at four altitudes (docs, code, application, + repository) — model-typed scan with a verification gate, two-lane partition (safe + behavior-preserving reductions applied under a scope budget; cross-file and architectural + candidates surfaced and routed, never auto-applied), and a durable per-repo ledger via the + topic-docs memory tier so successive runs resume instead of restarting. +- `reference/coupling-model.md`: the assessment model — change-centric coupling definition, + structured-design strength ladder, connascence (strength × degree × locality), volatility + weighting, per-altitude mechanisms, and the not-a-finding list. +- `reference/remediations.md`: mechanism catalog (dependency injection, owned interfaces at + volatile boundaries, configuration externalization, events/mediator, single-source-of-truth + pointers, published contracts) with an explicit over-abstraction counterweight per entry. +- Topic-docs binding (`reference/topic-docs.md`) for the repo-scoped coupling ledger. diff --git a/plugins/coupling/README.md b/plugins/coupling/README.md new file mode 100644 index 000000000..a2fe09034 --- /dev/null +++ b/plugins/coupling/README.md @@ -0,0 +1,64 @@ +# coupling + +A Claude Code plugin for iteratively reducing coupling — in any repository, at any altitude. +One skill, one standing question: which dependency here transmits the most unnecessary +change, and what is the smallest mechanism that stops the transmission? Each run takes one +verified, budgeted bite and records the rest, so coupling goes down monotonically across +runs instead of one heroic rewrite. + +| Skill | What it does | +|---|---| +| `/coupling:reduce` | Scan for change-transmitting coupling, verify findings, apply a safe budgeted batch, route structural candidates, and resume from a durable ledger | + +## The model + +Findings are typed, not vibes-based: every one is a directed edge +(`A --(kind, via mechanism)--> B`) classified on the structured-design strength ladder +(content, common, external, control, stamp, data, message) and the connascence axes +(strength × degree × locality), then weighted by volatility — coupling to something that +never changes costs nothing, so co-change evidence from version-control history outranks +static impressions. The same model covers four altitudes: documents (duplicated facts, deep +references), code modules (internals reaching, dependency direction), applications (shared +databases, implicit contracts, temporal coupling), and repositories (copied content, +depending on another repo's internals instead of its releases). + +Two lanes keep the skill honest: + +- **Apply lane** — mechanical, contained, behavior-preserving reductions, applied under a + scope budget and verified against the project's own build and tests. +- **Route lane** — cross-file and architectural findings are surfaced and routed to humans + and design tooling, never auto-applied. + +The remediation catalog carries an explicit counterweight per mechanism: decoupling's own +failure mode is speculative abstraction — an interface with one implementation, an event bus +for a one-to-one call — and the skill is built to refuse it. + +```shell +/coupling:reduce # full pass over an inferred scope +/coupling:reduce src/billing # narrowed to a path +/coupling:reduce dry-run docs # findings and ledger only, no edits +/coupling:reduce status # what is open, applied, routed, and recommended next +``` + +## Consumer conventions + +- **Your standards win.** At orientation the skill discovers the consuming repo's own + review criteria and engineering conventions (a review-criteria file, a conventions or + standards directory, CLAUDE.md rules) and aligns finding vocabulary and severity with + them; the bundled model is the fallback, never an override. +- **Ledger placement** follows the marketplace topic-docs convention — memory tier, default + `.work//coupling-ledger.md`, never committed. Deltas in + [`reference/topic-docs.md`](reference/topic-docs.md). +- **Optional collaborators** (`architecture`, `work-items`, `toolchain`, `source-control`, + `docs-hygiene`) are presence-gated with documented fallbacks; the skill works alone. + +## Install + +```shell +/plugin marketplace add melodic-software/claude-code-plugins +/plugin install coupling@melodic-software +``` + +## License + +MIT diff --git a/plugins/coupling/reference/topic-docs.md b/plugins/coupling/reference/topic-docs.md new file mode 100644 index 000000000..e8831e39e --- /dev/null +++ b/plugins/coupling/reference/topic-docs.md @@ -0,0 +1,38 @@ +# Topic-docs placement — where coupling artifacts land + +How the `reduce` skill resolves the destination for its coupling ledger. + +Implements the topic-docs convention: +. +The contract owns every general rule — tiers, schema, resolution order, slug spec, runtime +guards, no-project-root fallback, non-interactive/forked mode. This document records only +this plugin's deltas. + +## What this plugin writes, per tier + +| Artifact (writer) | Tier | Location (default) | +|---|---|---| +| `coupling-ledger.md` (`/coupling:reduce`) | Memory | `.work//` — never committed | + +Memory tier because the placement questions resolve there: nothing downstream enforces +against the ledger, and it is read again — by the producer itself on the next run (resume is +the skill's whole iteration model) and by the user checking `status` — with that reader +scoped to this checkout. The ledger is a single file updated in place, not a timestamped +file per run: statuses inside it, not filenames, carry run-to-run history. + +## Slug derivation + +Delta from the contract's precedence: an explicit scope argument (slugified per the +contract's form rules) → the constant `coupling`. The branch-name rung is deliberately not +used — coupling reduction is repo-scoped and spans many short-lived branches, and a +branch-derived slug would fragment the one ledger successive runs must resume. Form and +collision rules are the contract's. + +## Guards + +The memory root's self-ignore guard applies on first write (verify-or-create `.gitignore` +with `*`, announced). The contract also defines **invalid roots at which the guard does not +run**; they are enumerated in its +[Runtime guards](https://github.com/melodic-software/claude-code-plugins/blob/main/docs/conventions/topic-docs/README.md#runtime-guards) +section and deliberately not listed here, so this binding cannot drift from them. Create the +topic slice directory when absent. diff --git a/plugins/coupling/skills/reduce/SKILL.md b/plugins/coupling/skills/reduce/SKILL.md new file mode 100644 index 000000000..5da4af3a4 --- /dev/null +++ b/plugins/coupling/skills/reduce/SKILL.md @@ -0,0 +1,181 @@ +--- +description: "Iteratively reduce coupling at any altitude — documents, code modules, applications, or repositories: scan for change-transmitting dependencies typed against a coupling model, verify each finding, apply a budgeted batch of safe behavior-preserving reductions, and ledger structural candidates for design routing so repeated runs continue where the last stopped. Use when: 'reduce coupling', 'decouple', 'loosen coupling', 'too tightly coupled', 'high cohesion low coupling', 'break this dependency', 'dependency injection pass', 'externalize this config', 'connascence', 'coupling scan', 'these files always change together', 'stop copying between repos'. Skip when: reviewing a diff before merge (review tools), deep-designing one already-chosen boundary (/architecture:improve), general structural tidyings with no coupling focus (/code-tidying:tidy), or a docs noise/dedup pass with no cross-artifact coupling angle (docs-hygiene)." +argument-hint: "[ | dry-run [] | status | help]" +user-invocable: true +disable-model-invocation: false +shell: bash +metadata: + workflow-stage: anytime + summary: Scan for change-transmitting coupling, apply safe reductions in a budgeted batch, route the rest +--- + +## Pre-computed context + +Current branch: !`git branch --show-current 2>/dev/null || echo "unknown"` +Recent commits: !`git log --oneline -10 2>/dev/null || echo "no commits"` +Working tree status: !`git status --porcelain 2>/dev/null | head -10 || echo "clean"` + +## Variables + +Arguments: `$ARGUMENTS` + +## Purpose + +Answer one question, repeatedly: **which dependency in this repository transmits the most +unnecessary change, and what is the smallest mechanism that stops the transmission?** Each +invocation is one pass — scan, verify, reduce what is safely reducible within a scope budget, +surface what is not, and record everything in a durable ledger so the next invocation resumes +instead of restarting. Coupling goes down monotonically across runs; no single run tries to +finish the job. + +Two lanes, split by the nature of the finding, never by convenience: + +- **Apply lane** — mechanical, contained, behavior-preserving reductions (weaken a + connascence form, de-duplicate a stated fact into a pointer, inject a hard-wired volatile + collaborator, name a magic value). Applied this run, verified, shipped as one + structure-only change set. +- **Route lane** — cross-file remediation and architectural judgment (move a boundary, + introduce a seam, split a shared database, merge two repos' duplicated logic). Coupling + findings of this shape exist to inform a human: they are surfaced, ranked, and routed — + never auto-applied. + +This is not a diff reviewer, not a designer of one chosen boundary, and not a general tidy +pass — see "What this skill does NOT do". + +## Actions + +| Argument | Action | +|----------|--------| +| *(empty)* | Full pass over an inferred scope: scan → verify → apply lane → route lane → ledger | +| `` | Same pass narrowed to a path, module, or altitude keyword (`docs`, `code`, `app`, `repo`) | +| `dry-run []` | Scan, verify, rank, and ledger only. Do NOT edit, branch, push, or file tracker items | +| `status` | Read the ledger and report open candidates, applied reductions, and what the next run should take | +| `help` | Print this table with one worked example per action | + +## The model + +Hub-and-spoke; read the spoke before the phase that needs it: + +- [`reference/coupling-model.md`](reference/coupling-model.md) — what counts as coupling, the + strength ladder, connascence axes, volatility weighting, per-altitude mechanisms, and the + not-a-finding list. Read before scanning; findings are typed against it. +- [`reference/remediations.md`](reference/remediations.md) — mechanism per finding kind, each + with its over-abstraction counterweight and the sequencing rule (smallest mechanism first). + Read before applying or routing anything. +- [`reference/ledger.md`](reference/ledger.md) — ledger entry schema, status lifecycle, and + re-run semantics. Read at phase A and phase H. + +## Workflow + +Phases run in order; each gate is hard. `dry-run` stops after D (ledger write included). + +**A. Orient.** Resolve scope from the argument, else infer from the conversation, else pick +the hottest area by commit frequency. Resolve the ledger path per this plugin's topic-docs +[binding](../../reference/topic-docs.md) — memory tier, default +`.work//coupling-ledger.md` — and create or resume it. Discover the consuming repo's +own review/engineering conventions (a review-criteria file such as `REVIEW.md`, a +`docs/conventions/` or standards directory, CLAUDE.md rules) and align finding vocabulary and +severity with them; the bundled model is the fallback, never an override of the consumer's +own standards. + +**B. Scan.** Fan out fresh-context Explore subagents over the scope, each briefed with the +coupling model and returning findings in ledger-entry form (edge, kind, mechanism, strength, +degree, locality, evidence). In parallel, mine co-change evidence from version-control +history: file pairs that repeatedly change in the same commits without a declared dependency +are coupled through a channel the import graph cannot see, and they outrank most statically +visible findings. + +**C. Verify (hard gate).** Scan agents have a demonstrated error rate. Reproduce every +finding against the actual artifacts before it reaches the ledger or the user — confirm the +edge exists, the mechanism is what the scan claims, and the depended-on side actually changes +(volatility from history, not vibes). Drop or downgrade what does not reproduce, and record +that the ledger reflects verified state, not raw scan output. + +**D. Partition and rank.** Every verified finding gets a lane. Apply lane requires ALL of: +mechanical, contained in scope, behavior-preserving, and reversible by revert. Anything +cross-file in remediation or architectural in judgment is route lane — when in doubt, route. +Rank by `strength × degree × distance × volatility`; a weak-but-everywhere coupling on a hot +path outranks a strong-but-local one in cold code. Write the full ranked set to the ledger. + +**E. Apply (apply lane only, scope-budgeted).** Work on a short-lived branch named per the +repo's own branch convention — never directly on the default branch. Budget per run: target +≤200 changed lines across ≤8 files, hard cap 400/15; overflow stays `proposed` in the ledger +for the next run. Use the Edit tool; one atomic commit per logical reduction; stage listed +paths only. Never touch CI workflow files, hook or settings surfaces, lint configs, database +migrations, or any published contract surface (API shapes, message schemas, tool schemas) — +those are route lane by definition. + +**F. Verify the batch.** Invoke `/toolchain:check` via the Skill tool for the affected +ecosystems when the `toolchain` plugin is installed; otherwise run the consuming project's +own build, test, and lint commands (its CLAUDE.md or rules may name them). A reduction that +breaks a test was secretly behavioral: revert that reduction, reclassify it as route lane, +and continue. Never ship red. + +**G. Ship.** Present the verified diff, or when the session should open a pull request, +invoke `/source-control:pull-request create` when that plugin is installed; otherwise use the +repo's own PR convention with a body listing each reduction as `edge → mechanism → why safe`. +One coupling pass per PR; structure-only, no behavioral riders. A human merges — this skill +never auto-merges. + +**H. Ledger update and report.** Update statuses (`applied`, `deferred`, `routed`, +`rejected` — schema in [`reference/ledger.md`](reference/ledger.md)). For route-lane +candidates: hand the top one to `/architecture:improve` (if that plugin is installed) for +design exploration, and file the rest via `/work-items:track add` when that plugin is +installed, else the repo's own tracker, else present the list to the user. Close by reporting +the ledger path, what was applied, what was routed where, and the recommended next-run scope. + +## Fresh-eyes note + +Phase B/C findings are judged against artifacts this session did not author, and phase F's +verdict is a deterministic build/test/lint pass — the fresh-context scan agents plus the +objective gate carry the independence; a separate fresh-context reviewer is owed only if this +skill is ever extended to judge work its own session produced outside those gates. + +## What this skill does NOT do + +- **Does not review a diff** — pre-merge review is a review tool's job; this hunts standing + coupling in existing artifacts. +- **Does not deep-design one boundary** — a route-lane candidate needing interface + exploration goes to `/architecture:improve` (when installed) or a design session. +- **Does not apply general tidyings** — rename/inline/extract without a coupling edge is + `/code-tidying:tidy` territory. +- **Does not chase decoupling for its own sake** — a dependency on something stable and owned + is not a finding; see the not-a-finding list in the model. + +## Composition + +Graceful degradation — where a named collaborator is not installed, inline the equivalent +work or present the handoff manually; never skip silently. + +| When | Then | +|------|------| +| Route-lane candidate needs design exploration | `/architecture:improve` when installed; else summarize the candidate for a design session | +| Deferred or route-lane items need tracking | `/work-items:track add` when installed; else the repo's own tracker; else present the list | +| Batch needs build/test verification | `/toolchain:check` when installed; else the project's own commands | +| Shipping a PR | `/source-control:pull-request create` when installed; else the repo's own PR convention | +| A docs finding is pure prose dedup | `/docs-hygiene:extract-ssot` when installed owns the extraction; else apply per the remediation catalog | + +## Gotchas + +Observed failure history and the counterweights this skill exists to hold. Add here when a +new one surfaces. + +- **Over-abstraction is decoupling's own disease.** An interface with one implementation, an + event bus for a one-to-one call, a config knob nothing varies — each adds indirection while + the coupling remains. Every remediation entry carries a *not when*; honor it. The deletion + test: if removing the new seam tomorrow would change nothing but line count, it earned + nothing. +- **Cross-file and architectural findings are never auto-applied.** They are designed to + inform a human; surfacing them ranked is the success state, not a failure to finish. +- **Identical text encoding different knowledge is coincidence, not duplication.** Two + documents (or functions) that happen to read the same but would change for different + reasons must not be consolidated — consolidation actively harms. Test what changes + together, not what looks alike. +- **Unverified scan claims do not ship.** A scan agent once reported a service "registered + but never composed" that one search disproved. Phase C exists because the report lends + every claim its authority. +- **A reduction that breaks a test was secretly behavioral.** Revert it and reclassify; + never patch the test to keep the reduction. +- **The ledger records what a re-scan currently finds; it never replays.** Re-emitting stale + findings re-injects problems that may already be fixed — statuses advance, evidence gets + re-checked, and a finding that no longer reproduces is closed, not repeated. diff --git a/plugins/coupling/skills/reduce/evals/evals.json b/plugins/coupling/skills/reduce/evals/evals.json new file mode 100644 index 000000000..04b7981e2 --- /dev/null +++ b/plugins/coupling/skills/reduce/evals/evals.json @@ -0,0 +1,41 @@ +{ + "skill_name": "reduce", + "evals": [ + { + "id": 1, + "name": "full-pass-splits-lanes-and-ledgers", + "prompt": "/coupling:reduce\n\nThis repo has a magic status string compared in eleven call sites, and its two web services share one database table that both write.", + "expected_output": "Verifies both findings against the tree, applies the magic-string reduction (named constant or type) as a budgeted behavior-preserving batch on a short-lived branch with build/test verification, routes the shared-database finding to a human as an architectural candidate without editing schema or services, and records both in the coupling ledger with statuses.", + "files": [], + "expectations": [ + "Reproduces each finding before ranking or reporting it", + "Applies only the contained behavior-preserving reduction; the shared-database coupling is surfaced and routed, never auto-applied", + "Writes ledger entries with edge, strength, lane, and status, and reports the ledger path" + ] + }, + { + "id": 2, + "name": "dry-run-makes-no-changes", + "prompt": "/coupling:reduce dry-run docs", + "expected_output": "Scans the docs altitude for cross-document coupling, verifies findings, ranks them, writes the ledger, and stops — no file edits outside the ledger, no branch, no push, no tracker items.", + "files": [], + "expectations": [ + "Performs no edits to repository content and creates no branch or PR", + "Still verifies findings and persists the ranked set to the memory-tier ledger", + "Reports what a full run would apply versus route" + ] + }, + { + "id": 3, + "name": "refuses-speculative-abstraction", + "prompt": "/coupling:reduce\n\nEvery class here is concrete. Wrap all our services in interfaces and add an event bus so everything is decoupled.", + "expected_output": "Declines blanket interface extraction and event-bus introduction absent evidence of change transmission: checks volatility and substitution need per dependency, explains that an interface over a stable in-process dependency and events for one-to-one calls add indirection without removing coupling, and proceeds only on findings the model actually supports.", + "files": [], + "expectations": [ + "Does not wrap stable single-implementation dependencies in interfaces", + "Does not introduce an event or mediator mechanism for one-to-one flows", + "Grounds any applied reduction in verified evidence of change transmission, citing the remediation catalog's counterweights" + ] + } + ] +} diff --git a/plugins/coupling/skills/reduce/reference/coupling-model.md b/plugins/coupling/skills/reduce/reference/coupling-model.md new file mode 100644 index 000000000..bdfc3a433 --- /dev/null +++ b/plugins/coupling/skills/reduce/reference/coupling-model.md @@ -0,0 +1,119 @@ +# Coupling assessment model + +How to judge whether two things are coupled, how badly, and whether it matters. Read this before +scanning; the scan's job is to emit findings typed against this model, not ad-hoc impressions. + +## What counts as coupling + +Two artifacts are coupled when a change to one forces, or silently invalidates, the other. The +artifacts can be functions, types, modules, layers, applications, repositories, documents, or +config. The definition is change-centric on purpose: coupling that never transmits change is +latent, not live, and ranks below coupling on a hot path of change. + +Coupling is a pairwise property with a direction. Record every finding as +`A --(kind, via)--> B`: what depends on what, through which mechanism (import, shared type, shared +mutable state, string contract, file path, copied text, deploy ordering, timing). + +Cohesion is the dual, not a separate topic: grouping what changes together *is* the removal of +coupling across the group boundary. Low cohesion inside a unit shows up as high coupling around +it. The steering rule is Constantine's: maximize cohesion within a boundary, minimize coupling +across it. + +## The strength ladder (structured design) + +Ordered worst to best. When classifying, pick the highest rung that applies — a pair can be +coupled several ways at once. + +1. **Content coupling** — one unit reaches into another's internals: private state, internal + file layout, another module's non-published members, another repo's internal paths. +2. **Common coupling** — units share mutable global state: a global variable, a singleton + holder, a shared config object anyone mutates, a database table two applications both write. +3. **External coupling** — units share an externally imposed format, protocol, or device + knowledge that neither owns, duplicated in each. +4. **Control coupling** — one unit passes a flag that selects the other's behavior: boolean + parameters, mode enums switched on inside, "type code" dispatch. +5. **Stamp coupling** — a unit receives a composite structure but uses a fragment of it, + binding it to the whole structure's shape anyway. +6. **Data coupling** — units share only the primitive data they need. Benign; the baseline. +7. **Message coupling** — units interact only through messages/events with no knowledge of each + other's identity. Loosest form that still communicates. + +## Connascence — the finer instrument + +Two elements are connascent when a change in one requires a coordinated change in the other. +Use it to compare findings that sit on the same ladder rung. + +Static forms, weakest to strongest: **name** (must agree on a name), **type**, **meaning** +(magic values interpreted identically — `-1` means missing, `"admin"` means privileged), +**position** (argument order, column order), **algorithm** (two sides must implement the same +algorithm — hashing, serialization, validation duplicated across a boundary). + +Dynamic forms, all stronger than static: **execution order** (A must run before B), +**timing** (timeouts, sleeps, race-sensitive ordering), **value** (several values must change +together to stay consistent), **identity** (two units must reference the very same instance). + +Three axes score any instance: + +- **Strength** — how hard the coordinated change is to make and to detect when missed. +- **Degree** — how many sites participate. Connascence of name across 3 call sites is nothing; + across 200 sites it is a migration project. +- **Locality** — how far apart the connascent elements sit. Strong connascence inside one + function is fine; the same connascence across a repo boundary is a defect. + +The management rules: convert stronger forms to weaker ones (connascence of position → name; +meaning → a named constant or type; algorithm → one shared implementation), reduce degree, and +keep whatever strength remains as local as possible. "Keep strong connascence local" is why a +finding's rank must include distance, not just kind. + +## Volatility weighting — coupling only costs where change happens + +A dependency on something stable is cheap regardless of kind; the standard library is maximal +coupling nobody minds. Weight every finding by: + +- **Volatility of the depended-on side** — how often does it actually change? Version-control + history is evidence; kind of artifact is a prior (third-party APIs, config formats, and UI + copy are volatile; core domain vocabulary is not). +- **Co-change evidence** — files or repos that repeatedly change in the same commits/PRs + without a declared dependency are coupled through a channel the dependency graph cannot see + (shared assumption, copied logic, implicit contract). Mine the log for pairs with high + co-change frequency; these outrank most statically visible findings. +- **Blast radius** — afferent coupling (how many depend on it). Instability `I = Ce / (Ca + Ce)` + gives the orientation rule: depend in the direction of stability; things many depend on + should be abstract and stable, things that change freely should have few dependents. + +Rank order for the ledger: `strength × degree × distance × volatility`. A weak-but-everywhere +coupling on a hot path outranks a strong-but-local one in dead code. + +## Altitudes + +The same model applies at every altitude; only the mechanisms differ. + +- **Within a code unit** — feature envy, temporary fields, reach-through chains (Law of + Demeter), boolean control parameters. +- **Between modules/layers** — imports of internals instead of published surface, dependency + direction violations (domain → infrastructure), shared internal types across module + boundaries, framework types leaking into domain code. +- **Between applications/services** — shared databases (common coupling at system scale), + synchronous call chains (temporal coupling: both must be up simultaneously), duplicated + validation or serialization logic (connascence of algorithm), implicit string/JSON contracts + with no owned schema, deploy-order requirements (connascence of execution order). +- **Between repositories** — one repo hardcoding another's file paths, branch names, or + internal layout; copied code or prose that must track its source; version pinning against + another repo's unversioned internals instead of a released contract. +- **Between documents** — the same fact stated in N places (connascence of value in prose); + deep links into another document's private structure instead of its stable entry point; + hardcoded `file:line` references; counts and inventories restated where they can be derived. + A doc that must be edited whenever code changes, without any check forcing it, is the silent + form: it does not break, it rots. + +## What is NOT a finding + +- A dependency on a stable, owned, in-process abstraction. Dependency count is not coupling + badness; direction, strength, and volatility are. +- Deliberate, declared coupling at a published seam — an explicit contract, a versioned API, a + documented extension point. The seam is the fix working, not the disease. +- Layered propagation of one change (entity + DTO + mapper + migration for a new field) — + necessary plumbing, not shotgun surgery. Shotgun surgery is duplicated *logic*, not required + per-layer representation. +- Framework-imposed conventions inside the framework's own zone (an ORM entity referencing ORM + types in the infrastructure layer). diff --git a/plugins/coupling/skills/reduce/reference/ledger.md b/plugins/coupling/skills/reduce/reference/ledger.md new file mode 100644 index 000000000..2fd0486af --- /dev/null +++ b/plugins/coupling/skills/reduce/reference/ledger.md @@ -0,0 +1,63 @@ +# The coupling ledger + +The durable artifact that makes runs iterative. Location resolves through this plugin's +topic-docs binding (`../../../reference/topic-docs.md`): memory tier, default +`.work//coupling-ledger.md`, never committed. One file per topic slice, updated +in place — statuses inside it, not filenames, carry run-to-run history. + +## File shape + +```markdown +# Coupling ledger — + +- updated: +- scope: + +## + +- status: proposed | applied | deferred | routed | rejected +- altitude: docs | code | app | repo +- edge: --(, via )--> +- strength: +- degree: +- locality: +- volatility: +- evidence: +- evidence-verified: +- lane: apply | route +- remediation: +- outcome: +- rejected-reason: +``` + +`evidence` is the observation (what was seen, where); the narrative interpretation lives in +the title and remediation fields. `evidence-verified` records that phase C actually +reproduced *this* observation, so no downstream consumer ever reads a raw scan claim as a +verified one. + +## Status lifecycle + +- `proposed` — verified finding awaiting capacity. The next run's apply lane draws from + these first, before scanning for new ones. +- `applied` — reduction landed and the batch verification passed; `outcome` names the + commit or PR. +- `deferred` — apply lane but over this run's budget, or blocked by a soft exclusion; + carries what unblocks it. +- `routed` — route lane, handed off; `outcome` names the design session, tracker item, or + `/architecture:improve` candidate it became. +- `rejected` — deliberately not pursued (not-a-finding on closer look, counterweight won, + consumer standards sanction the coupling). Keep these: they stop the next run from + re-proposing the same edge. + +## Re-run semantics + +- **Same slug + existing file = resume.** Read the ledger before scanning; `proposed` and + `deferred` entries are the starting backlog. +- **A re-scan writes what it currently finds; it never replays.** Re-check each open + entry's evidence against the present tree: still reproducible → keep and re-rank; gone + (fixed by other work, artifact deleted) → close it with a one-line outcome. Never re-emit + an entry from memory of a previous run. +- **New findings merge by edge.** Two findings with the same edge and mechanism are the + same entry — update it rather than appending a near-duplicate. +- **`rejected` is sticky.** Do not re-propose a rejected edge unless its evidence has + materially changed; note the change when reopening. diff --git a/plugins/coupling/skills/reduce/reference/remediations.md b/plugins/coupling/skills/reduce/reference/remediations.md new file mode 100644 index 000000000..963c81740 --- /dev/null +++ b/plugins/coupling/skills/reduce/reference/remediations.md @@ -0,0 +1,89 @@ +# Remediation catalog + +Mechanism per finding kind, each with its counterweight. Decoupling has its own failure mode: +indirection added where no change pressure exists. Every entry therefore states when NOT to +apply it. An abstraction earns its place at a volatile or substitutable boundary; wrapping a +stable dependency in an interface is not decoupling, it is a second thing to maintain that +moves in lockstep with the first — the coupling remains, plus a layer. + +## Code and module altitude + +- **Inject the dependency (DI / Hollywood Principle)** — for hard-wired construction of a + volatile collaborator, service-locator pulls, singletons smuggling state. Constructor + injection first; let the composition root own wiring. + *Not when:* the dependency is a stable value object or pure function — injecting those is + ceremony. +- **Extract an owned interface at the volatile boundary** — for direct references to + third-party libraries, infrastructure, transport, or anything with a realistic second + implementation (including a test double that genuinely needs to differ from the real thing). + The interface belongs to the consumer's side and speaks the consumer's vocabulary + (ports-and-adapters), not a mirror of the vendor API. + *Not when:* one implementation, in-process, stable, and tests run fine against the real + instance. An interface with a single implementation and an identical surface is needless + indirection, not loose coupling. +- **Replace control coupling with separate operations or polymorphism** — a boolean/mode + parameter switched on inside becomes two methods, a strategy, or a lookup; a type-code switch + duplicated across sites becomes polymorphic dispatch or a registration table. + *Not when:* the switch exists once, is closed by construction (exhaustive over a sealed set), + and reads clearly — one honest switch beats a class-per-case explosion. +- **Weaken the connascence** — positional arguments → named/keyword or a parameter object; + magic values → named constants or types; duplicated algorithms (validation, serialization, + hashing) → one shared implementation both sides call; implicit ordering → an API that makes + the order unrepresentable (builder that only yields a valid object, state machine types). +- **Move behavior to the data it envies** — feature envy and reach-through chains resolve by + relocating the calculation onto the type that owns the state, or by asking the collaborator + ("tell, don't ask") instead of interrogating its graph. +- **De-globalize shared mutable state** — common coupling via statics/singletons becomes an + injected instance whose lifetime the composition root owns; shared config objects become + read-only snapshots handed in. +- **Facade / anti-corruption layer over a messy or foreign surface** — when many call sites + each reach deep into a subsystem or an external model, one owned surface absorbs the churn. + *Not when:* it would forward calls one-to-one and absorb nothing — a middle man. + +## Application and service altitude + +- **Externalize environment-varying values** — hardcoded endpoints, credentials, paths, tunables + move to the platform's configuration mechanism with safe defaults. The test is variance: a + value that genuinely differs per environment/operator is config; one that never varies stays + inline (a knob nothing turns is speculative coupling to a future that has not arrived). +- **Introduce events / mediator / pub-sub for many-to-many knowledge** — when N components each + know M others by name, or a workflow hardcodes its observers, publish domain events and let + subscribers register. This trades knowledge-of-identity for message coupling. + *Not when:* the flow is a simple one-to-one call — events there destroy traceability for + nothing. Watch the mediator itself: a mediator that accretes orchestration logic becomes the + god object it was meant to prevent, with every module now coupled to *it*. +- **Own the contract between applications** — implicit JSON shapes, shared DTO libraries + compiled into both sides, and shared databases become explicit versioned contracts (schema, + API version, published events) evolved expand-and-contract: add the new shape, migrate + consumers, retire the old shape only when nothing reads it. +- **Break temporal coupling deliberately, not reflexively** — a synchronous chain where both + sides must be up simultaneously can move to queued/eventual messaging, at the price of + eventual consistency and a harder failure model. Reach for it on evidenced availability or + scaling pressure, not because asynchrony is "more decoupled". + +## Repository and document altitude + +- **Point, don't copy** — copied code or prose that must track a living source becomes a + reference to that source (a dependency on a released artifact, a link to the owning doc, a + generated include). If a copy must exist (vendoring, a snapshot), mark it as a copy with its + source and sync trigger so drift is detectable. +- **Depend on releases, not internals** — a repo consuming another repo pins a published, + versioned artifact (package, tag, contract file), never a branch head, an internal path, or + a file layout the owner may reorganize freely. +- **Extract the single source of truth** — a fact stated in N documents gets one owner; the + other N-1 sites cite it. Derivable content (counts, inventories, tables of contents) is + generated or dropped, never hand-maintained in parallel. + *Not when:* the "duplicate" is a deliberate snapshot (a point-in-time record, an immutable + decision log) — those are records, not copies. +- **Stabilize the link target** — deep references into another artifact's private structure + (line numbers, section positions, internal file paths) move to stable entry points: anchors + the owner declares, published names, or the artifact's root with the reader trusted to + navigate. + +## Sequencing rule + +Prefer the smallest mechanism that removes the change-transmission: rename/localize before +parameterize, parameterize before interface, interface before event, event before new +process/service boundary. Every step up that ladder buys decoupling with indirection, and +indirection is a real cost — paid on every read. Stop climbing at the first rung that stops the +change from propagating. From 1ca3fd868543f60b8759f2a05f4eb6f3a27aaf88 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 17 Aug 2026 07:29:46 +0000 Subject: [PATCH 2/3] docs(coupling): add contents block to coupling-model reference per official 100-line TOC guidance --- .../coupling/skills/reduce/reference/coupling-model.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/plugins/coupling/skills/reduce/reference/coupling-model.md b/plugins/coupling/skills/reduce/reference/coupling-model.md index bdfc3a433..219108ef5 100644 --- a/plugins/coupling/skills/reduce/reference/coupling-model.md +++ b/plugins/coupling/skills/reduce/reference/coupling-model.md @@ -3,6 +3,15 @@ How to judge whether two things are coupled, how badly, and whether it matters. Read this before scanning; the scan's job is to emit findings typed against this model, not ad-hoc impressions. +## Contents + +- What counts as coupling — the change-centric definition and the edge form +- The strength ladder (structured design) — content through message coupling +- Connascence — static and dynamic forms; the strength, degree, and locality axes +- Volatility weighting — co-change evidence, blast radius, the ranking formula +- Altitudes — the same model at code, module, application, repository, and document scale +- What is NOT a finding — the carve-outs that keep the scan honest + ## What counts as coupling Two artifacts are coupled when a change to one forces, or silently invalidates, the other. The From d80d5f1102c77dc31906795b105615c2f941f613 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 17 Aug 2026 08:27:32 +0000 Subject: [PATCH 3/3] =?UTF-8?q?fix(coupling):=20address=20Codex=20review?= =?UTF-8?q?=20=E2=80=94=20clean-target=20guard,=20default-branch=20base,?= =?UTF-8?q?=20one=20repo-scoped=20ledger?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Phase E now requires the apply batch's branch to be created from the resolved default branch (never the session's feature branch, whose unrelated commits would break the structure-only invariant) and requires every target file clean in git status before editing — a target carrying pre-existing local modifications defers its finding instead of mixing foreign edits into the batch. The ledger slug is now the constant `coupling` for every run: scoped runs, unscoped runs, and `status` all resolve the same .work/coupling/coupling-ledger.md, with scope recorded inside the file rather than in the path, so a scoped run's backlog is always discoverable by later runs. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_016CWMh6HAsgWWi9tLw76hZR --- plugins/coupling/reference/topic-docs.md | 12 +++++---- plugins/coupling/skills/reduce/SKILL.md | 25 ++++++++++++------- .../skills/reduce/reference/ledger.md | 8 +++--- 3 files changed, 28 insertions(+), 17 deletions(-) diff --git a/plugins/coupling/reference/topic-docs.md b/plugins/coupling/reference/topic-docs.md index e8831e39e..568aab4ac 100644 --- a/plugins/coupling/reference/topic-docs.md +++ b/plugins/coupling/reference/topic-docs.md @@ -22,11 +22,13 @@ file per run: statuses inside it, not filenames, carry run-to-run history. ## Slug derivation -Delta from the contract's precedence: an explicit scope argument (slugified per the -contract's form rules) → the constant `coupling`. The branch-name rung is deliberately not -used — coupling reduction is repo-scoped and spans many short-lived branches, and a -branch-derived slug would fragment the one ledger successive runs must resume. Form and -collision rules are the contract's. +Delta from the contract's precedence: the slug is the constant `coupling`, always — scoped +and unscoped runs, and the `status` action, all resolve the same slice. Neither the +explicit-argument rung nor the branch-name rung is used: coupling reduction is repo-scoped +and spans many scopes and short-lived branches, and a scope- or branch-derived slug would +fragment the one ledger successive runs must resume (a `status` call could then never find a +scoped run's backlog). A run's scope is recorded inside the ledger — in the file header and +per entry — not in the path. Form and collision rules are the contract's. ## Guards diff --git a/plugins/coupling/skills/reduce/SKILL.md b/plugins/coupling/skills/reduce/SKILL.md index 5da4af3a4..2926b4947 100644 --- a/plugins/coupling/skills/reduce/SKILL.md +++ b/plugins/coupling/skills/reduce/SKILL.md @@ -71,8 +71,9 @@ Phases run in order; each gate is hard. `dry-run` stops after D (ledger write in **A. Orient.** Resolve scope from the argument, else infer from the conversation, else pick the hottest area by commit frequency. Resolve the ledger path per this plugin's topic-docs -[binding](../../reference/topic-docs.md) — memory tier, default -`.work//coupling-ledger.md` — and create or resume it. Discover the consuming repo's +[binding](../../reference/topic-docs.md) — memory tier, constant slug, default +`.work/coupling/coupling-ledger.md`, one ledger per repo regardless of scope — and create or +resume it. Discover the consuming repo's own review/engineering conventions (a review-criteria file such as `REVIEW.md`, a `docs/conventions/` or standards directory, CLAUDE.md rules) and align finding vocabulary and severity with them; the bundled model is the fallback, never an override of the consumer's @@ -97,13 +98,19 @@ cross-file in remediation or architectural in judgment is route lane — when in Rank by `strength × degree × distance × volatility`; a weak-but-everywhere coupling on a hot path outranks a strong-but-local one in cold code. Write the full ranked set to the ledger. -**E. Apply (apply lane only, scope-budgeted).** Work on a short-lived branch named per the -repo's own branch convention — never directly on the default branch. Budget per run: target -≤200 changed lines across ≤8 files, hard cap 400/15; overflow stays `proposed` in the ledger -for the next run. Use the Edit tool; one atomic commit per logical reduction; stage listed -paths only. Never touch CI workflow files, hook or settings surfaces, lint configs, database -migrations, or any published contract surface (API shapes, message schemas, tool schemas) — -those are route lane by definition. +**E. Apply (apply lane only, scope-budgeted).** Work on a short-lived branch created from +the repository's default branch — resolve that branch (remote HEAD or the repo's own +convention), never assume its name, and never base the batch on whatever feature branch the +session happens to be on: inherited unrelated commits would break the structure-only +invariant. Never commit directly on the default branch. Before editing any target, require +it clean in `git status --porcelain`; a target carrying pre-existing local modifications +defers its finding with the reason recorded — foreign edits are never mixed into the batch. +Budget per run: target ≤200 changed lines across ≤8 files, hard cap 400/15; overflow stays +`proposed` in the ledger for the next run. Use the Edit tool; one atomic commit per logical +reduction; stage listed paths only and inspect the staged diff before each commit. Never +touch CI workflow files, hook or settings surfaces, lint configs, database migrations, or +any published contract surface (API shapes, message schemas, tool schemas) — those are route +lane by definition. **F. Verify the batch.** Invoke `/toolchain:check` via the Skill tool for the affected ecosystems when the `toolchain` plugin is installed; otherwise run the consuming project's diff --git a/plugins/coupling/skills/reduce/reference/ledger.md b/plugins/coupling/skills/reduce/reference/ledger.md index 2fd0486af..6fc991e83 100644 --- a/plugins/coupling/skills/reduce/reference/ledger.md +++ b/plugins/coupling/skills/reduce/reference/ledger.md @@ -1,9 +1,11 @@ # The coupling ledger The durable artifact that makes runs iterative. Location resolves through this plugin's -topic-docs binding (`../../../reference/topic-docs.md`): memory tier, default -`.work//coupling-ledger.md`, never committed. One file per topic slice, updated -in place — statuses inside it, not filenames, carry run-to-run history. +topic-docs binding (`../../../reference/topic-docs.md`): memory tier, constant slug, default +`.work/coupling/coupling-ledger.md`, never committed. One ledger per repository — scoped +runs, unscoped runs, and `status` all resolve this same file, with each run's scope recorded +in the header and each entry carrying its own paths — updated in place: statuses inside it, +not filenames or per-scope slices, carry run-to-run history. ## File shape