Batch 17 of 17 — the terminal batch — in the ad hoc timeout literal
migration (epic #4445). Replaces every bare numeric timeout/timeoutMs
object-literal property in tests/cjs-command-router-adapter.test.cjs,
tests/dispatcher.test.cjs, tests/run-tests-temp-root.test.cjs, and
tests/shell-command-projection-dispatch.test.cjs with a named constant,
per eslint-rules/no-adhoc-timeout-literal.cjs. No src/bin file touched,
no numeric value changed anywhere.
Eslint ground truth (9 sites) matches the issue's own stated count
exactly for the first time in this epic — no drift to disclose.
Reuses PROBE_TIMEOUT_MS (1 site) and QUICK_SPAWN_TIMEOUT_MS (1 site).
Adds four file-local constants for shapes with no existing match:
RUN_TESTS_ISOLATED_PROBE_TIMEOUT_MS and RUN_TESTS_HARNESS_SPAWN_TIMEOUT_MS
(run-tests-temp-root.test.cjs, distinguishing a `node -e` isolated
function call from a real end-to-end spawn of the test runner itself,
despite each coinciding numerically with an unrelated existing
constant), and EXEC_TOOL_OPTION_PASSTHROUGH_TIMEOUT_MS and
DISPATCH_FORCED_TIMEOUT_MS (shell-command-projection-dispatch.test.cjs
— a mocked-spawnSync pass-through fixture and a deliberately-forced
real timeout, neither a real subprocess bound in the usual sense).
Terminal-batch cleanup: deletes
eslint-rules/no-adhoc-timeout-literal.allowlist.json entirely, drops
its require and the allowlist option from eslint.config.mjs's
local/no-adhoc-timeout-literal registration (now a bare 'error',
mirroring local/no-unbounded-spawn's own already-terminal
configuration in the same file), and updates TESTING-STANDARDS.md's
enforcement note to match — a stale pointer to the deleted file caught
by review, fixed inline. A full-repo eslint run with no cache confirms
zero violations anywhere in the tree under the now allowlist-free rule.
Co-authored-by: sim <sim@local>
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
Nothing enforced CONTRIBUTING.md's own stated preference ("A non-literal value
is trusted — that is the shape you should be writing") for timeout values in
tests. local/no-unbounded-spawn requires SOME bound but allows a bare literal;
no-magic-sleep-in-tests and no-elapsed-assertion cover different anti-patterns
entirely. This is exactly how PR #4428's Windows CI incident happened: two
independently-guessed 15000ms literals (one in production's check-latest-
version.cjs, one in this suite's own worker test) collided exactly and raced
two SIGKILLs against each other.
New rule local/no-adhoc-timeout-literal (eslint-rules/no-adhoc-timeout-
literal.cjs) flags a resolvable numeric timeout/timeoutMs literal; an
Identifier or MemberExpression value is trusted. No marker-comment escape —
the fix is always to extract a named constant, which is trivial.
Ships with a full legacy allowlist (126 files, 352 violations, generated
by running the rule with an empty allowlist against tests/) so it can go
live at error severity without breaking CI, mirroring how no-unbounded-spawn
itself was rolled out. Migration is tracked separately in #4445 (this PR
does not close it — only #4446, introducing the gate itself).
Documents the policy and the compliant shapes in TESTING-STANDARDS.md and
TEST-EXAMPLES.md.
Co-authored-by: sim <sim@local>
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
#3314 delivered the precondition (ADR-456 §(a) reachability-based
clock-control rule + deterministic backfill for commands.cts/init.cts/
io.cts). Current tests/**/*.cjs corpus has zero violations, verified
via `npx eslint 'tests/**/*.cjs' --rule '{"local/no-elapsed-assertion":"error"}'`
before flipping the config, so no fix/delete-and-replace work was needed.
* test(#3314): backfill deterministic clock-seam coverage (failing-first)
Replaces loose regex/range assertions with exact-value and boundary
tests for the CLI-subprocess and in-process clock-touching call sites
identified by H2's audit (epic #3053): cmdCurrentTimestamp,
_wsParseRetryAfter (commands.cts), cmdInitManager's is_active gate and
cmdInitQuick's quick_id generation (init.cts), and reapStaleTempFiles
(io.cts). The CLI-subprocess-pinned tests are expected RED until a
follow-up commit routes those call sites through realClock so
GSD_TEST_MODE+GSD_NOW_MS can reach them.
* refactor(#3314): route CLI-subprocess clock reads through realClock
cmdCurrentTimestamp, cmdInitManager's is_active gate, and cmdInitQuick's
quick_id generation read Date directly, which the GSD_TEST_MODE+GSD_NOW_MS
subprocess pin cannot reach (it only fires inside realClock.now()).
Behavior-preserving: realClock.now() falls through to Date.now() whenever
GSD_TEST_MODE is unset, which is every real invocation.
* docs(#3314): amend ADR-456 with reachability-based clock-control rule
ADR-456 §(a) documented one mechanism (injected {clock=Date} +
t.mock.timers). Adds the two this repo already relies on: t.mock.timers
for in-process direct-Date reads, and the GSD_TEST_MODE+GSD_NOW_MS
subprocess pin (routed through realClock) for CLI-spawned code. Updates
TESTING-STANDARDS.md's matching passages, which already referenced this
issue by number as the no-elapsed-assertion promotion precondition.
* fix(#3314): address orthogonal review findings
Spec-axis findings: file and link the no-elapsed-assertion promotion
follow-up (#3331) instead of leaving TESTING-STANDARDS.md pointing at
a dead #1885, and ship the module-by-module audit table in the ADR
itself rather than only in a gitignored phase artifact.
Standards-axis finding: pin the "hour-old file = not active" test via
GSD_TEST_MODE+GSD_NOW_MS for consistency with the reachability rule
this PR's own ADR amendment now documents.
---------
Co-authored-by: sim <sim@local>
Extends lint-allow-test-rule-refs.cjs with a second, independent check
alongside the existing uncited-citation identity ratchet: the total
number of distinct test files carrying any allow-test-rule marker
(cited or not) is now checked against a tight ceiling via the
previously-unwired assertTightCeiling primitive (allowlist-ratchet.cjs,
0 prior callers). A cited exemption is legitimate under ADR-456 but
nothing stopped the raw total from growing forever - this closes that
gap without duplicating the file walk (both checks consume one shared
walkTestFiles pass).
Ceiling introduced at the exact measured high-water mark (314 files,
grace 3) rather than a padded estimate, per "budgets may only
decrease."
Also lands the two F17 pieces (absorbed from the now-closed #1885)
that had no precondition:
- --max-warnings 0 added to lint/lint:ci
- local/no-source-grep promoted warn->error in the scripts/bin/
eslint-rules glob block (already error in the tests/ glob)
Both promotions were pre-verified against a zero-warning tree (fresh
non-cached eslint run) before flipping, per the maintainer's clean-
tree-first decision.
Not included: local/no-elapsed-assertion promotion, which stays warn
pending #3314 (H2) - 10 of 19 clock-touching src modules have no
sanctioned time-control mechanism until ADR-456 is amended there.
H1 of epic #3053, absorbing #1885 F17.
Co-authored-by: sim <sim@local>
Strengthens TESTING-STANDARDS.md contract 6 (counter-tests for negative
space): a test on an error/fallback branch must assert the specific
degraded verdict the branch produces, not merely that the call did not
throw. Generalizes the liveness-vs-correctness finding from #3050 and
epic #3051 (closed, all 14 enumerated modules drained) into a standing
review expectation, now that the one-time enumeration is done.
Worked examples are the real pre-fix and post-fix shapes of
tests/worktree-safety.test.cjs's resolveWorktreeContext timeout
counter-test, verified directly against source.
Deliberately not lint-enforced: a pattern scan for fail-open shapes
scored 1 true positive against 3 false positives during #3051's own
measurement (source: epic #3051 body, Phase 3). Cross-linked from
CONTRIBUTING.md's QA Matrix Requirements so reviewers see it where
they already apply the matrix.
H4 of epic #3053.
Co-authored-by: sim <sim@local>
* chore: rename npm package + bin to @opengsd/gsd-core (functional)
- package.json: name @opengsd/get-shit-done-redux → @opengsd/gsd-core,
bin key get-shit-done-redux → gsd-core, repository/homepage/bugs URLs
- package-lock.json: regenerated (npm install --package-lock-only)
- tests/**, scripts/**, bin/**, .github/**, agents/**, commands/**,
get-shit-done/bin/**, get-shit-done/workflows/**:
applied the 4-rule replacement (scoped npm ref, GitHub repo path,
bin/clone invocations) per #505 single-source refactor
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* docs: sweep live references to @opengsd/gsd-core
Update all live documentation (README.md + translations, docs/**,
CONTRIBUTING.md, VERSIONING.md, SECURITY.md, CONTEXT.md,
docs/CANARY.md) to reflect the renamed package and repository.
Rules applied:
- @opengsd/get-shit-done-redux → @opengsd/gsd-core (scoped npm name)
- open-gsd/get-shit-done-redux → open-gsd/gsd-core (GitHub repo)
- GSD-redux/get-shit-done-redux → open-gsd/gsd-core (stale badge org)
- bare bin/clone refs → gsd-core
CHANGELOG.md, docs/adr/**, docs/RELEASE-*.md, docs/research/**,
and .changeset/** are preserved byte-identical.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* fix: add negative lookbehind to slash-command regex in bug-2954 test
The extractSlashReferences regex matched /gsd-core inside npm package
URLs (@opengsd/gsd-core), producing a false /gsd:core command reference.
Adding a negative lookbehind (?<![a-z]) excludes matches preceded by a
letter, so only standalone /gsd-<cmd> and /gsd:<cmd> tokens are found.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* chore(#518): add changeset for package rename
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* test(#518): update package-identity expectations to the renamed coordinates
The rebase regenerated the seam to @opengsd/gsd-core (bin gsd-core, repo
open-gsd/gsd-core). The #498 seam tests assert deriveIdentity against the REAL
package.json, so their expected literals must follow the rename. The drift-lint
unit test is left as-is — its SEAM is a self-consistent fixture and its
stale-literal detection cases would shift if altered; the live-repo scan in it
already passes.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>