cohorte 2.3.0 → 2.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -7,6 +7,40 @@ short, user-facing, most recent first. One `## <version> — <YYYY-MM-DD>` secti
7
7
  > They are history and are deliberately not rewritten — every command gained a `cohorte-` prefix
8
8
  > in 2.0.0.
9
9
 
10
+ ## 2.4.0 — 2026-08-13
11
+
12
+ - **The pipeline froze *what* to build, never *how much*.** A spec pins the contract and the
13
+ acceptance criteria, so the feature was right — but nothing ever asked an implementer whether the
14
+ helper it was about to write already existed three files over, whether the stdlib shipped it, or
15
+ whether the abstraction it was wrapping had exactly one caller. The diff came out correct and
16
+ fatter than it needed to be, and every extra line was then paid twice: once at build, once again at
17
+ `/cohorte-review`, whose cost is linear in the diff it reads.
18
+
19
+ Implementers now walk a **minimality ladder** before inventing anything: does it need to exist at
20
+ all → already in this repo → stdlib/framework → native platform feature → an already-installed
21
+ dependency → a few inline lines → only then the minimum the contract requires. It governs the
22
+ **how**, never the **what** — a contract field, an acceptance criterion, a test, a validation or an
23
+ authz check is out of its reach, by construction. It is bounded to **one lookup per candidate**, so
24
+ it costs a symbol search and not an exploration, and a shortcut kept on purpose surfaces in the
25
+ handoff's `## TODO / not done` with its ceiling and its upgrade trigger, instead of rotting in a
26
+ comment.
27
+
28
+ The `review` agent gains the matching axis — over-engineering, tagged `delete:` / `stdlib:` /
29
+ `native:` / `yagni:` / `shrink:`, always naming the cheaper replacement. It is deliberately the
30
+ weakest thing in the report: **5 findings max, MEDIUM ceiling, never a CRITICAL, never a REVISE,
31
+ never a BLOCK**. A diff whose only findings are `complexity` ships, and they park in the backlog
32
+ like any other nit. Tests, fixtures and anything the contract mandates are out of bounds — coverage
33
+ is not bloat. In audit mode the axis widens to the whole target (10 per domain, biggest cut first,
34
+ closing with `net: -N lines, -M deps possible.`), and `/cohorte-audit` files them under a new
35
+ `complexity` backlog tag: the cheapest wins in the file, since deleting code needs no new test.
36
+
37
+ Doctrine adapted from [ponytail](https://github.com/dietrichgebert/ponytail) (MIT) — the decision
38
+ ladder and the finding tags are theirs; the subordination to the frozen contract and the
39
+ can't-block severity ceiling are what make them safe inside a gated pipeline.
40
+
41
+ Run `/cohorte-update-pipeline` to re-render your surface agents — the ladder lives in the
42
+ implementer template, so it only reaches your agents through a reconcile.
43
+
10
44
  ## 2.3.0 — 2026-08-12
11
45
 
12
46
  - **A bug fix had to pretend to be a feature.** The only way into the pipeline was
@@ -59,6 +59,33 @@ them over Grep/Glob + whole-file Reads**: locate code by symbol, read only the d
59
59
  and trace references before changing any shared shape. Fall back to Grep/Read only when the retrieval
60
60
  tools are unavailable or come up empty.
61
61
 
62
+ ## How you choose what to write — the minimality ladder
63
+
64
+ The spec froze the **what**; this ladder governs only the **how**. It never licenses you to skip a
65
+ contract field, an acceptance criterion, a test, a validation, an authz check or an accessibility
66
+ attribute — those are the *what*, and they are not yours to trim.
67
+
68
+ Before writing any helper, utility, wrapper, abstraction or new dependency, walk down and stop at the
69
+ first hit:
70
+
71
+ 1. **Does it need to exist at all?** An abstraction with one implementation, a config nobody sets, a
72
+ layer with one caller — don't write it. The second caller is when it earns its keep.
73
+ 2. **Is it already in this repo?** One retrieval/Grep lookup by symbol name, not a survey — you are
74
+ checking, not exploring. Reuse beats re-implementing, and it keeps the convention.
75
+ 3. **Is it in the standard library / framework?** Name it and use it.
76
+ 4. **Is it a native platform feature?** (CSS, the HTTP layer, the DB, the runtime.) Prefer it over code.
77
+ 5. **Is it in a dependency already installed?** Use that one. Adding a dependency for what tiers 3–5
78
+ already ship is a finding at review.
79
+ 6. **Can it be a few lines inline?** Then it doesn't need a file, a class, or a name.
80
+ 7. Only then: the **minimum implementation that satisfies the contract** — no speculative options, no
81
+ "we'll probably need" parameters, no premature generalisation.
82
+
83
+ Bound the cost: this is at most **one lookup per candidate**, and it applies to code you are inventing —
84
+ never to code the contract dictates. If a step would cost more searching than writing, write it.
85
+
86
+ Something you deliberately kept simple with a known ceiling goes in your handoff `## TODO / not done`
87
+ with its limit and what would trigger the upgrade — not in a comment, and not silently.
88
+
62
89
  ## How you work — strict TDD (red → green → refactor)
63
90
 
64
91
  <!-- <SURFACE_TDD_STEP1> is a LEAD-IN paragraph, not a numbered item: it is filled only for a
@@ -63,6 +63,20 @@ be precise and self-contained.
63
63
  additive `sm:/md:/lg:`, no fixed widths that break on mobile. (You can't render; judge from the code.)
64
64
  7. **TDD coverage.** Each surface's tests cover its slice of the contract (statuses, validation, auth,
65
65
  behavior). Flag untested contract surface.
66
+ 8. **Over-engineering (lowest priority, never blocking).** Code the diff *added* that didn't need to
67
+ exist. Tag each one and always name the replacement — a finding with no cheaper alternative is an
68
+ opinion, not a finding:
69
+ - `delete:` dead code, unused flexibility, a speculative feature nothing calls. Replacement: nothing.
70
+ - `stdlib:` hand-rolled thing the standard library or framework ships. Name the function.
71
+ - `native:` a dependency or code doing what the platform already does. Name the feature.
72
+ - `yagni:` abstraction with one implementation, config nobody sets, layer with one caller.
73
+ - `shrink:` same behaviour, materially fewer lines. Name the shorter form.
74
+
75
+ **Hard limits on this axis.** It is capped at **5 findings**, biggest cut first, and its severity
76
+ ceiling is **MEDIUM** — it can never produce CRITICAL, never REVISE, never BLOCK. Test code,
77
+ fixtures and anything the contract or an acceptance criterion mandates are **out of bounds**:
78
+ coverage is not bloat, and "simpler" is never a reason to drop a spec'd behaviour. Deduplication
79
+ that would cross a surface boundary is out of bounds too — that's an architecture call, not a review one.
66
80
 
67
81
  ## Language checks (apply only those matching the surfaces under review)
68
82
 
@@ -89,10 +103,19 @@ entry point / module with **no test**), and the lint/format/type debt staged at
89
103
  dispatch names (`specs/reports/audit-gates.txt`). Emit a **prioritized refactor backlog grouped by
90
104
  domain** (same finding-line shape) instead of a SHIP/REVISE/BLOCK verdict.
91
105
 
106
+ In audit mode the over-engineering axis (§8) widens: there is no diff, so the whole target is in
107
+ scope and the 5-finding cap lifts to **10 per domain**, ranked biggest cut first. Hunt the usual
108
+ shapes — deps the stdlib or platform already ships, single-implementation interfaces, factories with
109
+ one product, wrappers that only delegate, dead flags and config, hand-rolled stdlib. Close the
110
+ audit-mode report with one line: `net: -<N> lines, -<M> deps possible.` (`0`/`0` is a valid answer —
111
+ say it rather than inventing cuts).
112
+
92
113
  ## Severity & verdict
93
114
 
94
115
  - **CRITICAL** — spec violation or correctness bug that must be fixed ⇒ verdict **REVISE**.
95
116
  - **HIGH / MEDIUM / LOW** — quality/convention issues; note them.
117
+ - **Over-engineering (§8) caps at MEDIUM** and never drives the verdict — a diff whose only findings
118
+ are `complexity` ships. It is a cleanup signal, not a gate.
96
119
  - Any **security vulnerability** ⇒ verdict **BLOCK**.
97
120
  - No CRITICAL and no security issue ⇒ verdict **SHIP**.
98
121
 
@@ -117,7 +140,7 @@ they are **never lost and never cost a fix loop**.
117
140
  ## Your return — the REVIEW REPORT, exactly this shape
118
141
 
119
142
  Every finding must be **self-sufficient for a stateless agent**: `file:line` · severity ·
120
- `spec-violation | quality | security` · one concrete suggested fix — it gets appended verbatim to the
143
+ `spec-violation | quality | security | complexity` · one concrete suggested fix — it gets appended verbatim to the
121
144
  spec's `## Remediation`. Your final message **is** the report. **The shape is capped:** at most
122
145
  **20 findings**, ONE line each, **zero code excerpts** (the diff and the source are on disk — a
123
146
  `file:line` is enough for a stateless fixer). More than 20? Keep every CRITICAL/HIGH/security
@@ -140,12 +163,13 @@ Verdict: <SHIP | REVISE | BLOCK>
140
163
 
141
164
  ## Findings
142
165
 
143
- - **[<SEVERITY>]** `<file>:<line>` · <spec-violation|quality|security> · <problem> → **Fix:** <concrete change>
144
- (order by severity; "None." if none; max 20 lines, one per finding, no code excerpts)
166
+ - **[<SEVERITY>]** `<file>:<line>` · <spec-violation|quality|security|complexity> · <problem> → **Fix:** <concrete change>
167
+ (order by severity; "None." if none; max 20 lines, one per finding, no code excerpts.
168
+ `complexity` lines carry their §8 tag in the problem — `yagni: <what>` — and cap at 5)
145
169
 
146
170
  ## Deferred
147
171
 
148
- - **[<SEVERITY>]** `<file>:<line>` · <quality|security> · <problem> → **Fix:** <concrete change> · out of scope: <why this feature does not own it>
172
+ - **[<SEVERITY>]** `<file>:<line>` · <quality|security|complexity> · <problem> → **Fix:** <concrete change> · out of scope: <why this feature does not own it>
149
173
  (real but out of this feature's scope — see §Deferred; worst first; "None." if none; max 10 lines)
150
174
 
151
175
  ## Notes
@@ -32,8 +32,9 @@ bulk never sits in your history, then grep it for the `file:line` of every failu
32
32
 
33
33
  Dispatch `review` (read-only; static prompt first, variable slot last — prompt-cache prefix):
34
34
  "Audit a target against `PIPELINE.md` (no spec — **audit mode**). Check conventions (§Conventions
35
- per surface), TDD coverage (untested entry points / modules per surface), and — if the profile
36
- enables themmobile-first + design-system usage. Mechanical findings from the gates: read
35
+ per surface), TDD coverage (untested entry points / modules per surface), over-engineering (§8,
36
+ widened per your audit-mode rules ranked biggest cut first, closing `net:` line), and if the
37
+ profile enables them — mobile-first + design-system usage. Mechanical findings from the gates: read
37
38
  `specs/reports/audit-gates.txt`. Emit a prioritized refactor backlog (capped finding-line format
38
39
  from your instructions), grouped by domain (one group per surface + shared). — Target: `$ARGUMENTS`
39
40
  (default: whole repo)."
@@ -42,7 +43,11 @@ from your instructions), grouped by domain (one group per surface + shared). —
42
43
 
43
44
  Merge mechanical + convention findings into one prioritized backlog and **write
44
45
  `specs/refactor-backlog.md`**, grouped by domain, each item:
45
- `- [ ] <SEVERITY> · <file:line> · <rule|tdd|lint|format|type|security> · <concrete fix>`
46
+ `- [ ] <SEVERITY> · <file:line> · <rule|tdd|lint|format|type|security|complexity> · <concrete fix>`
47
+
48
+ `complexity` items are the over-engineering cuts, ranked biggest first inside their domain — they are
49
+ the cheapest wins in the backlog (deleting code needs no new tests) but they never outrank a
50
+ security, correctness or `tdd` item.
46
51
 
47
52
  **Carry over the deferred items** before overwriting: `grep -n 'deferred:' specs/refactor-backlog.md`
48
53
  and re-emit every **open** (`- [ ]`) match verbatim under its domain, tag included. Those lines were
@@ -165,7 +165,7 @@ exactly the leak this step closes. Append each merged `## Deferred` item to
165
165
  `/cohorte-refactor <domain>` picks them up with no extra plumbing):
166
166
 
167
167
  ```
168
- - [ ] <SEVERITY> · <file:line> · <quality|security|rule> · <concrete fix> · deferred:$ARGUMENTS
168
+ - [ ] <SEVERITY> · <file:line> · <quality|security|rule|complexity> · <concrete fix> · deferred:$ARGUMENTS
169
169
  ```
170
170
 
171
171
  - **Never into the spec's `## Remediation`** — that list is what `/cohorte-fix` re-dispatches, so a
@@ -125,7 +125,7 @@ const FINDING = {
125
125
  properties: {
126
126
  severity: { enum: ['CRITICAL', 'HIGH', 'MEDIUM', 'LOW'] },
127
127
  file: { type: 'string' }, line: { type: 'integer' },
128
- kind: { enum: ['spec-violation', 'quality', 'security'] },
128
+ kind: { enum: ['spec-violation', 'quality', 'security', 'complexity'] },
129
129
  problem: { type: 'string', description: 'one line, no code excerpts' },
130
130
  fix: { type: 'string', description: 'one concrete change, one line' },
131
131
  },
@@ -141,7 +141,7 @@ const DEFERRED = {
141
141
  properties: {
142
142
  severity: { enum: ['CRITICAL', 'HIGH', 'MEDIUM', 'LOW'] },
143
143
  file: { type: 'string' }, line: { type: 'integer' },
144
- kind: { enum: ['quality', 'security', 'rule'] },
144
+ kind: { enum: ['quality', 'security', 'rule', 'complexity'] },
145
145
  problem: { type: 'string', description: 'one line, no code excerpts' },
146
146
  fix: { type: 'string', description: 'one concrete change, one line' },
147
147
  outOfScope: { type: 'string', description: 'one line: why this feature does not own it' },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cohorte",
3
- "version": "2.3.0",
3
+ "version": "2.4.0",
4
4
  "description": "Portable, stack-agnostic multi-agent development pipeline for Claude Code, Codex CLI, Cursor, Gemini CLI and OpenCode — install the core, run /cohorte-init-pipeline, and it adapts to your project's stack.",
5
5
  "bin": {
6
6
  "cohorte": "bin/cli.js"