42f8c192a8eafd96a00216e263bed83dc034f708
9 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
a8ff46484b |
fix(#474): deterministic STATE dates via deepened clock seam (nowIso/today + GSD_NOW_MS adapter) (#477)
* fix(#474): route state date-stamping + installer lock loop through clock seam (nowIso/today + GSD_NOW_MS adapter) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(#474): use process.ppid (not pid 1) as held-lock owner in install-lock timeout test pid 1 is POSIX init/launchd (always alive) but does not exist on Windows, so isPidAlive(1) returns false, the lock is reclaimed as stale, and acquireInstallMigrationLock no longer throws -- failing the timeout assertion on windows-latest,22. process.ppid is a live, non-self process on every platform, so the lock is seen as held and the timeout path throws deterministically cross-platform. Refs #474 --------- Co-authored-by: CI Rebase Check <ci@gsd-redux> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> |
||
|
|
bf68ad4d93 |
fix(tests): deterministic concurrency via injectable clock seam; delete flaky racing tests (#459)
* feat(#453): add deterministic clock seam to lock modules Introduces get-shit-done/bin/lib/clock.cjs exporting realClock with now() (Date.now) and sleep() (Atomics.wait). acquireStateLock, writeStateMd, and readModifyWriteStateMd in state.cjs each accept an optional trailing clock param (default: realClock). withPlanningLock in planning-workspace.cjs gains the same seam. No production behavior change — all callers that omit the param continue to use realClock. Adds tests/helpers/clock.cjs (makeFakeClock) and tests/clock-seam.test.cjs with 20 deterministic in-process tests covering: lock serialization, timeout throw at maxWaitMs boundary, stale-lock takeover, lock released on error path, withPlanningLock timeout recovery, exit-cleanup integration, readModifyWriteStateMd call-site coverage (7 cmd*), and roadmap analyze behavioral assertion (50 phases, no elapsed-time gate). Deletes/converts per research verdicts: removes 11 source-grep/elapsed-time/ non-deterministic-concurrent tests across concurrency-safety.test.cjs, locking-bugs-1909-1916-1925-1927.test.cjs, and bug-1974-context-exhaustion- record.test.cjs. All deleted tests have deterministic replacements in clock-seam.test.cjs or surviving barrier-based tests. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(#453): update module inventory for clock.cjs; make EEXIST-retry assertion behavioral Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(#453): satisfy lint-tests — allow-test-rule annotation on readFileSync/includes runtime output check Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: CI Rebase Check <ci@gsd-redux> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
4b908e6bcd |
test(tests): antagonistic tier — fast-check property tests + Stryker mutation testing (PR-gated) (#461)
* feat(#454): add antagonistic tier — fast-check property tests + Stryker mutation config Adds property-based testing (fast-check v4) and mutation testing scaffolding (Stryker v8) as the antagonistic validation tier for lib/*.cjs pure logic. ## Files added ### Shared setup - tests/helpers/fast-check-setup.cjs — configureGlobal({ numRuns:200, seed:42 }) for deterministic CI; override locally with GSD_FC_SEED ### Property test suites (node:test + fast-check) - tests/context-utilization.property.test.cjs — boundary at 60%/70% thresholds (exact Math.ceil boundary, not Math.floor), TypeError on all invalid inputs, overflow clamping to 100%/critical, shape invariants (7 tests, all pass) - tests/prompt-budget.property.test.cjs — estimateTokens monotonicity + ceil(len/4) exactness; applyBudget shape invariant, instructions/roadmap verbatim, budget envelope, omit tracking (11 tests, all pass) - tests/frontmatter.property.test.cjs — extractFrontmatter/reconstructFrontmatter/ spliceFrontmatter never-throw + type shape + splice→extract round-trip (9 tests) - tests/adr-parser.property.test.cjs — shouldRejectAdrStatus boundary (3 statuses only), parseAdrMarkdown shape + title trim invariant (discovered: parser trims trailing whitespace) (9 tests, all pass) - tests/config-schema.property.test.cjs — isValidConfigKey never throws, returns boolean, accepts all VALID/RUNTIME_STATE_KEYS, rejects empty/null/unknown (8 tests) ### Stryker mutation config - stryker.config.mjs — testRunner:'command', mutate bin/lib/**/*.cjs minus 13 generated files, coverageAnalysis:'off', thresholds {high:80,low:60,break:50}, incremental:true, reporters html+clear-text+progress ### CI workflow - .github/workflows/mutation.yml — PR-gating job (pull_request + workflow_dispatch), runs stryker --incremental --since origin/next (changed files only), uploads HTML artifact; SINCE_REF via env not interpolation (injection-safe) ### Package config - package.json: +test:mutation, +test:mutation:since scripts - .gitignore: +.stryker-tmp/, +.stryker-incremental.json, +reports/mutation/ - package-lock.json: fast-check@4.8.0, @stryker-mutator/core@9.6.1 ## Verified node --test on all 5 property test files: 44 tests, 0 failures. Stryker NOT run (slow; reserved for CI). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(#454): pin upload-artifact to v7.0.1 SHA used across repo (bad SHA ea165f8d) The SHA ea165f8d65b6e75b540449d3ec4f5dde0c5a4e1 (labeled v4.6.2) does not resolve on GitHub Actions. All other workflows in this repo pin 043fb46d1a93c77aae656e7c1c64a875d1fc6a0a (v7.0.1) — align mutation.yml. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(#454): mutation workflow — replace invalid --since flag with changed-core-files --mutate scoping Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: CI Rebase Check <ci@gsd-redux> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
33afb4f6eb |
chore(#452): add ESLint 9 flat-config harness with three custom AST rules (#460)
Install eslint@9 + typescript-eslint@8 + globals@16 + eslint-plugin-n@17 + eslint-plugin-no-only-tests@3 + typescript as devDependencies. eslint.config.mjs (flat config): - Global ignores: node_modules, dist, .worktrees, .claude, coverage, the 12 generated get-shit-done/bin/lib/*.cjs files - Block for get-shit-done/bin/**/*.cjs + scripts/**/*.cjs: js.recommended + eslint-plugin-n + local plugin; generic quality rules (no-var, prefer-const, no-unused-vars, no-empty, n/no-process-exit) - Block for tests/**/*.test.cjs: no-only-tests (error), local timing rules, no-restricted-syntax timing bans eslint-rules/ local plugin (three AST rules, all at warn pending cleanup): - no-source-grep: flag readFileSync on source .cjs/.js/.ts + text methods - no-magic-sleep-in-tests: flag Atomics.wait and await-new-Promise(setTimeout) - no-elapsed-assertion: flag assert*() on timing props (elapsed/duration/took/ms) tsconfig.lint.json: allowJs + checkJs + noEmit for future type-aware passes. tests/eslint-rules.test.cjs: 15 RuleTester unit tests (all pass, 0 fail). package.json: add lint/lint:fix scripts; remove lint:tests (subsumed by ESLint local/no-source-grep). Rules that produced pre-existing errors downgraded to warn: no-useless-escape, no-unsafe-finally, no-regex-spaces, no-control-regex, no-irregular-whitespace. ESLint exits 0 (warnings ok). .github/workflows/test.yml lint-tests job: add npm ci + ESLint step; remove "Lint — no source-grep tests" step (now covered by ESLint); bump timeout 3→5 min. .gitignore: add node_modules/.cache/eslint/ entry. eslint --fix auto-cleaned: no-regex-spaces in tests, prefer-const in state.cjs, redundant eslint-disable-next-line comments. Co-authored-by: CI Rebase Check <ci@gsd-redux> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
c4e39bc23a |
refactor(tests): consolidate graphify Module — 7 files → 1 (#3769)
* refactor(tests): consolidate graphify Module — 7 files → 1 Closes #3761 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * refactor(tests): split graphify.test.cjs along describe-block seams — keep files ≤ 800 LOC - tests/graphify.test.cjs (653 LOC): status + build - tests/graphify-query.test.cjs (447 LOC): query - tests/graphify-visualization.test.cjs (577 LOC): staleness + mvp-viz + regressions - tests/graphify-auto-update.test.cjs (625 LOC): auto-update hook - tests/helpers/graphify.cjs (112 LOC): shared helpers extracted Total: 132 tests, 0 failures. Refs #3761. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> |
||
|
|
f955bf872c |
refactor(tests): consolidate Installer Module — 11 files → 2 (#3760)
* chore(tests): lint rule — cap test files per production module at 2 Adds scripts/lint-test-file-count.cjs with a ratcheted allowlist (scripts/lint-test-file-count.allowlist.json) capturing today's 30 violating clusters as a ceiling. New entries blocked at PR time; reductions ratchet automatically. Wires into .github/workflows/test.yml as a new step in lint-tests. Refs #3737 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * chore(tests): add docs-exempt to changeset fragment Internal CI lint rule — no user-facing docs impact. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * refactor(tests): consolidate Installer Module — 11 files → 2 Closes #3758 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(changeset): replace invalid type 'Chore' with 'Changed' — ALLOWED_TYPES only accepts Added|Changed|Deprecated|Removed|Fixed|Security Fragment already had a docs-exempt marker; only the type value was wrong. Refs #3758 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * refactor(tests): split install.test.cjs along section seams — keep files ≤ 800 LOC 1828-LOC monolith split into 3 files by semantic boundary: install.test.cjs (602 LOC) — S1-5: dir resolution, install/uninstall spot-checks, Kilo install-runtime-artifacts.test.cjs (347 LOC) — S6-8+12: layout loop, Contract 6, legacy migrations install-minimal-hooks.test.cjs (782 LOC) — S9-11+13: profiles, minimal E2E, hooks copy Shared constants and helpers extracted to tests/helpers/install-shared.cjs (216 LOC). Total test count unchanged: 210 tests (68+37+105). Refs #3758 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(tests): ratchet state test-file ceiling to 9 — actual count at baseline The allowlist was initialised with state=8 but the repo already had 9 files matching the 'state' prefix at the time the lint rule was created, causing lint-test-file-count.test.cjs to fail on the real repo immediately. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> |
||
|
|
037a49c9c2 |
test(3593): CLI negative-matrix harness + config family + universal sweep (#3627)
Adds the shared adversarial-input harness described in TEST-EXAMPLES.md
§"CLI Negative Matrix" and applies it across two layers:
1. tests/helpers/cli-negative.cjs — runCli() wraps spawnSync of
get-shit-done/bin/gsd-tools.cjs, prepends --json-errors by default,
and returns a typed IR { status, ok, reason, message,
hasStackTrace, ... } so adversarial-case tests assert on
reason codes — never on stderr prose.
2. tests/feat-3593-cli-negative-config.test.cjs — full 12-category
matrix for the config command family (the highest-risk read/write
surface): missing/empty/whitespace args, duplicate --cwd,
unknown subcommand, value-looks-like-a-flag, corrupt config.json,
50KB key, Unicode/emoji keys and values, and 9 distinct shell-
metacharacter payloads asserted as NOT-executed via per-test
sentinel-file probes.
3. tests/feat-3593-cli-negative-universal.test.cjs — narrower
cross-family sweep (phase, roadmap, state, config, workstream,
init, validate). Pins the three universal invariants every
family must satisfy: bare invocation does not crash with a V8
stack trace, unknown subcommand emits a typed reason, and shell
payloads as argv values are not executed.
4. tests/feat-3593-cli-negative-harness.test.cjs — meta-test that
pins the harness IR contract so a future regression in the
parser (stack-trace detection, JSON shape extraction, hostile
stderr handling) surfaces before it cascades through every
matrix file.
Bug fix surfaced by the new tests:
get-shit-done/bin/lib/config.cjs cmdConfigSet — invoking
`config-set <key>` with no value silently returned exit 0 and
emitted { updated: true } even though the value parameter was
undefined. JSON.stringify dropped the key during the write or
persisted a corrupt entry. Now rejected with typed ERROR_REASON.USAGE
before any write. Matching guard added to SDK configSet for parity.
Harness coverage delivered: 58 new tests (9 meta + 26 config + 23
universal sweep). Pre-existing config suites (101 tests) all pass.
lint-no-source-grep clean.
Refs #3593
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
370033e907 |
fix(phase-dir): apply project_code prefix in plan-milestone-gaps, import, and add-backlog workflows (PRED.k015) (#3306)
* test(phase-dir): add red test for k015 prefix-drift in plan-milestone-gaps and import workflows (#3298) Asserts that: - plan-milestone-gaps.md step 8 does not use bare {NN}-{name} mkdir pattern - plan-milestone-gaps.md step 8 uses phase.add or expected_phase_dir - import.md plan_convert does not use bare {NN}-{slug} mkdir pattern - import.md plan_convert uses expected_phase_dir from init.phase-op These 5 tests are RED until the fix lands. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(phase-dir): add projectCode prefix to phase-dir construction in plan-milestone-gaps and import workflows (#3298) Both plan-milestone-gaps.md step 8 and import.md plan_convert step were constructing phase directories using raw {NN}-{name}/{NN}-{slug} template patterns, bypassing the project_code prefix from .planning/config.json. Fix: both steps now call `gsd-sdk query init.phase-op <N>` and consume the `expected_phase_dir` field (which includes the `<CODE>-<NN>-<slug>` prefix when project_code is set), matching the pattern already established by PR #3292 for /gsd-discuss-phase and /gsd-plan-phase. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(phase-dir): apply project_code prefix to backlog phase dir in add-backlog workflow (k015 sibling, #3298) Sibling k015 audit found a third drift site: add-backlog.md step 4 was constructing the 999.x backlog phase directory using raw ${NEXT}-${SLUG} without applying the project_code prefix from .planning/config.json. Fix: read project_code via `gsd-sdk query config-get project_code --raw` and prepend `${CODE}-` when set, matching the pattern used by phase.insert (which already applies project_code to decimal phases in phase.cjs line 736). Also extends bug-3298 regression test to cover this third site. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * chore(changeset): add changeset for #3298 phase-dir prefix drift fix Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * chore(changeset): set pr: 3306 in changeset for #3298; resolve stash conflict in live-command-registry.cjs The conflict was cosmetic (string concat → template literals) introduced by accidental git stash during test verification. Taking the newer template-literal form throughout. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> |
||
|
|
3aaed8f5d7 |
test: replace deny-list parity tests with polarity-inverted live-registry (#3049) (#3284)
* test: reproduce Windows SDK not found after fresh npx install (#3211) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * test: red — docs-parity live-registry tests fail against stub helper (#3049) Adds: - tests/helpers/live-command-registry.cjs (stub: returns empty Set) - tests/docs-parity-live-registry.test.cjs (new polarity-inverted test) - tests/fixtures/live-command-registry/ (fixture .md files) All parity and helper-contract tests fail because the stub returns an empty registry. This is the intentional RED state before GREEN implementation. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * feat(test-helpers): live-command-registry derives canonical tokens from commands/gsd/*.md (#3049) Implements GREEN phase: - tests/helpers/live-command-registry.cjs: walks commands/gsd/*.md, parses YAML frontmatter name: field, emits /gsd-slug, /gsd:slug, $gsd-slug per command. Memoized per process. Fails loud on malformed frontmatter (k302). - tests/docs-parity-live-registry.test.cjs: updated with INTERNAL_COMPONENT_SLUGS exemption for path-component and placeholder tokens (gsd-build from GitHub org URLs, gsd-workspaces from ~/gsd-workspaces/ paths, gsd-tools from bin/gsd-tools.cjs paths, etc.) Docs drift caught and fixed: - ns-* rename: /gsd-ns-workflow→/gsd-workflow etc. in COMMANDS, FEATURES, INVENTORY, USER-GUIDE (6 commands across 4 English files) - /gsd-scan → /gsd-map-codebase --fast (FEATURES, INVENTORY, USER-GUIDE) - /gsd-note → /gsd-capture (FEATURES, issue-driven-orchestration, ja-JP, ko-KR) - /gsd-do → /gsd-fast (FEATURES, ja-JP, ko-KR) - /gsd-from-gsd2 → /gsd-import --from-gsd2 (CLI-TOOLS, FEATURES, INVENTORY) - /gsd-verify-phase → /gsd-validate-phase (STATE-MD-LIFECYCLE) - /gsd-settings-integrations → /gsd-settings or /gsd-config --integrations (CLI-TOOLS) - /gsd-dev-preferences removed from profile-user artifact lists (AGENTS, COMMANDS, FEATURES in English, ja-JP, ko-KR) - /gsd-select-framework removed from gsd-framework-selector spawner list (AGENTS, INVENTORY) All 28 new tests pass. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * refactor(test): replace deny-list parity tests with polarity-inverted live-registry approach (#3049) - Delete bug-3010-reapply-patches-references.test.cjs (hardcoded deny-list) - Delete bug-3029-3034-stale-command-routes.test.cjs (hardcoded deny-list) - Delete bug-3042-3044-research-flag-and-stale-refs.test.cjs (deny-list + frontmatter checks) - Add tests/skill-frontmatter-contract.test.cjs (frontmatter structural checks extracted from deleted file) - Update tests/commands-doc-parity.test.cjs to derive slug from name: frontmatter field instead of filename, so ns-* commands resolve to their actual deployed tokens Closes #3049 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * test: annotate commands-doc-parity with source-text-is-the-product exemption (#3049 lint fix) The readFileSync on commands/gsd/*.md reads product markdown whose deployed text IS what the user sees — content.startsWith('---') detects YAML frontmatter in those files, not source-code structure. Add the allow-test-rule exemption matching the same rationale used in docs-parity-live-registry.test.cjs. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * test: walk docs/** recursively to cover nested locale trees (CR finding 7) Replaced the non-recursive listMdFiles() with a hand-rolled DFS walker compatible with Node 20+. Surfaces unreadable-directory errors as stderr warnings (PRED.k302) rather than silently skipping. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * test: annotate live-command-registry helper and commands-doc-parity with source-text exemptions (CR findings 6, 8) Adds allow-test-rule comments to suppress lint-no-source-grep false positives on YAML frontmatter structure checks in both files. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * test: anchor --research-phase assertions to arg-parsing section and verify combined refresh (CR findings 9, 10) Finding 9: scopes --research-phase check to within 1200 chars of the flag description section header, preventing false positives from prose mentions. Finding 10: tightens the force-refresh assertion to require BOTH --research and force/refresh semantics within the --research-phase description section, verifying the combined-mode contract rather than standalone --research presence. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * test: fix execSync mock to accept opts parameter, forward to saved implementation (CR finding 5) The mock at line 212 dropped the options parameter when delegating to savedExecSync. Updated to (cmd, opts) signature and pass opts through. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * docs: correct routing entrypoint, --fast default, /gsd-review collision, verifying-stage mapping (CR findings 1-4) Finding 1: Change Freeform Routing command from /gsd-fast to /gsd-progress --do. /gsd-fast is the inline trivial-task executor, not the routing entrypoint. Finding 2: Clarify that /gsd-map-codebase --fast REQ-SCAN-02 default (tech+arch) runs as a single combined-focus agent, resolving the contradiction with REQ-SCAN-01. Finding 3: Rename the namespace router /gsd-review to /gsd-quality across all docs, command file, and help.md to eliminate the naming collision with the concrete cross-AI peer-review command (review.md, name: gsd:review). Finding 4: Replace /gsd-validate-phase with /gsd-verify-work in the STATE-MD-LIFECYCLE.md verifying-stage table. /gsd-validate-phase is the retroactive Nyquist-validation flow, not the normal phase-verification step. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * docs+test: fix locale doc drift surfaced by recursive walker (CR finding 7 follow-up) The recursive listMdFiles() walker newly covered docs/**/*.md subdirs. Stale command references in locale docs are now caught and fixed: - docs/zh-CN/references/model-profiles.md: remove /gsd-set-profile (deleted command); config.json is the current mechanism - docs/zh-CN/references/ui-brand.md: remove /gsd-alternative-1/2 template placeholders - docs/{ja-JP,ko-KR,pt-BR}/superpowers/specs/2026-03-20-*: replace /gsd-new-workspace, /gsd-list-workspaces, /gsd-remove-workspace with /gsd-workspace --new / --list / --remove (consolidated in #2790) Also adds smoke- and alternative-{1,2} to INTERNAL_COMPONENT_SLUGS (filesystem path and template placeholder patterns, not slash commands) and introduces listEnglishMdFiles() to scope the English parity check to docs/ excluding locale subdirectories (which have their own per-locale describe blocks). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * docs: add bash language tag to fenced code blocks in ja-JP and ko-KR workspace specs (CR round 2) Satisfies MD040 fenced-code-language requirement. These blocks contain shell commands and were missing the language specifier. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> |