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
|
|
111
|
-
|
|
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
|
|
119
|
-
`deep`, cover all
|
|
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