@thedecipherist/mdd 1.6.11 → 1.6.13

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.
@@ -158,6 +158,8 @@ Integration context: .mdd/jobs/audit-<date>/integration-context.md
158
158
  - "Immutable" rule arrays exported as plain mutable arrays — not `Object.freeze()` + `readonly`
159
159
  - Untrusted MCP/API/CLI input used without validation or sanitization
160
160
  - Data cached or stored without masking applied first
161
+ - Local reimplementation of security logic — any function named `isConfined`, `isAllowed`, `isSafe`, `isBlocked`, or similar that replicates what a documented security module already provides. Require replacement with the canonical security module function.
162
+ - Contract function undefined — if `integration_contracts` specifies a function name, grep the entire package for that name as an export. If the function does not exist anywhere, flag P1 regardless of whether call sites are present.
161
163
 
162
164
  **Note:** `satisfies_contracts status: pending` is checked by main in Phase A1, not here — agents cannot read feature docs.
163
165
 
@@ -168,7 +170,9 @@ Integration context: .mdd/jobs/audit-<date>/integration-context.md
168
170
  - File exceeds 300 lines
169
171
  - Function exceeds 50 lines
170
172
  - Transformation/substitution function handles some but not all AST/domain types (silent fallthrough for unhandled types)
173
+ - Switch on a string-union type or operation enum with no `default:` case, or where `default:` returns a value rather than throwing. Check all `switch` statements in execution, adapter, and transformation code. Approved pattern: `default: throw new Error(\`unhandled type: \${x satisfies never}\`)` — the `satisfies never` check produces a compile error when a new variant is added without updating the switch.
171
174
  - MCP-exposed function accepts untrusted params with no explicit validation
175
+ - Security parameter never passed — if a function accepts a policy param (allowedKeys, blockedDomains, securityConfig, etc.) that must come from a caller, verify the caller passes a non-empty, non-null value. If the parameter always arrives as `undefined`, `null`, or `[]`, the enforcement is a no-op.
172
176
 
173
177
  ### P3 Medium
174
178
  - TypeScript strict mode not enabled in tsconfig
@@ -176,6 +180,8 @@ Integration context: .mdd/jobs/audit-<date>/integration-context.md
176
180
  - Missing test cases for documented business rules
177
181
  - CLI command missing any of the universal flags (--env, --cwd, --verbose, --strict, --silent) — check all commands against the CLI feature doc's universal flags requirement
178
182
  - `file.*` filesystem helpers or path-resolving functions accept arbitrary paths without confinement to a documented jailRoot
183
+ - Code that constructs a `SecurityConfig` or equivalent security object sets `jailRoot: null`. A null jailRoot disables filesystem confinement — the default should be the document's directory (`dirname(resolvedPath)`), not `null`, unless the caller explicitly provides an override.
184
+ - `String.replace()` uses a captured group reference (`$1`, `$2`, etc.) in the replacement argument where the captured value originates from untrusted input. Values containing `$1`, `$&`, `$'`, etc. are silently mangled by JavaScript's substitution semantics. Sanitize with `.replace(/\$/g, '$$$$')` before interpolating into a replacement string.
179
185
  - Silent error swallow: catch block returns empty/undefined without pushing to warnings array
180
186
  - Template/substitution function matches `{{varname}}` without spaces but not `{{ varname }}` with spaces — spec uses spaced form; use regex `\s*` not exact string
181
187
 
@@ -262,11 +262,14 @@ satisfies_contracts:
262
262
  - from: <dependency-feature-id>
263
263
  function: <function-name>(<args>)
264
264
  when: <condition — e.g. "before any file read in executeInclude">
265
- status: pending change to "verified: <file>:<line>" during Phase 6
265
+ status: pending # change to done during Phase 6
266
+ verified_at: "" # set to "path/to/file.ts:lineN" when status is done
266
267
  ```
267
268
 
268
269
  **Leaving `satisfies_contracts` empty when a dependency has mandatory `integration_contracts` is a build error.** Do not proceed past Phase 3a until all applicable contracts are acknowledged.
269
270
 
271
+ **Before marking any `satisfies_contracts` entry `status: done`:** run `grep -rn '<function-name>'` across the entire package. Every call site must invoke the contract function — not just the one currently in focus. If the function is only wired in one layer (e.g. dispatcher) but not another (e.g. executor), the contract is not satisfied. Set `verified_at` to the confirmed call site before updating status.
272
+
270
273
  **Cross-cutting concerns that always require contract resolution:**
271
274
  - Any dependency tagged with `security`, `auth`, `masking`, `filesystem`, `audit`, `immutable` — its contracts are always mandatory
272
275
  - Any dependency that provides a "check before X" or "enforce Y" function — that function must be in your `satisfies_contracts`
@@ -339,6 +342,8 @@ describe('<Feature Name>', () => {
339
342
  - If BOTH unit AND E2E tests are needed → launch 2 parallel `general-purpose` agents. Each receives: the full MDD doc content, the skeleton template above, project testing conventions, and the exact output file path. Agent A writes `tests/unit/<feature-name>.test.ts`, Agent B writes `tests/e2e/<feature-name>.spec.ts`. These are different files — no write conflict is possible.
340
343
  - If only unit tests needed → generate directly in the main conversation (no agent overhead for a single file).
341
344
 
345
+ **CLI feature additional check:** If the feature adds or modifies CLI commands, add a skeleton that invokes each new command with `--help` and asserts all five universal flags (`--env`, `--cwd`, `--verbose`, `--strict`, `--silent`) appear in the output. This catches missing `universalOptions()` wiring before implementation begins.
346
+
342
347
  **E2E skeleton template (if applicable):**
343
348
  ```typescript
344
349
  import { test, expect } from '@playwright/test';
@@ -530,6 +535,8 @@ Execute blocks in dependency layer order (Layer 1 → 2 → 3 → 4). Within the
530
535
 
531
536
  **For sequential blocks:** read the MDD doc, read the relevant test skeletons, implement, run the Green Gate loop below.
532
537
 
538
+ **Directive/constant change ripple rule:** If this block changes any directive syntax, canonical header string, config key, or other string constant that other parts of the codebase may consume (e.g. language grammars, test fixtures, snippets, detection code), run `grep -rn 'old_string'` across the entire repo before marking the block complete. Update every consumer found — tmLanguage files, E2E fixtures, snippets, and any hardcoded string comparisons — in the same block, not as a follow-up.
539
+
533
540
  #### Step 6b — Green Gate loop (per block)
534
541
 
535
542
  After each block's implementation (sequential or parallel), run the Green Gate:
@@ -678,7 +685,8 @@ where the agent patches the wrong thing because it accepted an external excuse t
678
685
 
679
686
  1. **Contract verification gate** — before marking complete, check the feature doc's `satisfies_contracts`:
680
687
  - Any entry still `status: pending` means the integration was never wired
681
- - For each pending entry: locate the call site in the implementation, verify it exists, update to `verified: <file>:<line>`
688
+ - For each entry: run `grep -rn '<function-name>'` across the entire package. Every call site must invoke the contract function not just the one originally in scope. If a layer (e.g. executor vs dispatcher) is missing the call, the contract is not satisfied.
689
+ - Update each confirmed entry to `status: done` and `verified_at: "path/to/file.ts:lineN"` pointing to the confirmed call site.
682
690
  - If the call site is missing: implement it now (do not mark complete without it)
683
691
  - **A feature with any `pending` contract cannot be marked `status: complete`**
684
692
 
@@ -1,20 +1,20 @@
1
- ## MANUAL MODE `/mdd manual [--force]`
1
+ ## MANUAL MODE - `/mdd manual [--force]`
2
2
 
3
3
  Triggered when arguments start with `manual`.
4
4
 
5
5
  Generates a comprehensive, print-ready user manual at `.mdd/manual/manual.md` from all
6
6
  MDD feature docs and ops runbooks. Uses content hashes to detect what changed since the
7
- last run only stale sections are regenerated.
7
+ last run - only stale sections are regenerated.
8
8
 
9
- Sections are written to disk **immediately after each generation batch completes** never
9
+ Sections are written to disk **immediately after each generation batch completes** - never
10
10
  held in memory until the end. This means compaction mid-run loses at most one batch of
11
11
  sections, and the next run can resume from the saved state.
12
12
 
13
13
  ---
14
14
 
15
- ### Phase M1 Scope & Hash Check
15
+ ### Phase M1 - Scope & Hash Check
16
16
 
17
- **Step 1 Guard against empty projects**
17
+ **Step 1 - Guard against empty projects**
18
18
 
19
19
  Check `.mdd/docs/`. If it contains zero `.md` files:
20
20
  ```
@@ -23,7 +23,7 @@ Run /mdd <feature> to create your first doc, then re-run /mdd manual.
23
23
  ```
24
24
  Stop here.
25
25
 
26
- **Step 2 Load stored hashes**
26
+ **Step 2 - Load stored hashes**
27
27
 
28
28
  Read `.mdd/manual/.hashes.json` if it exists. If absent, treat every doc as new (full
29
29
  generation run).
@@ -38,24 +38,24 @@ Stored hash format:
38
38
  }
39
39
  ```
40
40
 
41
- **Step 3 Compute current hashes**
41
+ **Step 3 - Compute current hashes**
42
42
 
43
43
  For every file in `.mdd/docs/*.md` and `.mdd/ops/*.md`, compute SHA256 of file contents:
44
44
  ```bash
45
45
  sha256sum .mdd/docs/*.md .mdd/ops/*.md 2>/dev/null
46
46
  ```
47
47
 
48
- **Step 4 Classify each doc**
48
+ **Step 4 - Classify each doc**
49
49
 
50
50
  Compare current vs stored hashes:
51
- - `unchanged` hash matches stored value → skip section regeneration
52
- - `changed` hash differs → regenerate section
53
- - `new` no stored hash → generate section
54
- - `deleted` stored hash exists but file no longer present → remove section
51
+ - `unchanged` - hash matches stored value → skip section regeneration
52
+ - `changed` - hash differs → regenerate section
53
+ - `new` - no stored hash → generate section
54
+ - `deleted` - stored hash exists but file no longer present → remove section
55
55
 
56
56
  If `--force` was passed: treat every doc as `changed` regardless of hashes.
57
57
 
58
- **Step 5 Report scope**
58
+ **Step 5 - Report scope**
59
59
 
60
60
  ```
61
61
  📖 MDD Manual Generator
@@ -78,24 +78,24 @@ Stop here.
78
78
 
79
79
  ---
80
80
 
81
- ### Phase M2 Skeleton Init (before generating any sections)
81
+ ### Phase M2 - Skeleton Init (before generating any sections)
82
82
 
83
83
  Before generating any sections, ensure `manual.md` is in a writable state on disk.
84
- This protects against compaction each section written to disk is durable.
84
+ This protects against compaction - each section written to disk is durable.
85
85
 
86
- **Step 1 Ensure output directory exists**
86
+ **Step 1 - Ensure output directory exists**
87
87
  ```bash
88
88
  mkdir -p .mdd/manual
89
89
  ```
90
90
 
91
- **Step 2 Load existing manual or build skeleton**
91
+ **Step 2 - Load existing manual or build skeleton**
92
92
 
93
93
  Read `.mdd/manual/manual.md` if it exists. Identify the preface: everything before the
94
94
  first `<!-- mdd-section: -->` marker. If the file is new, generate a default preface
95
95
  (see Phase M3 Step 2 below for the preface format) and write the skeleton immediately:
96
96
 
97
97
  ```markdown
98
- # <Project Name> User Manual
98
+ # <Project Name> - User Manual
99
99
 
100
100
  > <tagline>
101
101
 
@@ -121,13 +121,13 @@ first `<!-- mdd-section: -->` marker. If the file is new, generate a default pre
121
121
 
122
122
  ## Features
123
123
 
124
- (sections generating re-run /mdd manual if interrupted)
124
+ (sections generating - re-run /mdd manual if interrupted)
125
125
 
126
126
  ---
127
127
 
128
128
  ## Operations
129
129
 
130
- (sections generating re-run /mdd manual if interrupted)
130
+ (sections generating - re-run /mdd manual if interrupted)
131
131
 
132
132
  ---
133
133
 
@@ -141,7 +141,7 @@ first `<!-- mdd-section: -->` marker. If the file is new, generate a default pre
141
141
  Write this skeleton to `.mdd/manual/manual.md` now, before any agents are launched.
142
142
  This ensures the file exists on disk even if compaction occurs mid-generation.
143
143
 
144
- **Step 3 Remove deleted sections**
144
+ **Step 3 - Remove deleted sections**
145
145
 
146
146
  For each doc classified as `deleted`: find and remove the entire
147
147
  `<!-- mdd-section: <id> -->` … `<!-- /mdd-section: <id> -->` block (including
@@ -150,10 +150,10 @@ each removal.
150
150
 
151
151
  ---
152
152
 
153
- ### Phase M3 Section Generation (incremental, batch-by-batch)
153
+ ### Phase M3 - Section Generation (incremental, batch-by-batch)
154
154
 
155
155
  For each `changed` or `new` doc, generate a user-friendly manual section. The section
156
- must be readable by someone who has never seen the source code focus on WHAT the
156
+ must be readable by someone who has never seen the source code - focus on WHAT the
157
157
  feature does and HOW to use it, not implementation details.
158
158
 
159
159
  **Section structure per feature doc:**
@@ -171,18 +171,18 @@ feature does and HOW to use it, not implementation details.
171
171
  <Step-by-step user instructions. Include command syntax, options, examples.>
172
172
 
173
173
  #### Commands
174
- <If the feature has CLI commands table with command, description, flags.>
174
+ <If the feature has CLI commands - table with command, description, flags.>
175
175
  | Command | Description | Flags |
176
176
  |---------|-------------|-------|
177
177
  | `mdd <cmd>` | … | `--flag` |
178
178
 
179
179
  #### API Endpoints
180
- <If the feature exposes HTTP endpoints table with method, path, description.>
180
+ <If the feature exposes HTTP endpoints - table with method, path, description.>
181
181
  | Method | Path | Description | Auth |
182
182
  |--------|------|-------------|------|
183
183
 
184
184
  #### Configuration
185
- <If the feature has configurable options env vars, settings, flags.>
185
+ <If the feature has configurable options - env vars, settings, flags.>
186
186
  | Option | Type | Default | Description |
187
187
  |--------|------|---------|-------------|
188
188
 
@@ -209,7 +209,7 @@ For ops runbooks, use a condensed format:
209
209
  <!-- /mdd-section: ops/<slug> -->
210
210
  ```
211
211
 
212
- **Parallelism and incremental writing CRITICAL:**
212
+ **Parallelism and incremental writing - CRITICAL:**
213
213
 
214
214
  - **1–4 changed docs** → generate sequentially in main conversation. After EACH section
215
215
  is generated, immediately patch it into `manual.md` on disk (see patching rules below)
@@ -243,44 +243,44 @@ For each returned section:
243
243
 
244
244
  **Reading source files during generation:**
245
245
  When the feature doc lists `source_files`, read those files briefly to verify the section
246
- accurately reflects what is implemented do not invent capabilities not present in code.
246
+ accurately reflects what is implemented - do not invent capabilities not present in code.
247
247
  If source files don't exist yet (draft feature), note the section as "(planned)" in the
248
248
  section header.
249
249
 
250
250
  ---
251
251
 
252
- ### Phase M4 Final Assembly
252
+ ### Phase M4 - Final Assembly
253
253
 
254
254
  After all sections are on disk, perform final assembly passes on `manual.md`.
255
255
 
256
- **Step 1 Rebuild aggregated reference sections**
256
+ **Step 1 - Rebuild aggregated reference sections**
257
257
 
258
258
  Scan every `<!-- mdd-section: -->` block in the current `manual.md` for:
259
259
 
260
- **Command Reference** find all `#### Commands` tables. Merge into one master table,
260
+ **Command Reference** - find all `#### Commands` tables. Merge into one master table,
261
261
  sorted alphabetically by command. Include a "Feature" column. Replace the existing
262
262
  `## Command Reference` section (or append if missing).
263
263
 
264
- **API Reference** find all `#### API Endpoints` tables. Merge into one master table,
264
+ **API Reference** - find all `#### API Endpoints` tables. Merge into one master table,
265
265
  sorted by path. Include a "Feature" column. Replace the existing `## API Reference`
266
266
  section (or append if missing). Omit this section entirely if no API endpoints were found.
267
267
 
268
- **Configuration** find all `#### Configuration` tables. Merge into one master table,
268
+ **Configuration** - find all `#### Configuration` tables. Merge into one master table,
269
269
  grouped by feature. Replace the existing `## Configuration` section (or append if
270
270
  missing). Omit this section entirely if no configuration options were found.
271
271
 
272
- **Step 2 Regenerate TOC**
272
+ **Step 2 - Regenerate TOC**
273
273
 
274
274
  Scan the assembled document for all `##` and `###` headings. Build a markdown TOC with
275
275
  anchor links. Replace the `<!-- toc -->` … `<!-- /toc -->` block (between
276
276
  `## Table of Contents` and the next `---` divider) with the new TOC.
277
277
 
278
- **Step 3 Final document structure**
278
+ **Step 3 - Final document structure**
279
279
 
280
280
  The assembled `manual.md` must follow this order:
281
281
 
282
282
  ```markdown
283
- # <Project Name> User Manual ← preface (preserved or generated)
283
+ # <Project Name> - User Manual ← preface (preserved or generated)
284
284
  > <tagline>
285
285
 
286
286
  **Version:** … **Generated:** …
@@ -339,7 +339,7 @@ The assembled `manual.md` must follow this order:
339
339
  | Option | Type | Default | Description | Feature |
340
340
  ```
341
341
 
342
- **Step 2 Build/update preface** (if generating for the first time)
342
+ **Step 2 - Build/update preface** (if generating for the first time)
343
343
 
344
344
  If the preface was newly generated in Phase M2, ensure it uses this content:
345
345
 
@@ -347,11 +347,11 @@ Read `.mdd/.startup.md` for: project name, stack, tagline. Read `package.json` (
347
347
  present) for version. Read `README.md` introduction (first 3 paragraphs, if present).
348
348
 
349
349
  ```markdown
350
- # <Project Name> User Manual
350
+ # <Project Name> - User Manual
351
351
 
352
352
  > <tagline or one-sentence description>
353
353
 
354
- **Version:** <version from package.json, or "">
354
+ **Version:** <version from package.json, or "-">
355
355
  **Generated:** <date>
356
356
 
357
357
  <2-3 paragraph project overview synthesized from README and .startup.md>
@@ -363,9 +363,9 @@ Write the final assembled `manual.md` to disk.
363
363
 
364
364
  ---
365
365
 
366
- ### Phase M5 Write Hashes & Report
366
+ ### Phase M5 - Write Hashes & Report
367
367
 
368
- **Step 1 Update hash store**
368
+ **Step 1 - Update hash store**
369
369
 
370
370
  Write `.mdd/manual/.hashes.json` with:
371
371
  - One entry per doc that now exists on disk (use the current hash)
@@ -374,10 +374,10 @@ Write `.mdd/manual/.hashes.json` with:
374
374
  - Set `_manual_version: 1` (or increment if already set)
375
375
 
376
376
  **Only write this file after manual.md is fully complete.** The hash file is the
377
- completion marker if `.hashes.json` is missing or stale, the next run will know
377
+ completion marker - if `.hashes.json` is missing or stale, the next run will know
378
378
  to regenerate all sections.
379
379
 
380
- **Step 2 Report**
380
+ **Step 2 - Report**
381
381
 
382
382
  ```
383
383
  ✅ Manual generated
@@ -395,7 +395,7 @@ Tip: manual.md is print-ready markdown. Open in any markdown viewer,
395
395
  export to PDF, or use as source material for blog posts and docs.
396
396
  ```
397
397
 
398
- **Step 3 Gitignore check**
398
+ **Step 3 - Gitignore check**
399
399
 
400
400
  Check whether `.mdd/manual/` is in `.gitignore`. If not, suggest:
401
401
  ```
@@ -409,8 +409,8 @@ Check whether `.mdd/manual/` is in `.gitignore`. If not, suggest:
409
409
 
410
410
  | Flag | Effect |
411
411
  |------|--------|
412
- | `--force` | Bypass hash check regenerate all sections |
413
- | (none) | Default only regenerate changed/new sections |
412
+ | `--force` | Bypass hash check - regenerate all sections |
413
+ | (none) | Default - only regenerate changed/new sections |
414
414
 
415
415
  ---
416
416
 
@@ -419,12 +419,13 @@ Check whether `.mdd/manual/` is in `.gitignore`. If not, suggest:
419
419
  When generating each section, the goal is a document a non-technical user or executive
420
420
  can read and understand. Rules for section writers:
421
421
 
422
+ - **No em dashes** - never use `-` anywhere in generated content; use a plain hyphen `-` instead
422
423
  - **No internal file paths** in body text (they belong in the feature doc, not the manual)
423
- - **No jargon without definition** if a term needs explanation, add it
424
- - **Active voice** "The auth system validates your token" not "Tokens are validated"
425
- - **One idea per paragraph** keep paragraphs to 35 sentences
424
+ - **No jargon without definition** - if a term needs explanation, add it
425
+ - **Active voice** - "The auth system validates your token" not "Tokens are validated"
426
+ - **One idea per paragraph** - keep paragraphs to 3-5 sentences
426
427
  - **Examples are mandatory** for any command or API endpoint listed
427
- - **Planned features** are clearly marked `(planned not yet implemented)`
428
+ - **Planned features** are clearly marked `(planned - not yet implemented)`
428
429
 
429
430
  ### Recovery from Interrupted Runs
430
431
 
@@ -433,7 +434,7 @@ If `/mdd manual` was interrupted mid-generation (context compaction, session end
433
434
  1. Re-run `/mdd manual`. The hash check will find that `.hashes.json` is missing or
434
435
  incomplete (since it's only written at the very end in Phase M5).
435
436
  2. Sections already written to `manual.md` (from completed batches) will be detected as
436
- present but since their hashes aren't in `.hashes.json`, they'll be classified as
437
+ present - but since their hashes aren't in `.hashes.json`, they'll be classified as
437
438
  `new` and regenerated.
438
439
  3. The regenerated sections will simply replace what was already there. No data is lost.
439
440
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thedecipherist/mdd",
3
- "version": "1.6.11",
3
+ "version": "1.6.13",
4
4
  "description": "MDD — Manual-Driven Development workflow for Claude Code",
5
5
  "type": "module",
6
6
  "bin": {