test(#2665): widen the hermeticity guard to its two blind surfaces, and cover its budget

Round 2, both Majors. They are one defect seen twice: the recurrence guard did
not cover the surface it exists to guard.

Blind surfaces. resolveLiveConfigRoots enumerates getGlobalConfigDir per registry
runtime plus a hardcoded grok branch, so it can only ever see runtime config
ROOTS. Two live write surfaces are not roots and passed through silently:

  $GSD_HOME/.gsd     — GSD's user-owned store. Watched WHOLESALE: unlike ~/.claude
                       this root is exclusively ours, so the shared-root
                       false-positive trap the module documents does not apply.
  <kimi>/config.toml — the file GSD writes its native [[hooks]] block into. The
                       INVERSE case: ~/.kimi belongs to Kimi CLI, so only the one
                       file GSD writes is watched, never the root.

That asymmetry is why this is not a two-line "add two roots" patch — one target
needs the whole tree, the other needs exactly one file, and collapsing them
either under-watches the store or trips the guard's own documented
false-positive trap on a third party's directory.

Extras are passed to snapshotLiveConfig explicitly rather than resolved inside
it, so a caller snapshotting a fixture root cannot silently pull the developer's
real ~/.gsd into its own assertions. run-tests.cjs now snapshots when EITHER the
roots or the extras are non-empty — previously an unbuilt tree yielding zero
roots disabled the entire guard without saying so.

Budget coverage. The MAX_ENTRIES/MAX_DEPTH bound and the truncated -> 'unverified'
branch had zero tests, despite this module's own docstring naming "a truncated
scan reading as clean" as the safety-critical case. Added per
RULESET.TESTS.boundary-coverage (N in {limit-1, limit, limit+1}, exercised
through newestMtime's injected budget so the boundary is real without
materialising 20000 files) and RULESET.TESTS.property-based-testing (fast-check:
truncation is monotone in the budget; reported newest never exceeds the true
maximum). A regression flipping `truncated` to false on an exhausted budget now
breaks the property for every budget below the tree size.

Negative-controlled: neutering the extras wiring fails exactly the two
new-surface tests and nothing else. 21/21 green with it restored.
This commit is contained in:
0xdhx
2026-08-01 02:01:18 -05:00
parent 3c580b77dc
commit a294ec2a2b
3 changed files with 285 additions and 3 deletions

View File

@@ -41,6 +41,7 @@ const { execFileSync } = require('child_process');
const { ExitError, runMain } = require('./lib/cli-exit.cjs');
const {
resolveLiveConfigRoots,
resolveExtraWatchTargets,
snapshotLiveConfig,
diffLiveConfig,
formatViolations,
@@ -977,10 +978,19 @@ function main() {
// scripts/lib/live-config-guard.cjs for why the scope is narrow.
const liveConfigGuardEnabled = process.env.GSD_SKIP_LIVE_CONFIG_GUARD !== '1';
let liveConfigRoots = [];
let liveConfigExtras = [];
let liveConfigBefore = null;
if (liveConfigGuardEnabled) {
liveConfigRoots = resolveLiveConfigRoots();
if (liveConfigRoots.length > 0) liveConfigBefore = snapshotLiveConfig(liveConfigRoots);
// #2665 round 3: $GSD_HOME/.gsd and kimi's native config.toml are live write
// surfaces that are not runtime config ROOTS, so they are invisible to the
// line above. Watched independently — and note the OR: the extras alone are
// reason enough to snapshot, so an unbuilt tree that yields zero roots no
// longer silently disables the whole guard.
liveConfigExtras = resolveExtraWatchTargets();
if (liveConfigRoots.length > 0 || liveConfigExtras.length > 0) {
liveConfigBefore = snapshotLiveConfig(liveConfigRoots, liveConfigExtras);
}
}
let firstFailureExit = 0;
@@ -1052,7 +1062,10 @@ function main() {
// global install is worth reporting alongside the failure that hid it, and
// suppressing it on red would hide it exactly when the suite is least trusted.
if (liveConfigBefore) {
const violations = diffLiveConfig(liveConfigBefore, snapshotLiveConfig(liveConfigRoots));
const violations = diffLiveConfig(
liveConfigBefore,
snapshotLiveConfig(liveConfigRoots, liveConfigExtras),
);
if (violations.length > 0) {
console.error(formatViolations(violations));
// Reports by default; fails only under opt-in strict mode. See the