You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
v0.18.18.0 test: Track 6B — Track 5A test follow-ups (#73)
* test(audit): doc-type math boundary tests (Track 6B)
Five new tests pinning the heuristic at its actual decision points:
- empty file (0 content lines, skip)
- 4 content lines all checkboxes (under MIN_CONTENT_LINES, skip)
- density 0.4 (4/10, below 0.5 threshold, skip)
- density 0.5 EXACTLY (5/10, fires per `>=`)
- density 0.6 (6/10, fires)
10-line denominators are required to land at 0.4 / 0.5 / 0.6 cleanly --
a 5-line denominator only produces {0, 0.2, 0.4, 0.6, 0.8, 1.0}, which
misses the 0.5 boundary entirely.
Also folds in a mkdir-p assertion in the existing plantuml-fence test
so the implicit "destination parent missing" branch can't regress to
a bare git mv.
* test(update): post-upgrade path-1 resolution + cache-clear (Track 6B)
Adds opt-in fixture variant `createFixtureRepoWithRealSetup` that copies
the real setup + bin/lib/install-safety.sh + empty placeholder skill .md
files into a fixture repo, so update-run's post-pull setup invocation
actually rebuilds ~/.claude/skills/{name}/SKILL.md symlinks. Kept separate
from createFixtureRepo so the lighter happy/branch-switch/dirty/diverged
scenarios don't take on install-safety + bun-on-PATH dependencies.
Four assertions after update-run completes:
1. UPGRADE_OK fires (sanity).
2. Path-1 holds a symlink (not regular file/missing).
3. readlinkSync target resolves into the fixture (not ROOT -- proves no
developer-home leakage through unscoped env vars).
4. CP#3 readlink-chain bash probe yields $_EXTEND_ROOT = fixture root.
CP#3 probe spawn is hardened: env scoped to { HOME, PATH } (no
process.env spread that would inherit GSTACK_EXTEND_*/BASH_ENV/PWD), cwd
pinned to homeDir (so the fallback `.claude/skills/...` readlink can't
match a stale workspace-local .claude/ directory), and explicit exit-0
+ non-empty-stdout guards before realpathSync to defend against the
failure mode where `set -u` plus command substitution silently yields
an empty $_SKILL_SRC.
Also folds in cache-clear seeding in the existing happy-path beforeAll:
pre-seeds last-update-check and update-snoozed in stateDir before the
update-run invocation, then asserts both files are removed. Previously
the implicit existsSync(...).toBe(false) would have passed even if
update-run did nothing.
* chore: bump version and changelog (v0.18.18.0)
* docs: update ROADMAP + PROGRESS for v0.18.18.0 (Track 6B shipped)
Copy file name to clipboardExpand all lines: CHANGELOG.md
+18Lines changed: 18 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -2,6 +2,24 @@
2
2
3
3
All notable changes to this project will be documented in this file.
4
4
5
+
## [0.18.18.0] - 2026-05-10
6
+
7
+
### Added: Track 6B — Track 5A test follow-ups
8
+
9
+
Closes two test-coverage gaps surfaced during /ship of v0.18.14.0.
10
+
11
+
-**Post-upgrade path-1 resolution integration test** in `tests/update.test.ts`. New opt-in fixture variant `createFixtureRepoWithRealSetup` copies the real `setup` + `bin/lib/install-safety.sh` + empty placeholder skill `.md` files into a fixture repo so `update-run`'s post-pull `setup` invocation actually rebuilds `~/.claude/skills/{name}/SKILL.md` symlinks. Four assertions after `update-run` completes: `UPGRADE_OK` fires, path-1 holds a symlink, the symlink target resolves into the fixture (not ROOT — proves no developer-home leakage), and the CP#3 readlink-chain probe yields `$_EXTEND_ROOT` = fixture root. Bash probe runs with scoped `env: { HOME, PATH }` only (no `process.env` spread) and `cwd: homeDir`, so the test cannot pass for the wrong reason via inherited developer env or a stale workspace-local `.claude/` directory. Probe also asserts exit 0 + non-empty stdout to defend against the failure mode where `set -u` + command substitution silently produces an empty `$_SKILL_SRC`.
12
+
13
+
-**Doc-type math boundary tests** in `tests/checks-doc-type.test.ts`. Five new tests pin the heuristic at its actual decision boundaries: empty file (0 content lines, skip), 4 content lines all checkboxes (under `MIN_CONTENT_LINES`, skip), density 0.4 (4/10, below `>=` 0.5 threshold, skip), density 0.5 EXACTLY (5/10, fires per `>=`), density 0.6 (6/10, fires). Fixtures use 10-line content so 4/10·5/10·6/10 land at the 0.4·0.5·0.6 boundary cleanly — a 5-line denominator can only produce {0, 0.2, 0.4, 0.6, 0.8, 1.0}, which misses 0.5 entirely.
14
+
15
+
### Changed: cache-clear assertions in update-run happy-path test now seeded
16
+
17
+
The existing happy-path test now pre-seeds `last-update-check` and `update-snoozed` in `stateDir` before invoking `update-run`, then asserts both files are removed. Previously the implicit `existsSync(...).toBe(false)` would have passed even if `update-run` did nothing (the files never existed to begin with).
18
+
19
+
### Changed: plantuml fence test pins `mkdir -p` prefix
20
+
21
+
The existing plantuml-fence design-mismatch test now asserts `mkdir -p 'docs/designs' && ` appears in the suggestion. Previously the test only matched the destination filename, so removing the `mkdir -p` branch from `suggestionFor` would have left the test green.
22
+
5
23
## [0.18.17.0] - 2026-05-10
6
24
7
25
### Added: `/roadmap-new` Group/Track ID-renames mapping at apply time
Copy file name to clipboardExpand all lines: docs/PROGRESS.md
+1Lines changed: 1 addition & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -6,6 +6,7 @@ Graft gstack's consistency patterns into extend's three daily-use skills (pair-r
6
6
7
7
| Version | Date | Summary |
8
8
|---------|------|---------|
9
+
| 0.18.18.0 | 2026-05-10 | Track 6B — Track 5A test follow-ups. Test-only ship (~318 LOC across `tests/update.test.ts` + `tests/checks-doc-type.test.ts`); no production code touched. **Added:** opt-in `createFixtureRepoWithRealSetup` helper that copies the real `setup` + `bin/lib/install-safety.sh` + empty placeholder skill `.md` files into a fixture repo so `update-run`'s post-pull `setup` invocation actually rebuilds `~/.claude/skills/{name}/SKILL.md` symlinks. Four post-`update-run` assertions: `UPGRADE_OK` fires, path-1 holds a symlink, the symlink target resolves into the fixture (not ROOT — proves no developer-home leakage), and the CP#3 readlink-chain probe yields `$_EXTEND_ROOT` = fixture root. Probe runs with scoped `env: { HOME, PATH }` only (no `process.env` spread) and `cwd: homeDir`, so the test cannot pass for the wrong reason via inherited env or a stale workspace-local `.claude/`. Probe also asserts exit 0 + non-empty stdout to defend against the failure mode where `set -u` + command substitution silently produces an empty `$_SKILL_SRC`. **Added:** five doc-type math boundary tests in `tests/checks-doc-type.test.ts` — empty file (0 lines, skip), 4 content lines all checkboxes (under `MIN_CONTENT_LINES`, skip), density 0.4 (4/10, below `>=` 0.5 threshold, skip), density 0.5 EXACTLY (5/10, fires per `>=`), density 0.6 (6/10, fires). Fixtures use 10-line content so 4/10·5/10·6/10 land at the 0.4·0.5·0.6 boundary cleanly (a 5-line denominator can only produce {0, 0.2, 0.4, 0.6, 0.8, 1.0}, which misses 0.5 entirely). **Changed:** the existing update-run happy-path test now pre-seeds `last-update-check` and `update-snoozed` in `stateDir` before invoking `update-run`, then asserts both files are removed — previously the implicit `existsSync(...).toBe(false)` would have passed even if `update-run` did nothing. **Changed:** the plantuml-fence design-mismatch test now asserts the full `mkdir -p 'docs/designs' && ` prefix appears in the suggestion (was filename-only, so removing the `mkdir -p` branch would have left the test green). Closes the two test-coverage gaps surfaced during /ship of v0.18.14.0. Group 6 remains in progress (Tracks 6A + 6C unshipped). |
9
10
| 0.18.15.0 | 2026-05-07 | Session state for `/pair-review`, `/full-review`, `/roadmap` moved off workspace-local `.context/<skill>/` (which Conductor archives on merge, taking the state with it) onto `${GSTACK_STATE_ROOT:-$HOME/.gstack}/projects/<slug>/<skill>/` — mirrors gstack core's `/context-save` `checkpoints/` shape. **Added:** `bin/lib/session-paths.sh` (sourced helper; `session_dir <skill>` and `session_archive_dir <skill> <ts>` echoing functions per `effort.sh`'s idiom; slug resolution mirrors gstack-slug's `basename "$PWD"` fallback). `tests/lib-session-paths.test.ts` covers happy path + `GSTACK_STATE_ROOT` override + basename fallback + sanitization + sentinel + empty-arg errors. **Changed:** `skills/pair-review.md`, `skills/full-review.md`, `skills/test-plan.md`, `skills/roadmap.md`, `skills/review-apparatus.md` — every `.context/<skill>/` ref replaced with the helper-resolved `<SESSION_DIR>` placeholder, Active Session Guards use `session_archive_dir`, roadmap proposal artifact moved to `<PROPOSAL_DIR>/proposal-{ts}.md` (flat, sibling of gstack's `checkpoints/`). **Test drift-lock:** `tests/skill-protocols.test.ts` now asserts every affected skill sources `bin/lib/session-paths.sh`, calls `session_dir <name>` with the expected name, and contains zero `.context/<skill>/` literals. **Migration:** none (sole-user repo). **Removed:** `.context/` from `.gitignore`. Full suite: 892 pass, 0 fail. |
10
11
| 0.18.14.0 | 2026-05-06 | Track 5A (Install pipeline polish) — closes the v0.16.0 known-limitation gap where `--skills-dir <custom>` shipped working symlink installs but skill preambles silently no-op'd helper resolution. Resolution mirrors gstack core's behavior instead of extending the env-var/RC-file hack: skill preambles probe `~/.claude/skills/{name}/SKILL.md` then `.claude/skills/{name}/SKILL.md` and stop. **Breaking:** `./setup --skills-dir <path>` (without `--uninstall`) now exits 1 with a migration message; the flag is preserved only when paired with `--uninstall` as a one-way escape hatch for cleaning up v0.16.0-era installs. **Added:** all 5 skill preambles (`pair-review`, `roadmap`, `full-review`, `review-apparatus`, `test-plan`) gain path-2 fallthrough for vendored installs at `<project-root>/.claude/skills/{name}/SKILL.md` (must be absolute symlinks; `setup`'s install loop already creates them via `pwd -P`); `tests/skill-protocols.test.ts` asserts the fallthrough line is present in all 5 preambles to lock against drift; `skills/test-plan.md`'s Phase 8 inline-Read of `pair-review.md` uses the same two-path probe. **Added (defense in depth):** new `bin/lib/install-safety.sh` with `is_safe_install_path` (resolved-path + numeric-uid ownership + world-writable + inside-`$HOME`, ancestor-walk for non-existent install dirs, permits Dropbox/chezmoi/GNU stow setups) and `is_safe_target_path` (refuses install when `$SKILLS_DIR/{name}` is a symlink, regular file, FIFO, or any non-directory entry). Preflight: ALL targets validated before ANY mutation, so a failed safety check on skill 3 cannot leave skills 1 and 2 partially installed. Cross-platform via `stat -f '%u'` (BSD) / `stat -c '%u'` (GNU) and `cd -P && pwd -P`. **Added:** `DOC_TYPE_MISMATCH` audit check (`src/audit/checks/doc-type.ts`) emits warnings when content disagrees with location — design doc outside `docs/designs/` (mermaid/plantuml fence) or inbox doc outside `TODOS.md` (checkbox density ≥ 0.50, files with <5 content lines skipped). Each finding includes a copy-pasteable `git mv -- <quoted-src> <quoted-dst>` suggestion (or `mkdir -p` variant when parent missing, or "review and move" when destination collides). All paths single-quoted via a POSIX `shellQuote` helper using `--` end-of-options sentinel; defends against malicious filenames like `a;curl evil|sh.md` (codex ship review caught this as P0). Inbox-mismatch destination resolution honors whichever `TODOS.md` location actually exists (root vs `docs/`) per the existing `PROJECT_DOC_PAIRS` rule, defaulting to `docs/TODOS.md` when neither exists — avoids the bug where suggestions would create a shadow root-level `TODOS.md` masking `docs/TODOS.md`. Filename allowlist exempts `CONTRIBUTING.md`, `CODE_OF_CONDUCT.md`, `RUNBOOK.md`, `SECURITY.md`, `SUPPORT.md`, `GOVERNANCE.md`, `*checklist*`. Registered as a CANONICAL section adjacent to `DOC_LOCATION` in `src/audit/sections.ts`; 23 existing snapshot fixtures regenerated mechanically (all `pass`); new `tests/roadmap-audit/doc-type-mismatch/` fixture exercises both heuristics end-to-end. New `tests/lib-install-safety.test.ts` (15 unit tests for both helper functions via shell-out); `tests/update.test.ts` drops `--skills-dir` install cluster, adds rejection test, expanded D6 coverage (world-writable, outside-`$HOME`, per-target symlink, regular file at target), CP#3 integration tests (default install + vendored fallthrough + truly-broken silent no-op). README.md drops the v0.16.0 "Per-project installs (`--skills-dir`)" section + the known-limitation note pointing at this Track. 3 of 5 Track 5A tasks shipped; the layout-scaffolding and update-run-dir-propagation tasks were deferred (codex outside-voice flagged scope creep — first reshapes into a separate Project Bootstrapping Group, second into TODOS.md follow-up since `bin/update-run` was unchanged in this Track and post-upgrade resolution goes through path-1 which is exercised). |
11
12
| 0.18.13.0 | 2026-05-05 | Auto-create GitHub Releases on `VERSION` change. The existing `auto-tag.yml` workflow already pushed an annotated tag whenever `VERSION` changed on `main`, but no `gh release create` ever ran — 53 tags accumulated on the repo with zero entries on the Releases page. The workflow now extracts the matching `## [X.Y.Z]` section from `CHANGELOG.md` (via the new `scripts/extract-changelog-section.sh`, reusable from local scripts and CI) and creates a GitHub Release with those notes, falling back to gh's `--generate-notes` plus a `::warning::` if the section is missing. The release step is idempotent (`gh release view "$TAG"` short-circuits on re-runs), composes cleanly with the tag step's existing idempotency, and runs under the workflow's existing `contents: write` permission. Backfill: all 53 historical tags (`v0.1.1` → `v0.18.12.1`) now have releases, with `v0.18.12.1` marked Latest; the two pre-CHANGELOG tags got a placeholder note. The extractor handles the trailing-`.0` mismatch where 4-digit tags like `v0.18.5.0` map to 3-digit CHANGELOG entries like `## [0.18.5]`. |
-**Rename STALENESS → VERSION_TAG_STALENESS + skill prose clarifier** -- mechanical rename in `src/audit/checks/staleness.ts` (+ `expected.txt` fixtures), plus a one-line clarifier in `skills/roadmap.md` Interpreting Audit Findings: "VERSION_TAG_STALENESS only fires on items with explicit (shipped vN.N.N) annotations; broader recency belongs to FRESHNESS." Closes the dogfood-noted misread that `STALENESS: pass` settles the freshness question. _src/audit/checks/, tests/, skills/roadmap.md, ~30 lines._ (S)
27
21
-**Extend FRESHNESS scan to TODOS.md `## Unprocessed`** -- new `_inferred_freshness_for_todo` walks Unprocessed items, extracts referenced file paths from prose, runs the same per-file commit-since-introduction lookup as the ROADMAP scan (incl. Track-ID-or-title-fuzzy-match relaxation). Surfaces shipped-but-unclosed inbox items in the FRESHNESS AskUserQuestion flow. _src/audit/checks/freshness.ts, tests/, ~120 lines._ (M)
-**`bin/update-run` upgrade-flow integration test** -- trigger `bin/update-run` and verify post-upgrade skills still resolve via path-1. Closes a Track 5A test-coverage gap surfaced during /ship of v0.18.14.0; low priority because (a) `bin/update-run` was unchanged in 5A scope, (b) post-upgrade resolution goes through path-1 which IS exercised, (c) update-run has its own non-Track-5A test coverage. _tests/update.test.ts, ~20 lines + git-fetch fixture._ (S)
33
-
-**Doc-type math unit tests** -- boundary cases (empty file, exactly 4 content lines, exactly 5 content lines with 25% density vs 60% density) for the `_inferred_doc_type` math. End-to-end coverage already exists via `tests/roadmap-audit/doc-type-mismatch/`; this Track adds isolated unit tests for the boundary cases. _tests/checks-doc-type.test.ts, ~30 lines._ (S)
23
+
##### Track 6B: Track 5A test follow-ups ✓ Shipped (v0.18.18.0)
-**Rewrite Step 5 PROGRESS.md flow** -- replace direct row-write with detect-staleness → AskUserQuestion → optional scoped general-purpose subagent appends rows from CHANGELOG. Honors the documentation taxonomy (PROGRESS.md content owned by /document-release) without invoking the full skill. _skills/roadmap-new.md, ~+25 lines._ (S)
40
30
-**Add ID-renames helper + apply-summary integration** -- new `src/audit/lib/renames-diff.ts` (parseEntities, computeRenames, formatRenamesTable) with `tests/lib-renames-diff.test.ts` (15 tests). Skill prose at apply-summary time runs the helper against pre/post ROADMAP.md and includes the table in the apply summary + commit message body. _src/audit/lib/renames-diff.ts, tests/lib-renames-diff.test.ts, skills/roadmap-new.md, ~+200 lines._ (S)
41
31
32
+
---
33
+
34
+
## Current Plan
35
+
42
36
### Group 7: Tighten `git commit` Failure Handling
43
37
44
38
All three review skills currently treat any non-zero exit from `git commit`
@@ -184,7 +178,7 @@ Track detail per group:
184
178
```
185
179
Group 6: Audit Polish + Track 5A Test Follow-ups + /roadmap-new refactor
0 commit comments