diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json
index 3aeb17f..7d90eda 100644
--- a/.claude-plugin/plugin.json
+++ b/.claude-plugin/plugin.json
@@ -1,6 +1,6 @@
{
"name": "idstack",
- "version": "3.3.0.3",
+ "version": "3.3.0.4",
"description": "Evidence-based instructional design pipeline. 11 skills backed by peer-reviewed research across 11 domains. Analyze, design, build, review, and export courses with every recommendation citing its evidence tier.",
"author": {
"name": "Philippos Savvides",
diff --git a/CHANGELOG.md b/CHANGELOG.md
index c1c3b10..6044ce3 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,16 @@
# Changelog
+## v3.3.0.4 (2026-08-06)
+
+No user-facing change — this release is test coverage for the two scripts a user runs when something has gone wrong.
+
+### For contributors
+
+- **`bin/idstack-doctor` now has execution coverage.** It had none: smoke-test checked only that the file existed and parsed. Since doctor's entire job is telling a user why `/idstack:` is missing, every branch it prints is one somebody acts on. 13 cases covering both missing manifests, an unparseable `plugin.json` (doctor parses it as JSON, so a regex-shaped test would miss this), missing `SKILL.md`, absent `claude` as a WARNING rather than a failure, installed-but-disabled, not-installed, all three legacy-conflict shapes, and an unrecognized directory being warned about rather than claimed.
+- **`bin/idstack-status --readiness` now has coverage** — roughly 100 lines deciding whether a course is fit to export. Each threshold is probed at its own boundary with the other two held passing (quality 70 vs 69, accessibility 80 vs 79, red-team 0 vs 1 critical), because a fixture failing everything at once still passes when a single constant is wrong. The WCAG Level-A override is asserted in both places it is implemented; removing either one alone leaves the other reporting.
+- **One shared assertion helper.** Nine suites each carried their own `PASS`/`FAIL`/`TOTAL` and copy of `check()`, and they had drifted: two spelled it `assert`, and one ran assertions with `>/dev/null 2>&1` and printed a bare `FAIL` — a red CI run that said something broke but not what. `test/test-helper.sh` owns it now. Two suites keep a differently-shaped wrapper, named so they cannot shadow the shared one. smoke-test asserts no suite regrows private counters, and a mutation proves that guard works.
+- Test suites 9 → 11 in CI. smoke-test 371 → 393 assertions, mutation suite 14 → 18.
+
## v3.3.0.3 (2026-08-06)
To get this fix: `cd` into your idstack clone, then `git pull && ./setup`. Restart Claude Code afterward — plugins load at session start.
diff --git a/VERSION b/VERSION
index da062d0..93b770f 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-3.3.0.3
+3.3.0.4
diff --git a/docs/index.html b/docs/index.html
index 2beb8c9..a968682 100644
--- a/docs/index.html
+++ b/docs/index.html
@@ -926,7 +926,7 @@
MIT
- v3.3.0.3 — Course memory fixed
+ v3.3.0.4 — Course memory fixed
Evidence-based instructional design, transparently cited.
108 peer-reviewed studies across 11 research domains. Every recommendation tagged with its evidence tier — T1 meta-analyses and RCTs through T5 expert opinion. Runs in Claude Code, OpenAI Codex CLI, and (soon) Gemini.
@@ -1176,7 +1176,7 @@ v3.3.0.0 — Course memory that actually remembers.
- August 4, 2026 · v3.3.0.0 · patched through v3.3.0.3
+ August 4, 2026 · v3.3.0.0 · patched through v3.3.0.4
Welcome-back messages work on stock macOS now.
On any Python older than 3.12 — including the 3.9 that macOS ships — the session-memory code inside every skill hit a silent syntax error. No welcome-back summary, no quality-score trend, no suggested next step. Fixed, and now exercised on Python 3.9 in CI so it stays fixed.
Also in this release: /idstack:pipeline invokes its child skills correctly in Claude Code, skills notice previous runs again ("update the results or start fresh?"), imported courses get a proper next-step suggestion, and a course name with an apostrophe no longer blanks the status dashboard. To update: cd into your idstack clone, then git pull && ./setup.