Mechanical rename produced by scripts/msd-rename.cjs: gsd/Gsd/GSD -> msd/Msd/MSD
across contents and paths, upstream package/repo coordinates -> @golem15/msd-core
and golem15com/msd-core. Deep links into upstream history, sibling upstream
packages, the GSD-2 import feature, CHANGELOG.md and .changeset/ are kept as-is.
Hand edits on top: MSD block-letter banner and logos, LICENSE copyright line,
package/plugin identity, regenerated lockfile, install-tree fixtures, derived
registries and benchmark baseline; migration checksum baseline re-locked
(MSD keeps its own install state, so no install had applied the old sums);
sort-order and regex-escaped expectations in tests adjusted.
Batch 16 of 17 in the ad hoc timeout literal migration (epic #4445).
Replaces every bare numeric timeout/timeoutMs object-literal property in
9 test files with a named constant, per
eslint-rules/no-adhoc-timeout-literal.cjs. No src/bin file touched, no
numeric value changed anywhere.
Ground truth via eslint found 48 sites, not the issue's stated 38 —
tests/code-review.test.cjs alone has 11, not 1 (a 10-site undercount,
the largest single-file drift in this epic). All 11 are migrated.
Reuses PROBE_TIMEOUT_MS (17 sites across assumption-delta.test.cjs and
code-review.test.cjs), LOOP_HOOK_POINT_CLI_TIMEOUT_MS (1 site),
QUICK_SPAWN_TIMEOUT_MS (1 site). Adds a new shared constant,
HTTP_REACHABLE_PROBE_TIMEOUT_FIXTURE_MS, promoted because two files
(reviewer-manifest-body.test.cjs, reviewer-trust-disclosure.test.cjs)
independently arrived at the same probe-fixture value across 3 sites.
File-local constants elsewhere for values not shared across files:
FALLOW_AUDIT_TIMEOUT_MS (code-review-pipeline-regression.test.cjs);
a 5-constant set covering runBashScript's own override/forced-timeout/
boundary-triple tests (plan-phase-stall-detection.test.cjs); 9
lane-specific NATIVE_TIMEOUT_MS constants, one per shipped reviewer CLI
tool, even where 4 lanes coincidentally share a value
(review-lane-invocation.test.cjs); and a 6-constant set covering
reviewer-manifest-body.test.cjs's own probe-kind fixtures and its
separate, unrelated boundary/invalid set that coincidentally overlaps
in shape (not value) with plan-phase-stall-detection.test.cjs's triple.
Fixes applied inline from review: GENERATOR_SCRIPT_TIMEOUT_MS was
misapplied to 3 sites in plan-review-convergence.test.cjs whose actual
shape (nested bash -> node -> gsd-tools.cjs chain) doesn't match that
constant's documented direct-spawn class, confirmed against its own
cited precedent files — replaced with a new file-local constant
naming the correct class, same value. Two stray un-renamed literals in
review-lane-invocation.test.cjs (missed by eslint's object-literal-only
detection) were investigated and left as disclosed literals with an
explanatory comment rather than force-fit onto an unrelated lane's
constant, since they belong to a distinct config-override code path.
Co-authored-by: sim <sim@local>
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
* test(#3909): failing-first suite for the fabricated probe fallbacks
Binds the four fabrication sites found by executing the surfaces (ADR-3889
failure class (c)), each with a positive control so an over-firing fix goes red:
- the blocking api-coverage.verify-pre gate certifying "no external-API
integration" from a zero-byte phase scope
- the assumption-delta query route scanning an unresolvable phase section as
the empty string and reporting it as an examined negative
- both capability fragments' probe fallbacks, which append a fabricated
verdict rather than replacing, and fire on the legitimate exit-1 negative
Verification runs on the remote runner.
Refs #3909
* enhance(#3909): a probe that could not run no longer asserts a verdict
ADR-3889 Phase 5. Four sites turned a failed or unexamined probe into a
confident negative; each now reports what it could not establish.
- check api-coverage.verify-pre: a phase with no plan body and no roadmap
section ran detection over zero bytes and PASSED the blocking seal gate,
certifying "no external-API integration" from input it never read. It now
holds with scope_unavailable. The discriminator is bytes examined, never
signals found, so a phase whose plans are real and simply carry no API
vocabulary passes exactly as before.
- query assumption-delta scan: an unresolvable phase section was scanned as
the empty string and reported as an examined negative. It now returns
{skipped, reason: phase_unresolved}, still at exit 0 — an ADR-2980 degraded
result in the payload, leaving the gsd-tools exit projection to P8.
- both capability fragments: `|| echo '{"detected":false}'` appended rather
than replaced, and fired on the legitimate exit-1 negative, so a correct
answer and an honest skip both arrived as two concatenated objects. They now
keep the probe's own payload and manufacture only an explicit
probe_unavailable skip when the probe produced nothing at all.
Every registered outcome is more restrictive on a blocking gate, so this can
turn a false green red and never a red green.
Docs: FEATURES 156, CONFIGURATION (both keys), references/api-coverage.md
seal-time outcome table, and a new how-to for the reason-code vocabulary.
Verification runs on the remote runner.
Closes#3909
* test(#3909): correct the stale unknown-phase assertion
`unknown phase → detected:false, no throw (graceful)` scanned phase 999
against a two-phase roadmap and asserted `detected === false`. That pinned
the fabrication as intended behavior: the phase does not exist, so the
detector was handed the empty string and its "no core assumption changed"
answer described nothing that was ever read.
It now asserts the skipped-with-reason shape. The graceful-degradation
contract the test was actually protecting — the query succeeds and does not
throw on an unknown phase — is unchanged.
Found by code review, not by the author.
Refs #3909
* docs(#3909): author the FEATURES entry in its generator source
`docs/FEATURES.md` is generated by `scripts/gen-features.cjs` from the
per-feature fragments in `docs/features/`. The API-coverage entry was edited
in the generated file, so the next regeneration silently dropped it.
The text now lives in `docs/features/api-coverage-gate.md` and
`docs/FEATURES.md` is regenerated from it, leaving the shipped file
byte-identical and its content actually derivable.
Caught by `lint:generated-sync`.
Refs #3909
* test(#3909): bind the skip to "not found", and pin the discriminator
The first verification run went red on one case, and the case was wrong
rather than the code.
`getRoadmapPhaseWithFallback` returns `null` for an unknown phase and for a
missing ROADMAP.md, but for a section whose body is whitespace-only it returns
the heading line alone — which is not empty. So a body-less section WAS found,
and reporting `detected:false` over its heading is a real negative, not a
fabrication. The test had assumed the resolver yielded `''` there.
Correcting the test rather than the resolver keeps `skipped` bound to the
distinction the issue asks for — found versus not found — and avoids diverging
`assumption-delta scan` from `roadmap.get-phase`, which the fragment documents
as sharing one resolver.
Also adds the seeded property the test matrix had promised: for any plan body,
the scope read back is whitespace-only exactly when the body was. That pins the
gate's discriminator to bytes examined, so it cannot quietly become "no signals
found", across unicode whitespace and CRLF.
`docs/INVENTORY.md` picks up the reference doc's new seal-time outcome table —
surfaced by the co-change gate, not by a lint failure.
Refs #3909
* chore(#3909): backfill the changeset PR number
Refs #3909
---------
Co-authored-by: sim <sim@local>
Eight declarations were kept in sync by hand with no parity assertion. The drift
was already in the tree: api-coverage-gate-e2e and representative-corpus declared
TERM_SESSION, but the real variable is TERM_SESSION_ID, so both scrubbed nothing
for that slot and leaked TERM_SESSION_ID into every child. Deleting the copies
removes the dead key with them -- there is no longer a second place to get wrong.
run-tests-harness keeps its local session-identity literal: that helper mirrors
the production runGsdTools to prove its CONTRACT, so it must not re-import what
it is testing. The config-LOCATION keys are a safety scrub rather than part of
that contract, so it spreads the canonical derived set and keeps the rest local.
Addresses review findings: Blocker 2, Blocker 3.
TEST_ENV_BASE blanks session-identity variables but none of the three that
decide WHERE a child process writes: CLAUDE_CONFIG_DIR, GSD_RUNTIME and
CODEX_HOME. The config-home resolver is env-first (runtime-homes.cts, the
dot-home case consults the env var before the home-derived fallback), so an
ambient CLAUDE_CONFIG_DIR in the developer's shell beats a call site that
sandboxes only HOME. The suite then writes into the developer's real config
directory -- including a registered skill under <configDir>/skills/ whose
body carries behavioural directives that load into later sessions.
Blank all three alongside the session-identity vars. `...env` still spreads
last, so the five call sites that already constrain these locally keep
winning with their explicit values.
TEST_ENV_BASE is re-declared in nine files, so the three lines are added
nine times rather than once. Consolidating the nine into a single exported
constant -- and fixing the TERM_SESSION / TERM_SESSION_ID drift between the
copies -- is deliberately left out of this change; see the PR body.
One call site needed adjusting. capability-state.test.cjs's
`capability state --runtime claude` CLI test passed no env at all and
compared the CHILD's resolved config dir against the PARENT process's
getGlobalConfigDir('claude'). That agreed only because the child inherited
the developer's ambient CLAUDE_CONFIG_DIR -- i.e. it passed *because of*
the leak. It now redirects both runtime homes into the sandbox and asserts
against values the test controls, so it is hermetic with the variable set
or unset.
Regression case folded into the owning module's test file rather than a new
bug-NNNN file, per scripts/lint-regression-test-names.cjs. It sets the
variable on the PARENT process, which is the actual vector; setting it in
the per-call env argument would exercise a path that was never broken.