diff --git a/docs/audits/2026-06-09.md b/docs/audits/2026-06-09.md
new file mode 100644
index 0000000..d92e331
--- /dev/null
+++ b/docs/audits/2026-06-09.md
@@ -0,0 +1,72 @@
+# Audit Log: 2026-06-09
+
+Foundational audit pass against The Pragmatic Programmer principles
+plus a11y on `site/` and dep vuln scan. PR: `audit/2026-06-09` → main.
+
+## Shipped in this PR
+
+**Orthogonality (`/coupling`):**
+- Verdict: codebase is genuinely exemplary. `shared/recommend.js`,
+ `shared/questions.json`, `shared/labels.json`, `shared/constants.js`,
+ `cli/data.js` are documented canonical singletons in CLAUDE.md,
+ consumed by both CLI and site (via the build artifact pattern).
+- Verified `shared/recommend.js` and `site/recommend.js` are
+ byte-identical — `scripts/build-site.js` copies one to the other
+ and the result is in sync. The "don't fork the recommendation
+ engine" rule holds.
+- Zero cycles, zero wildcards, zero cross-layer violations.
+
+**DRY (`/drift`):**
+- No model IDs, no year-bound constants, no hand-typed enums.
+- Em-dash usage exists in `site/data.json` (tool descriptions). It's
+ content, not code, and CLAUDE.md doesn't forbid em-dashes here.
+ Not drift.
+- One hardcoded `https://surfrrosa.github.io/solo-stack/` in
+ `cli/index.js:70` (a help message). Single site = not duplication.
+
+**Broken windows (`/zombie`):**
+- Zero commented-out code blocks, zero TODOs/FIXMEs/HACKs, zero empty
+ catch blocks, zero dead exports across `cli/`, `shared/`, `scripts/`.
+
+**Accessibility (`/a11y`) on `site/`:**
+- Added `` landmark wrapping the page's
+ primary content (previously `
`).
+- Added a visible-on-focus skip-to-content link at the top of ``.
+ Defined new `.skip-link` class in `style.css`. Keyboard users now
+ have a one-tap escape from the masthead repeats.
+- Wrapped the `←` glyph in the "Back to start" button in
+ `aria-hidden="true"` so screen readers don't announce it as
+ content. Added explicit `type="button"` for clarity.
+
+**Dependency vulnerability (`/vuln`):**
+- `npm audit fix` resolved the high-severity lodash CVEs
+ (prototype-pollution + code-injection) via a transitive bump.
+ Zero vulnerabilities remaining.
+- The fix also reconciled drift between `package.json` (which had
+ `playwright` in `dependencies`) and `package-lock.json` (which had
+ treated it as a dev dep). The lock now matches package.json's
+ declaration.
+
+## Light verifications
+
+- `node scripts/validate-yaml.js` — clean (35 files, 0 errors, 4
+ pre-existing warnings unrelated to this PR).
+- `node scripts/build-site.js` — clean (32 tools, 3 stacks).
+
+## Out of scope (declined / not needed)
+
+- A `` landmark on `404.html`. The 404 page is intentionally
+ minimal; not worth the churn.
+- Em-dash sweep in `site/data.json` tool descriptions. Content, not
+ drift.
+- The `playwright` package being declared as a regular `dependency`
+ rather than `devDependency`. Pre-existing decision; the audit
+ surfaces it but doesn't change it.
+
+## Onlooker takeaway
+
+The repo's discipline is already strong: canonical singletons in
+`shared/`, documented "don't fork" rule (with a commit referenced for
+the original incident), schema-validated YAML, weekly Playwright
+pricing checks. The audit's most visible additions are the ``
+landmark and skip link.
diff --git a/package-lock.json b/package-lock.json
index 5487514..8e4b231 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -7,13 +7,15 @@
"": {
"name": "solo-stack",
"version": "1.0.0",
+ "license": "MIT",
"dependencies": {
"chalk": "^4.1.2",
"inquirer": "^8.2.7",
- "js-yaml": "^4.1.0"
- },
- "devDependencies": {
+ "js-yaml": "^4.1.0",
"playwright": "^1.50.0"
+ },
+ "bin": {
+ "solo-stack": "cli/index.js"
}
},
"node_modules/@inquirer/external-editor": {
@@ -265,7 +267,6 @@
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
"integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
- "dev": true,
"hasInstallScript": true,
"license": "MIT",
"optional": true,
@@ -396,9 +397,9 @@
}
},
"node_modules/lodash": {
- "version": "4.17.23",
- "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.23.tgz",
- "integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==",
+ "version": "4.18.1",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz",
+ "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==",
"license": "MIT"
},
"node_modules/log-symbols": {
@@ -474,7 +475,6 @@
"version": "1.58.2",
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.58.2.tgz",
"integrity": "sha512-vA30H8Nvkq/cPBnNw4Q8TWz1EJyqgpuinBcHET0YVJVFldr8JDNiU9LaWAE1KqSkRYazuaBhTpB5ZzShOezQ6A==",
- "dev": true,
"license": "Apache-2.0",
"dependencies": {
"playwright-core": "1.58.2"
@@ -493,7 +493,6 @@
"version": "1.58.2",
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.58.2.tgz",
"integrity": "sha512-yZkEtftgwS8CsfYo7nm0KE8jsvm6i/PTgVtB8DL726wNf6H2IMsDuxCpJj59KDaxCtSnrWan2AeDqM7JBaultg==",
- "dev": true,
"license": "Apache-2.0",
"bin": {
"playwright-core": "cli.js"
diff --git a/site/index.html b/site/index.html
index cd5cb84..8b95aa4 100644
--- a/site/index.html
+++ b/site/index.html
@@ -37,6 +37,7 @@
+ Skip to main content
-