mandrel 1.83.0 → 1.84.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.
@@ -161,6 +161,20 @@ assertions into a single "kitchen sink" test — split them.
161
161
  - Coverage targets apply to production code. Test helpers, fixtures, and
162
162
  generated code are excluded per the project's coverage config.
163
163
 
164
+ ## Anti-Gaming (review-side complement)
165
+
166
+ These standards define what a *correct* test looks like; they cannot, on
167
+ their own, catch a change that reaches green by **weakening the check rather
168
+ than fixing the code** — a relaxed assertion, a skipped or deleted test, a
169
+ swallowed error, a stub return, a fake rename, or a warning silenced by
170
+ comment deletion. That shortcut taxonomy is enumerated, and the reviewer-facing
171
+ detection lens for it lives, in the **Anti-Gaming / Shortcut Detection** pillar
172
+ (Pillar 4) of
173
+ [`../workflows/helpers/code-review.md`](../workflows/helpers/code-review.md#pillar-4-anti-gaming--shortcut-detection).
174
+ When you loosen a matcher, quarantine a test, or remove coverage, record the
175
+ spec-sanctioned rationale in the commit body or Story comment so that pillar
176
+ reads it as a deliberate decision rather than gaming.
177
+
164
178
  ## Property-Based Testing (a technique, not a tier)
165
179
 
166
180
  Property-based testing is a **technique** — generating a domain of inputs and
@@ -19,6 +19,18 @@ is merged upstream. It runs in two scopes:
19
19
  - **Epic scope** — reviews the cumulative diff between an Epic branch and
20
20
  `main`, before `/deliver` opens the integration pull request.
21
21
 
22
+ **Invariant — Story-scope review runs outside the maker's LLM context.**
23
+ The Story-scope review executes inside the `story-close.js` /
24
+ `single-story-close.js` close subprocess, **not** in the delivering
25
+ child's (maker agent's) LLM context. The close pipeline invokes it after
26
+ the delivering child has exited, so the change set is reviewed by a
27
+ process the maker cannot influence. The enforcing code path is
28
+ [`.agents/scripts/lib/orchestration/story-close/phases/code-review.js`](../../scripts/lib/orchestration/story-close/phases/code-review.js)
29
+ (invoked from `runStoryCloseLocked`; both close entry points reach it
30
+ through the shared `runStoryReviewCore` spine). A future refactor MUST
31
+ preserve this isolation: do not move Story-scope review into the maker's
32
+ context or run it as a step of the delivering child.
33
+
22
34
  > **Persona**: `architect` · **Skills**: `core/code-review-and-quality`,
23
35
  > `core/security-and-hardening`
24
36
 
@@ -107,18 +119,21 @@ The pipeline will:
107
119
 
108
120
  ## Step 2 — Review Pillars
109
121
 
110
- For each changed file, execute a strict review against three pillars. The
111
- middle pillar (**Integration Review**) deliberately defers the security /
122
+ For each changed file, execute a strict review against four pillars. The
123
+ second pillar (**Integration Review**) deliberately defers the security /
112
124
  performance / quality / coverage sweeps to the change-set-scoped audits
113
125
  that already ran upstream — re-walking them here is duplication, not
114
126
  defense-in-depth.
115
127
 
116
128
  **Apply the `depth` lever** (see **Review depth** above) to how hard you walk
117
129
  these pillars: at `light`, focus on Pillar 1 and reduce Pillars 2–3 to a quick
118
- scan for obvious breakage; at `standard`, cover all three at today's depth; at
119
- `deep`, cover all three at full depth and then make a second adversarial pass
130
+ scan for obvious breakage; at `standard`, cover all four at today's depth; at
131
+ `deep`, cover all four at full depth and then make a second adversarial pass
120
132
  over the diff hunting for integration regressions and security-relevant edges
121
- before finalizing findings.
133
+ before finalizing findings. Pillar 4 (**Anti-Gaming / Shortcut Detection**)
134
+ is walked at **every** depth, including `light` — it targets the class of
135
+ correctness failure the deterministic gates structurally cannot see, so it is
136
+ never reduced to a scan.
122
137
 
123
138
  ### Pillar 1: Spec Adherence
124
139
 
@@ -182,6 +197,56 @@ Verify documentation stays synchronized with code:
182
197
  - README and CHANGELOG reflect the changes if applicable.
183
198
  - Inline comments explain *why*, not *what*.
184
199
 
200
+ ### Pillar 4: Anti-Gaming / Shortcut Detection
201
+
202
+ Does the change reach "done" by *fixing the code*, or by *weakening the check
203
+ that would have caught it broken?* This is the class of correctness failure the
204
+ deterministic `verify[]` commands and the ratchet gates structurally cannot
205
+ see: a green suite, a passing lint, and an unchanged maintainability score all
206
+ report success whether the code got correct or the test got quieter. Walk the
207
+ diff for the shortcut taxonomy below and flag every instance — a plausible-but-
208
+ unjustified match is a 🟠 finding, an unambiguous one (test deletion without a
209
+ spec decision, a swallowed error on a real failure path) is a 🔴.
210
+
211
+ - **Relaxed tests** — an assertion loosened to pass rather than the code fixed
212
+ to satisfy it: a tightened matcher swapped for a looser one
213
+ (`toEqual` → `toBeTruthy`, an exact value → `expect.anything()`), a
214
+ narrowed expected value widened, a strict schema check softened, or a
215
+ threshold moved to admit the current (wrong) output.
216
+ - **Skipped tests** — a failing test quarantined instead of fixed:
217
+ `it.skip` / `test.skip` / `xit` / `describe.skip`, a `return` early in the
218
+ test body, a `--test-name-pattern` / grep exclusion, an `@skip`/`@ignore`
219
+ tag, or a test commented out wholesale. Deleting a test outright is the
220
+ most severe form — treat unexplained coverage removal as `test-deletion`
221
+ (Step 4.5) and never auto-fix it.
222
+ - **Swallowed errors** — a failure path silently absorbed: an empty
223
+ `catch {}`, `catch (e) {}` with no rethrow/log/handle, a bare
224
+ `.catch(() => {})` on a promise, a `try` wrapped solely to suppress a
225
+ throw the caller needs, or an error downgraded to a no-op return so the
226
+ happy path "passes".
227
+ - **Stub returns** — a hardcoded value standing in for real logic: a function
228
+ that `return true` / `return []` / `return null` / `return {}` regardless of
229
+ input, a mock left wired into production code, a `TODO`/`FIXME` guarding an
230
+ unimplemented branch that the acceptance criteria required, or a constant
231
+ substituted for a computation the Story asked for.
232
+ - **Fake renames** — a change dressed up as a rename that is actually a
233
+ deletion or a behavior change: content dropped under cover of a
234
+ move/rename, a "rename" whose diff quietly alters logic, or a re-export
235
+ shim that orphans the real implementation while the symbol name survives.
236
+ - **Comment-deletion-as-fix** — a warning silenced by removing its evidence
237
+ rather than its cause: a failing assertion turned into a comment, a
238
+ `// TODO: this is broken` note deleted while the breakage remains, a
239
+ disabled-code block removed to make a diff look clean, or a lint-suppression
240
+ comment (`biome-ignore`, `eslint-disable`, `@ts-expect-error`) added to mute
241
+ a real diagnostic instead of fixing it.
242
+
243
+ For every hit, name the file and line, the taxonomy category, and *why the
244
+ code — not the check — should have changed*. A finding here is legitimate only
245
+ when the diff itself lacks a recorded rationale (a commit-body or Story-comment
246
+ note explaining a deliberate, spec-sanctioned relaxation clears it — per the
247
+ engineer persona's Implementation Latitude, unlogged reshaping is the
248
+ anti-pattern this pillar surfaces).
249
+
185
250
  ## Step 3 — Maintainability Ratchet
186
251
 
187
252
  Verify that no file's maintainability score has decreased below the project
package/docs/CHANGELOG.md CHANGED
@@ -2,6 +2,13 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file.
4
4
 
5
+ ## [1.84.0](https://github.com/dsj1984/mandrel/compare/mandrel-v1.83.0...mandrel-v1.84.0) (2026-07-05)
6
+
7
+
8
+ ### Added
9
+
10
+ * Epic [#4349](https://github.com/dsj1984/mandrel/issues/4349) ([#4353](https://github.com/dsj1984/mandrel/issues/4353)) ([6d17937](https://github.com/dsj1984/mandrel/commit/6d1793753fc193cd21b2126587af86957fb2aa24))
11
+
5
12
  ## [1.83.0](https://github.com/dsj1984/mandrel/compare/mandrel-v1.82.0...mandrel-v1.83.0) (2026-07-05)
6
13
 
7
14
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mandrel",
3
- "version": "1.83.0",
3
+ "version": "1.84.0",
4
4
  "description": "Claude Code-first opinionated workflow framework: instructions, personas, skills, and SDLC workflows that govern AI coding assistants.",
5
5
  "files": [
6
6
  ".agents/",