From 89add0d38eee119d5c6e55049cf4cf7219535980 Mon Sep 17 00:00:00 2001 From: Philippos Savvides Date: Fri, 14 Aug 2026 16:16:58 -0700 Subject: [PATCH 01/12] docs: add design spec for landing page accuracy audit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Audits idstack.org against the repo and finds 11 defects across three kinds: claims that are untrue, material omissions, and files published that were never meant to be public. Two mechanism decisions worth noting: - Internal design docs and og-template.html are excluded at build time in static.yml rather than relocated. The brainstorming skill hardcodes docs/superpowers/specs/, so a move alone gets silently undone on its next run; and smoke-test.sh asserts docs/og-template.html exists, so that file cannot move at all. - dateModified and sitemap lastmod are deleted rather than corrected. A CI check asserting either date is current fails on commits that did not introduce the defect, and a check that cries wolf is one people learn to bypass. The guard becomes an absence assertion instead. Spec lives outside docs/ on purpose — the skill's default location is finding 10. Co-Authored-By: Claude Opus 5 (1M context) --- .../2026-08-14-github-page-accuracy-design.md | 214 ++++++++++++++++++ 1 file changed, 214 insertions(+) create mode 100644 superpowers/specs/2026-08-14-github-page-accuracy-design.md diff --git a/superpowers/specs/2026-08-14-github-page-accuracy-design.md b/superpowers/specs/2026-08-14-github-page-accuracy-design.md new file mode 100644 index 0000000..c70a210 --- /dev/null +++ b/superpowers/specs/2026-08-14-github-page-accuracy-design.md @@ -0,0 +1,214 @@ +# Landing page accuracy audit — design + +- **Date:** 2026-08-14 +- **Status:** approved, ready for planning +- **Audited surfaces:** `docs/` (the published idstack.org site) and `README.md` +- **Files changed:** `docs/index.html`, `docs/sitemap.xml`, `.github/workflows/static.yml`, + `test/check-doc-accuracy.py`, `test/mutation-test.sh`, plus two `git mv`s. + `README.md` was audited and needs no edit — see the change inventory. +- **Baseline commit:** `13db318` + +## Problem + +idstack.org is generated from `docs/` and deployed on every push to `main`. Two automated checks +guard it — `test/check-doc-accuracy.py` (version strings) and `test/check-evidence-cards.py` +(study counts and tier spans). Both pass. Everything they do not cover is unverified, and an audit +of the page against the repo found eleven defects across three kinds: + +1. **The page states something untrue.** +2. **The page omits something material about the repo.** +3. **The site publishes files that were never meant to be public.** + +## Findings and scoring + +Findings are weighted by user impact: **4** = wastes a user's time or is a real obligation gap · +**3** = a visitor would notice and be misled · **2** = countable inconsistency, low cost · +**1** = machine-readable only, invisible to humans. + +| # | Finding | Location | Kind | Wt | +|---|---|---|---|---| +| 5 | JSON-LD claims Windows support with no WSL/Git Bash caveat; `./setup` is a bash script that PowerShell and `cmd` cannot run | `docs/index.html:44` | wrong | 4 | +| 6 | Email signup form with no link to the `PRIVACY.md` that exists in the repo | `docs/index.html:1177` | omission | 4 | +| 10 | Internal design docs served at idstack.org | `docs/superpowers/{specs,plans}/` | hygiene | 4 | +| 1 | "Install in about five minutes" contradicts README's "Install — 30 seconds" | `docs/index.html:1127`, `README.md:15,95` | wrong | 3 | +| 4 | v3.4.0.1 release note covers only the evidence-card fix; ROADMAP lists two more shipped items | `docs/index.html:1153` | wrong | 3 | +| 7 | `bin/idstack-doctor` and `bin/idstack-status` never mentioned on the page | `docs/index.html` install section | omission | 3 | +| 8 | Prerequisites unstated — bash shell required, python3 recommended | `docs/index.html` install section | omission | 3 | +| 9 | "Eleven skills" headline names only ten | `docs/index.html:1012` | omission | 2 | +| 2 | JSON-LD `dateModified: 2026-08-06`; docs changed through 2026-08-12 | `docs/index.html:47` | wrong | 1 | +| 3 | Sitemap `lastmod: 2026-05-13` — three months stale | `docs/sitemap.xml:5` | wrong | 1 | +| 11 | `og-template.html` (the OG-card generator source) served publicly | `docs/og-template.html` | hygiene | 1 | + +**Total gap: 29 points.** This design closes all 29. + +Items 2 and 3 close *permanently* — by deleting the fields rather than correcting them, so they +cannot decay. Every other item is a one-time correction that cannot silently regress. + +### Verified accurate — no action + +Confirmed correct against the repo, recorded so a future audit does not re-derive them: all version +strings; "108 peer-reviewed studies across 11 research domains" (108 unique references counted in +`evidence/references.md`, 11 domains); all 11 evidence cards; every per-skill claim in the pipeline +section (`UDL 3.0`, `WCAG 2.1 AA`, `SCORM 1.2`, red-team's 5 dimensions, Nicol's 7 feedback +principles, three-level needs assessment — each matches its `SKILL.md`); `og-image.png` (no baked-in +version, no reference to the retired Codex build); all 11 outbound links (HTTP 200); and the GitHub +repo's description, topics, and homepage URL. + +## Design decisions + +### D1 — Stop publishing internal docs by excluding at build, not by moving files + +`.github/workflows/static.yml` uploads `docs/` verbatim via `actions/upload-pages-artifact@v3`, +which accepts a single `path`. Add a staging step that copies `docs/`, removes the non-public +paths, and uploads the staged directory: + +```yaml +- name: Stage publishable files + run: | + rm -rf _site + cp -R docs _site + rm -rf _site/superpowers + rm -f _site/og-template.html + +- name: Upload artifact + uses: actions/upload-pages-artifact@v3 + with: + path: '_site' +``` + +**Why the exclusion is load-bearing and a `git mv` is not.** The brainstorming skill writes specs to +`docs/superpowers/specs/` by default. Relocating today's two files without a build exclusion gets +silently undone the next time anyone runs that skill. The `rm -rf _site/superpowers` line is the +durable fix; it remains a no-op backstop after the relocation below. + +**Why `og-template.html` can only be excluded, never moved.** `test/smoke-test.sh:136-141` asserts +the file exists at `docs/og-template.html` and lints its gradient-text fallbacks. It must stay where +it is; build-time exclusion is the only mechanism that removes it from the published site without +breaking the suite. + +Additionally, relocate the two existing design docs from `docs/superpowers/` to `superpowers/` at +the repo root. This is cosmetic once the exclusion exists, but it keeps `docs/` meaning "the +website." Verified safe: nothing in the repo references `docs/superpowers/`. + +### D2 — Delete the two staleness-prone fields rather than correct them + +Remove `"dateModified"` from the JSON-LD block and `` from `sitemap.xml`. Keep +`"datePublished": "2026-04-20"` (a historical fact that cannot go stale) and the sitemap's +`changefreq`/`priority`. + +**Rejected: assert the date is current in CI.** The natural guard — `dateModified` must be no older +than the last commit touching `docs/` — fails on commits that did not introduce the defect. A pull +request that sits open for a week, or a merge dated after the docs edit, red-lights `main` for a +reason unrelated to the change being made. CI here runs every suite on every push and pull request; +a check that cries wolf is a check people learn to bypass. + +**Why deletion is not a downgrade.** Both fields are optional. Google's documented behaviour is to +use sitemap `lastmod` only when it is consistently and verifiably accurate, and to disregard it +otherwise — so a value three months stale earns nothing today. An absent field and an untrusted +field are worth the same in search; the difference is that the absent one cannot mislead a human +reading the page source. Under the scoring model both items are weight 1, "machine-readable only, +invisible to humans." + +> **Assumption, stated explicitly.** The approved scope was "fix `dateModified` and sitemap +> `lastmod`." Deleting them is a *different action* that reaches the same score. Proceeding on the +> owner's approval of D2 as presented. Reverting to "keep the fields, bump them by hand" is a +> one-line change to this section and drops the guard in D3. + +### D3 — Guard by asserting absence + +Extend `test/check-doc-accuracy.py` with a `check_no_stale_dates(root, problems)` function, called +from `main()` alongside the existing checks: + +- `docs/index.html` must not contain `dateModified` +- `docs/sitemap.xml` must not contain `lastmod` + +An absence assertion cannot false-positive: it fails only when someone reintroduces the exact field +this design removed. Add a corresponding entry to `test/mutation-test.sh` (mutation 22, following +the established `fresh` → mutate → `expect_fail` pattern used by mutations 20 and 21) that +reintroduces `"dateModified": "2026-08-06",` into `docs/index.html` and asserts `smoke-test.sh` +fails. + +### D4 — All page changes reuse existing landing-page styles + +`DESIGN.md`'s decisions log (2026-06-12) records that the landing page is an intentional separate +dark/indigo surface that no longer tracks the report token system. Every change below therefore +reuses the page's existing inline classes — `.install-prose`, `.footer-links a`, `.lede`. **No new +CSS, no new visual patterns, no new components.** Nothing here constitutes a design decision, so +`DESIGN.md` needs no update and `templates/assets/idstack.css` is untouched. + +## Change inventory + +Line numbers are as of `13db318`; anchor text is authoritative. + +### `docs/index.html` + +| Anchor | Change | Closes | +|---|---|---| +| `"operatingSystem": "macOS, Linux, Windows"` (L44) | → `"macOS, Linux, Windows (WSL or Git Bash)"` | 5 | +| `"dateModified": "2026-08-06",` (L47) | delete the line | 2 | +| `

` lede (L1013) | the lede accounts for 8 pipeline skills + 2 asides = 10; revise so `/idstack:pipeline` is counted as the eleventh rather than only appearing in the track label, so a reader who counts reaches eleven | 9 | +| `

Install in about five minutes.

` (L1127) | → `Install in 30 seconds.` | 1 | +| after `.install-prose` (L1136) | new `.install-prose` paragraph: bash shell required (WSL or Git Bash on Windows), python3 recommended; `bin/idstack-doctor` diagnoses a broken install, `bin/idstack-status` shows course health | 7, 8, and reinforces 5 in human-readable prose | +| v3.4.0.1 patch paragraph (L1153) | add the two other shipped items per ROADMAP — `PRIVACY.md` disclosures for Canvas API uploads and `bin/idstack-update-check` git fetches, and the Windows/WSL install instructions | 4 | +| `.footer-links` block (L1177) | add `` to `PRIVACY.md` on `main`, beside MIT License / Contribute / Roadmap | 6 | + +### `docs/sitemap.xml` + +Delete `2026-05-13` (L5). Closes 3. + +### `README.md` + +No change. It is already internally consistent at "30 seconds" (L15, L95); `docs/index.html` +reconciles to README, not the reverse, because README's number describes the exact command the page +displays. The page's separate "New to Claude Code? Download it first" line already carries the +Claude Code install time. + +### `.github/workflows/static.yml` + +Add the staging step from D1; repoint `upload-pages-artifact` at `_site`. Closes 10 and 11. + +### `superpowers/specs/`, `superpowers/plans/` + +`git mv docs/superpowers/specs/2026-08-12-documentation-accuracy-design.md` and +`git mv docs/superpowers/plans/2026-08-12-documentation-accuracy.md` to the repo-root +`superpowers/` tree. Closes 10. + +### `test/check-doc-accuracy.py`, `test/mutation-test.sh` + +Add the D3 guard and its mutation. + +## Verification + +Success criteria, each independently checkable: + +1. `python3 test/check-doc-accuracy.py .` → exit 0 with the new check present. +2. `./test/smoke-test.sh` → green (it runs the validator and the `og-template.html` assertions). +3. `python3 test/check-evidence-cards.py .` → green, unchanged. +4. `./test/mutation-test.sh` → mutation 22 reports `GUARDED`; every prior mutation still `GUARDED`. +5. Reintroducing `dateModified` by hand makes check 1 fail — confirms the guard bites outside the + mutation harness. +6. Staging step simulated locally (`rm -rf _site && cp -R docs _site && rm -rf _site/superpowers && + rm -f _site/og-template.html`) → `_site` contains `index.html`, `sitemap.xml`, `robots.txt`, + `CNAME`, both favicons, `og-image.png`, and `why-ai-native.md`; contains neither `superpowers/` + nor `og-template.html`. +7. Post-merge: `curl -o /dev/null -w "%{http_code}"` on + `https://idstack.org/superpowers/specs/2026-08-12-documentation-accuracy-design.md` and on + `https://idstack.org/og-template.html` → both 404. `https://idstack.org/` → 200. +8. Re-run the outbound link sweep over `docs/index.html` — all links 200, including the new + `PRIVACY.md` link. + +## Non-goals + +- **Repo About blurb, topics, homepage URL.** Checked via `gh repo view`; current and accurate. +- **Any visual redesign.** D4 constrains this to existing classes. +- **`docs/why-ai-native.md`.** Served as raw Markdown at idstack.org, but it is intended public + content, linked from README, and reachable only by direct URL. Out of scope. +- **Rewriting the What's-new section beyond finding 4.** Only the incomplete v3.4.0.1 note changes. +- **A general link-checker in CI.** All 11 links currently resolve; adding network-dependent checks + to the suite is a separate decision with its own flakiness tradeoff. + +## Note on this document's location + +Written to `superpowers/specs/` at the repo root, deviating from the brainstorming skill's +`docs/superpowers/specs/` default. That default is finding 10 — following it would publish this +design document at idstack.org, which is the defect being fixed. From 1d84c166445fc0d38667e3dcff879c143dfb0947 Mon Sep 17 00:00:00 2001 From: Philippos Savvides Date: Fri, 14 Aug 2026 16:18:16 -0700 Subject: [PATCH 02/12] docs: tighten spec after review - Item 5's primary fix is the install prose, not the JSON-LD string. A Windows visitor is stopped by prose they read, not by metadata they never see. The operatingSystem edit is a precision improvement only. - Drop the search-engine claim from D2's rationale. The argument stands on the scoring model alone, and the spec should not carry a third-party assertion it cannot verify. - Pin the staging step's position in static.yml and require the local dry-run before the workflow is edited. - Note that superpowers/plans/ must be created; git mv won't. Co-Authored-By: Claude Opus 5 (1M context) --- .../2026-08-14-github-page-accuracy-design.md | 28 +++++++++++-------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/superpowers/specs/2026-08-14-github-page-accuracy-design.md b/superpowers/specs/2026-08-14-github-page-accuracy-design.md index c70a210..1debf1e 100644 --- a/superpowers/specs/2026-08-14-github-page-accuracy-design.md +++ b/superpowers/specs/2026-08-14-github-page-accuracy-design.md @@ -63,6 +63,7 @@ which accepts a single `path`. Add a staging step that copies `docs/`, removes t paths, and uploads the staged directory: ```yaml +# ordering: after Checkout and Setup Pages, before Upload - name: Stage publishable files run: | rm -rf _site @@ -76,6 +77,10 @@ paths, and uploads the staged directory: path: '_site' ``` +Step order matters: staging must run after `actions/checkout@v4` and before +`upload-pages-artifact@v3`. Run verification item 6 (the three shell lines, locally) *before* +editing the workflow, so a staging bug is caught without a deploy round-trip. + **Why the exclusion is load-bearing and a `git mv` is not.** The brainstorming skill writes specs to `docs/superpowers/specs/` by default. Relocating today's two files without a build exclusion gets silently undone the next time anyone runs that skill. The `rm -rf _site/superpowers` line is the @@ -102,12 +107,12 @@ request that sits open for a week, or a merge dated after the docs edit, red-lig reason unrelated to the change being made. CI here runs every suite on every push and pull request; a check that cries wolf is a check people learn to bypass. -**Why deletion is not a downgrade.** Both fields are optional. Google's documented behaviour is to -use sitemap `lastmod` only when it is consistently and verifiably accurate, and to disregard it -otherwise — so a value three months stale earns nothing today. An absent field and an untrusted -field are worth the same in search; the difference is that the absent one cannot mislead a human -reading the page source. Under the scoring model both items are weight 1, "machine-readable only, -invisible to humans." +**Why deletion is not a downgrade.** Both fields are optional, and under the scoring model both +items are weight 1 — "machine-readable only, invisible to humans." Whatever value a freshness +signal carries, a value three months stale is not delivering it: the field currently asserts +something false, and the choice is between an absent field and a wrong one. Absent wins. Search- +engine treatment of `lastmod` is deliberately left out of this rationale; the argument does not +need it and this document should not carry a third-party claim it cannot verify. > **Assumption, stated explicitly.** The approved scope was "fix `dateModified` and sitemap > `lastmod`." Deleting them is a *different action* that reaches the same score. Proceeding on the @@ -144,11 +149,11 @@ Line numbers are as of `13db318`; anchor text is authoritative. | Anchor | Change | Closes | |---|---|---| -| `"operatingSystem": "macOS, Linux, Windows"` (L44) | → `"macOS, Linux, Windows (WSL or Git Bash)"` | 5 | +| `"operatingSystem": "macOS, Linux, Windows"` (L44) | → `"macOS, Linux, Windows (WSL or Git Bash)"`. **Secondary.** Schema.org expects OS names here; a parenthetical caveat is a precision improvement, not a machine-readable constraint. Do not treat this as the fix for 5 | 5 (partial) | | `"dateModified": "2026-08-06",` (L47) | delete the line | 2 | | `

` lede (L1013) | the lede accounts for 8 pipeline skills + 2 asides = 10; revise so `/idstack:pipeline` is counted as the eleventh rather than only appearing in the track label, so a reader who counts reaches eleven | 9 | | `

Install in about five minutes.

` (L1127) | → `Install in 30 seconds.` | 1 | -| after `.install-prose` (L1136) | new `.install-prose` paragraph: bash shell required (WSL or Git Bash on Windows), python3 recommended; `bin/idstack-doctor` diagnoses a broken install, `bin/idstack-status` shows course health | 7, 8, and reinforces 5 in human-readable prose | +| after `.install-prose` (L1136) | new `.install-prose` paragraph: bash shell required (WSL or Git Bash on Windows), python3 recommended; `bin/idstack-doctor` diagnoses a broken install, `bin/idstack-status` shows course health. **This is the primary fix for 5** — a Windows visitor is stopped by prose they can read, not by a JSON-LD string they never see | **5**, 7, 8 | | v3.4.0.1 patch paragraph (L1153) | add the two other shipped items per ROADMAP — `PRIVACY.md` disclosures for Canvas API uploads and `bin/idstack-update-check` git fetches, and the Windows/WSL install instructions | 4 | | `.footer-links` block (L1177) | add `
` to `PRIVACY.md` on `main`, beside MIT License / Contribute / Roadmap | 6 | @@ -171,7 +176,8 @@ Add the staging step from D1; repoint `upload-pages-artifact` at `_site`. Closes `git mv docs/superpowers/specs/2026-08-12-documentation-accuracy-design.md` and `git mv docs/superpowers/plans/2026-08-12-documentation-accuracy.md` to the repo-root -`superpowers/` tree. Closes 10. +`superpowers/` tree. `superpowers/specs/` already exists (this document); `superpowers/plans/` must +be created first — `git mv` will not create it. Remove the now-empty `docs/superpowers/`. Closes 10. ### `test/check-doc-accuracy.py`, `test/mutation-test.sh` @@ -189,8 +195,8 @@ Success criteria, each independently checkable: mutation harness. 6. Staging step simulated locally (`rm -rf _site && cp -R docs _site && rm -rf _site/superpowers && rm -f _site/og-template.html`) → `_site` contains `index.html`, `sitemap.xml`, `robots.txt`, - `CNAME`, both favicons, `og-image.png`, and `why-ai-native.md`; contains neither `superpowers/` - nor `og-template.html`. + `CNAME`, both favicons, `og-image.png`, and `why-ai-native.md` (raw Markdown, intended public + content — see Non-goals); contains neither `superpowers/` nor `og-template.html`. 7. Post-merge: `curl -o /dev/null -w "%{http_code}"` on `https://idstack.org/superpowers/specs/2026-08-12-documentation-accuracy-design.md` and on `https://idstack.org/og-template.html` → both 404. `https://idstack.org/` → 200. From c6a6321e00d194f306207ce8eb7e9d8997c9af7a Mon Sep 17 00:00:00 2001 From: Philippos Savvides Date: Fri, 14 Aug 2026 16:23:43 -0700 Subject: [PATCH 03/12] docs: add implementation plan for landing page accuracy audit Five tasks, each with its own test cycle. Task 1 is a genuine red-green cycle: the new absence check fails against the current files, and deleting the two stale date fields turns it green. Both non-obvious verification commands were run against the tree before being written into the plan -- the JSON-LD parse snippet and the Pages staging dry-run, which produces exactly the eight entries the plan lists. The dry-run also surfaced that _site was not gitignored, so a forgotten cleanup could be committed. Added as Task 4 Step 1. Co-Authored-By: Claude Opus 5 (1M context) --- .../plans/2026-08-14-landing-page-accuracy.md | 694 ++++++++++++++++++ 1 file changed, 694 insertions(+) create mode 100644 superpowers/plans/2026-08-14-landing-page-accuracy.md diff --git a/superpowers/plans/2026-08-14-landing-page-accuracy.md b/superpowers/plans/2026-08-14-landing-page-accuracy.md new file mode 100644 index 0000000..70c7ad3 --- /dev/null +++ b/superpowers/plans/2026-08-14-landing-page-accuracy.md @@ -0,0 +1,694 @@ +# Landing Page Accuracy Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Close all 11 accuracy defects between idstack.org and the repo, and guard the two that would otherwise silently return. + +**Architecture:** Five tasks, each with its own test cycle. Task 1 is a genuine red-green cycle — the new validator check fails against the current files, and deleting the two stale date fields turns it green. Tasks 2 and 3 are content edits to `docs/index.html` gated by `smoke-test.sh`. Task 4 changes what GitHub Pages publishes, verified by simulating the staging step locally before the workflow is touched. Task 5 is the full-suite sweep plus the post-merge live checks. + +**Tech Stack:** Static HTML (no build step for the page), Python 3.9-compatible validators, bash test suites, GitHub Actions. + +**Spec:** `superpowers/specs/2026-08-14-github-page-accuracy-design.md`. Read D1–D4 before starting; this plan implements them and does not restate their rationale. + +**Branch:** `docs/landing-page-accuracy` (already created, spec already committed). + +## Global Constraints + +- **No new CSS, no new visual patterns, no new components.** `DESIGN.md` decisions log (2026-06-12) records the landing page as an intentional separate dark/indigo surface that no longer tracks the report token system. Every addition reuses existing classes: `.install-prose`, `.footer-links a`, `.lede`. `DESIGN.md` and `templates/assets/idstack.css` are **not** modified. +- **Skill references use the namespaced form** `/idstack:`. A bare `/pipeline` does not resolve and `smoke-test.sh` fails on one. +- **`docs/og-template.html` must stay at that exact path.** `test/smoke-test.sh:136-141` asserts it exists and lints its gradient-text fallbacks. It is removed from the published site at build time only — never moved or deleted. +- **Python must parse on 3.9** (the version macOS ships). No `match`, no PEP 604 unions, no PEP 701 f-string quote reuse. +- **Do not add a local PASS/FAIL counter to any test suite.** `test/test-helper.sh` owns `PASS`/`FAIL`/`TOTAL` and `check()`; smoke-test fails on a local counter block. +- **`README.md` is not modified.** It is already internally consistent at "30 seconds"; the page reconciles to it. +- **VERSION is `3.4.0.1`** and must keep appearing as `v3.4.0.1` in `docs/index.html` and in README's first 10 lines. Do not touch version strings. + +--- + +### Task 1: Delete the stale date fields and guard their return + +Implements spec D2 and D3. Closes findings 2 and 3. + +**Files:** +- Modify: `test/check-doc-accuracy.py` (add function after `check_binaries_and_flags`, ~line 76; register in `main()`, ~line 190) +- Modify: `docs/index.html:47` (delete) +- Modify: `docs/sitemap.xml:5` (delete) +- Modify: `test/mutation-test.sh` (append mutation 22 before the summary `echo`) + +**Interfaces:** +- Consumes: nothing from earlier tasks. +- Produces: `check_no_stale_dates(root, problems) -> None` in `test/check-doc-accuracy.py`. Appends strings to `problems`; returns nothing. Follows the exact signature of the four existing check functions. + +- [ ] **Step 1: Write the failing check** + +Add to `test/check-doc-accuracy.py`, immediately after `check_binaries_and_flags` ends (before `def check_public_surfaces`): + +```python +def check_no_stale_dates(root, problems): + """Assert two deleted date fields have not come back. + + docs/index.html carried a JSON-LD "dateModified" and docs/sitemap.xml a + . Both were deleted rather than corrected: no CI check can assert + such a date is current without failing on commits that did not introduce + the defect (a PR left open a week, a merge dated after the docs edit), and + a check that cries wolf is one people learn to bypass. Absence is the only + assertion here that cannot false-positive. + + See superpowers/specs/2026-08-14-github-page-accuracy-design.md, D2 and D3. + """ + index_html = os.path.join(root, "docs", "index.html") + if os.path.isfile(index_html): + with open(index_html, "r", encoding="utf-8") as f: + if "dateModified" in f.read(): + problems.append( + "docs/index.html reintroduced dateModified; it was removed " + "because it cannot be kept accurate (spec D2)" + ) + + sitemap = os.path.join(root, "docs", "sitemap.xml") + if os.path.isfile(sitemap): + with open(sitemap, "r", encoding="utf-8") as f: + if "lastmod" in f.read(): + problems.append( + "docs/sitemap.xml reintroduced lastmod; it was removed " + "because it cannot be kept accurate (spec D2)" + ) +``` + +Register it in `main()`, after the `check_public_surfaces(root, problems)` line: + +```python + check_public_surfaces(root, problems) + check_no_stale_dates(root, problems) + check_developer_surfaces(root, problems) +``` + +- [ ] **Step 2: Run the check to verify it fails** + +```bash +python3 test/check-doc-accuracy.py . ; echo "exit=$?" +``` + +Expected: `exit=1` and both lines printed — +``` +docs/index.html reintroduced dateModified; it was removed because it cannot be kept accurate (spec D2) +docs/sitemap.xml reintroduced lastmod; it was removed because it cannot be kept accurate (spec D2) +``` + +This is the red state. The fields are still present; the check is doing its job. + +- [ ] **Step 3: Delete the two fields** + +In `docs/index.html`, delete line 47 in its entirety: + +``` + "dateModified": "2026-08-06", +``` + +The preceding line `"datePublished": "2026-04-20",` keeps its trailing comma — `"offers"` follows, so the JSON stays valid. **Do not delete `datePublished`**; it is a historical fact that cannot go stale. + +In `docs/sitemap.xml`, delete line 5 in its entirety: + +``` + 2026-05-13 +``` + +Leave `` and `` alone. + +- [ ] **Step 4: Run the check to verify it passes** + +```bash +python3 test/check-doc-accuracy.py . ; echo "exit=$?" +``` + +Expected: `exit=0`, no output. + +Confirm the JSON-LD is still parseable: + +```bash +python3 -c " +import json, re +s = open('docs/index.html').read() +m = re.search(r'', s, re.S) +d = json.loads(m.group(1)) +print('datePublished:', d['datePublished']) +print('dateModified present:', 'dateModified' in d) +" +``` + +Expected: `datePublished: 2026-04-20` and `dateModified present: False`. + +- [ ] **Step 5: Add mutation 22** + +In `test/mutation-test.sh`, insert immediately before the final `echo ""` / summary block (after mutation 21): + +```bash +# 22. dateModified reintroduced into the landing page -> smoke-test must fail. +# The field was deleted rather than corrected (spec D2); this proves the +# absence assertion in check-doc-accuracy.py actually guards that decision. +fresh +python3 - "$WORK/r/docs/index.html" <<'PY' +import sys +p = sys.argv[1]; s = open(p).read() +s = s.replace('"datePublished": "2026-04-20",', + '"datePublished": "2026-04-20",\n "dateModified": "2026-08-06",', 1) +open(p, 'w').write(s) +PY +expect_fail "dateModified reintroduced into docs/index.html" "$WORK/r/test/smoke-test.sh" "$WORK/r" +``` + +No `regen` call is needed — no template or spliced file is mutated. + +- [ ] **Step 6: Run the mutation suite** + +```bash +./test/mutation-test.sh +``` + +Expected: a line reading `GUARDED: dateModified reintroduced into docs/index.html (test failed as it should)`, every prior mutation still `GUARDED`, and the summary reporting `NOT guarded: 0`. + +If it reports `NOT-GUARDED`, the check is not wired into `smoke-test.sh`'s run — confirm `test/smoke-test.sh:133` still invokes `check-doc-accuracy.py`. + +- [ ] **Step 7: Run the full gate suite** + +```bash +./test/smoke-test.sh && python3 test/check-evidence-cards.py . && echo ALL-GREEN +``` + +Expected: `ALL-GREEN`. + +- [ ] **Step 8: Commit** + +```bash +git add test/check-doc-accuracy.py test/mutation-test.sh docs/index.html docs/sitemap.xml +git commit -m "fix(docs): delete unmaintainable date fields and guard their return + +dateModified in the JSON-LD and lastmod in sitemap.xml were both stale -- +2026-08-06 and 2026-05-13 against docs changed through 2026-08-12. They are +deleted rather than corrected: any check asserting such a date is current +fails on commits that did not introduce the defect, and a check that cries +wolf gets bypassed. check-doc-accuracy.py now asserts neither field returns, +which cannot false-positive. Mutation 22 proves the guard bites." +``` + +--- + +### Task 2: Correct the false claims in docs/index.html + +Closes findings 1, 4, and 9, plus the secondary half of 5. + +**Files:** +- Modify: `docs/index.html:44` (operatingSystem), `:1013` (pipeline lede), `:1127` (install headline), `:1153` (release note) + +**Interfaces:** +- Consumes: nothing. Task 1 already removed line 47, so **line numbers below have shifted by one** — anchor on the quoted text, not the number. +- Produces: nothing consumed by later tasks. + +- [ ] **Step 1: Fix the install-time contradiction (finding 1)** + +Replace: + +```html +

Install in about five minutes.

+``` + +with: + +```html +

Install in 30 seconds.

+``` + +README says "30 seconds" at lines 15 and 95 and describes the same command the page displays. The page's separate "New to Claude Code?" paragraph already accounts for installing Claude Code itself, which is where the extra time went. + +- [ ] **Step 2: Make the eleven-skills count add up (finding 9)** + +Replace the `.lede` paragraph under `

`: + +```html +

Eight of them run end-to-end as the standard sequence; two utilities (course-import and learn) sit outside it. Use one command for the full pipeline, or invoke any skill on its own — none of them require an existing manifest.

+``` + +with: + +```html +

Eight run end-to-end as the standard sequence, /idstack:pipeline orchestrates them, and two utilities (course-import and learn) sit outside the chain. Invoke any skill on its own — none of them require an existing manifest.

+``` + +That is 8 + 1 + 2 = 11, so a reader who counts reaches the eleven the headline promises. The dropped "Use one command for the full pipeline" clause is now redundant with naming the orchestrator, and `.pipeline-foot` further down already says it. + +- [ ] **Step 3: Add the Windows caveat to the JSON-LD (finding 5, secondary)** + +Replace: + +```html + "operatingSystem": "macOS, Linux, Windows", +``` + +with: + +```html + "operatingSystem": "macOS, Linux, Windows (WSL or Git Bash)", +``` + +This is a precision improvement, not the fix for finding 5 — Task 3 Step 1 carries that. Schema.org expects OS names here, so a parenthetical is not machine-readable. + +- [ ] **Step 4: Complete the v3.4.0.1 release note (finding 4)** + +Replace: + +```html +

Patched in v3.4.0.1 (August 7): three evidence cards on this page overstated their domain's evidence tier. They are derived from evidence/references.md now, and the test suite fails if they ever disagree again.

+``` + +with: + +```html +

Patched in v3.4.0.1 (August 7): three evidence cards on this page overstated their domain's evidence tier. They are derived from evidence/references.md now, and the test suite fails if they ever disagree again. The same patch added the outbound Canvas API upload in /idstack:course-export and the git fetch in bin/idstack-update-check to the privacy policy, and named WSL or Git Bash in the Windows install instructions.

+``` + +Both additions are drawn from `ROADMAP.md`'s "Documentation accuracy & automated verification (v3.4.0.1)" section — do not invent items beyond the two listed there. + +- [ ] **Step 5: Verify the JSON-LD still parses and the page is unchanged structurally** + +```bash +python3 -c " +import json, re +s = open('docs/index.html').read() +m = re.search(r'', s, re.S) +d = json.loads(m.group(1)) +print('os:', d['operatingSystem']) +" +grep -c "about five minutes" docs/index.html +``` + +Expected: `os: macOS, Linux, Windows (WSL or Git Bash)` and a count of `0`. + +- [ ] **Step 6: Run the gate suite** + +```bash +./test/smoke-test.sh && python3 test/check-evidence-cards.py . && python3 test/check-doc-accuracy.py . && echo ALL-GREEN +``` + +Expected: `ALL-GREEN`. `check-evidence-cards.py` must stay green — Step 4 touches a release card, not an evidence card, so any failure there means the wrong block was edited. + +- [ ] **Step 7: Commit** + +```bash +git add docs/index.html +git commit -m "fix(docs): correct false claims on the landing page + +- Install headline said five minutes; README says 30 seconds for the same + command. Reconciled to README. +- Pipeline lede accounted for ten skills under an 'Eleven skills' headline; + /idstack:pipeline is the eleventh and now appears in the count. +- JSON-LD claimed plain Windows support; ./setup is a bash script. +- v3.4.0.1 release note covered only the evidence-card fix; ROADMAP lists + two more items shipped in that patch." +``` + +--- + +### Task 3: Add the material omissions to docs/index.html + +Closes findings 5 (primary), 6, 7, and 8. + +**Files:** +- Modify: `docs/index.html` — install section (after the `./setup` prose paragraph), footer `.footer-links` block + +**Interfaces:** +- Consumes: nothing from Tasks 1–2. +- Produces: nothing consumed by Task 4. + +- [ ] **Step 1: State the prerequisites (findings 5 primary, 8)** + +In the install section, insert **between** the `./setup` prose paragraph and the "New to Claude Code?" paragraph. The block currently reads: + +```html +

./setup registers idstack with Claude Code and installs all 11 skills. Re-run it after a git pull to update.

+ +

New to Claude Code? Download it first (free), then paste the command above. When Claude Code starts, run /idstack:pipeline.

+``` + +Insert these two paragraphs between them: + +```html +

Requires a bash shell — Terminal on macOS or Linux, WSL or Git Bash on Windows. ./setup is a bash script, so PowerShell and cmd can't run it. python3 is recommended but not required; without it, quality-score trends and search filtering are unavailable.

+ +

If something looks wrong afterwards, bin/idstack-doctor diagnoses the plugin registration, and bin/idstack-status reports course health from inside a project directory.

+``` + +Both reuse the existing `.install-prose` class. No new CSS. + +The first paragraph is the primary fix for finding 5 — a Windows visitor is stopped by prose they read, not by the JSON-LD string from Task 2. Its wording follows `README.md:126-127` and the python3 FAQ at `README.md:383-384`; do not overstate what python3 unlocks. + +- [ ] **Step 2: Link the privacy policy (finding 6)** + +The page collects email addresses through a Formspree form in the footer and never links the `PRIVACY.md` that exists in the repo. In the `.footer-links` block, add a `Privacy` link after `MIT License`: + +```html + +``` + +`.footer-links a` is already styled (`docs/index.html:800-804`). No new CSS. + +- [ ] **Step 3: Verify every outbound link resolves** + +```bash +grep -oE 'href="https?://[^"]+"' docs/index.html | sed 's/href="//;s/"//' | sort -u | while read u; do + printf '%s %s\n' "$(curl -s -o /dev/null -w '%{http_code}' -L --max-time 12 "$u")" "$u" +done +``` + +Expected: every line starts `200`, and the list now includes +`https://github.com/savvides/idstack/blob/main/PRIVACY.md` (added twice — the footer here and the release note in Task 2 — but `sort -u` collapses it to one row). + +- [ ] **Step 4: Confirm no new CSS was introduced** + +```bash +git diff docs/index.html | grep -E '^\+' | grep -E '^\+\s*(\.|@media|--)' || echo "NO-NEW-CSS" +``` + +Expected: `NO-NEW-CSS`. Any output here violates the global constraint — the additions must reuse `.install-prose` and `.footer-links a`. + +- [ ] **Step 5: Run the gate suite** + +```bash +./test/smoke-test.sh && python3 test/check-evidence-cards.py . && python3 test/check-doc-accuracy.py . && echo ALL-GREEN +``` + +Expected: `ALL-GREEN`. + +- [ ] **Step 6: Commit** + +```bash +git add docs/index.html +git commit -m "feat(docs): state prerequisites, tooling, and privacy policy on the landing page + +The page asked visitors to paste a bash script without saying a bash shell +is required, never mentioned bin/idstack-doctor or bin/idstack-status, and +collected email addresses without linking the privacy policy that already +exists in the repo." +``` + +--- + +### Task 4: Stop publishing internal files on idstack.org + +Implements spec D1. Closes findings 10 and 11. + +**Files:** +- Move: `docs/superpowers/specs/2026-08-12-documentation-accuracy-design.md` → `superpowers/specs/` +- Move: `docs/superpowers/plans/2026-08-12-documentation-accuracy.md` → `superpowers/plans/` +- Modify: `.github/workflows/static.yml:36-40` +- Modify: `.gitignore` + +**Interfaces:** +- Consumes: nothing from Tasks 1–3. +- Produces: a staged `_site` directory at deploy time; nothing later depends on it. + +- [ ] **Step 1: Ignore the staging directory** + +The dry-runs below create `_site` in the working tree. Add it to `.gitignore` first, so a forgotten +cleanup cannot be committed. Append after the existing `.gstack/` line: + +``` +_site/ +``` + +Verify: + +```bash +mkdir -p _site && git status --porcelain | grep -q "_site" && echo "LEAKING" || echo "IGNORED" +rmdir _site +``` + +Expected: `IGNORED`. + +- [ ] **Step 2: Dry-run the staging logic before touching the workflow** + +Run the exact shell the workflow will run, against the current tree: + +```bash +rm -rf _site && cp -R docs _site && rm -rf _site/superpowers && rm -f _site/og-template.html +ls -A _site +``` + +Expected exactly these entries and no others: +``` +CNAME +favicon.png +favicon.svg +index.html +og-image.png +robots.txt +sitemap.xml +why-ai-native.md +``` + +`why-ai-native.md` is intended public content, linked from README — see the spec's Non-goals. `superpowers/` and `og-template.html` must both be absent. + +Confirm the source tree is untouched: + +```bash +test -f docs/og-template.html && test -d docs/superpowers && echo "SOURCE-INTACT" +rm -rf _site +``` + +Expected: `SOURCE-INTACT`. Running the dry-run first means a staging bug costs nothing; discovering it after a deploy costs a live site. + +- [ ] **Step 3: Relocate the two design documents** + +`superpowers/specs/` and `superpowers/plans/` already exist (this plan and its spec live there). `git mv` will not create a missing directory, so verify first: + +```bash +test -d superpowers/specs && test -d superpowers/plans && echo DIRS-OK +git mv docs/superpowers/specs/2026-08-12-documentation-accuracy-design.md superpowers/specs/ +git mv docs/superpowers/plans/2026-08-12-documentation-accuracy.md superpowers/plans/ +rmdir docs/superpowers/specs docs/superpowers/plans docs/superpowers +``` + +Verified safe: nothing in the repo references `docs/superpowers/`. Confirm that still holds: + +```bash +grep -rn "docs/superpowers" --include="*.md" --include="*.sh" --include="*.py" --include="*.yml" --include="*.html" . || echo "NO-REFERENCES" +``` + +Expected: `NO-REFERENCES`. + +- [ ] **Step 4: Add the staging step to the Pages workflow** + +In `.github/workflows/static.yml`, replace: + +```yaml + - name: Upload artifact + uses: actions/upload-pages-artifact@v3 + with: + # Upload entire repository + path: 'docs' +``` + +with: + +```yaml + - name: Stage publishable files + # docs/ holds two things that must exist in the repo but not on the + # site: internal design docs (the brainstorming skill writes specs to + # docs/superpowers/ by default, so relocating them is not enough -- + # its next run recreates the directory) and og-template.html (the OG + # card's regenerable source, which smoke-test.sh asserts exists at + # that exact path, so it cannot be moved). Stage a copy and drop both. + run: | + rm -rf _site + cp -R docs _site + rm -rf _site/superpowers + rm -f _site/og-template.html + - name: Upload artifact + uses: actions/upload-pages-artifact@v3 + with: + path: '_site' +``` + +Order matters: this step must sit after `actions/checkout@v4` and `actions/configure-pages@v5`, and before `actions/deploy-pages@v5`. Quote `'_site'` the same way `'docs'` was quoted. + +- [ ] **Step 5: Re-run the dry-run against the relocated tree** + +```bash +rm -rf _site && cp -R docs _site && rm -rf _site/superpowers && rm -f _site/og-template.html +ls -A _site +rm -rf _site +``` + +Expected: the same eight entries as Step 2. `rm -rf _site/superpowers` is now a no-op on this tree — that is intentional. It is the backstop that catches the next brainstorming run, not a cleanup of today's files. + +- [ ] **Step 6: Validate the workflow YAML parses** + +```bash +python3 -c " +import sys +try: + import yaml +except ImportError: + sys.exit('SKIP: pyyaml not installed, inspect the file by eye') +d = yaml.safe_load(open('.github/workflows/static.yml')) +steps = d['jobs']['deploy']['steps'] +names = [s.get('name') for s in steps] +print(names) +up = [s for s in steps if 'upload-pages-artifact' in str(s.get('uses'))][0] +print('upload path:', up['with']['path']) +assert names.index('Stage publishable files') < names.index('Upload artifact') +print('ORDER-OK') +" +``` + +Expected: the step list in order, `upload path: _site`, and `ORDER-OK`. If pyyaml is unavailable, confirm by reading the file that staging precedes upload. + +- [ ] **Step 7: Run the gate suite** + +```bash +./test/smoke-test.sh && python3 test/check-doc-accuracy.py . && echo ALL-GREEN +``` + +Expected: `ALL-GREEN`. This is the check that matters most in this task — `smoke-test.sh:136-141` asserts `docs/og-template.html` still exists. If it fails, the file was moved or deleted instead of excluded at build time. + +- [ ] **Step 8: Commit** + +```bash +git add .github/workflows/static.yml .gitignore superpowers/ docs/ +git commit -m "fix(pages): stop publishing internal design docs and the OG template + +static.yml uploaded docs/ verbatim, so design specs and og-template.html +were served at idstack.org. Stage a copy and drop both instead of moving +them: the brainstorming skill writes specs to docs/superpowers/ by default +so a move alone gets undone on its next run, and smoke-test.sh asserts +docs/og-template.html exists at that exact path so it cannot move at all." +``` + +--- + +### Task 5: Full verification sweep + +No production changes. Confirms all 11 findings are closed and nothing regressed. + +**Files:** none modified. + +**Interfaces:** +- Consumes: the complete state after Tasks 1–4. +- Produces: a merge-ready branch. + +- [ ] **Step 1: Run every suite** + +```bash +./test/smoke-test.sh && \ +./test/integration-test.sh && \ +./test/test-setup.sh && \ +./test/test-doctor.sh && \ +./test/test-status.sh && \ +./test/test-manifest-merge.sh && \ +./test/test-version-classifier.sh && \ +./test/test-plugin-status.sh && \ +./test/test-preamble-python.sh && \ +python3 test/check-evidence-cards.py . && \ +python3 test/check-doc-accuracy.py . && \ +echo ALL-SUITES-GREEN +``` + +Expected: `ALL-SUITES-GREEN`. + +- [ ] **Step 2: Run the mutation suite** + +```bash +./test/mutation-test.sh +``` + +Expected: `NOT guarded: 0`, and mutation 22 reports `GUARDED`. + +- [ ] **Step 3: Confirm the working tree is clean and the suites left nothing behind** + +```bash +git status --porcelain +``` + +Expected: empty output. The integration suite is documented to leave the working tree untouched; anything here is a bug worth reporting before merge. + +- [ ] **Step 4: Walk the findings list** + +```bash +echo "--- 1 install time (expect 'Install in 30 seconds.', and 0 for five minutes)" +grep -c "about five minutes" docs/index.html; grep -o "Install in 30 seconds." docs/index.html +echo "--- 2 dateModified (expect 0)"; grep -c "dateModified" docs/index.html +echo "--- 3 lastmod (expect 0)"; grep -c "lastmod" docs/sitemap.xml +echo "--- 4 release note (expect 1)"; grep -c "named WSL or Git Bash in the Windows install" docs/index.html +echo "--- 5 windows caveat (expect 1 each)"; grep -c "WSL or Git Bash on Windows" docs/index.html; grep -c "Windows (WSL or Git Bash)" docs/index.html +echo "--- 6 privacy link (expect 2: footer + release note)"; grep -c "blob/main/PRIVACY.md" docs/index.html +echo "--- 7 tooling (expect 1 each)"; grep -c "bin/idstack-doctor" docs/index.html; grep -c "bin/idstack-status" docs/index.html +echo "--- 8 python3 note (expect 1)"; grep -c "python3 is recommended" docs/index.html +echo "--- 9 eleventh skill (expect 1)"; grep -c "orchestrates them" docs/index.html +echo "--- 10/11 excluded at build (expect _site path)"; grep -c "_site" .github/workflows/static.yml +echo "--- 10 relocated (expect NO-REFERENCES)"; grep -rn "docs/superpowers" --include="*.md" --include="*.sh" --include="*.py" --include="*.yml" --include="*.html" . || echo NO-REFERENCES +echo "--- 11 og-template still in repo (expect the file)"; ls docs/og-template.html +``` + +Every line must match its stated expectation. + +- [ ] **Step 5: Push and open the pull request** + +```bash +git push -u origin docs/landing-page-accuracy +gh pr create --title "docs: close 11 accuracy defects between idstack.org and the repo" --body "$(cat <<'BODY' +Implements `superpowers/specs/2026-08-14-github-page-accuracy-design.md`. + +An audit of idstack.org against the repo found 11 defects that the two +existing validators do not cover. All 11 are closed here. + +**Corrected** — install time contradicted README, the JSON-LD claimed plain +Windows support for a bash script, the v3.4.0.1 release note covered one of +three shipped items, and an "Eleven skills" headline accounted for ten. + +**Added** — prerequisites, `bin/idstack-doctor` / `bin/idstack-status`, and a +link to the privacy policy under the email signup form. + +**Unpublished** — internal design docs and `og-template.html` are excluded +from the Pages artifact at build time. Excluded rather than moved: the +brainstorming skill writes specs to `docs/superpowers/` by default, and +`smoke-test.sh` asserts `docs/og-template.html` exists at that exact path. + +**Guarded** — `dateModified` and sitemap `lastmod` were both stale. They are +deleted rather than corrected, because any check asserting such a date is +current fails on commits that did not introduce the defect. The new check +asserts absence, which cannot false-positive, and mutation 22 proves it bites. + +Verified accurate and left alone: all version strings, the 108-studies / +11-domains claim, all 11 evidence cards, every per-skill capability claim, +`og-image.png`, and the repo's About/topics/homepage. +BODY +)" +``` + +- [ ] **Step 6: Confirm the deploy after merge** + +The Pages workflow runs on push to `main`. Once it completes: + +```bash +for u in \ + "https://idstack.org/" \ + "https://idstack.org/superpowers/specs/2026-08-12-documentation-accuracy-design.md" \ + "https://idstack.org/og-template.html" ; do + printf '%s %s\n' "$(curl -s -o /dev/null -w '%{http_code}' -L --max-time 15 "$u")" "$u" +done +``` + +Expected: `200` for the site root, `404` for both others. + +If either returns 200, the staging step did not take effect — check the workflow run's "Stage publishable files" step output before assuming the exclusion logic is wrong. + +--- + +## Rollback + +Every task is a single commit on `docs/landing-page-accuracy`. `git revert` any one independently; none depends on another's output. The only change with a live-site effect is Task 4, and reverting it restores the previous `path: 'docs'` upload on the next push to `main`. From 4f64c9499c85d1c0e81e05fbe99d65505b48a784 Mon Sep 17 00:00:00 2001 From: Philippos Savvides Date: Fri, 14 Aug 2026 16:24:34 -0700 Subject: [PATCH 04/12] docs: patch plan verification notes after review - Confirm the PRIVACY.md blob URL resolves on main (200), so a 404 in the link sweep points at a typo rather than a missing file upstream. - grep -c counts matching lines, not occurrences; the privacy-link check now uses grep -o | wc -l so a reflowed paragraph cannot read as failure. - Note that a stray _site/ in git status is an uncleaned dry-run. Co-Authored-By: Claude Opus 5 (1M context) --- superpowers/plans/2026-08-14-landing-page-accuracy.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/superpowers/plans/2026-08-14-landing-page-accuracy.md b/superpowers/plans/2026-08-14-landing-page-accuracy.md index 70c7ad3..f3d5433 100644 --- a/superpowers/plans/2026-08-14-landing-page-accuracy.md +++ b/superpowers/plans/2026-08-14-landing-page-accuracy.md @@ -368,6 +368,8 @@ done Expected: every line starts `200`, and the list now includes `https://github.com/savvides/idstack/blob/main/PRIVACY.md` (added twice — the footer here and the release note in Task 2 — but `sort -u` collapses it to one row). +That URL was verified against `main` while writing this plan: `PRIVACY.md` is tracked at the repo root and the blob URL returns 200. If the sweep 404s on it, the link was mistyped, not missing upstream. + - [ ] **Step 4: Confirm no new CSS was introduced** ```bash @@ -616,6 +618,8 @@ git status --porcelain Expected: empty output. The integration suite is documented to leave the working tree untouched; anything here is a bug worth reporting before merge. +One exception: if `_site/` appears, that is an uncleaned staging dry-run from Task 4, not a suite bug. `rm -rf _site` and re-run. (It is gitignored as of Task 4 Step 1, so it should not appear at all.) + - [ ] **Step 4: Walk the findings list** ```bash @@ -625,7 +629,7 @@ echo "--- 2 dateModified (expect 0)"; grep -c "dateModified" docs/index.html echo "--- 3 lastmod (expect 0)"; grep -c "lastmod" docs/sitemap.xml echo "--- 4 release note (expect 1)"; grep -c "named WSL or Git Bash in the Windows install" docs/index.html echo "--- 5 windows caveat (expect 1 each)"; grep -c "WSL or Git Bash on Windows" docs/index.html; grep -c "Windows (WSL or Git Bash)" docs/index.html -echo "--- 6 privacy link (expect 2: footer + release note)"; grep -c "blob/main/PRIVACY.md" docs/index.html +echo "--- 6 privacy link (expect 2: footer + release note)"; grep -o "blob/main/PRIVACY.md" docs/index.html | wc -l echo "--- 7 tooling (expect 1 each)"; grep -c "bin/idstack-doctor" docs/index.html; grep -c "bin/idstack-status" docs/index.html echo "--- 8 python3 note (expect 1)"; grep -c "python3 is recommended" docs/index.html echo "--- 9 eleventh skill (expect 1)"; grep -c "orchestrates them" docs/index.html From 1e4ef8205cf11882adc4dd8781275dbf886ddc65 Mon Sep 17 00:00:00 2001 From: Philippos Savvides Date: Fri, 14 Aug 2026 16:41:30 -0700 Subject: [PATCH 05/12] fix(docs): delete unmaintainable date fields and guard their return dateModified in the JSON-LD and lastmod in sitemap.xml were both stale -- 2026-08-06 and 2026-05-13 against docs changed through 2026-08-12. They are deleted rather than corrected: any check asserting such a date is current fails on commits that did not introduce the defect, and a check that cries wolf gets bypassed. check-doc-accuracy.py now asserts neither field returns, which cannot false-positive. Mutation 22 proves the guard bites. --- docs/index.html | 1 - docs/sitemap.xml | 1 - test/check-doc-accuracy.py | 32 ++++++++++++++++++++++++++++++++ test/mutation-test.sh | 13 +++++++++++++ 4 files changed, 45 insertions(+), 2 deletions(-) diff --git a/docs/index.html b/docs/index.html index 3189d78..d510540 100644 --- a/docs/index.html +++ b/docs/index.html @@ -44,7 +44,6 @@ "operatingSystem": "macOS, Linux, Windows", "softwareVersion": "3.4.0.1", "datePublished": "2026-04-20", - "dateModified": "2026-08-06", "offers": { "@type": "Offer", "price": "0", diff --git a/docs/sitemap.xml b/docs/sitemap.xml index e754c97..67f05ed 100644 --- a/docs/sitemap.xml +++ b/docs/sitemap.xml @@ -2,7 +2,6 @@ https://idstack.org/ - 2026-05-13 weekly 1.0 diff --git a/test/check-doc-accuracy.py b/test/check-doc-accuracy.py index 023f54e..56d4527 100755 --- a/test/check-doc-accuracy.py +++ b/test/check-doc-accuracy.py @@ -74,6 +74,37 @@ def check_binaries_and_flags(root, problems): problems.append("README.md references non-executable binary: %s" % ref) +def check_no_stale_dates(root, problems): + """Assert two deleted date fields have not come back. + + docs/index.html carried a JSON-LD "dateModified" and docs/sitemap.xml a + . Both were deleted rather than corrected: no CI check can assert + such a date is current without failing on commits that did not introduce + the defect (a PR left open a week, a merge dated after the docs edit), and + a check that cries wolf is one people learn to bypass. Absence is the only + assertion here that cannot false-positive. + + See superpowers/specs/2026-08-14-github-page-accuracy-design.md, D2 and D3. + """ + index_html = os.path.join(root, "docs", "index.html") + if os.path.isfile(index_html): + with open(index_html, "r", encoding="utf-8") as f: + if "dateModified" in f.read(): + problems.append( + "docs/index.html reintroduced dateModified; it was removed " + "because it cannot be kept accurate (spec D2)" + ) + + sitemap = os.path.join(root, "docs", "sitemap.xml") + if os.path.isfile(sitemap): + with open(sitemap, "r", encoding="utf-8") as f: + if "lastmod" in f.read(): + problems.append( + "docs/sitemap.xml reintroduced lastmod; it was removed " + "because it cannot be kept accurate (spec D2)" + ) + + def check_public_surfaces(root, problems): v_file = os.path.join(root, "VERSION") if not os.path.isfile(v_file): @@ -187,6 +218,7 @@ def main(): check_manifest_schema_version(root, problems) check_binaries_and_flags(root, problems) check_public_surfaces(root, problems) + check_no_stale_dates(root, problems) check_developer_surfaces(root, problems) for p in problems: diff --git a/test/mutation-test.sh b/test/mutation-test.sh index 84d1716..82251af 100755 --- a/test/mutation-test.sh +++ b/test/mutation-test.sh @@ -383,6 +383,19 @@ open(p,'w').write(s) PY expect_fail "non-existent binary reference in README" "$WORK/r/test/smoke-test.sh" "$WORK/r" +# 22. dateModified reintroduced into the landing page -> smoke-test must fail. +# The field was deleted rather than corrected (spec D2); this proves the +# absence assertion in check-doc-accuracy.py actually guards that decision. +fresh +python3 - "$WORK/r/docs/index.html" <<'PY' +import sys +p = sys.argv[1]; s = open(p).read() +s = s.replace('"datePublished": "2026-04-20",', + '"datePublished": "2026-04-20",\n "dateModified": "2026-08-06",', 1) +open(p, 'w').write(s) +PY +expect_fail "dateModified reintroduced into docs/index.html" "$WORK/r/test/smoke-test.sh" "$WORK/r" + echo "" echo "guarded: $pass NOT guarded: $fail skipped: $skip" [ "$fail" -eq 0 ] From f7affab5cd4fee5aa21f1df4e0f4cebc7c60c887 Mon Sep 17 00:00:00 2001 From: Philippos Savvides Date: Fri, 14 Aug 2026 16:45:43 -0700 Subject: [PATCH 06/12] docs: drop retired-CLI product name from the spec smoke-test.sh sweeps every tracked file for references to the retired CLI and this spec named it while describing an og-image verification result. Reworded rather than tagged with IDSTACK_CLI_LEAK_ALLOW: the tag is for dated historical mentions, and weakening the invariant to accommodate my own prose is the wrong trade. Co-Authored-By: Claude Opus 5 (1M context) --- superpowers/specs/2026-08-14-github-page-accuracy-design.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/superpowers/specs/2026-08-14-github-page-accuracy-design.md b/superpowers/specs/2026-08-14-github-page-accuracy-design.md index 1debf1e..80f8dd6 100644 --- a/superpowers/specs/2026-08-14-github-page-accuracy-design.md +++ b/superpowers/specs/2026-08-14-github-page-accuracy-design.md @@ -51,7 +51,7 @@ strings; "108 peer-reviewed studies across 11 research domains" (108 unique refe `evidence/references.md`, 11 domains); all 11 evidence cards; every per-skill claim in the pipeline section (`UDL 3.0`, `WCAG 2.1 AA`, `SCORM 1.2`, red-team's 5 dimensions, Nicol's 7 feedback principles, three-level needs assessment — each matches its `SKILL.md`); `og-image.png` (no baked-in -version, no reference to the retired Codex build); all 11 outbound links (HTTP 200); and the GitHub +version, no reference to the retired CLI build); all 11 outbound links (HTTP 200); and the GitHub repo's description, topics, and homepage URL. ## Design decisions From 93bb6a401f6e1a9e31bb8b052639a244c33c0480 Mon Sep 17 00:00:00 2001 From: Philippos Savvides Date: Fri, 14 Aug 2026 17:48:56 -0700 Subject: [PATCH 07/12] test: exclude git-ignored agent scratch from the retired-CLI sweep .superpowers/ holds implementation reports and review notes written during development. It is not shipped and CI never sees it, but notes discussing the sweep tripped it, making the local gate unreliable. Matches the .gstack/.idstack/.claude exclusions already on that line. Co-Authored-By: Claude Opus 5 (1M context) --- test/smoke-test.sh | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/test/smoke-test.sh b/test/smoke-test.sh index 143e0a6..15ab2b8 100755 --- a/test/smoke-test.sh +++ b/test/smoke-test.sh @@ -390,11 +390,15 @@ check "generator takes no --target flag" "! grep -q -- '--target' '$IDSTACK_DIR/ check "resolve chain drops the ~/.agents fallbacks" "! grep -q '\.agents/' '$IDSTACK_DIR/templates/snippets/idstack-resolve.sh'" check "preamble embeds no ~/.agents fallbacks" "! grep -q '\.agents/' '$IDSTACK_DIR/templates/preamble.md'" -# Repo-wide sweep for the retired CLI's name. Two exemptions: +# Repo-wide sweep for the retired CLI's name. Three exemptions: # # 1. CHANGELOG.md — the release record, which has to keep describing what was # removed and how to clean up after it. -# 2. Lines tagged IDSTACK_CLI_LEAK_ALLOW. Three kinds of line carry the tag: +# 2. .superpowers/, .gstack/, .idstack/, .claude/ — git-ignored tool scratch +# directories. Implementation reports and review notes written during +# development are not shipped and CI never sees them (fresh checkout), but +# they can discuss the sweep and trip it unreliably. +# 3. Lines tagged IDSTACK_CLI_LEAK_ALLOW. Three kinds of line carry the tag: # this block's own patterns, the dated release note on the landing page, # and the comments crediting "Gemini Code Assist" — a PR-review bot # IDSTACK_CLI_LEAK_ALLOW # that flagged the version classifier four times, unrelated to the CLI and @@ -408,7 +412,7 @@ check "preamble embeds no ~/.agents fallbacks" "! grep -q '\.agents/' '$IDSTACK_ CLI_LEAK_RE='codex|gemini' # IDSTACK_CLI_LEAK_ALLOW CLI_LEAK="$(grep -rIiE "$CLI_LEAK_RE" "$IDSTACK_DIR" \ --exclude-dir=.git --exclude-dir=.gstack --exclude-dir=.idstack \ - --exclude-dir=.claude --exclude=CHANGELOG.md 2>/dev/null || true)" + --exclude-dir=.claude --exclude-dir=.superpowers --exclude=CHANGELOG.md 2>/dev/null || true)" CLI_LEAK="$(printf '%s' "$CLI_LEAK" | grep -vF 'IDSTACK_CLI_LEAK_ALLOW' || true)" # Printed through the command itself, not tested with -z, so a failure names # the offending lines instead of just saying the string was non-empty. From 25bbf2581061186b9976977f0400dd1ebf5d63ad Mon Sep 17 00:00:00 2001 From: Philippos Savvides Date: Fri, 14 Aug 2026 17:51:10 -0700 Subject: [PATCH 08/12] fix(docs): correct false claims on the landing page - Install headline said five minutes; README says 30 seconds for the same command. Reconciled to README. - Pipeline lede accounted for ten skills under an 'Eleven skills' headline; /idstack:pipeline is the eleventh and now appears in the count. - JSON-LD claimed plain Windows support; ./setup is a bash script. - v3.4.0.1 release note covered only the evidence-card fix; ROADMAP lists two more items shipped in that patch. --- docs/index.html | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/index.html b/docs/index.html index d510540..b4c625f 100644 --- a/docs/index.html +++ b/docs/index.html @@ -41,7 +41,7 @@ "description": "Open-source instructional design skills backed by peer-reviewed research across 11 domains. Every recommendation cites its evidence tier. Runs in Claude Code.", "url": "https://idstack.org", "applicationCategory": "EducationalApplication", - "operatingSystem": "macOS, Linux, Windows", + "operatingSystem": "macOS, Linux, Windows (WSL or Git Bash)", "softwareVersion": "3.4.0.1", "datePublished": "2026-04-20", "offers": { @@ -1009,7 +1009,7 @@

Accessibility & Universal Design for Learnin

Pipeline

Eleven skills. Pipeline optional.

-

Eight of them run end-to-end as the standard sequence; two utilities (course-import and learn) sit outside it. Use one command for the full pipeline, or invoke any skill on its own — none of them require an existing manifest.

+

Eight run end-to-end as the standard sequence, /idstack:pipeline orchestrates them, and two utilities (course-import and learn) sit outside the chain. Invoke any skill on its own — none of them require an existing manifest.

@@ -1123,7 +1123,7 @@

Install

-

Install in about five minutes.

+

Install in 30 seconds.

@@ -1149,7 +1149,7 @@

v3.4.0.0 — idstack is a Claude Code plugin.

One host, supported properly.

idstack shipped an OpenAI Codex CLI build from v2.5.0.0 through v3.3.0.4. It is removed. Every skill, the evidence base, the project manifest, and the HTML reports are unchanged — idstack now targets Claude Code and nothing else, which is the only place it was ever tested end to end.

To update: cd into your idstack clone, then git pull && ./setup. If you had the Codex build installed, ./setup can no longer clean it up — the release notes carry the two paths to remove.

-

Patched in v3.4.0.1 (August 7): three evidence cards on this page overstated their domain's evidence tier. They are derived from evidence/references.md now, and the test suite fails if they ever disagree again.

+

Patched in v3.4.0.1 (August 7): three evidence cards on this page overstated their domain's evidence tier. They are derived from evidence/references.md now, and the test suite fails if they ever disagree again. The same patch added the outbound Canvas API upload in /idstack:course-export and the git fetch in bin/idstack-update-check to the privacy policy, and named WSL or Git Bash in the Windows install instructions.

From 21ea72059fb21dd36d60d77bc871bcf777786e3e Mon Sep 17 00:00:00 2001 From: Philippos Savvides Date: Fri, 14 Aug 2026 17:57:50 -0700 Subject: [PATCH 09/12] feat(docs): state prerequisites, tooling, and privacy policy on the landing page The page asked visitors to paste a bash script without saying a bash shell is required, never mentioned bin/idstack-doctor or bin/idstack-status, and collected email addresses without linking the privacy policy that already exists in the repo. --- docs/index.html | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/index.html b/docs/index.html index b4c625f..60a0c3b 100644 --- a/docs/index.html +++ b/docs/index.html @@ -1134,6 +1134,10 @@

Install in 30 seconds.

./setup registers idstack with Claude Code and installs all 11 skills. Re-run it after a git pull to update.

+

Requires a bash shell — Terminal on macOS or Linux, WSL or Git Bash on Windows. ./setup is a bash script, so PowerShell and cmd can't run it. python3 is recommended but not required; without it, quality-score trends and search filtering are unavailable.

+ +

If something looks wrong afterwards, bin/idstack-doctor diagnoses the plugin registration, and bin/idstack-status reports course health from inside a project directory.

+

New to Claude Code? Download it first (free), then paste the command above. When Claude Code starts, run /idstack:pipeline.

@@ -1176,6 +1180,7 @@

Welcome-back messages work on stock macOS now.