Skip to content

Commit e8f2612

Browse files
mcp-tool-shopclaude
andcommitted
chore(swarm): Stage A — make the falsifiability thesis actually true
Dogfood swarm Stage A (bug/security/quality) across 4 amend cycles. Audit found that the repo's central claim — "deterministic marketing infrastructure with falsifiable claims and hash-verified evidence" — was largely unenforced. Stage A makes it true. Validator hardening (marketing/scripts/): - validate.mjs now hash-verifies every evidence file (was paper-only) - gen-lock.mjs is byte-stable (dropped non-deterministic generatedAt) - forbiddenPhrases, message constraints, path-traversal — all enforced - ajv runs strict (was strict:false silently accepting schema typos) - error envelopes replace raw Node stack traces - _paths.mjs single source of truth for repo path resolution Schema strictness (marketing/schema/): - minLength:1 on freeform strings - uniqueItems on reference arrays - pressContact format-per-method validation - sourceCommit oneOf [40-char SHA, "unknown-pending-public-release" sentinel] - $defs/nonEmptyString registered Data honesty (marketing/data/, manifests/): - All zip-meta-map claims downgraded to aspirational pending upstream public release - Dead evidence URLs removed (3 of 4 entries pointed to non-existent repo) - "pip install zip-meta-map" replaced — package was 404 on PyPI - targeting.seedRepos fixed (Aider-AI/aider, was aider-chat/aider 404) - press.quotes emptied (was first-party self-quotes attributed to "team") - All 5 messages rewritten in conditional/future tense with pre-launch markers Test coverage (test/): - 5 → 46 tests (+41) across 5 suites - gen-lock.test.mjs: determinism roundtrip + lockfile drift detection - validate.test.mjs: 10 negative-path tests (forbidden phrases, max chars, hash mismatch, dangling refs, duplicate IDs) - hash-file.test.mjs: known-vector + POSIX path normalization - _paths.test.mjs: 20 path-traversal guard tests - version.test.mjs: hardened (canonical semver, MAJOR-matches-CHANGELOG) - npm test wired (was missing; CI never ran tests) CI hardening (.github/): - Tests step added, ordered before lockfile drift check - actions/setup-node SHA-pinned (was @v4 floating tag) - permissions: contents: read (was inheriting broad GITHUB_TOKEN) - paths filter expanded (.editorconfig, .gitattributes, .prettierignore, .github/**) - Dependabot for npm + github-actions - CodeQL workflow (javascript) - CODEOWNERS - timeout-minutes: 10 (was default 360) Doc accuracy (README, CHANGELOG, SCORECARD, SHIP_GATE, SECURITY): - README script names match package.json (was format:check, actual fmt:check) - SHIP_GATE rows annotated with verification dates and [x]* legend - SCORECARD revised to honest 42/50 (was unearned 50/50) - SECURITY uses GHSA URL (was no-reply email that doesn't deliver) - CHANGELOG [Unreleased] in Keep-a-Changelog format 5 swarm waves, 6 owned domains, exclusive file ownership enforced. Final state: validate ✓ lock:check ✓ 46/46 tests ✓ fmt:check ✓ 0 ajv strict-mode warnings (was 3). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 82e847b commit e8f2612

27 files changed

Lines changed: 2060 additions & 441 deletions

.gitattributes

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,15 @@
66
*.jpg binary
77
*.gif binary
88
*.mp4 binary
9+
*.webp binary
10+
*.ico binary
11+
*.pdf binary
12+
*.zip binary
13+
*.woff binary
14+
*.woff2 binary
15+
*.ttf binary
16+
*.otf binary
17+
*.eot binary
18+
19+
# Generated files
20+
marketing/manifests/marketing.lock.json linguist-generated=true

.github/CODEOWNERS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
* @mcp-tool-shop

.github/dependabot.yml

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
version: 2
2+
updates:
3+
- package-ecosystem: "npm"
4+
directory: "/"
5+
schedule:
6+
interval: "weekly"
7+
open-pull-requests-limit: 5
8+
commit-message:
9+
prefix: "deps"
10+
labels:
11+
- "dependencies"
12+
groups:
13+
npm-minor-patch:
14+
update-types:
15+
- "minor"
16+
- "patch"
17+
- package-ecosystem: "github-actions"
18+
directory: "/"
19+
schedule:
20+
interval: "weekly"
21+
open-pull-requests-limit: 5
22+
commit-message:
23+
prefix: "deps"
24+
labels:
25+
- "dependencies"

.github/workflows/ci.yml

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,33 +5,50 @@ on:
55
branches: [main]
66
paths:
77
- "marketing/**"
8+
- "test/**"
89
- "package.json"
910
- "package-lock.json"
1011
- ".prettierrc"
11-
- ".github/workflows/**"
12+
- ".prettierignore"
13+
- ".editorconfig"
14+
- ".gitattributes"
15+
- ".github/**"
1216
pull_request:
1317
branches: [main]
1418
paths:
1519
- "marketing/**"
20+
- "test/**"
1621
- "package.json"
1722
- "package-lock.json"
1823
- ".prettierrc"
19-
- ".github/workflows/**"
24+
- ".prettierignore"
25+
- ".editorconfig"
26+
- ".gitattributes"
27+
- ".github/**"
2028
workflow_dispatch:
2129

2230
concurrency:
2331
group: ${{ github.workflow }}-${{ github.ref }}
24-
cancel-in-progress: true
32+
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
33+
34+
permissions:
35+
contents: read
2536

2637
jobs:
2738
validate:
28-
runs-on: ubuntu-latest
39+
runs-on: ${{ matrix.os }}
40+
timeout-minutes: 10
41+
strategy:
42+
fail-fast: false
43+
matrix:
44+
os: [ubuntu-latest, windows-latest]
45+
node-version: ["22"]
2946
steps:
3047
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
3148

32-
- uses: actions/setup-node@v4
49+
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
3350
with:
34-
node-version: 22
51+
node-version: ${{ matrix.node-version }}
3552
cache: npm
3653

3754
- name: Install dependencies
@@ -43,5 +60,8 @@ jobs:
4360
- name: Schema + invariant validation
4461
run: npm run validate
4562

63+
- name: Tests
64+
run: npm test
65+
4666
- name: Lockfile drift check
4767
run: npm run lock:check

.github/workflows/codeql.yml

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
name: CodeQL
2+
3+
on:
4+
push:
5+
branches: [main]
6+
pull_request:
7+
branches: [main]
8+
schedule:
9+
- cron: "0 6 * * 1"
10+
11+
concurrency:
12+
group: ${{ github.workflow }}-${{ github.ref }}
13+
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
14+
15+
permissions:
16+
contents: read
17+
security-events: write
18+
19+
jobs:
20+
analyze:
21+
name: Analyze (javascript)
22+
runs-on: ubuntu-latest
23+
timeout-minutes: 20
24+
steps:
25+
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
26+
27+
- name: Initialize CodeQL
28+
uses: github/codeql-action/init@458d36d7d4f47d0dd16ca424c1d3cda0060f1360 # v3.35.5
29+
with:
30+
languages: javascript
31+
32+
- name: Perform CodeQL Analysis
33+
uses: github/codeql-action/analyze@458d36d7d4f47d0dd16ca424c1d3cda0060f1360 # v3.35.5

.gitignore

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,13 @@ dist/
44
Thumbs.db
55
*.swp
66
*.swo
7+
.env
8+
.env.*
9+
!.env.example
10+
.idea/
11+
.vscode/
12+
*.iml
13+
npm-debug.log*
14+
.npm/
15+
coverage/
16+
desktop.ini

.prettierignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,7 @@
11
node_modules/
22
marketing/manifests/marketing.lock.json
3+
coverage/
4+
dist/
5+
package-lock.json
6+
*.min.js
7+
*.min.css

.prettierrc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,6 @@
33
"singleQuote": false,
44
"trailingComma": "all",
55
"printWidth": 100,
6-
"tabWidth": 2
6+
"tabWidth": 2,
7+
"overrides": [{ "files": "*.md", "options": { "proseWrap": "preserve" } }]
78
}

CHANGELOG.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,38 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/),
66
and this project adheres to [Semantic Versioning](https://semver.org/).
77

8+
## [Unreleased]
9+
10+
Dogfood swarm wave 2 (2026-05-15) landed cross-cutting hardening.
11+
12+
### Added
13+
14+
- 41 new test cases under `test/` (5 → 46 total): `test/gen-lock.test.mjs` (determinism + lockfile drift, 7 tests), `test/validate.test.mjs` (schema + invariant negative paths, 10 tests), `test/hash-file.test.mjs` (hashing utility, 4 tests), `test/_paths.test.mjs` (path-traversal guards, 20 tests).
15+
- CI: Dependabot config (`.github/dependabot.yml`) for automated dependency updates.
16+
- CI: CodeQL workflow (`.github/workflows/codeql.yml`) for code scanning on every push and PR.
17+
- CI: minimal-permissions block on GitHub Actions workflows.
18+
- Repo ownership: `.github/CODEOWNERS`.
19+
- Scripts: `marketing/scripts/_paths.mjs` shared-paths module (single source of truth for repo path resolution across scripts).
20+
- Docs: top-level README Testing section.
21+
22+
### Changed
23+
24+
- Marketing-data contract: dead URLs and unverified PyPI claims downgraded to aspirational.
25+
- Validator hardening: `validate.mjs` enforces hash-verified evidence; `gen-lock.mjs` is fully deterministic; AJV runs in strict mode.
26+
- Error envelopes: scripts wrap failures in friendly try/catch envelopes (full Structured Error Shape with `code`/`hint`/`retryable` is **planned for v1.1**).
27+
- Docs accuracy: README script names match `package.json`.
28+
- SCORECARD methodology: now reports honest revised scores (42/50) alongside the original self-score (50/50) — see SCORECARD.md "Why scores were revised down."
29+
- SHIP_GATE: gate rows annotated with explicit verification dates (`(YYYY-MM-DD)`).
30+
31+
### Fixed
32+
33+
- SECURITY.md disclosure address switched to GitHub's private vulnerability advisory (GHSA URL).
34+
35+
### Deferred
36+
37+
- `verify` umbrella script (composing `validate` + `lock:check` + `test`) — **planned for v1.1**. Today the equivalent is the explicit `npm run validate && npm run lock:check && npm test` chain that CI runs.
38+
- Full Structured Error Shape (`code` / `message` / `hint` / `cause?` / `retryable?`) — **planned for v1.1**. Wave 2 shipped basic try/catch envelopes only.
39+
840
## [1.0.0] - 2026-02-27
941

1042
### Added

README.md

Lines changed: 47 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ marketing/
4949
evidence.manifest.json # Evidence registry with sha256 + provenance
5050
marketing.lock.json # Lockfile pinning all files by hash
5151
scripts/ # validate, hash, gen-lock
52+
test/ # node:test suites — version, gen-lock, validate, hash-file, _paths (46 tests)
5253
```
5354

5455
### Authored vs generated
@@ -111,13 +112,16 @@ All JSON uses sorted keys, stable array ordering, and trailing newlines. This pr
111112
npm install
112113

113114
# Format check (Prettier)
114-
npm run format:check
115+
npm run fmt:check
115116

116117
# Schema + invariant validation
117118
npm run validate
118119

119120
# Lockfile drift check (CI mode)
120121
npm run lock:check
122+
123+
# Tests (version + structure invariants)
124+
npm test
121125
```
122126

123127
**Typical development loop:**
@@ -126,7 +130,8 @@ npm run lock:check
126130
2. Add evidence entries to `marketing/manifests/evidence.manifest.json` (and artifacts under `marketing/evidence/` if applicable)
127131
3. Regenerate the lockfile: `node marketing/scripts/gen-lock.mjs`
128132
4. Validate: `npm run validate`
129-
5. Format: `npm run format:check` (fix with `npm run format`)
133+
5. Format: `npm run fmt:check` (fix with `npm run fmt`)
134+
6. Run tests: `npm test`
130135

131136
---
132137

@@ -162,9 +167,26 @@ The quality bar is simple and non-negotiable:
162167

163168
---
164169

165-
## Security
170+
## Testing
166171

167-
No secrets, private URLs, API keys, or customer identifiers belong in this repo. Evidence means public artifacts — screenshots, CI links, test results — not internal logs or credentials. If something can't be shown publicly, it's not evidence.
172+
```bash
173+
npm test
174+
```
175+
176+
Runs 46 tests across five suites under `test/` via the Node built-in test runner (no external test framework):
177+
178+
- **`test/version.test.mjs`** — 5 version-consistency tests
179+
- `package.json` version is canonical semver (X.Y.Z\[-pre]\[+build])
180+
- `package.json` MAJOR matches the latest `## [X.Y.Z]` heading in `CHANGELOG.md`
181+
- `CHANGELOG.md` contains a section heading for the current version (not just a link reference)
182+
- `LICENSE` begins with "MIT License"
183+
- `marketing/` exists and contains `schema/`, `data/`, `manifests/` subdirectories
184+
- **`test/gen-lock.test.mjs`** — 7 determinism + lockfile tests (lockfile drift detection, byte-stable serialization, ref-traversal hardening)
185+
- **`test/validate.test.mjs`** — 10 schema + invariant tests (negative-path coverage for proven-without-evidence, orphan files, hash mismatch, forbidden phrases, message length, etc.)
186+
- **`test/hash-file.test.mjs`** — 4 hashing-utility tests (known-vector, empty file, POSIX path normalization, usage error)
187+
- **`test/_paths.test.mjs`** — 20 path-traversal-guard tests (`assertSafeRef` and `assertSafePath` rejection + acceptance paths)
188+
189+
CI runs `npm test` on every push and pull request.
168190

169191
---
170192

@@ -174,7 +196,11 @@ MarketIR changes are versioned via `schemaVersion` in the schema and data files.
174196

175197
---
176198

177-
## Security & Data Scope
199+
## Security
200+
201+
No secrets, private URLs, API keys, or customer identifiers belong in this repo. Evidence means public artifacts — screenshots, CI links, test results — not internal logs or credentials. If something can't be shown publicly, it's not evidence.
202+
203+
### Data scope
178204

179205
| Aspect | Detail |
180206
| -------------------- | --------------------------------------------------------------------------- |
@@ -186,18 +212,26 @@ MarketIR changes are versioned via `schemaVersion` in the schema and data files.
186212

187213
See [SECURITY.md](SECURITY.md) for vulnerability reporting.
188214

215+
---
216+
189217
## Scorecard
190218

191219
| Category | Score |
192220
| ------------------- | --------- |
193-
| A. Security | 10 |
194-
| B. Error Handling | 10 |
195-
| C. Operator Docs | 10 |
196-
| D. Shipping Hygiene | 10 |
197-
| E. Identity (soft) | 10 |
198-
| **Overall** | **50/50** |
199-
200-
> Full audit: [SHIP_GATE.md](SHIP_GATE.md) · [SCORECARD.md](SCORECARD.md)
221+
| A. Security | 9 |
222+
| B. Error Handling | 7 |
223+
| C. Operator Docs | 9 |
224+
| D. Shipping Hygiene | 9 |
225+
| E. Identity (soft) | 8 |
226+
| **Overall** | **42/50** |
227+
228+
> **Score: 42/50** (revised down from 50/50 after honest re-audit; see [SCORECARD.md](SCORECARD.md#why-scores-were-revised-down) for methodology).
229+
>
230+
> Last reviewed: 2026-05-15. Full audit: [SHIP_GATE.md](SHIP_GATE.md) · [SCORECARD.md](SCORECARD.md)
231+
>
232+
> **Audit cadence:** re-score on every minor release, or quarterly — whichever comes first.
233+
234+
---
201235

202236
## License
203237

0 commit comments

Comments
 (0)