hstack 0.18.0 → 0.19.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 +19 -0
- package/README.md +1 -1
- package/VERSION +1 -1
- package/package.json +1 -1
- package/template/.claude/agents/adversarial-reviewer.md +6 -5
- package/template/.claude/agents/test-strategist.md +8 -9
- package/template/.claude/skills/hstack-adversarial-review/SKILL.md +4 -4
- package/template/.claude/skills/hstack-adversarial-review/references/finding-categories.md +4 -3
- package/template/.claude/skills/hstack-commit/SKILL.md +1 -1
- package/template/.claude/skills/hstack-test-audit/SKILL.md +8 -7
- package/template/.claude/skills/hstack-wrap/SKILL.md +3 -3
- package/template/.claude/skills/hstack-wrap/references/pr-description.md +7 -0
- package/template/KERNEL.md +13 -13
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,25 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to hstack are documented here. Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); versioning follows [SemVer](https://semver.org/).
|
|
4
4
|
|
|
5
|
+
## [0.19.0] - 2026-09-19
|
|
6
|
+
|
|
7
|
+
Changing an existing test stops needing permission and starts needing a label (ADR-0017). The authorization phrase is abolished; disclosure replaces it. This is the last per-change confirmation gate that survived the light pivot, and it is removed for the reason ADR-0015 removed the others — its cost was paid on every change and its protection was never once observed working.
|
|
8
|
+
|
|
9
|
+
### Changed
|
|
10
|
+
|
|
11
|
+
- **§ Test immutability is gone as a top-level law** and becomes four paragraphs inside § Tests. Three carve-outs and five prohibitions become one prohibition: changing a test so a red suite goes green when the code under test is what is wrong. Changing a test because the intended behaviour moved is stated, in the kernel, to be normal work — no phrase, no halt, no permission to request.
|
|
12
|
+
- **Disclosure replaces authorization.** A commit that modifies or deletes a test file that existed at the merge-base tags each file with exactly one of `behavior-change`, `refactor`, `obsolete`. There is no fourth tag: if the honest word would be *it was failing*, that is the forbidden move and not a disclosure. The PR description repeats the list in plain language under **Tests changed** — the commit body is for the audit, that section is for the human, who reads the description and not the diff.
|
|
13
|
+
- **The four canonical authorization phrases are removed from the corpus.** `Ok to change test <name>` and its siblings were kept verbatim by ADR-0013 and again by ADR-0014, both times on the argument that the wording *is* the mechanism. The argument was sound and the mechanism was never exercised: `REC-0003` measured 265 candidate violations over 90 days, the watch-list repeated verbatim for seven weeks, and no human ever reviewed a row.
|
|
14
|
+
- **The escalation clause is a disclosure, not a halt.** An agent that cannot tell whether the test or the code is wrong makes the most plausible change and names the doubt in the PR description as an open question. Halting was the previous answer and it put the owner in the loop at a moment he is generally not in it.
|
|
15
|
+
- **Still hard, for one stated reason — they hide from the diff.** Bulk snapshot updates (`vitest -u`, `--updateSnapshot`, any equivalent, including in hooks) and silent neutralization (`.skip`, `test.todo`, a deleted case, a `.toBe()` broadened to `.toContain()`, a timeout raised to mask a bug). A hidden edit cannot be disclosed, which is the whole argument for keeping these two where everything else was relaxed.
|
|
16
|
+
- **The enforcement points follow the rule.** The adversarial reviewer and `/hstack-adversarial-review` keep a mandatory audit and check for the disclosure tag instead of the authorization echo; `/hstack-wrap` writes the **Tests changed** section rather than blocking the PR; the test strategist may now change an existing test instead of being told existing tests are read-only always; `/hstack-test-audit` keeps its own read-only posture, re-justified on the grounds that an audit which rewrites what it audits is worthless.
|
|
17
|
+
- **The two places the disclosure is physically produced now say so.** The PR-description template (`hstack-wrap/references/pr-description.md`) gains a **Tests changed** heading before **Review findings**, because a step that requires a section the template never offers is a step that will be skipped. And `/hstack-commit` step 4 names the tag in its body guidance — it is the one moment where a staged test file and a commit body exist at the same time.
|
|
18
|
+
- **QO-3's labels change and its field name does not.** `qo_3_test_immutability_audit` is produced by the telemetry sidecar outside this repo, so renaming it here would break the contract. Until that sidecar counts undisclosed edits instead of unphrased ones, the metric reads empty rather than wrong — and there is no audit signal in the interval. Named in ADR-0017 as a consequence, not a detail.
|
|
19
|
+
|
|
20
|
+
### Added
|
|
21
|
+
|
|
22
|
+
- **`adr/ADR-0017-disclosure-replaces-authorization-on-tests.md`** — supersedes ADR-0013 and ADR-0014 on the single arbitration where each declined to touch this rule; the rest of both stands. It records the two consequences that look bad: the net is now weaker in exactly the case it was built for, because a tag can be typed by the model where the old phrase could not; and the decision is made on the cost side with the benefit side still unmeasured, since hstack has never detected one unauthorized test edit — equally consistent with *it never happened* and with *we cannot see it*.
|
|
23
|
+
|
|
5
24
|
## [0.18.0] - 2026-09-18
|
|
6
25
|
|
|
7
26
|
Code quality gets a mechanical half and a judgment half, with a hard line between them (ADR-0016). The first consumer's audit found the prose rules ignored at scale and the one lint rule at `error` respected everywhere; this release draws the conclusion.
|
package/README.md
CHANGED
|
@@ -116,7 +116,7 @@ The nine Skills:
|
|
|
116
116
|
|
|
117
117
|
| Skill | What it is for |
|
|
118
118
|
| --- | --- |
|
|
119
|
-
| `/hstack-wrap` | The end of a change: runs `/review` and `/security-review`, audits test
|
|
119
|
+
| `/hstack-wrap` | The end of a change: runs `/review` and `/security-review`, audits test disclosure, updates the living docs the diff invalidated, writes the PR description. |
|
|
120
120
|
| `/hstack-promote` | The release: pending production migrations, a smoke test on the unpromoted build, then promotion. Commands live in `infrastructure.md` § Deploy Pipeline. |
|
|
121
121
|
| `/hstack-commit` | The one Commitizen format humans and agents both write. |
|
|
122
122
|
| `/hstack-adversarial-review` | The deep pass on a sensitive surface, from a session that never saw the change being written. Findings land as a PR comment. |
|
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
0.
|
|
1
|
+
0.19.0
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: adversarial-reviewer
|
|
3
3
|
model: opus
|
|
4
|
-
description: "Use to critique a PR cold, from a session that never saw it being written — the six lenses, the mandatory test-
|
|
4
|
+
description: "Use to critique a PR cold, from a session that never saw it being written — the six lenses, the mandatory test-disclosure audit, an empty result that has to be defended. Surfaces findings; never resolves them."
|
|
5
5
|
tools:
|
|
6
6
|
- Read
|
|
7
7
|
- Grep
|
|
@@ -44,11 +44,12 @@ Nothing. Findings are returned to the Skill, which posts them on the PR.
|
|
|
44
44
|
code-quality — the last one against `code-standards.md`, a finding naming the rule it breaks.
|
|
45
45
|
They are lenses to look through, not buckets to fill — a change carrying all its
|
|
46
46
|
risk in one dimension produces findings in one category, and that is the honest answer.
|
|
47
|
-
- **The test-
|
|
47
|
+
- **The test-disclosure audit is mandatory** (protocol: `KERNEL.md` § Tests). Diff
|
|
48
48
|
every test file that existed at the base. For each modified, content-drifted or deleted test,
|
|
49
|
-
look for its
|
|
50
|
-
|
|
51
|
-
|
|
49
|
+
look for its disclosure tag — `behavior-change`, `refactor` or `obsolete` — in a commit body, and
|
|
50
|
+
its plain-language line under **Tests changed** in the PR description. Missing disclosure: a
|
|
51
|
+
finding under intent-compliance at `high` minimum, `critical` for a bulk snapshot update or a
|
|
52
|
+
silent neutralization. This one is not subject to your judgment about whether it is worth filing.
|
|
52
53
|
- **Intent is what the PR says it does.** The description names the perimeter, the shortcuts and
|
|
53
54
|
the docs it updated; the diff either matches or it does not.
|
|
54
55
|
- **Severity is about the consequence, not the likelihood.** Cross-tenant leakage and irreversible
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: test-strategist
|
|
3
3
|
model: opus
|
|
4
|
-
description: "Use during a test audit of one module: map its business rules against the existing tests and return the gaps, then write the tests the engineer chose to add. Existing tests stay read-only."
|
|
4
|
+
description: "Use during a test audit of one module: map its business rules against the existing tests and return the gaps, then write the tests the engineer chose to add. Existing tests stay read-only during the audit itself."
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
## Role
|
|
@@ -18,8 +18,7 @@ the right argument.
|
|
|
18
18
|
## When to invoke
|
|
19
19
|
|
|
20
20
|
When `/hstack-test-audit <module>` needs the module's rules mapped against its tests, or needs the
|
|
21
|
-
chosen gaps closed.
|
|
22
|
-
protocol, in the engineer's session, never here.
|
|
21
|
+
chosen gaps closed.
|
|
23
22
|
|
|
24
23
|
## Reads
|
|
25
24
|
|
|
@@ -32,11 +31,12 @@ New test files, and `hstack/context/invariants.md`. Nothing else.
|
|
|
32
31
|
|
|
33
32
|
## Behavior rules
|
|
34
33
|
|
|
35
|
-
- **Existing tests
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
34
|
+
- **Existing tests stay read-only here** — not because they are frozen. Changing one is ordinary
|
|
35
|
+
work when the intended behaviour moved, disclosed with its tag (`KERNEL.md` § Tests). It is that
|
|
36
|
+
an audit which rewrites the tests it is auditing has audited nothing. Name the change the gap
|
|
37
|
+
needs and leave it to the engineer's normal flow; a new test superseding the old one is often
|
|
38
|
+
better anyway, since it keeps the old expectation legible. What is never done, here or in the
|
|
39
|
+
engineer's session, is bending a test so a red suite goes green when the code is what is wrong.
|
|
40
40
|
- **Pyramid bias.** Unit for pure functions and reducers; integration for behaviour that crosses
|
|
41
41
|
modules or the database; end-to-end for user-visible journeys. Refuse a strategy that rests
|
|
42
42
|
primarily on end-to-end tests — slow and flaky is how a suite stops being run.
|
|
@@ -52,7 +52,6 @@ New test files, and `hstack/context/invariants.md`. Nothing else.
|
|
|
52
52
|
|
|
53
53
|
## Stop conditions
|
|
54
54
|
|
|
55
|
-
- Closing a gap requires touching an existing test.
|
|
56
55
|
- The module has no identifiable business rule — report that rather than propose tests.
|
|
57
56
|
- A rule surfaced contradicts one already in `invariants.md`. Surface both; the engineer decides.
|
|
58
57
|
- A performance budget is wanted but the repo has no way to assert one. Say so; do not write a
|
|
@@ -31,11 +31,11 @@ honor-system, as the kernel says; a sentence is the whole protocol.
|
|
|
31
31
|
reconstruct the conversation that produced the change.
|
|
32
32
|
2. **Invoke `adversarial-reviewer`** with that material. The subagent sweeps six lenses and returns
|
|
33
33
|
findings; it does not resolve them and does not touch the code.
|
|
34
|
-
3. **The test-
|
|
34
|
+
3. **The test-disclosure audit is mandatory** and is not subject to anyone's judgment about
|
|
35
35
|
whether it is worth filing. Every test file that existed at the base is diffed; a modification
|
|
36
|
-
or deletion without its
|
|
37
|
-
|
|
38
|
-
minimum. A bulk snapshot update is `critical`.
|
|
36
|
+
or deletion without its disclosure — a `behavior-change` / `refactor` / `obsolete` tag in a
|
|
37
|
+
commit body, repeated under **Tests changed** in the PR description — is a finding at `high`
|
|
38
|
+
minimum. A bulk snapshot update or a silent neutralization is `critical`.
|
|
39
39
|
4. **Post the findings** with `gh pr comment <n>`, or as a GitHub review when they are anchored to
|
|
40
40
|
lines. Each finding carries a severity, a category, the evidence in the diff, and what would
|
|
41
41
|
resolve it.
|
|
@@ -74,13 +74,14 @@ feature, the shortcuts taken, the living docs updated.
|
|
|
74
74
|
Behaviour the diff adds that no line of the description anticipated — undeclared scope is a
|
|
75
75
|
compliance gap in the other direction. A living doc the change invalidated and left untouched
|
|
76
76
|
(kernel § Context docs). A conscious shortcut visible in the code and named nowhere. **Any
|
|
77
|
-
test-file modification without its
|
|
78
|
-
|
|
77
|
+
test-file modification without its disclosure tag** (`KERNEL.md` § Tests); this one is mandatory
|
|
78
|
+
and never subject to judgment about whether it is worth filing.
|
|
79
79
|
|
|
80
80
|
**Filler looks like.** "The description could have been clearer." Style disagreements with how the
|
|
81
81
|
work was sequenced.
|
|
82
82
|
|
|
83
|
-
**Severity.**
|
|
83
|
+
**Severity.** Undisclosed test changes: `high` minimum, `critical` for a bulk snapshot update or a
|
|
84
|
+
silent neutralization. A
|
|
84
85
|
stale living doc: `high`, because the next session will read it and believe it. Everything else:
|
|
85
86
|
judgment.
|
|
86
87
|
|
|
@@ -27,7 +27,7 @@ Optional `--push`: push after committing — still subject to per-invocation con
|
|
|
27
27
|
- `<type>(<scope>): <summary>`, where `<type>` is one of `feat`, `fix`, `chore`, `docs`, `refactor`, `test`, `style`, `perf`, `ci`.
|
|
28
28
|
- `<scope>` names the area actually touched — never an invented or aspirational one. When the change spans unrelated areas, no single honest scope exists: propose splitting it into several commits.
|
|
29
29
|
- `<summary>` ≤ 72 characters, imperative present ("add", not "added"), no trailing period.
|
|
30
|
-
- Body, when it earns its place: the why, not the what.
|
|
30
|
+
- Body, when it earns its place: the why, not the what. A staged test file that existed at the merge-base is declared there, one line per file, tagged `behavior-change`, `refactor` or `obsolete` (kernel § Tests).
|
|
31
31
|
- **Never "Generated with Claude Code" or any similar attribution.**
|
|
32
32
|
- Footer: conventional-commits footers only (`BREAKING CHANGE:`, `Refs: <issue>`).
|
|
33
33
|
|
|
@@ -26,8 +26,9 @@ question at plan time, and this Skill is never a phase of a change.
|
|
|
26
26
|
`data-architecture.md` when the module touches the database. Write each rule as *decides X;
|
|
27
27
|
wrong in silence if Y*. A module whose code decides nothing has no gap to close — say so and
|
|
28
28
|
stop rather than write tests for the sake of coverage.
|
|
29
|
-
2. **Map the existing tests onto the rules.** Existing test files are read-only here
|
|
30
|
-
|
|
29
|
+
2. **Map the existing tests onto the rules.** Existing test files are read-only here — an audit
|
|
30
|
+
that rewrites the tests it is auditing has audited nothing; this step reads them, never edits
|
|
31
|
+
them.
|
|
31
32
|
3. **Name the gaps** — rules with no test, and tests asserting something no rule needs.
|
|
32
33
|
4. **Interview the edges.** A handful of questions, not a script: *what does the user notice if
|
|
33
34
|
this breaks in silence?* — plus concurrency, retries, and the cross-tenant case when the module
|
|
@@ -38,9 +39,10 @@ question at plan time, and this Skill is never a phase of a change.
|
|
|
38
39
|
6. **The engineer picks the gaps to close now.** A module with twenty uncovered rules would make
|
|
39
40
|
an unreviewable PR. Close the chosen ones; name the rest in the PR description so the next
|
|
40
41
|
audit starts there.
|
|
41
|
-
7. **Write the tests.** New test files
|
|
42
|
-
|
|
43
|
-
|
|
42
|
+
7. **Write the tests.** New test files only — "new" means the path did not exist at session start.
|
|
43
|
+
When closing a gap means editing or deleting an existing test, name that change in the output
|
|
44
|
+
rather than make it here; the engineer makes it in the normal flow, where it is ordinary work
|
|
45
|
+
carrying its disclosure line (kernel § Tests).
|
|
44
46
|
8. **Record the invariants.** Every rule the audit surfaced goes into `hstack/context/invariants.md`
|
|
45
47
|
in this PR — **including the gaps left open**. The memory is the cheap half; write it whether or
|
|
46
48
|
not the test was written.
|
|
@@ -51,13 +53,12 @@ and the gap list. Steps 4 and 6 are questions for the engineer and happen here,
|
|
|
51
53
|
## Output
|
|
52
54
|
|
|
53
55
|
New test files, an `invariants.md` diff, and a summary for the PR description naming the gaps left
|
|
54
|
-
open. Nothing else.
|
|
56
|
+
open and the existing tests that need changing. Nothing else.
|
|
55
57
|
|
|
56
58
|
## Stop conditions
|
|
57
59
|
|
|
58
60
|
Beyond the kernel's:
|
|
59
61
|
|
|
60
|
-
- Closing a gap would require touching an existing test. Halt (§ Test immutability).
|
|
61
62
|
- The module cannot be located, or spans so much of the repo that "one module" is not what is
|
|
62
63
|
being audited. Ask which one.
|
|
63
64
|
- An invariant the audit surfaces contradicts one already in `invariants.md`. Surface both; the
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: hstack-wrap
|
|
3
|
-
description: Use at the end of a change, before the PR — reads the diff against code-standards, runs /review and /security-review, audits test
|
|
3
|
+
description: Use at the end of a change, before the PR — reads the diff against code-standards, runs /review and /security-review, audits test disclosure, updates the living docs the diff invalidated, writes the PR description.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
## Purpose
|
|
@@ -25,7 +25,7 @@ None. The diff under review is everything that will land in the PR — committed
|
|
|
25
25
|
|
|
26
26
|
3. **Run `/review`, then `/security-review`** on that diff. Fix what is fixable inside the announced perimeter. Everything else is declared in the PR description — the finding, and why it was not fixed. A finding is never dropped silently, and an empty result is reported as what it is: the reviewer found nothing.
|
|
27
27
|
|
|
28
|
-
4. **Audit test
|
|
28
|
+
4. **Audit test disclosure.** Diff the test files that already existed at the merge-base. Each one modified or deleted carries its tag — `behavior-change`, `refactor` or `obsolete` — in a commit body, and its plain-language line under a **Tests changed** heading in the PR description; writing that section is part of this step (kernel § Tests). An undisclosed edit is fixed here by disclosing it, not by halting. The one exception: if the honest tag would be *it was failing*, halt and fix the code instead.
|
|
29
29
|
|
|
30
30
|
5. **Ask each living doc whether this diff invalidated it**, and update it in this PR when it did (kernel § Context docs). When an entry point changed status — live, routable, off — the exposure column of the Module Map in `app-architecture.md` moves with it.
|
|
31
31
|
|
|
@@ -45,6 +45,6 @@ One open PR against the default branch, carrying the code, the living-doc update
|
|
|
45
45
|
|
|
46
46
|
Beyond the kernel's:
|
|
47
47
|
|
|
48
|
-
- A pre-existing test was
|
|
48
|
+
- A pre-existing test was changed to turn a red suite green when the code is what is wrong.
|
|
49
49
|
- A hook or a check was bypassed to get here.
|
|
50
50
|
- A living doc is invalidated and you cannot update it. Say "stale" in the PR description; never invent the content.
|
|
@@ -33,6 +33,13 @@
|
|
|
33
33
|
<!-- Conscious shortcuts that survive the merge, each with its hstack/tech-debt/TD-NNNN-<slug>.md
|
|
34
34
|
file. "None" is a real answer when it is true. -->
|
|
35
35
|
|
|
36
|
+
## Tests changed
|
|
37
|
+
|
|
38
|
+
<!-- Every test that existed at the merge-base and was modified or deleted here, one line each,
|
|
39
|
+
in plain language, tagged behavior-change / refactor / obsolete as in the commit body. A PR
|
|
40
|
+
that touches a test and has no such list is incomplete. Where it was unclear whether the
|
|
41
|
+
test or the code was wrong, say so here as an open question. -->
|
|
42
|
+
|
|
36
43
|
## Review findings
|
|
37
44
|
|
|
38
45
|
<!-- /review and /security-review, in full. These are LLM judgments, not evidence: an empty list
|
package/template/KERNEL.md
CHANGED
|
@@ -64,27 +64,27 @@ Two CI lanes: the fast one — typecheck, lint, critical tests — blocks the me
|
|
|
64
64
|
|
|
65
65
|
Tests are mandatory on critical paths and on every business invariant a change touches. At plan time, one question: *does this code decide something that would be wrong silently?* If it does, a test names the invariant. `/hstack-test-audit` is on demand, never a per-change phase.
|
|
66
66
|
|
|
67
|
-
|
|
67
|
+
**Changing an existing test is normal work.** A product before product-market fit changes its intended behaviour several times a week, and the tests move with it. No authorization phrase, no halt, no permission to request.
|
|
68
68
|
|
|
69
|
-
|
|
69
|
+
**The one forbidden move** is changing a test so that a red suite goes green when the code under test is what is wrong. Before editing an existing test, one question: *is the test wrong, or is the code wrong?* Fix whichever one is wrong — never the other one.
|
|
70
70
|
|
|
71
|
-
|
|
71
|
+
**When it cannot tell**, the agent makes the most plausible change and names the doubt in the PR description as an open question, never silently and never by halting. An unresolved doubt is information the reviewer needs, not a reason to stop working.
|
|
72
72
|
|
|
73
|
-
**
|
|
73
|
+
**Disclosure replaces authorization.** Any commit that modifies or deletes a test file that existed at the merge-base says so in its body, one line per file, tagged with exactly one word:
|
|
74
74
|
|
|
75
|
-
|
|
75
|
+
- `behavior-change` — the intended behaviour moved and the test followed it.
|
|
76
|
+
- `refactor` — same assertions, moved or renamed or rewired (imports, mocks, fixtures).
|
|
77
|
+
- `obsolete` — the subject of the test no longer exists.
|
|
76
78
|
|
|
77
|
-
|
|
79
|
+
There is no fourth tag. If the honest word would be *it was failing*, that is the forbidden move, not a disclosure.
|
|
78
80
|
|
|
79
|
-
**
|
|
81
|
+
The PR description repeats the same list in plain language, under a **Tests changed** heading. The commit body is for the audit; that section is for the human, who reads the description and not the diff. A PR that touches a test and has no such section is incomplete.
|
|
82
|
+
|
|
83
|
+
**What counts as a test.** Files matching the repo's test patterns (e.g. `*.test.ts`, `*.spec.ts`, `__tests__/**/*`, `e2e/**/*`, `*_test.go`), snapshot files (`__snapshots__/*`), and assertion-bearing fixtures — factories and seed data encoding expected outputs.
|
|
80
84
|
|
|
81
|
-
-
|
|
82
|
-
- Bulk snapshot updates via `--update-snapshots`, `jest --updateSnapshot`, `vitest -u`, or any equivalent flag, including in pre-commit hooks.
|
|
83
|
-
- Relaxing an assertion without authorization (e.g., tightening a regex to a substring match, broadening a `.toBe()` to `.toContain()`, increasing a timeout to mask a real bug).
|
|
84
|
-
- Deleting a `.skip` annotation, replacing a `test()` call with `test.todo()`, or otherwise neutralizing a test without authorization. Neutralization is a form of deletion.
|
|
85
|
-
- Editing a test as part of "cleaning up" a phase without an explicit authorization for that test, even if the edit is cosmetic.
|
|
85
|
+
**Two things stay hard, because they hide from the diff.** Bulk snapshot updates via `--update-snapshots`, `jest --updateSnapshot`, `vitest -u` or any equivalent flag, including in hooks — a mass edit nobody reads is not a disclosure. And neutralizing a test silently: adding `.skip`, replacing `test()` with `test.todo()`, deleting a case, or loosening an assertion (a `.toBe()` broadened to `.toContain()`, a timeout raised to mask a real bug) are edits like any other and carry their disclosure line.
|
|
86
86
|
|
|
87
|
-
|
|
87
|
+
An undisclosed test edit is a review finding. A disclosed one is just work.
|
|
88
88
|
|
|
89
89
|
---
|
|
90
90
|
|