@massu/core 2.5.1 → 2.5.3

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.
Files changed (92) hide show
  1. package/CHANGELOG.md +240 -0
  2. package/agents/massu-output-scorer.md +2 -2
  3. package/agents/massu-plan-auditor.md +1 -1
  4. package/commands/_shared-references/test-first-protocol.md +4 -4
  5. package/commands/_shared-references/verification-table.md +5 -5
  6. package/commands/massu-audit-deps.md +2 -2
  7. package/commands/massu-batch.md +3 -3
  8. package/commands/massu-checkpoint.md +7 -7
  9. package/commands/massu-ci-fix.md +1 -1
  10. package/commands/massu-cleanup.md +16 -16
  11. package/commands/massu-commit.md +7 -7
  12. package/commands/massu-create-plan.md +7 -7
  13. package/commands/massu-dead-code.md +3 -3
  14. package/commands/massu-debug/references/common-shortcuts.md +1 -1
  15. package/commands/massu-debug/references/investigation-phases.md +4 -4
  16. package/commands/massu-debug/references/report-format.md +2 -2
  17. package/commands/massu-deploy.md +1 -1
  18. package/commands/massu-deps.md +5 -5
  19. package/commands/massu-doc-gen.md +3 -3
  20. package/commands/massu-docs.md +6 -6
  21. package/commands/massu-estimate.md +3 -3
  22. package/commands/massu-golden-path/references/competitive-mode.md +2 -2
  23. package/commands/massu-golden-path/references/phase-1-plan-creation.md +1 -1
  24. package/commands/massu-golden-path/references/phase-2-implementation.md +2 -2
  25. package/commands/massu-golden-path/references/phase-4-commit.md +3 -3
  26. package/commands/massu-golden-path/references/phase-5-push.md +5 -5
  27. package/commands/massu-guide.md +3 -3
  28. package/commands/massu-hotfix.md +14 -14
  29. package/commands/massu-loop/references/checkpoint-audit.md +3 -3
  30. package/commands/massu-loop/references/iteration-structure.md +3 -3
  31. package/commands/massu-loop/references/loop-controller.md +5 -5
  32. package/commands/massu-loop/references/plan-extraction.md +4 -4
  33. package/commands/massu-loop/references/vr-plan-spec.md +3 -3
  34. package/commands/massu-loop-playwright.md +5 -5
  35. package/commands/massu-loop.md +1 -1
  36. package/commands/massu-new-feature.md +6 -24
  37. package/commands/massu-perf.md +1 -1
  38. package/commands/massu-plan.md +21 -21
  39. package/commands/massu-push-light.md +9 -9
  40. package/commands/massu-recap.md +1 -1
  41. package/commands/massu-refactor.md +8 -8
  42. package/commands/massu-release.md +3 -3
  43. package/commands/massu-review.md +1 -1
  44. package/commands/massu-rollback.md +6 -6
  45. package/commands/massu-scaffold-page.md +1 -1
  46. package/commands/massu-scaffold-router.md +1 -1
  47. package/commands/massu-status.md +9 -9
  48. package/commands/massu-tdd.md +2 -2
  49. package/commands/massu-test.md +13 -13
  50. package/commands/massu-verify-playwright.md +1 -1
  51. package/commands/massu-verify.md +20 -20
  52. package/dist/cli.js +1731 -976
  53. package/dist/hooks/auto-learning-pipeline.js +745 -87
  54. package/dist/hooks/classify-failure.js +747 -45
  55. package/dist/hooks/cost-tracker.js +89 -28
  56. package/dist/hooks/fix-detector.js +536 -48
  57. package/dist/hooks/incident-pipeline.js +96 -29
  58. package/dist/hooks/intent-suggester.js +89 -28
  59. package/dist/hooks/memory-recall.js +89 -28
  60. package/dist/hooks/post-edit-context.js +137 -29
  61. package/dist/hooks/post-tool-use.js +95 -30
  62. package/dist/hooks/pre-compact.js +89 -28
  63. package/dist/hooks/pre-delete-check.js +137 -31
  64. package/dist/hooks/pre-tool-use-gate.js +271 -43
  65. package/dist/hooks/quality-event.js +89 -28
  66. package/dist/hooks/rule-enforcement-pipeline.js +89 -28
  67. package/dist/hooks/security-gate.js +219 -39
  68. package/dist/hooks/session-end.js +92 -28
  69. package/dist/hooks/session-start.js +140 -62
  70. package/dist/hooks/user-prompt.js +89 -28
  71. package/fragments/feature-components.md +15 -0
  72. package/fragments/feature-components.python.md +15 -0
  73. package/fragments/feature-components.typescript.md +15 -0
  74. package/package.json +6 -5
  75. package/patterns/testing-patterns.md +8 -8
  76. package/protocols/plan-implementation.md +2 -2
  77. package/protocols/verification.md +4 -4
  78. package/reference/lessons-learned.md +4 -4
  79. package/reference/vr-verification-reference.md +9 -9
  80. package/templates/aspnet/massu.config.yaml +2 -0
  81. package/templates/go-chi/massu.config.yaml +2 -0
  82. package/templates/multi-runtime/massu.config.yaml +4 -2
  83. package/templates/phoenix/massu.config.yaml +2 -0
  84. package/templates/python-django/massu.config.yaml +3 -1
  85. package/templates/python-fastapi/massu.config.yaml +3 -1
  86. package/templates/python-flask/massu.config.yaml +3 -1
  87. package/templates/rails/massu.config.yaml +4 -2
  88. package/templates/rust-actix/massu.config.yaml +2 -0
  89. package/templates/spring/massu.config.yaml +2 -0
  90. package/templates/swift-ios/massu.config.yaml +3 -1
  91. package/templates/ts-nestjs/massu.config.yaml +2 -0
  92. package/templates/ts-nextjs/massu.config.yaml +2 -0
package/CHANGELOG.md CHANGED
@@ -10,6 +10,246 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
10
10
  > redistributed under the **Apache License 2.0**. Full license + NOTICE:
11
11
  > `packages/core/assets/embedder/MODEL-LICENSE`.
12
12
 
13
+ ## [2.5.3] - 2026-11-08
14
+
15
+ ### Added
16
+
17
+ - **Installed commands and agents now match your stack, not massu's own.** massu detected a
18
+ project's stack correctly and then installed the same TypeScript-shaped command set into every
19
+ repository, so a Python project's checks ran `npm test` and `npx tsc --noEmit` against a tree
20
+ that has neither, found nothing, and reported clean. The shipped assets now render the
21
+ toolchain from `massu.config.yaml`: measured on a python-fastapi fixture, the 83 `npm test`
22
+ references became `pytest`, and `npx tsc --noEmit` became `mypy`. Stack capabilities are
23
+ resolved once and all 13 shipped templates are held to that contract.
24
+ - **`paths.tests` config key.** About 25 assets told every project its tests belong in massu's
25
+ own `packages/core/src/__tests__/`. The test directory is now a config property. It is
26
+ optional, so every existing config keeps working.
27
+ - **`{{> name}}` fragments in templates.** Block-level, stack-specific content (for example the
28
+ "where a new feature goes" section of `/massu-new-feature`) now lives in one shared body with a
29
+ per-stack fragment, instead of telling a FastAPI user to edit `tools.ts`.
30
+
31
+ ### Fixed
32
+
33
+ - **`massu show-template` printed the raw template while the installer wrote rendered bytes.**
34
+ The diff the installer suggests (`diff <target> <(npx massu show-template <base>)`) therefore
35
+ reported differences that did not exist. It now prints what would be installed.
36
+ - **The template-syntax README was silently dropped from every install since 1.3.0.** It
37
+ documents `{{variable.path}}` literally, the renderer tried to resolve it, and the error was
38
+ counted as "skipped" with exit 0. Documentation is no longer rendered.
39
+ - **The knowledge index read about half of a project's canonical rules.** The CR-table parser's
40
+ `[^|]+` matched newlines, so in a three-column table each row consumed the next: 21 of 41
41
+ rules were indexed in this repository, for the life of the feature. Every row is now read.
42
+ - **The fix detector cried wolf on English.** `auth`, `lock` and `rate.limit` matched inside
43
+ "author", "blocked" and "corporate_limits". Every heuristic is now word-bounded,
44
+ `method_name_correction` (which fired on any two differently named method calls) is retired,
45
+ and a numbered Markdown heading is no longer read as an incident title.
46
+ - **The security gate flagged its own documentation.** `os.system() — shell injection risk`
47
+ fired on a comment quoting the call and on a test fixture holding it as a string. Python
48
+ content is now judged on code, not on prose that mentions the pattern.
49
+ - **`corrections.md` has one owner.** Its filename, path and placement were rebuilt in five
50
+ places. One module now owns them, so a hook and the indexer cannot disagree about where it is.
51
+ - **`zod` moves to 4 (GHSA-mrhx-c7xc-m3w5, high, covers every zod 3 release).** Config parsing is
52
+ unchanged. zod 4's `.default()` no longer parses its value, so every object-level config default
53
+ now uses `.prefault()`; without that, a section left out of `massu.config.yaml` would have come
54
+ back empty instead of filled with its defaults.
55
+ - **Dependency advisories cleared** (`smol-toml` ^1.8.0, `vitest` ^4.1.12).
56
+ - **The auto-learning Stop hook no longer counts keywords inside strings and comments, and no
57
+ longer repeats itself.** It matched fix keywords (`try`, `catch`, `raise`, …) against raw diff
58
+ text, so `"The catch"` in a Python string counted as error handling, and it re-read the working
59
+ tree on every Stop with no record of what it had already shown. One false positive repeated
60
+ after every reply until the file was committed. Added lines are now scored on their CODE spans by
61
+ a per-language lexer (`hooks/lib/code-spans.ts`: escapes, triple quotes, template literals,
62
+ block comments, regex literals), which the per-edit fix detector now shares. Languages without a
63
+ lexer are judged as before and named in the hook's debug output. The hook keeps a per-session
64
+ record of the matched lines it has shown and speaks again only when a new one appears. Diff file
65
+ headers (`--- a/src/error.ts`) are no longer scored as removed lines.
66
+
67
+ - **The release ceremony contained a step it could not reach.** CR-64 makes a published
68
+ version immutable: once `X.Y.Z` is on npm, HEAD must be exactly the `vX.Y.Z` tag, so any
69
+ further commit at that version cannot be pushed. The ceremony nonetheless listed the
70
+ `.mcp.json` pin update (step 8) and the master-plan row (step 10) *after* `npm publish`
71
+ (step 6) — two commits at a version that forbids commits. Unreachable by construction, and
72
+ only visible at the moment someone tried to perform them.
73
+
74
+ The step order now matches what has always actually worked: every repository commit lands
75
+ first, the tag is placed at the final tip, and publishing happens last. Nothing about the
76
+ invariant changed; the written order was wrong.
77
+
78
+ - **`.mcp.json` pin drift is now caught on the commit that causes it, not at the next
79
+ release.** A drive-by edit in an unrelated commit had replaced the pin with a machine-local
80
+ path and a stale version, breaking the publish path for two days while every commit, push
81
+ and CI run stayed green — the only check that catches it runs at publish time.
82
+
83
+ ## [2.5.2] - 2026-08-14
84
+
85
+ ### Fixed
86
+
87
+ - **The code-intelligence index was empty, and an empty index looked exactly like a project
88
+ with no imports.** Ten places across seven modules each answered "where does this project's
89
+ source live?" with the literal `src/`. In any layout that is not single-package every one of
90
+ them matched nothing: the import index consumed **0 of 1266** indexed files, the page index
91
+ found **0 of 69** real pages, cross-domain analysis saw one package of four, and two hooks
92
+ exited silently on every edit and every deletion. Nothing reported it, because a builder that
93
+ reads no rows returns `0` and the caller prints that as a normal result.
94
+
95
+ The layout now declares itself in `massu.config.yaml` and every consumer asks one module.
96
+ Everything is derived from declarations that already existed — `paths.source`,
97
+ `paths.monorepo_roots`, `framework.languages.*.source_dirs`, `paths.pages`,
98
+ `paths.components` — and one definition feeds both the SQL predicates and the in-JS path
99
+ guards, so widening a query cannot leave its recursion guard behind. A builder whose declared
100
+ source dirs match **0 rows of a non-empty** file table now raises an error naming the
101
+ denominator, the declaration, and the prefixes actually present. The contract is `0-of-N`,
102
+ never `0`: a repo with an empty or not-yet-built index legitimately matches nothing and must
103
+ not trip it.
104
+
105
+ Measured after, on the same corpus: 1128 of 1266 files consumed, 1096 import edges where the
106
+ table had been empty, 69 pages indexed, and every downstream read site non-empty.
107
+
108
+ - **A failed knowledge re-index was indistinguishable from a successful one.** The helper that
109
+ refreshes the markdown corpus caught every exception without binding it and returned a boolean
110
+ the only call site discarded. A corrupt database, a permissions error and a search-index
111
+ failure therefore produced byte-identical output to a healthy rebuild: the tool answered from
112
+ whatever the index held before and said nothing.
113
+
114
+ The error is now bound and recorded, and a failed refresh prepends a notice to the response so
115
+ the caller knows the answer may be stale. Loud is not fatal — the tool still answers from the
116
+ index it has, because turning a degradation into an outage for all twelve knowledge tools is
117
+ what the "degrade gracefully" contract exists to avoid.
118
+
119
+ The rebuild itself is no longer a side effect of dispatching. It cost 677 documents / 11,954
120
+ chunks on any file-modification under four scanned roots, and no caller had asked for it;
121
+ callers now state their intent explicitly, with no default, so an unrequested full rebuild
122
+ cannot happen by omission.
123
+
124
+ - **The session-end fix reminder fired on other sessions' work, and could not be discharged.**
125
+ Three defects compounded. Documentation was excluded from two of the three git reads but not
126
+ from the one whose text is actually scored, so the exclusion held only when a diff was
127
+ documentation-only — change any code file and prose was scored as code again. The diff was
128
+ read over the whole working tree with no notion of who made the changes, so on a machine where
129
+ several sessions hold one repository at once the reminder routinely demanded an artifact for
130
+ work the blocked session had not done. And the `autoLearning.fixDetection.enabled` switch,
131
+ which reads as the control for fix detection, never reached this reminder at all.
132
+
133
+ All three git reads now carry the documentation exclusion; the scan is intersected with files
134
+ the acting session actually touched, including the body read and not merely the gate; and the
135
+ switch gates both halves. When the actor cannot be established the reminder stays **silent** —
136
+ a demand that no legal action can discharge is one people route around, after which nothing is
137
+ enforced. The verdict carries a reason and a scanned-file count, so a negative result is never
138
+ an unexplained silence.
139
+
140
+ - **The reality gate's hook check was red forever, and the only way to green it was to
141
+ destroy its own evidence.** R-3 failed on the LIFETIME row count of
142
+ `.massu/hook-failures.jsonl`, an append-only log retained on purpose. From the first
143
+ failure ever recorded the gate stayed red permanently — at 11,116 rows it had long since
144
+ stopped carrying information, and a gate whose sole remedy is deleting its input is one
145
+ people learn to route around.
146
+
147
+ The predicate is now RECENCY: the check fails when a failure lies inside a bounded window
148
+ (default 24h, `MASSU_HOOK_FAILURE_WINDOW_HOURS`) and names the offending row's timestamp
149
+ and hook, while the historical backlog is reported as context and never truncated. The
150
+ denominator prints on every run, so "scanned 0 rows, found 0 failures" can never be
151
+ mistaken for a clean log.
152
+
153
+ An absent log is no longer collapsed into either answer. It is corroborated against the
154
+ independent `hook_health` table the same writer populates: rows there prove failures were
155
+ recorded in this checkout, so a missing file means the evidence was destroyed and the gate
156
+ fails; no rows means there is nothing to measure and the check skips with the reason
157
+ named. Treating absence as an error — as originally specified — would have made the
158
+ nightly gate permanently red in CI, where the log is gitignored, and on every fresh
159
+ install, where it is created lazily on first failure.
160
+
161
+ Not a package change: `scripts/` is not in the published `files` array.
162
+ Plan `plan-2026-08-11-hook-failure-signal-truthfulness`.
163
+
164
+ - **The release verifier reported FAIL on a publish that had fully succeeded.** It slept two
165
+ seconds, read the npm registry once, and treated "the replica has not caught up" and "the
166
+ publish did not land" as the same answer. npm is read-after-write eventually consistent, so
167
+ both states produce the identical value.
168
+
169
+ This is the blind-gate law with the polarity flipped: usually absence reads as PASS, here it
170
+ read as FAIL — the same defect, a check that cannot distinguish *not yet* from *not ever*.
171
+ The flipped polarity is what makes it dangerous, because a false FAIL on a release tool
172
+ invites a re-publish or a version bump against a registry where versions are immutable.
173
+
174
+ Replaced with a deadline-bounded poll (90s, 3s interval, overridable) that reports how long
175
+ it waited and, on failure, states plainly that the absence is not propagation lag. The
176
+ demand itself was correct and is unchanged — `+ @massu/core@x.y.z` on stdout is not a
177
+ receipt; only the timeout was wrong.
178
+
179
+ Not a package change: `scripts/` is not in the published `files` array.
180
+
181
+ - **`require()` of a TypeScript specifier held CI red in both repos for two days.** A
182
+ `require()` is resolved by whatever loader is running — not by `tsc`, and not by the vitest
183
+ transform. Node only gained require-of-TypeScript in 22.18; `packages/core` declares
184
+ `engines.node >= 22.16.0` and CI pins exactly that floor, so three such calls in
185
+ `hooks-stdout-convention.test.ts` passed on a Node 26 dev machine and threw
186
+ `SyntaxError: Unexpected identifier 'as'` on every runner. Replaced with a static ESM import
187
+ and guarded by a new drift-guard, which is a static property of the source and so goes red on
188
+ any Node version. A fourth call site in production code was found by enumerating the tree
189
+ rather than the failure, and stays: `require()` defers evaluation while a static import is
190
+ eager, and that laziness is what keeps a database load failure from silencing the hook-failure
191
+ signal it records.
192
+
193
+ - **Publication to the public mirror now goes through a pull request.** A direct push to the
194
+ mirror's `main` cannot be gated by its required status checks — checks have not run on a
195
+ commit that does not exist yet — so every sync reported `Bypassed rule violations` and landed
196
+ regardless. That is what hid the above for two days. `scripts/ops/publish-public-mirror.sh`
197
+ derives the required contexts from the live ruleset, polls each to a deadline, treats a
198
+ cancelled or missing verdict as *not* a pass, and merges by rebase only when every one is
199
+ SUCCESS. It enforces the verdict itself rather than relying on the ruleset, because the
200
+ ruleset grants the pushing account a standing bypass.
201
+
202
+ - **A bcrypt cost factor was a wall-clock budget in disguise.** `generateApiKey()` hashes at
203
+ cost 12 — ~350ms of deliberate CPU — in three tests that do not test hashing, which blew
204
+ vitest's 5000ms timeout under the concurrent coverage run while passing in isolation. Lowering
205
+ the cost factor would have been a security regression with nothing in the tree to catch it, so
206
+ `BCRYPT_COST` is now named and the property is asserted directly: the configured cost reaches
207
+ bcrypt, with the full key and never the plaintext-stored prefix.
208
+
209
+ - **Importing any of 18 hook modules executed the hook.** A bare `main()` at module scope means
210
+ importing the module reads stdin, does its work, and exits the host process. Enumerating the
211
+ tree found 15 with no guard and 2 more guarded by a filename suffix — invisible to a sweep for
212
+ "unguarded", and disarmed silently by a rename. All 18 now share one
213
+ `isDirectInvocation(import.meta.url)` helper, proven behaviourally against the built bundles.
214
+
215
+ - **A live destructive-path defect was hiding behind a permanently-red CI job.** Three sites in a
216
+ test harness widened to the filesystem root when a variable was empty, one of them under the
217
+ memory-store tree. The guard had been reporting it correctly on every run for long enough that
218
+ its redness stopped carrying information. Destructive paths there now go through a chokepoint
219
+ that cannot express the unsafe form. (Plan
220
+ `plan-2026-08-08-incident-coverage-range-discharge`: the CR-62 linkage ratchet shipped
221
+ 2026-08-09 gains its real-history differential, which shows all 10 post-ratchet obligated
222
+ commits discharging via containment or citation and none via the legacy fallback.)
223
+
224
+ None of these are package changes: `scripts/` and `__tests__/` are not in the published
225
+ `files` array, and `website/` is not published.
226
+
227
+ - **`massu watch` could start a file watcher that was dead for its entire lifetime.** chokidar
228
+ can return a watcher that emits `ready`, emits no `error`, and then delivers nothing, ever.
229
+ Interleaved A/B in a single load window: fsevents **8 of 60** dead against **0 of 60** for the
230
+ same directories with polling (Fisher's exact ≈ 0.006). The consequence for a user is silent
231
+ staleness — `.claude/` stops refreshing, `massu watch --status` looks healthy, and nothing is
232
+ logged. Nothing in the daemon would ever have noticed: its only reconcile trigger was a tick
233
+ gap over 30s, whose predicate is *"did the clock jump?"* while the property is *"might we have
234
+ missed events?"*, and a watcher dead from birth produces no tick gap at all.
235
+
236
+ The tick now writes a sentinel the watcher itself must echo back. Silence is treated as death:
237
+ log loudly, reconcile, and after two consecutive dead intervals close and re-watch. Escalation
238
+ fires on powers of two of the dead streak, so a permanently dead watcher cannot trade a
239
+ silent-staleness bug for a full refresh plus a watcher rebuild every ten seconds forever.
240
+ Polling was rejected as the fix — it trades a correctness bug for a battery-life bug.
241
+
242
+ Two constants here are claims about the outside world and were measured rather than assumed.
243
+ The canary shares ONE recursive FSEvents stream with the watched source directories (verified
244
+ by recording the paths streams are actually opened on — a canary on its own stream could have
245
+ been alive while the source watcher was dead), and its grace floor is set from measured echo
246
+ latency: ~48ms median, but a tail to 941ms under contention.
247
+ `scripts/ops/measure-canary-echo-latency.mjs` ships so the number can be re-checked instead of
248
+ trusted. Plan `plan-2026-08-12-watch-daemon-silent-dead-watcher`.
249
+
250
+ This one IS a package change: `packages/core/src/watch/daemon.ts` and the new
251
+ `packages/core/src/watch/canary.ts` are published.
252
+
13
253
  ## [2.5.1] - 2026-08-09
14
254
 
15
255
  ### Fixed
@@ -73,7 +73,7 @@ Input: List of files changed, plan document path, feature description.
73
73
  #### Dimension 5: Test Coverage
74
74
  - Check: test files exist for new features
75
75
  - Check: critical paths have test coverage
76
- - Run `npm test` to verify passing
76
+ - Run `{{verify.test | default("declare verification.LANG.test in massu.config.yaml")}}` to verify passing
77
77
  - 1=no tests, 3=basic tests pass, 5=comprehensive coverage
78
78
 
79
79
  ### Step 3: Generate Scorecard
@@ -86,7 +86,7 @@ Input: List of files changed, plan document path, feature description.
86
86
  | Pattern Compliance | X/5 | pattern-scanner exit code | |
87
87
  | Error Handling | X/5 | [grep results for error states] | |
88
88
  | UX Quality | X/5 | [responsive/a11y checks] | |
89
- | Test Coverage | X/5 | npm test result | |
89
+ | Test Coverage | X/5 | {{verify.test | default("declare verification.LANG.test in massu.config.yaml")}} result | |
90
90
 
91
91
  ### Summary
92
92
  - Average: X.X/5
@@ -129,7 +129,7 @@ grep -rn "[old-pattern]" src/
129
129
  ### Step 7: Pattern Compliance
130
130
  ```bash
131
131
  ./scripts/pattern-scanner.sh
132
- npx tsc --noEmit
132
+ {{verify.type | default("declare verification.LANG.type in massu.config.yaml")}}
133
133
  ```
134
134
 
135
135
  ### Step 8: Generate Structured Audit Report
@@ -40,7 +40,7 @@ it('should serialize BigInt fields to Number', () => {
40
40
  Run the test and confirm it fails for the expected reason:
41
41
 
42
42
  ```bash
43
- npm test -- -t "should serialize BigInt"
43
+ {{verify.test | default("declare verification.LANG.test in massu.config.yaml")}} -- -t "should serialize BigInt"
44
44
  # Expected: FAIL with the specific assertion error
45
45
  # Note: This project uses Vitest. Use -t (--testNamePattern) for filtering, NOT --grep.
46
46
  ```
@@ -57,14 +57,14 @@ Now fix the source code. The fix should be minimal and targeted.
57
57
  ### Step 4: Verify Test Passes
58
58
 
59
59
  ```bash
60
- npm test -- -t "should serialize BigInt"
60
+ {{verify.test | default("declare verification.LANG.test in massu.config.yaml")}} -- -t "should serialize BigInt"
61
61
  # Expected: PASS
62
62
  ```
63
63
 
64
64
  Run the full test suite to check for regressions:
65
65
 
66
66
  ```bash
67
- npm test
67
+ {{verify.test | default("declare verification.LANG.test in massu.config.yaml")}}
68
68
  # Expected: ALL pass
69
69
  ```
70
70
 
@@ -77,7 +77,7 @@ TEST-FIRST PROTOCOL for: [finding description]
77
77
  Step 1: Test written → [file:line]
78
78
  Step 2: Test fails → [error message confirming the bug]
79
79
  Step 3: Fix applied → [file:line, description]
80
- Step 4: Test passes → [npm test output showing pass]
80
+ Step 4: Test passes → [{{verify.test | default("declare verification.LANG.test in massu.config.yaml")}} output showing pass]
81
81
  TEST_FIRST_GATE: PASS
82
82
  ```
83
83
 
@@ -10,9 +10,9 @@
10
10
 
11
11
  | Type | Command | Expected | Use When |
12
12
  |------|---------|----------|----------|
13
- | VR-BUILD | `npm run build` | Exit 0 | Claiming production ready |
14
- | VR-TYPE | `npx tsc --noEmit` | 0 errors | Claiming type safety |
15
- | VR-TEST | `npm test` | ALL pass (MANDATORY) | ALWAYS before claiming complete |
13
+ | VR-BUILD | `{{verify.build | default("(this stack declares no build step)")}}` | Exit 0 | Claiming production ready |
14
+ | VR-TYPE | `{{verify.type | default("declare verification.LANG.type in massu.config.yaml")}}` | 0 errors | Claiming type safety |
15
+ | VR-TEST | `{{verify.test | default("declare verification.LANG.test in massu.config.yaml")}}` | ALL pass (MANDATORY) | ALWAYS before claiming complete |
16
16
  | VR-SCHEMA-PRE | `SELECT column_name FROM information_schema.columns WHERE table_name = 'X'` | All columns exist | BEFORE writing ANY query |
17
17
  | VR-NEGATIVE | `grep -rn "[old]" src/` | 0 matches | Claiming removal |
18
18
  | VR-GREP | `grep "[pattern]" [file]` | Match found | Claiming code added |
@@ -35,8 +35,8 @@
35
35
  | Gate | Command | Must |
36
36
  |------|---------|------|
37
37
  | 1. Pattern Scanner | `./scripts/pattern-scanner.sh` | Exit 0 |
38
- | 2. Type Safety | `npx tsc --noEmit` | 0 errors |
39
- | 3. Build | `npm run build` | Exit 0 |
38
+ | 2. Type Safety | `{{verify.type | default("declare verification.LANG.type in massu.config.yaml")}}` | 0 errors |
39
+ | 3. Build | `{{verify.build | default("(this stack declares no build step)")}}` | Exit 0 |
40
40
  | 4. Lint | `npm run lint` | Exit 0 |
41
41
  | 5. Schema | `npx prisma validate` | Exit 0 |
42
42
  | 6. Secrets Staged | `git diff --cached --name-only \| grep -E '\.(env\|pem\|key\|secret)'` | 0 files |
@@ -144,8 +144,8 @@ cat package.json | node -e "
144
144
  ```bash
145
145
  # Check if each dependency is actually imported in source
146
146
  for dep in $(node -e "const p=require('./package.json'); Object.keys(p.dependencies||{}).forEach(d=>console.log(d))"); do
147
- count=$(grep -rn "from ['\"]$dep" packages/core/src/ --include="*.ts" 2>/dev/null | wc -l | tr -d ' ')
148
- count2=$(grep -rn "require(['\"]$dep" packages/core/src/ --include="*.ts" 2>/dev/null | wc -l | tr -d ' ')
147
+ count=$(grep -rn "from ['\"]$dep" {{paths.source}}/ --include="*.ts" 2>/dev/null | wc -l | tr -d ' ')
148
+ count2=$(grep -rn "require(['\"]$dep" {{paths.source}}/ --include="*.ts" 2>/dev/null | wc -l | tr -d ' ')
149
149
  total=$((count + count2))
150
150
  if [ "$total" -eq 0 ]; then
151
151
  echo "UNUSED: $dep (0 imports found)"
@@ -191,7 +191,7 @@ FOR each batch (IN PARALLEL):
191
191
  After ALL files are modified:
192
192
  7. Run: ./scripts/pattern-scanner.sh --single-file [file] for each changed file
193
193
  8. If pattern-scanner finds violations, fix them
194
- 9. Run: NODE_OPTIONS='--max-old-space-size=8192' npx tsc --noEmit
194
+ 9. Run: NODE_OPTIONS='--max-old-space-size=8192' {{verify.type | default("declare verification.LANG.type in massu.config.yaml")}}
195
195
  10. If tsc finds errors in your changed files, fix them
196
196
 
197
197
  ## Output Format (MANDATORY)
@@ -240,10 +240,10 @@ Run on the consolidated result:
240
240
  ./scripts/pattern-scanner.sh
241
241
 
242
242
  # Full type check
243
- NODE_OPTIONS="--max-old-space-size=8192" npx tsc --noEmit
243
+ NODE_OPTIONS="--max-old-space-size=8192" {{verify.type | default("declare verification.LANG.type in massu.config.yaml")}}
244
244
 
245
245
  # Build check
246
- npm run build
246
+ {{verify.build | default("(this stack declares no build step)")}}
247
247
  ```
248
248
 
249
249
  ### Step 8: Output Structured Result
@@ -265,16 +265,16 @@ Then manual checks (all expect 0):
265
265
  ### Step 6: RUN Build Verification (VR-BUILD)
266
266
 
267
267
  ```bash
268
- npm run build
268
+ {{verify.build | default("(this stack declares no build step)")}}
269
269
  ```
270
270
 
271
271
  ### Step 6.5: Additional Verification Gates
272
272
 
273
273
  ```bash
274
- npx tsc --noEmit # VR-TYPE: 0 errors
274
+ {{verify.type | default("declare verification.LANG.type in massu.config.yaml")}} # VR-TYPE: 0 errors
275
275
  npm run lint # VR-LINT: Exit 0
276
276
  npx prisma validate # VR-SCHEMA-VALIDATE: Exit 0
277
- npm test # VR-TEST: MANDATORY, ALL pass
277
+ {{verify.test | default("declare verification.LANG.test in massu.config.yaml")}} # VR-TEST: MANDATORY, ALL pass
278
278
  ./scripts/pre-deploy-check.sh 2>/dev/null || echo "No pre-deploy script"
279
279
  ```
280
280
 
@@ -282,10 +282,10 @@ npm test # VR-TEST: MANDATORY, ALL pass
282
282
  ### Additional Gates
283
283
  | Gate | Command | Result | Status |
284
284
  |------|---------|--------|--------|
285
- | Type Safety | npx tsc --noEmit | 0 errors | PASS/FAIL |
285
+ | Type Safety | {{verify.type | default("declare verification.LANG.type in massu.config.yaml")}} | 0 errors | PASS/FAIL |
286
286
  | Lint | npm run lint | Exit 0 | PASS/FAIL |
287
287
  | Prisma Validate | npx prisma validate | Valid | PASS/FAIL |
288
- | Tests | npm test | ALL Pass | PASS/FAIL |
288
+ | Tests | {{verify.test | default("declare verification.LANG.test in massu.config.yaml")}} | ALL Pass | PASS/FAIL |
289
289
  | Pre-deploy | pre-deploy-check.sh | Pass/N/A | PASS/FAIL/N/A |
290
290
  ```
291
291
 
@@ -566,9 +566,9 @@ Checkpoint MUST abort if: pattern scanner fails, security violation detected, bu
566
566
  ## PARALLEL EXECUTION
567
567
 
568
568
  Independent checks can run simultaneously via Task agents:
569
- - Agent 1: `npx tsc --noEmit`
569
+ - Agent 1: `{{verify.type | default("declare verification.LANG.type in massu.config.yaml")}}`
570
570
  - Agent 2: `./scripts/pattern-scanner.sh`
571
- - Agent 3: `npm run build`
571
+ - Agent 3: `{{verify.build | default("(this stack declares no build step)")}}`
572
572
  - Agent 4: `npm run test:run`
573
573
 
574
574
  ---
@@ -59,7 +59,7 @@ Map the failure to a known pattern:
59
59
  2. Run the same check locally to verify:
60
60
  ```bash
61
61
  # Run the specific check that failed
62
- npm run build # or whatever CI step failed
62
+ {{verify.build | default("(this stack declares no build step)")}} # or whatever CI step failed
63
63
  ```
64
64
  3. Verify fix passes locally
65
65
 
@@ -48,7 +48,7 @@ Capture the behavioral baseline BEFORE making any changes:
48
48
  ### 1a. Test Baseline
49
49
 
50
50
  ```bash
51
- npm test 2>&1
51
+ {{verify.test | default("declare verification.LANG.test in massu.config.yaml")}} 2>&1
52
52
  ```
53
53
 
54
54
  Record:
@@ -64,7 +64,7 @@ Record:
64
64
  ### 1b. Type Check Baseline
65
65
 
66
66
  ```bash
67
- cd packages/core && npx tsc --noEmit 2>&1
67
+ {{verify.type | default("declare verification.LANG.type in massu.config.yaml")}} 2>&1
68
68
  ```
69
69
 
70
70
  Record:
@@ -90,20 +90,20 @@ Scan all categories in parallel. Do NOT remove anything yet.
90
90
 
91
91
  ```bash
92
92
  # TypeScript unused imports (ts error 6133)
93
- cd packages/core && npx tsc --noEmit 2>&1 | grep "is declared but"
93
+ {{verify.type | default("declare verification.LANG.type in massu.config.yaml")}} 2>&1 | grep "is declared but"
94
94
 
95
95
  # ESLint-style: imports never referenced in file body
96
- grep -rn "^import" packages/core/src/ --include="*.ts" | head -50
96
+ grep -rn "^import" {{paths.source}}/ --include="*.ts" | head -50
97
97
  ```
98
98
 
99
99
  ### 2b. Dead Exports
100
100
 
101
101
  ```bash
102
102
  # Exported symbols with zero external references
103
- grep -rn "^export " packages/core/src/ --include="*.ts" | grep -v "__tests__" | while IFS=: read file line content; do
103
+ grep -rn "^export " {{paths.source}}/ --include="*.ts" | grep -v "__tests__" | while IFS=: read file line content; do
104
104
  name=$(echo "$content" | grep -oP '(?<=export (function|const|class|type|interface|enum) )\w+' | head -1)
105
105
  if [ -n "$name" ]; then
106
- count=$(grep -rn "$name" packages/core/src/ --include="*.ts" | grep -v "^$file:" | grep -v "__tests__" | wc -l)
106
+ count=$(grep -rn "$name" {{paths.source}}/ --include="*.ts" | grep -v "^$file:" | grep -v "__tests__" | wc -l)
107
107
  if [ "$count" -eq 0 ]; then
108
108
  echo "DEAD EXPORT: $name in $file"
109
109
  fi
@@ -121,7 +121,7 @@ for f in packages/core/src/*.ts; do
121
121
  if [[ "$base" == "server" || "$base" == "index" || "$f" == *"__tests__"* ]]; then
122
122
  continue
123
123
  fi
124
- count=$(grep -rn "from.*['\"]\./${base}" packages/core/src/ --include="*.ts" | grep -v "__tests__" | wc -l)
124
+ count=$(grep -rn "from.*['\"]\./${base}" {{paths.source}}/ --include="*.ts" | grep -v "__tests__" | wc -l)
125
125
  if [ "$count" -eq 0 ]; then
126
126
  echo "POSSIBLY ORPHANED: $f"
127
127
  fi
@@ -135,15 +135,15 @@ done
135
135
  cat packages/core/package.json | grep -A 50 '"dependencies"'
136
136
 
137
137
  # Check each dependency usage
138
- grep -rn "from.*'better-sqlite3'\|require.*better-sqlite3" packages/core/src/ --include="*.ts" | wc -l
139
- grep -rn "from.*'yaml'\|require.*yaml" packages/core/src/ --include="*.ts" | wc -l
138
+ grep -rn "from.*'better-sqlite3'\|require.*better-sqlite3" {{paths.source}}/ --include="*.ts" | wc -l
139
+ grep -rn "from.*'yaml'\|require.*yaml" {{paths.source}}/ --include="*.ts" | wc -l
140
140
  ```
141
141
 
142
142
  ### 2e. TODO/FIXME/HACK Comments
143
143
 
144
144
  ```bash
145
145
  # Enumerate all stale markers — informational only (no auto-removal)
146
- grep -rn "TODO\|FIXME\|HACK\|XXX\|DEPRECATED" packages/core/src/ --include="*.ts" | grep -v "__tests__"
146
+ grep -rn "TODO\|FIXME\|HACK\|XXX\|DEPRECATED" {{paths.source}}/ --include="*.ts" | grep -v "__tests__"
147
147
  ```
148
148
 
149
149
  ---
@@ -180,9 +180,9 @@ CLEANUP LOOP:
180
180
  1. Select all REMOVE items in this category
181
181
  2. Apply removals
182
182
  3. Run type check:
183
- cd packages/core && npx tsc --noEmit 2>&1
183
+ {{verify.type | default("declare verification.LANG.type in massu.config.yaml")}} 2>&1
184
184
  4. Run tests:
185
- npm test 2>&1
185
+ {{verify.test | default("declare verification.LANG.test in massu.config.yaml")}} 2>&1
186
186
  5. Compare against baseline:
187
187
  - Type errors must be <= baseline
188
188
  - Passing tests must be >= baseline
@@ -218,11 +218,11 @@ For every removed item, confirm it is gone:
218
218
 
219
219
  ```bash
220
220
  # Unused import removed
221
- grep -rn "[import_name]" packages/core/src/ --include="*.ts"
221
+ grep -rn "[import_name]" {{paths.source}}/ --include="*.ts"
222
222
  # MUST return 0 matches (or only in unrelated contexts)
223
223
 
224
224
  # Dead export removed
225
- grep -rn "export.*[export_name]" packages/core/src/ --include="*.ts"
225
+ grep -rn "export.*[export_name]" {{paths.source}}/ --include="*.ts"
226
226
  # MUST return 0 matches
227
227
 
228
228
  # Orphaned file removed
@@ -253,13 +253,13 @@ bash scripts/massu-pattern-scanner.sh
253
253
 
254
254
  ### Gate 2: Type Check (VR-TYPE)
255
255
  ```bash
256
- cd packages/core && npx tsc --noEmit
256
+ {{verify.type | default("declare verification.LANG.type in massu.config.yaml")}}
257
257
  # MUST show 0 errors (or <= baseline)
258
258
  ```
259
259
 
260
260
  ### Gate 3: All Tests (VR-TEST)
261
261
  ```bash
262
- npm test
262
+ {{verify.test | default("declare verification.LANG.test in massu.config.yaml")}}
263
263
  # MUST exit 0, all tests pass
264
264
  ```
265
265
 
@@ -64,7 +64,7 @@ grep -n "name:" packages/core/src/[module]-tools.ts
64
64
  grep -n "case " packages/core/src/[module]-tools.ts
65
65
 
66
66
  # Verify config keys match getConfig() usage
67
- grep -rn "getConfig()" packages/core/src/ | head -20
67
+ grep -rn "getConfig()" {{paths.source}}/ | head -20
68
68
  ```
69
69
 
70
70
  ---
@@ -276,13 +276,13 @@ bash scripts/massu-pattern-scanner.sh
276
276
 
277
277
  ### Gate 2: Type Safety (VR-TYPE)
278
278
  ```bash
279
- cd packages/core && npx tsc --noEmit
279
+ {{verify.type | default("declare verification.LANG.type in massu.config.yaml")}}
280
280
  # MUST show 0 errors
281
281
  ```
282
282
 
283
283
  ### Gate 3: All Tests Pass (VR-TEST)
284
284
  ```bash
285
- npm test
285
+ {{verify.test | default("declare verification.LANG.test in massu.config.yaml")}}
286
286
  # MUST exit 0, all vitest tests pass
287
287
  ```
288
288
 
@@ -306,9 +306,9 @@ echo "PASS: No secrets staged"
306
306
 
307
307
  ### Gate 7: Security - No Credentials in Code
308
308
  ```bash
309
- # Check packages/core/src/ for hardcoded credentials
309
+ # Check {{paths.source}}/ for hardcoded credentials
310
310
  grep -rn 'sk-[a-zA-Z0-9]\{20,\}\|password.*=.*["\x27][^"\x27]\{8,\}' --include="*.ts" --include="*.tsx" \
311
- packages/core/src/ 2>/dev/null \
311
+ {{paths.source}}/ 2>/dev/null \
312
312
  | grep -v "process.env" \
313
313
  | grep -v 'RegExp\|regex\|REDACT\|redact\|sanitize\|mask' \
314
314
  | grep -v '\.test\.ts:' \
@@ -355,7 +355,7 @@ npm audit --audit-level=high # 0 high/critical vulnerabilities
355
355
  |------|---------|--------|--------|
356
356
  | 1. Pattern Scanner | massu-pattern-scanner.sh | Exit [X] | PASS/FAIL |
357
357
  | 2. Type Safety | tsc --noEmit | [X] errors | PASS/FAIL |
358
- | 3. Tests | npm test | [X] pass, [X] fail | PASS/FAIL |
358
+ | 3. Tests | {{verify.test | default("declare verification.LANG.test in massu.config.yaml")}} | [X] pass, [X] fail | PASS/FAIL |
359
359
  | 4. Hook Build | build:hooks | Exit [X] | PASS/FAIL |
360
360
  | 5. Generalization | massu-generalization-scanner.sh | Exit [X] | PASS/FAIL |
361
361
  | 6. No Secrets Staged | git diff --cached check | [result] | PASS/FAIL |
@@ -465,7 +465,7 @@ Analyze `git diff --cached --name-only` to determine scope:
465
465
 
466
466
  | Changed Files Location | Suggested Scope |
467
467
  |------------------------|-----------------|
468
- | All in `packages/core/src/` | `core` |
468
+ | All in `{{paths.source}}/` | `core` |
469
469
  | All in `website/` | `website` |
470
470
  | All in `.claude/commands/` | `commands` |
471
471
  | All in `scripts/` | `tooling` |
@@ -330,13 +330,13 @@ Proceed directly to PHASE 1 (Feature Understanding) as normal. Not every request
330
330
 
331
331
  ```bash
332
332
  # Search for similar features in codebase
333
- grep -rn "[feature_keyword]" packages/core/src/ --include="*.ts" | head -20
333
+ grep -rn "[feature_keyword]" {{paths.source}}/ --include="*.ts" | head -20
334
334
 
335
335
  # Find similar tool modules
336
336
  ls -la packages/core/src/*-tools.ts
337
337
 
338
338
  # Find similar tests
339
- ls -la packages/core/src/__tests__/
339
+ ls -la {{paths.tests | default("tests")}}/
340
340
  ```
341
341
 
342
342
  **Document findings:**
@@ -429,7 +429,7 @@ ls packages/core/src/__tests__/*.test.ts | wc -l
429
429
 
430
430
  ```bash
431
431
  # Check if target directories exist
432
- ls -la packages/core/src/
432
+ ls -la {{paths.source}}/
433
433
 
434
434
  # Check if files to modify exist
435
435
  ls -la [file_path]
@@ -692,7 +692,7 @@ Update coverage map: mark D6, D7, D8, D10 as `done`.
692
692
  - **File**: packages/core/src/__tests__/[module].test.ts
693
693
  - **Action**: CREATE
694
694
  - **Covers**: Tool definitions, handlers, edge cases
695
- - **Verification**: VR-TEST (npm test)
695
+ - **Verification**: VR-TEST ({{verify.test | default("declare verification.LANG.test in massu.config.yaml")}})
696
696
 
697
697
  ---
698
698
 
@@ -713,7 +713,7 @@ Update coverage map: mark D6, D7, D8, D10 as `done`.
713
713
  |------|------|---------------------|
714
714
  | P1-001 | MODULE | `ls -la packages/core/src/[module].ts` |
715
715
  | P1-002 | TOOL_WIRE | `grep "getXToolDefinitions" packages/core/src/tools.ts` |
716
- | P2-001 | TEST | `npm test` |
716
+ | P2-001 | TEST | `{{verify.test | default("declare verification.LANG.test in massu.config.yaml")}}` |
717
717
  | P3-001 | CONFIG | Parse config without error |
718
718
 
719
719
  ---
@@ -780,8 +780,8 @@ Update coverage map: mark D6, D7, D8, D10 as `done`.
780
780
  #### Build Feasibility
781
781
  | Check | Command | Result | Status |
782
782
  |-------|---------|--------|--------|
783
- | TypeScript compiles | cd packages/core && npx tsc --noEmit | 0 errors | PASS/FAIL |
784
- | Tests pass | npm test | All pass | PASS/FAIL |
783
+ | TypeScript compiles | {{verify.type | default("declare verification.LANG.type in massu.config.yaml")}} | 0 errors | PASS/FAIL |
784
+ | Tests pass | {{verify.test | default("declare verification.LANG.test in massu.config.yaml")}} | All pass | PASS/FAIL |
785
785
  | Hooks compile | cd packages/core && npm run build:hooks | Exit 0 | PASS/FAIL |
786
786
 
787
787
  **FEASIBILITY GATE: PASS / FAIL**