refactor: hard-fork GSD -> MSD (Make Software Done)
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.
This commit is contained in:
@@ -16,7 +16,7 @@
|
||||
* So the class is silent by construction: it damages the developer's machine and
|
||||
* reports nothing. #2665 records two prior authors each diagnosing it and fixing
|
||||
* only the instance in front of them. This module converts it from silent to
|
||||
* loud by snapshotting GSD's own install footprint before the suite and
|
||||
* loud by snapshotting MSD's own install footprint before the suite and
|
||||
* re-checking it after.
|
||||
*
|
||||
* LOCATION — `scripts/`, deliberately NOT `scripts/lib/`. The installer copies
|
||||
@@ -28,9 +28,9 @@
|
||||
* run-affected-tests.cjs — excluding one link alone would trip the #2858
|
||||
* shipped-requires-only-shipped gate on the links that still shipped).
|
||||
*
|
||||
* SCOPE — ownership-based, not whole-root. It watches entries GSD unambiguously
|
||||
* owns: the top-level install footprint (`GSD_OWNED_ENTRIES`) plus `gsd-`-prefixed
|
||||
* children of the dirs GSD shares with the host agent (`GSD_PREFIXED_PARENTS`).
|
||||
* SCOPE — ownership-based, not whole-root. It watches entries MSD unambiguously
|
||||
* owns: the top-level install footprint (`MSD_OWNED_ENTRIES`) plus `msd-`-prefixed
|
||||
* children of the dirs MSD shares with the host agent (`MSD_PREFIXED_PARENTS`).
|
||||
* It does NOT watch whole config roots. A root such as `~/.claude` is shared with
|
||||
* the host agent, which may legitimately write `history.jsonl`, `todos/`, or
|
||||
* `settings.json` while the suite runs; watching the root would turn that into a
|
||||
@@ -39,21 +39,21 @@
|
||||
*
|
||||
* The ownership test is the prefix, not the location. That distinction is load
|
||||
* bearing: the first version of this guard watched only the three top-level
|
||||
* entries and MISSED a real leak into `<live>/skills/gsd-dev-preferences/`.
|
||||
* entries and MISSED a real leak into `<live>/skills/msd-dev-preferences/`.
|
||||
*
|
||||
* KNOWN GAP — a leak into a file GSD does not own (e.g. mutating the host's own
|
||||
* KNOWN GAP — a leak into a file MSD does not own (e.g. mutating the host's own
|
||||
* `.claude.json`, `settings.json`, `hooks.json`, `kilo.json`, `opencode.json`) is
|
||||
* outside this guard by construction. Closing it would require watching shared
|
||||
* files, which is the false-positive trap above.
|
||||
*
|
||||
* NAMED RESIDUALS — stated rather than implied, because two successive rounds
|
||||
* asserted this list was complete and both were refuted. Still NOT watched:
|
||||
* - `agents/subagents/**` (kimi stages `subagents/gsd-executor.yaml` under an
|
||||
* - `agents/subagents/**` (kimi stages `subagents/msd-executor.yaml` under an
|
||||
* UNPREFIXED intermediate dir, so no prefix scan of `agents/` reaches it);
|
||||
* - the loose capability generators copied to `<root>/scripts/*.cjs`
|
||||
* (`fix-slash-commands.cjs` is watched by name; the generators are not);
|
||||
* - `extensions/package.json` and `plugins/package.json` — CommonJS markers in
|
||||
* dirs GSD fills but does not own, so they fall under the shared-ground rule
|
||||
* dirs MSD fills but does not own, so they fall under the shared-ground rule
|
||||
* below rather than being watched;
|
||||
* - the shared-hooks bundle in a NON-registry root's `<root>/hooks/` (kimi) —
|
||||
* see resolveExtraWatchTargets; closing it is a layout decision.
|
||||
@@ -64,10 +64,10 @@
|
||||
* Every item above under-watches, which fails quiet: a missed leak, never a
|
||||
* false alarm.
|
||||
*
|
||||
* SEVERITY — reports by default, fails only under GSD_STRICT_LIVE_CONFIG_GUARD=1.
|
||||
* SEVERITY — reports by default, fails only under MSD_STRICT_LIVE_CONFIG_GUARD=1.
|
||||
* Not timidity: on its first CI run this guard found PRE-EXISTING leaks on the
|
||||
* Windows lane (`C:\Users\runneradmin\.claude\gsd-core` and
|
||||
* `skills\gsd-dev-preferences`), because os.homedir() reads USERPROFILE there and
|
||||
* Windows lane (`C:\Users\runneradmin\.claude\msd-core` and
|
||||
* `skills\msd-dev-preferences`), because os.homedir() reads USERPROFILE there and
|
||||
* ~190 test sites sandbox HOME alone. Those are real and worth fixing, but they
|
||||
* are a different defect class from the one #2665 closes, and a brand-new gate
|
||||
* that immediately reds an unrelated lane gets bypassed or reverted rather than
|
||||
@@ -81,40 +81,40 @@ const os = require('os');
|
||||
const path = require('path');
|
||||
|
||||
/**
|
||||
* Top-level entries only a GSD install creates. See SCOPE above before widening.
|
||||
* Top-level entries only a MSD install creates. See SCOPE above before widening.
|
||||
*
|
||||
* `.gsd-source` and `.gsd-profile` were added by the round-5 census (see below):
|
||||
* `.msd-source` and `.msd-profile` were added by the round-5 census (see below):
|
||||
* bin/install.js writes both at the config ROOT for a global install, and an
|
||||
* exact-name list does not match a dot-prefixed name by the `gsd-` prefix rule.
|
||||
* exact-name list does not match a dot-prefixed name by the `msd-` prefix rule.
|
||||
*/
|
||||
const GSD_OWNED_ENTRIES = [
|
||||
'gsd-core',
|
||||
'gsd-file-manifest.json',
|
||||
'gsd-pristine',
|
||||
'.gsd-source',
|
||||
'.gsd-profile',
|
||||
const MSD_OWNED_ENTRIES = [
|
||||
'msd-core',
|
||||
'msd-file-manifest.json',
|
||||
'msd-pristine',
|
||||
'.msd-source',
|
||||
'.msd-profile',
|
||||
];
|
||||
|
||||
/**
|
||||
* Directories GSD SHARES with the host agent. Watching them wholesale would
|
||||
* false-positive on the host's own writes, so only `gsd-`-prefixed children are
|
||||
* Directories MSD SHARES with the host agent. Watching them wholesale would
|
||||
* false-positive on the host's own writes, so only `msd-`-prefixed children are
|
||||
* watched — those are unambiguously ours.
|
||||
*
|
||||
* Added after the first version of this guard MISSED a real leak: a raw
|
||||
* `spawnSync` that sandboxed HOME but inherited an ambient CLAUDE_CONFIG_DIR
|
||||
* wrote `<live>/skills/gsd-dev-preferences/SKILL.md`, which sits under none of
|
||||
* wrote `<live>/skills/msd-dev-preferences/SKILL.md`, which sits under none of
|
||||
* the three top-level entries above.
|
||||
*
|
||||
* `hooks` joined them in round 5, found by re-deriving the census rather than by
|
||||
* a review finding — the SAME shape one parent over. bin/install.js writes
|
||||
* `hooks/gsd-check-update.js`, `hooks/gsd-context-monitor.js` and
|
||||
* `hooks/gsd-update-banner.js` into the config root, and with `hooks` absent from
|
||||
* `hooks/msd-check-update.js`, `hooks/msd-context-monitor.js` and
|
||||
* `hooks/msd-update-banner.js` into the config root, and with `hooks` absent from
|
||||
* this list a leak of any of them passed the guard silently. The lesson the first
|
||||
* miss taught is that this list is the weak point, so it is re-derived from the
|
||||
* installer's own write sites each round rather than trusted.
|
||||
*/
|
||||
const GSD_PREFIXED_PARENTS = ['agents', 'commands', 'skills', 'hooks'];
|
||||
const GSD_ARTIFACT_PREFIX = 'gsd-';
|
||||
const MSD_PREFIXED_PARENTS = ['agents', 'commands', 'skills', 'hooks'];
|
||||
const MSD_ARTIFACT_PREFIX = 'msd-';
|
||||
|
||||
/**
|
||||
* Artifact parents that are NOT registry-declared — the installer writes these
|
||||
@@ -124,14 +124,14 @@ const NON_REGISTRY_ARTIFACT_PARENTS = ['hooks', 'plugins', 'scripts', 'extension
|
||||
|
||||
/**
|
||||
* Prefixes used for a parent with no registry-declared one. BOTH forms are the
|
||||
* point: GSD writes `gsd-`-hyphen artifacts (`hooks/gsd-check-update.js`) AND
|
||||
* bare `gsd.`-dotted ones (pi's `extensions/gsd.js`), and a lone `gsd-` sees
|
||||
* point: MSD writes `msd-`-hyphen artifacts (`hooks/msd-check-update.js`) AND
|
||||
* bare `msd.`-dotted ones (pi's `extensions/msd.js`), and a lone `msd-` sees
|
||||
* only the first.
|
||||
*/
|
||||
const DEFAULT_ARTIFACT_PREFIXES = ['gsd-', 'gsd.'];
|
||||
const DEFAULT_ARTIFACT_PREFIXES = ['msd-', 'msd.'];
|
||||
|
||||
/**
|
||||
* Files GSD owns by EXACT NAME inside a directory it shares — deliberately NOT
|
||||
* Files MSD owns by EXACT NAME inside a directory it shares — deliberately NOT
|
||||
* the directories themselves.
|
||||
*
|
||||
* `hooks/lib`, `hooks/package.json`, `scripts/lib` and `scripts/changeset` were
|
||||
@@ -142,7 +142,7 @@ const DEFAULT_ARTIFACT_PREFIXES = ['gsd-', 'gsd.'];
|
||||
* helper into a violation, which is the false-positive trap the SCOPE note above
|
||||
* exists to refuse. Under-watching fails quiet; over-watching disarms the guard.
|
||||
*/
|
||||
const GSD_OWNED_NESTED = [
|
||||
const MSD_OWNED_NESTED = [
|
||||
'scripts/fix-slash-commands.cjs',
|
||||
'hooks/managed-hooks-registry.cjs',
|
||||
];
|
||||
@@ -153,13 +153,13 @@ const GSD_OWNED_NESTED = [
|
||||
* ever as complete as its author's recall, and this one was measurably not.
|
||||
*
|
||||
* Round 5's adversarial review found the hand-list missing Kilo's SINGULAR
|
||||
* `command/`, `workflows/`, and Hermes' `skills/gsd` -- the last being a whole
|
||||
* directory whose name carries no `gsd-` prefix, so no prefix rule reaches it.
|
||||
* `command/`, `workflows/`, and Hermes' `skills/msd` -- the last being a whole
|
||||
* directory whose name carries no `msd-` prefix, so no prefix rule reaches it.
|
||||
* A capability that declares a new destSubpath now extends this set in the same
|
||||
* commit that declares it.
|
||||
*
|
||||
* @returns {{parents: string[], owned: string[]}} parents = watch gsd-prefixed
|
||||
* children only; owned = watch the path wholesale (its own name is GSD's).
|
||||
* @returns {{parents: string[], owned: string[]}} parents = watch msd-prefixed
|
||||
* children only; owned = watch the path wholesale (its own name is MSD's).
|
||||
*/
|
||||
function deriveArtifactTargets(runtimes) {
|
||||
const parents = new Map();
|
||||
@@ -167,21 +167,21 @@ function deriveArtifactTargets(runtimes) {
|
||||
if (!parents.has(dest)) parents.set(dest, new Set());
|
||||
for (const pre of prefixes) parents.get(dest).add(pre);
|
||||
};
|
||||
for (const dest of [...GSD_PREFIXED_PARENTS, ...NON_REGISTRY_ARTIFACT_PARENTS]) {
|
||||
for (const dest of [...MSD_PREFIXED_PARENTS, ...NON_REGISTRY_ARTIFACT_PARENTS]) {
|
||||
addParent(dest, DEFAULT_ARTIFACT_PREFIXES);
|
||||
}
|
||||
const owned = new Set(GSD_OWNED_NESTED);
|
||||
const owned = new Set(MSD_OWNED_NESTED);
|
||||
for (const entry of Object.values(runtimes || {})) {
|
||||
for (const layout of entry?.runtime?.artifactLayout?.global ?? []) {
|
||||
const dest = layout?.destSubpath;
|
||||
if (typeof dest !== 'string' || !dest) continue;
|
||||
const last = dest.split('/').pop() || '';
|
||||
// A destination whose own final segment is GSD's (hermes' `skills/gsd`) is
|
||||
// A destination whose own final segment is MSD's (hermes' `skills/msd`) is
|
||||
// owned wholesale — that directory is ours, not shared.
|
||||
if (last.startsWith('gsd')) { owned.add(dest); continue; }
|
||||
if (last.startsWith('msd')) { owned.add(dest); continue; }
|
||||
// The layout declares its OWN prefix, and it varies: kimi's `kimi-agents`
|
||||
// layout declares `gsd` (no hyphen) and writes `agents/gsd.yaml` +
|
||||
// `agents/gsd.md`, invisible to a fixed `gsd-` scan. The same destSubpath
|
||||
// layout declares `msd` (no hyphen) and writes `agents/msd.yaml` +
|
||||
// `agents/msd.md`, invisible to a fixed `msd-` scan. The same destSubpath
|
||||
// also carries different prefixes across runtimes, so a parent maps to a SET.
|
||||
const declared = typeof layout?.prefix === 'string' && layout.prefix
|
||||
? [layout.prefix]
|
||||
@@ -198,7 +198,7 @@ function deriveArtifactTargets(runtimes) {
|
||||
let _artifactTargets = null;
|
||||
function artifactTargets(deps = {}) {
|
||||
if (_artifactTargets && !deps.libDir) return _artifactTargets;
|
||||
const libDir = deps.libDir || path.join(__dirname, '..', 'gsd-core', 'bin', 'lib');
|
||||
const libDir = deps.libDir || path.join(__dirname, '..', 'msd-core', 'bin', 'lib');
|
||||
let runtimes;
|
||||
try {
|
||||
({ runtimes } = require(path.join(libDir, 'capability-registry.cjs')));
|
||||
@@ -212,10 +212,10 @@ function artifactTargets(deps = {}) {
|
||||
}
|
||||
|
||||
/**
|
||||
* The file GSD writes into a NON-REGISTRY config home.
|
||||
* The file MSD writes into a NON-REGISTRY config home.
|
||||
*
|
||||
* Both current descriptors are Kimi's — Kimi CLI's `~/.kimi` (KIMI_SHARE_DIR) and
|
||||
* Kimi Code's `~/.kimi-code` (KIMI_CODE_HOME) — and GSD writes its native
|
||||
* Kimi Code's `~/.kimi-code` (KIMI_CODE_HOME) — and MSD writes its native
|
||||
* `[[hooks]]` block into `config.toml` in each, so the single filename below holds
|
||||
* for both. NAMED RESIDUAL: this assumes every non-registry descriptor is written
|
||||
* the same way. That assumption is now load-bearing rather than vacuous — it is
|
||||
@@ -233,7 +233,7 @@ const NON_REGISTRY_OWNED_FILE = 'config.toml';
|
||||
* budget threaded across every target, which made the guard's verdict depend on
|
||||
* directory ORDER and on unrelated local state: one large early target exhausted
|
||||
* it, and every target scanned afterwards reported `truncated` -> `unverified`,
|
||||
* which under GSD_STRICT_LIVE_CONFIG_GUARD=1 is a failed run. Per-target means a
|
||||
* which under MSD_STRICT_LIVE_CONFIG_GUARD=1 is a failed run. Per-target means a
|
||||
* pathological tree truncates ITSELF and nothing else.
|
||||
*
|
||||
* MAX_TOTAL_ENTRIES keeps the aggregate bounded, which is what the single budget
|
||||
@@ -267,7 +267,7 @@ const MAX_DEPTH = 12;
|
||||
* @returns {string[]} deduped, sorted roots; empty if the built lib is absent.
|
||||
*/
|
||||
function resolveLiveConfigRoots(deps = {}) {
|
||||
const libDir = deps.libDir || path.join(__dirname, '..', 'gsd-core', 'bin', 'lib');
|
||||
const libDir = deps.libDir || path.join(__dirname, '..', 'msd-core', 'bin', 'lib');
|
||||
const homedir = (deps.os || os).homedir;
|
||||
let getGlobalConfigDir;
|
||||
let resolveConfigHomeFromDescriptor;
|
||||
@@ -316,10 +316,10 @@ function resolveLiveConfigRoots(deps = {}) {
|
||||
//
|
||||
// DELIBERATE NON-ROOT: getGlobalSkillsBase(runtime) is NOT added here. The
|
||||
// skills base (e.g. codex's ~/.agents/skills) is not a config ROOT, and the
|
||||
// snapshot applies the config-root layout (GSD_OWNED_ENTRIES x
|
||||
// GSD_PREFIXED_PARENTS) beneath every root it is given — measured on a
|
||||
// sandboxed HOME, adding it both false-positives on `<skillsBase>/gsd-core`
|
||||
// and misses a real `<skillsBase>/gsd-help` write. Watching skills bases
|
||||
// snapshot applies the config-root layout (MSD_OWNED_ENTRIES x
|
||||
// MSD_PREFIXED_PARENTS) beneath every root it is given — measured on a
|
||||
// sandboxed HOME, adding it both false-positives on `<skillsBase>/msd-core`
|
||||
// and misses a real `<skillsBase>/msd-help` write. Watching skills bases
|
||||
// needs its own layout, like resolveExtraWatchTargets — a separate change.
|
||||
for (const runtime of [...Object.keys(runtimes || {}), 'grok']) {
|
||||
try {
|
||||
@@ -334,26 +334,26 @@ function resolveLiveConfigRoots(deps = {}) {
|
||||
|
||||
/**
|
||||
* Watch targets that are NOT runtime config roots, and so cannot be expressed as
|
||||
* `root x GSD_OWNED_ENTRIES`.
|
||||
* `root x MSD_OWNED_ENTRIES`.
|
||||
*
|
||||
* #2665 round 3: resolveLiveConfigRoots enumerates getGlobalConfigDir per registry
|
||||
* runtime plus grok. A live write surface that is not a config ROOT is invisible to
|
||||
* that shape, so a leak on one passed through this guard — the PR's own safety net —
|
||||
* silently. There are THREE today ($GSD_HOME/.gsd, plus one config.toml per entry in
|
||||
* silently. There are THREE today ($MSD_HOME/.msd, plus one config.toml per entry in
|
||||
* NON_REGISTRY_CONFIG_HOME_DESCRIPTORS, which #2755 took from one entry to two):
|
||||
*
|
||||
* $GSD_HOME/.gsd — GSD's user-owned store (consent.json, defaults.json, capability
|
||||
* $MSD_HOME/.msd — MSD's user-owned store (consent.json, defaults.json, capability
|
||||
* overlays). Watched WHOLESALE: unlike ~/.claude this root is
|
||||
* exclusively ours, so the shared-root false-positive trap in
|
||||
* SCOPE above does not apply and an ownership filter would only
|
||||
* narrow the guard for nothing.
|
||||
* <non-registry home>/config.toml — the file GSD writes its native [[hooks]] block
|
||||
* <non-registry home>/config.toml — the file MSD writes its native [[hooks]] block
|
||||
* into, one per NON_REGISTRY_CONFIG_HOME_DESCRIPTORS entry: Kimi
|
||||
* CLI's ~/.kimi (KIMI_SHARE_DIR) and, since #2755, Kimi Code's
|
||||
* ~/.kimi-code (KIMI_CODE_HOME). The INVERSE case: those roots
|
||||
* belong to their products, so the root is never watched
|
||||
* wholesale. This is the KNOWN GAP above accepted deliberately
|
||||
* in one direction — GSD demonstrably writes these files
|
||||
* in one direction — MSD demonstrably writes these files
|
||||
* (bin/install.js resolves the hooks-toml dir at two sites), so
|
||||
* a concurrent write by those products is the only false
|
||||
* positive, and neither runs during the suite. NOT watched, and
|
||||
@@ -365,7 +365,7 @@ function resolveLiveConfigRoots(deps = {}) {
|
||||
* @returns {string[]} absolute paths; empty if the built lib is absent.
|
||||
*/
|
||||
function resolveExtraWatchTargets(deps = {}) {
|
||||
const libDir = deps.libDir || path.join(__dirname, '..', 'gsd-core', 'bin', 'lib');
|
||||
const libDir = deps.libDir || path.join(__dirname, '..', 'msd-core', 'bin', 'lib');
|
||||
const env = deps.env || process.env;
|
||||
const homedir = (deps.os || os).homedir;
|
||||
|
||||
@@ -374,8 +374,8 @@ function resolveExtraWatchTargets(deps = {}) {
|
||||
// path leaves the fallback unwatched, which is the same defect B3 closed for the
|
||||
// registry roots; it lived here too until round 5's adversarial review found it.
|
||||
const targets = [
|
||||
path.resolve(path.join(env.GSD_HOME || homedir(), '.gsd')),
|
||||
path.resolve(path.join(homedir(), '.gsd')),
|
||||
path.resolve(path.join(env.MSD_HOME || homedir(), '.msd')),
|
||||
path.resolve(path.join(homedir(), '.msd')),
|
||||
];
|
||||
|
||||
try {
|
||||
@@ -406,9 +406,9 @@ function resolveExtraWatchTargets(deps = {}) {
|
||||
// the named file below.
|
||||
//
|
||||
// NAMED RESIDUAL (#2665, found pre-push while rebasing): config.toml is NOT
|
||||
// the only thing GSD writes here. bin/install.js also calls
|
||||
// the only thing MSD writes here. bin/install.js also calls
|
||||
// installSharedHooksBundle(kimiHooksRoot), which populates <root>/hooks/
|
||||
// with GSD's hook scripts and a CommonJS marker. That subtree is UNWATCHED,
|
||||
// with MSD's hook scripts and a CommonJS marker. That subtree is UNWATCHED,
|
||||
// so a suite-produced leak of a hook bundle into a developer's real ~/.kimi
|
||||
// or ~/.kimi-code passes this guard silently. Closing it needs a layout
|
||||
// decision, not one more path: the same reason getGlobalSkillsBase is a
|
||||
@@ -465,7 +465,7 @@ function newestMtime(target, budget) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Snapshot GSD-owned entries under each root.
|
||||
* Snapshot MSD-owned entries under each root.
|
||||
*
|
||||
* @returns {Record<string, {exists: boolean, newest: number, truncated: boolean}>}
|
||||
* keyed by absolute entry path.
|
||||
@@ -500,18 +500,18 @@ function snapshotLiveConfig(roots, extraTargets = [], limits = {}) {
|
||||
// Non-root targets (resolveExtraWatchTargets) are recorded verbatim — they are
|
||||
// already the exact path to watch, whole-dir or single-file. Passed explicitly
|
||||
// rather than resolved here so a caller testing a fixture root does not silently
|
||||
// pull the developer's real ~/.gsd into its snapshot.
|
||||
// pull the developer's real ~/.msd into its snapshot.
|
||||
for (const target of extraTargets) record(path.resolve(target));
|
||||
|
||||
const { parents: watchParents, owned: watchOwned } = artifactTargets();
|
||||
|
||||
for (const root of roots) {
|
||||
for (const entry of GSD_OWNED_ENTRIES) record(path.join(root, entry));
|
||||
// Paths whose own name is GSD's, nested inside a shared root (hermes'
|
||||
// `skills/gsd`, `hooks/lib`, `scripts/lib`, …) — no prefix rule sees these.
|
||||
for (const entry of MSD_OWNED_ENTRIES) record(path.join(root, entry));
|
||||
// Paths whose own name is MSD's, nested inside a shared root (hermes'
|
||||
// `skills/msd`, `hooks/lib`, `scripts/lib`, …) — no prefix rule sees these.
|
||||
for (const entry of watchOwned) record(path.join(root, ...entry.split('/')));
|
||||
|
||||
// Shared dirs: enumerate only gsd-prefixed children. A child that appears
|
||||
// Shared dirs: enumerate only msd-prefixed children. A child that appears
|
||||
// between the two snapshots is absent from `before` entirely — diffLiveConfig
|
||||
// treats after-only paths as created, which is exactly the leak signal.
|
||||
for (const [parent, prefixes] of Object.entries(watchParents)) {
|
||||
@@ -537,10 +537,10 @@ function snapshotLiveConfig(roots, extraTargets = [], limits = {}) {
|
||||
* Iterate the UNION of both key sets, never `after` alone. Deletion reaches this
|
||||
* function in two shapes and an after-only walk sees neither:
|
||||
*
|
||||
* - A FIXED owned entry (GSD_OWNED_ENTRIES x roots, and every extra target) is
|
||||
* - A FIXED owned entry (MSD_OWNED_ENTRIES x roots, and every extra target) is
|
||||
* recorded at both ends whether or not it exists, so a deletion reads
|
||||
* {exists:true} -> {exists:false} and falls through every branch — silently.
|
||||
* - A gsd-prefixed child is DISCOVERED by readdir, so a deleted one is absent
|
||||
* - A msd-prefixed child is DISCOVERED by readdir, so a deleted one is absent
|
||||
* from `after` entirely and never enters an after-keyed loop at all.
|
||||
*
|
||||
* The second shape is why adding a `pre.exists && !post.exists` branch is not on
|
||||
@@ -555,7 +555,7 @@ function diffLiveConfig(before, after) {
|
||||
for (const target of targets) {
|
||||
const pre = before[target];
|
||||
const post = after[target];
|
||||
// Absent from `before` entirely: a gsd-prefixed child that did not exist
|
||||
// Absent from `before` entirely: a msd-prefixed child that did not exist
|
||||
// when the run started. Both snapshots cover the same roots, so an
|
||||
// after-only path was created BY the run — never skip it.
|
||||
if (!pre) {
|
||||
@@ -608,25 +608,25 @@ function formatViolations(violations) {
|
||||
// failure captioned "Reporting only" sends the reader away from the very
|
||||
// violation that just reddened their run.
|
||||
lines.push(
|
||||
process.env.GSD_STRICT_LIVE_CONFIG_GUARD === '1'
|
||||
? 'STRICT MODE (GSD_STRICT_LIVE_CONFIG_GUARD=1): these violations fail the run. ' +
|
||||
'GSD_SKIP_LIVE_CONFIG_GUARD=1 skips the check entirely.'
|
||||
: 'Reporting only. Set GSD_STRICT_LIVE_CONFIG_GUARD=1 to make this fail the run, ' +
|
||||
'or GSD_SKIP_LIVE_CONFIG_GUARD=1 to skip the check entirely.',
|
||||
process.env.MSD_STRICT_LIVE_CONFIG_GUARD === '1'
|
||||
? 'STRICT MODE (MSD_STRICT_LIVE_CONFIG_GUARD=1): these violations fail the run. ' +
|
||||
'MSD_SKIP_LIVE_CONFIG_GUARD=1 skips the check entirely.'
|
||||
: 'Reporting only. Set MSD_STRICT_LIVE_CONFIG_GUARD=1 to make this fail the run, ' +
|
||||
'or MSD_SKIP_LIVE_CONFIG_GUARD=1 to skip the check entirely.',
|
||||
);
|
||||
lines.push('');
|
||||
return lines.join('\n');
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
GSD_OWNED_ENTRIES,
|
||||
GSD_PREFIXED_PARENTS,
|
||||
GSD_OWNED_NESTED,
|
||||
MSD_OWNED_ENTRIES,
|
||||
MSD_PREFIXED_PARENTS,
|
||||
MSD_OWNED_NESTED,
|
||||
NON_REGISTRY_ARTIFACT_PARENTS,
|
||||
DEFAULT_ARTIFACT_PREFIXES,
|
||||
deriveArtifactTargets,
|
||||
artifactTargets,
|
||||
GSD_ARTIFACT_PREFIX,
|
||||
MSD_ARTIFACT_PREFIX,
|
||||
MAX_ENTRIES,
|
||||
MAX_TOTAL_ENTRIES,
|
||||
MAX_DEPTH,
|
||||
|
||||
Reference in New Issue
Block a user