* test(6): reproduce W007 + phaseVariants + W006 drift between CJS verify and SDK validate
Adds tests/6-validate-cjs-drift-regression.test.cjs with 5 RED tests covering the
three drift items from issue #6 between verify.cjs (Check 8) and validate.ts (Check 8):
1. W007 activeDiskPhases — verify.cjs uses diskPhases (includes archived) for W007;
archived phase "1" absent from current ROADMAP fires false W007.
validate.ts: activeDiskPhases (active phasesDir only) correctly excludes archives.
2. phaseVariants() normalization — ROADMAP says "01A", disk has "1A-foo".
verify.cjs parseInt("01A")=1 → padded "01" (drops letter suffix) → miss.
validate.ts phaseVariants("01A") = {"01A","1A","01A"} → "1A" matched.
Both W006 and W007 fire as false positives in verify.cjs.
3. W006 letter-suffix padding mismatch — ROADMAP says "3B", disk has "03B-foo".
verify.cjs parseInt("3B")=3 → padded "03" (drops "B") → diskPhases.has("03B") missed.
W006 and W007 fire as false positives.
All 5 tests RED on origin/main. Will turn GREEN after generator + verify.cjs migration.
References:
- Issue #6 (open-gsd/get-shit-done-redux) — maintainer acceptance criteria:
"Port all three items to verify.cjs; add parity tests confirming identical output
for all three cases on both paths"
- ADR-3524 (docs/adr/3524-cjs-sdk-hard-seam.md)
- PR #154 (issue #4) — precedent for the generator pattern
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* chore(6): add sdk/scripts/gen-validate.mjs generator
Extracts phaseVariants() from sdk/dist/query/validate.js via brace-balanced
source-text parsing (phaseVariants is a closure inside validateHealth, not a
module export, so Function.prototype.toString() is unavailable).
Emits get-shit-done/bin/lib/validate.generated.cjs with three pure helpers:
- phaseVariants(phase): normalized Set of padded/unpadded/letter-suffix variants
- buildRoadmapPhaseVariants(content): {roadmapPhases, roadmapPhaseVariants}
- buildNotStartedPhaseVariants(content): Set of unchecked-phase variants
These three helpers directly address the three drift items in issue #6.
Follows the gen-phase-lifecycle-policy.mjs extraction pattern from PR #154.
References:
- Issue #6 (open-gsd/get-shit-done-redux)
- ADR-3524 (docs/adr/3524-cjs-sdk-hard-seam.md)
- PR #154 (issue #4) — generator pattern precedent
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* chore(6): add sdk/scripts/check-validate-fresh.mjs freshness check
Mirrors check-phase-lifecycle-policy-fresh.mjs from PR #154: imports
buildValidateCjs() directly, regenerates in-memory, and diffs against the
committed validate.generated.cjs. Exits 1 if stale (CI gate).
References:
- Issue #6 (open-gsd/get-shit-done-redux)
- ADR-3524 (docs/adr/3524-cjs-sdk-hard-seam.md)
- PR #154 (issue #4) — precedent
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* chore(6): emit validate.generated.cjs from validate.ts
Generated by: node sdk/scripts/gen-validate.mjs
Exports three pure helpers extracted from sdk/src/query/validate.ts Check 8:
- phaseVariants(phase): Set of normalized variants {"01A","1A"} etc.
- buildRoadmapPhaseVariants(content): {roadmapPhases, roadmapPhaseVariants}
- buildNotStartedPhaseVariants(content): Set of unchecked-phase variants
Freshness check: node sdk/scripts/check-validate-fresh.mjs → FRESH
References:
- Issue #6 (open-gsd/get-shit-done-redux)
- ADR-3524 (docs/adr/3524-cjs-sdk-hard-seam.md)
- PR #154 (issue #4)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(6): migrate verify.cjs to consume validate.generated.cjs helpers (GREEN)
Check 8 in verify.cjs now uses three generated helpers from validate.generated.cjs:
1. buildRoadmapPhaseVariants(roadmapContent) — replaces hand-rolled roadmapPhases
Set. Produces both roadmapPhases (raw, for W006 message) and roadmapPhaseVariants
(all variants, for W007 membership check). Fixes false W007 for letter-suffix
phases with padding mismatch.
2. activeDiskPhases — now uses collectDiskPhases() WITHOUT forEachArchivedPhaseToken.
W007 iterates activeDiskPhases, not diskPhases, so archived phases absent from
current ROADMAP no longer trigger false W007.
3. buildNotStartedPhaseVariants(roadmapContent) — replaces raw+parseInt-padded
notStartedPhases population. Uses phaseVariants() expansion so zero-padded
letter-suffix unchecked entries (e.g. "03B") correctly suppress W006 for
their un-padded counterpart ("3B") and vice versa.
4. phaseVariants() in W006 loop — replaces parseInt-padded disk-existence check.
"3B" now matches disk dir "03B-foo" via variant expansion.
Also updates test fixture for drift item 1 to use two milestone archives (v1.0 + v1.1),
accurately reproducing the scenario where forEachArchivedPhaseToken walks ALL archives
while getActiveMilestoneArchiveDir returns only the most recent one.
All 5 tests GREEN. Confirmed RED on pre-fix code (git stash test).
References:
- Issue #6 (open-gsd/get-shit-done-redux) — maintainer acceptance criteria:
"Port all three items to verify.cjs; add parity tests confirming identical output"
- ADR-3524 (docs/adr/3524-cjs-sdk-hard-seam.md)
- PR #154 (issue #4) — generator pattern precedent
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* ci(6): wire validate freshness check into test workflow
Adds 'SDK generated validate artifact drift check' step to .github/workflows/test.yml,
mirroring the pattern used by all PR #154 generator freshness checks.
Runs on ubuntu-latest/node-24 only (same as other artifact drift checks).
Placement: after workstream-name-policy check, before Shared Module hand-sync drift check.
References:
- Issue #6 (open-gsd/get-shit-done-redux)
- ADR-3524 (docs/adr/3524-cjs-sdk-hard-seam.md)
- PR #154 (issue #4) — precedent
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* chore(6): wire gen:validate into sdk/package.json, root package.json, and allowlist
sdk/package.json: adds gen:validate and check:validate-fresh npm scripts.
package.json: adds check:validate-fresh script (mirrors other check:*-fresh entries).
scripts/shared-module-handsync-allowlist.json: updates verify.cjs justification to
note that Check 8 W006/W007 helpers are now generated from validate.ts via
gen-validate.mjs (issue #6), with freshness check at check-validate-fresh.mjs.
References:
- Issue #6 (open-gsd/get-shit-done-redux)
- ADR-3524 (docs/adr/3524-cjs-sdk-hard-seam.md)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* docs(6): amend ADR-3524 — validate.ts now uses generator pattern
Adds 2026-05-23 amendment section to docs/adr/3524-cjs-sdk-hard-seam.md documenting:
- Generator/artifact/freshness-check/CI paths
- Three drift items resolved (W007 activeDiskPhases, phaseVariants normalization,
W006 unchecked-phase variant skip)
- phaseVariants extraction technique (brace-balanced source-text parsing)
- Parity test coverage (5 tests, RED→GREEN)
- Allowlist classification preserved (cooperating-sibling)
References:
- Issue #6 (open-gsd/get-shit-done-redux)
- ADR-3524 (docs/adr/3524-cjs-sdk-hard-seam.md)
- PR #154 (issue #4)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* chore(6): add changeset fragment for validate.ts/verify.cjs generator migration
Touches get-shit-done/bin/lib/validate.generated.cjs and verify.cjs which
match USER_FACING_PREFIXES. Required by the fix-template checklist + the
changeset-lint CI workflow.
Refs #6#156
* docs(6): register validate.generated.cjs in INVENTORY + manifest
INVENTORY parity test demanded a row for the new generated CJS surface
and a matching entry in INVENTORY-MANIFEST.json. Headline count bumped
from 74 → 75.
Refs #6
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>