docs(#2665): catalog the config-location and live-config-guard seams in CONTEXT.md
Round 2, Minor. "Workspace seams" carried WORKTREE.SEAM.* and
CONFIG.SEAM.loadConfig-context but nothing for this PR's mechanism or its env
vars, so the one machine-readable place a future author would look said nothing
about the class that has now recurred three times.
Ten predicates across two groups:
CONFIG.LOCATION.SEAM.* — the scrub set's four derivation sources and the rule
that a new var is made ENUMERABLE rather than
appended; the two-families distinction (runtime
configHomes vs GSD's own GSD_HOME/GSD_AGENTS_DIR)
that round 2 turned on; kimi's two config-location
vars; and the in-process scrub requirement, since
HOME sandboxing alone is the trap that produced
Blocker 1 twice.
LIVE-CONFIG.GUARD.SEAM.* — module + exports + why it is scripts/ and not
scripts/lib/; ownership-based scope; the two
non-root targets and their asymmetric treatment;
the truncation contract; the report-not-fatal
severity ratchet; and that CI is structurally blind
here, so green CI is not evidence.
Both generated indexes regenerated. docs/CONTEXT-INDEX.json is checked by
lint:generated-sync (`gen-context-index.cjs --check`) LINE-NUMBER-SENSITIVELY,
and the example's own committed index is separately checked by
lint-example-parser-parity.cjs, which the first regen did not satisfy — editing
CONTEXT.md requires both, and only one of them says so in its error text.
Verified: parity lint rc=0, gen-context-index --check rc=0, full
lint:generated-sync rc=0. Regen diff audited — 10 predicates added, 0 removed,
0 values changed; the example index's remaining churn is line-number re-baking,
which is exactly why the parity lint excludes line numbers.
This commit is contained in:
10
CONTEXT.md
10
CONTEXT.md
@@ -588,6 +588,16 @@ The prompt-level data/instruction isolation seam for untrusted web/document ingr
|
||||
`WORKSTREAM.NAME.POLICY.cjs-module=gsd-core/bin/lib/workstream-name-policy.cjs owns toWorkstreamSlug + active-name/path-segment validation`
|
||||
`WORKSTREAM.POINTER.SEAM.cjs-module=gsd-core/bin/lib/active-workstream-store.cjs owns read/write self-heal for .planning/active-workstream`
|
||||
`CONFIG.SEAM.loadConfig-context=loadConfig(cwd,{workstream}) replaces env-mutation fallback; no temporary process.env GSD_WORKSTREAM rewrites`
|
||||
`CONFIG.LOCATION.SEAM.scrub-set=tests/helpers.cjs CONFIG_LOCATION_ENV_KEYS is DERIVED from four sources, never hand-listed: capability-registry runtimes[].runtime.configHome.env + runtime-homes NON_REGISTRY_CONFIG_HOME_DESCRIPTORS[].env + runtime-homes GSD_LOCATION_ENV_KEYS + a residue list (GROK_AGENTS_HOME, GSD_RUNTIME, GSD_PROJECT, GSD_WORKSTREAM); adding a config-location var means making it ENUMERABLE at one of those sources, not appending a literal`
|
||||
`CONFIG.LOCATION.SEAM.two-families=runtime configHomes (where a third-party runtime keeps config, registry- or descriptor-declared) and GSD's OWN location vars (GSD_HOME -> $GSD_HOME/.gsd store, GSD_AGENTS_DIR -> getAgentsDir priority 1) are DISTINCT families; no registry derivation reaches the second, and treating a miss there as a registry gap is what produced review round 2`
|
||||
`CONFIG.LOCATION.SEAM.kimi-two-homes=kimi declares TWO config-location vars: KIMI_CONFIG_DIR (registry, generic Agent-Skills root via resolveKimiGlobalDir) and KIMI_SHARE_DIR (KIMI_HOOKS_TOML_DESCRIPTOR, kimi's OWN native config.toml carrying GSD's [[hooks]] block via resolveKimiHooksTomlDir); a registry-only derivation covers the first and silently misses the second`
|
||||
`CONFIG.LOCATION.SEAM.in-process-scrub=TEST_ENV_BASE reaches CHILD env only; a test calling install() IN-PROCESS must additionally use helpers.scrubConfigLocationEnv() in beforeEach + its restorer in afterEach — HOME/USERPROFILE sandboxing is NOT sufficient because getGlobalConfigDir is env-FIRST`
|
||||
`LIVE-CONFIG.GUARD.SEAM.module=scripts/live-config-guard.cjs (deliberately NOT scripts/lib/, which the installer copies to users wholesale while uninstall removes only an allowlist); exports [resolveLiveConfigRoots, resolveExtraWatchTargets, snapshotLiveConfig, diffLiveConfig, formatViolations, newestMtime]; driven by scripts/run-tests.cjs pre/post suite`
|
||||
`LIVE-CONFIG.GUARD.SEAM.scope=ownership-based, never whole-root: GSD_OWNED_ENTRIES top-level footprint + gsd--prefixed children of GSD_PREFIXED_PARENTS (dirs shared with the host agent); watching a shared root wholesale false-positives on the host's own writes and a guard that cries wolf gets disabled`
|
||||
`LIVE-CONFIG.GUARD.SEAM.non-root-targets=resolveExtraWatchTargets covers the two live write surfaces that are not runtime config ROOTS: $GSD_HOME/.gsd watched WHOLESALE (exclusively GSD-owned, so the shared-root trap does not apply) and <resolveKimiHooksTomlDir()>/config.toml watched as a SINGLE FILE (the root belongs to Kimi CLI); passed to snapshotLiveConfig explicitly so a fixture-root caller cannot pull the real ~/.gsd into its snapshot`
|
||||
`LIVE-CONFIG.GUARD.SEAM.truncation=MAX_ENTRIES/MAX_DEPTH bound the walk; a bound hit sets truncated and diffLiveConfig emits kind:'unverified' — a truncated scan MUST NOT read as clean; boundary covered at {limit-1,limit,limit+1} via newestMtime's injected budget plus fast-check monotonicity, per RULESET.TESTS.boundary-coverage + RULESET.TESTS.property-based-testing`
|
||||
`LIVE-CONFIG.GUARD.SEAM.severity=reports by default; fails only under GSD_STRICT_LIVE_CONFIG_GUARD=1, skipped by GSD_SKIP_LIVE_CONFIG_GUARD=1; promote to fatal once the USERPROFILE sweep lands, mirroring local/no-source-grep warn->error (ADR 452)`
|
||||
`LIVE-CONFIG.GUARD.SEAM.ci-blind=CI cannot catch the ambient-env half of this class at all — CI never has these vars set, so green CI is not evidence; the guard is the only loud signal`
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"count": 416,
|
||||
"count": 425,
|
||||
"classes": {
|
||||
"ARCH": 1,
|
||||
"CI": 2,
|
||||
"CONFIG": 1,
|
||||
"DEFECT": 168,
|
||||
"CONFIG": 5,
|
||||
"DEFECT": 167,
|
||||
"EXEC": 8,
|
||||
"GSD-RESEARCH": 6,
|
||||
"LEARNING": 1,
|
||||
"LIVE-CONFIG": 6,
|
||||
"META": 4,
|
||||
"PLANNING": 3,
|
||||
"PR": 2,
|
||||
@@ -39,6 +40,26 @@
|
||||
"klass": "CI",
|
||||
"value": "hard-fail if PR body lacks closes/fixes/resolves #<issue>"
|
||||
},
|
||||
{
|
||||
"id": "CONFIG.LOCATION.SEAM.in-process-scrub",
|
||||
"klass": "CONFIG",
|
||||
"value": "TEST_ENV_BASE reaches CHILD env only; a test calling install() IN-PROCESS must additionally use helpers.scrubConfigLocationEnv() in beforeEach + its restorer in afterEach — HOME/USERPROFILE sandboxing is NOT sufficient because getGlobalConfigDir is env-FIRST"
|
||||
},
|
||||
{
|
||||
"id": "CONFIG.LOCATION.SEAM.kimi-two-homes",
|
||||
"klass": "CONFIG",
|
||||
"value": "kimi declares TWO config-location vars: KIMI_CONFIG_DIR (registry, generic Agent-Skills root via resolveKimiGlobalDir) and KIMI_SHARE_DIR (KIMI_HOOKS_TOML_DESCRIPTOR, kimi's OWN native config.toml carrying GSD's [[hooks]] block via resolveKimiHooksTomlDir); a registry-only derivation covers the first and silently misses the second"
|
||||
},
|
||||
{
|
||||
"id": "CONFIG.LOCATION.SEAM.scrub-set",
|
||||
"klass": "CONFIG",
|
||||
"value": "tests/helpers.cjs CONFIG_LOCATION_ENV_KEYS is DERIVED from four sources, never hand-listed: capability-registry runtimes[].runtime.configHome.env + runtime-homes NON_REGISTRY_CONFIG_HOME_DESCRIPTORS[].env + runtime-homes GSD_LOCATION_ENV_KEYS + a residue list (GROK_AGENTS_HOME, GSD_RUNTIME, GSD_PROJECT, GSD_WORKSTREAM); adding a config-location var means making it ENUMERABLE at one of those sources, not appending a literal"
|
||||
},
|
||||
{
|
||||
"id": "CONFIG.LOCATION.SEAM.two-families",
|
||||
"klass": "CONFIG",
|
||||
"value": "runtime configHomes (where a third-party runtime keeps config, registry- or descriptor-declared) and GSD's OWN location vars (GSD_HOME -> $GSD_HOME/.gsd store, GSD_AGENTS_DIR -> getAgentsDir priority 1) are DISTINCT families; no registry derivation reaches the second, and treating a miss there as a registry gap is what produced review round 2"
|
||||
},
|
||||
{
|
||||
"id": "CONFIG.SEAM.loadConfig-context",
|
||||
"klass": "CONFIG",
|
||||
@@ -334,11 +355,6 @@
|
||||
"klass": "DEFECT",
|
||||
"value": "security_reminder_hook can block Write on substring match (e.g. a literal child-process call-expression token); workaround is heredoc to /tmp then mv into place, or use Edit instead — Edit hooks are more lenient than Write hooks"
|
||||
},
|
||||
{
|
||||
"id": "DEFECT.HOST-RESERVED-DIR-NAME",
|
||||
"klass": "DEFECT",
|
||||
"value": "a host runtime reserves a directory NAME that GSD also writes verbatim, so the mere presence of GSD's directory trips the host's own reserved-name detection regardless of contents; example: pi (#3023) treats GSD's shared-hooks bundle dir hooks/ as its own deprecated extension location and printed a startup warning purely because checkDeprecatedExtensionDirs() in packages/coding-agent/src/migrations.ts gates on a bare existsSync(hooksDir) with no readdir/emptiness check (unlike its tools/ sibling); fix-forward=make the shared-hooks directory name descriptor-driven (hostBehaviors.sharedHooksDirName, default hooks) and override it per-runtime when a name collision is detected (pi sets gsd-hooks), with adapters probing the new name then falling back to the legacy name for dev/half-upgraded trees"
|
||||
},
|
||||
{
|
||||
"id": "DEFECT.INVENTORY-DRIFT.detect",
|
||||
"klass": "DEFECT",
|
||||
@@ -959,6 +975,36 @@
|
||||
"klass": "LEARNING",
|
||||
"value": "PR #3708 commit 2df566ed reserved NOTE_RESERVE_TOKENS in pressure-threshold AND in minSet pre-check; both buggy paths only fire when baseTokens ∈ (effectiveBudget - NOTE_RESERVE_TOKENS, effectiveBudget]; original test suite used budgets far from that band so neither path was exercised; fix bde1ae8f confines NOTE_RESERVE accounting to post-trim assembly path only; future budget/limit code MUST add boundary fixtures per RULESET.TESTS.boundary-coverage.fixtures"
|
||||
},
|
||||
{
|
||||
"id": "LIVE-CONFIG.GUARD.SEAM.ci-blind",
|
||||
"klass": "LIVE-CONFIG",
|
||||
"value": "CI cannot catch the ambient-env half of this class at all — CI never has these vars set, so green CI is not evidence; the guard is the only loud signal"
|
||||
},
|
||||
{
|
||||
"id": "LIVE-CONFIG.GUARD.SEAM.module",
|
||||
"klass": "LIVE-CONFIG",
|
||||
"value": "scripts/live-config-guard.cjs (deliberately NOT scripts/lib/, which the installer copies to users wholesale while uninstall removes only an allowlist); exports [resolveLiveConfigRoots, resolveExtraWatchTargets, snapshotLiveConfig, diffLiveConfig, formatViolations, newestMtime]; driven by scripts/run-tests.cjs pre/post suite"
|
||||
},
|
||||
{
|
||||
"id": "LIVE-CONFIG.GUARD.SEAM.non-root-targets",
|
||||
"klass": "LIVE-CONFIG",
|
||||
"value": "resolveExtraWatchTargets covers the two live write surfaces that are not runtime config ROOTS: $GSD_HOME/.gsd watched WHOLESALE (exclusively GSD-owned, so the shared-root trap does not apply) and <resolveKimiHooksTomlDir()>/config.toml watched as a SINGLE FILE (the root belongs to Kimi CLI); passed to snapshotLiveConfig explicitly so a fixture-root caller cannot pull the real ~/.gsd into its snapshot"
|
||||
},
|
||||
{
|
||||
"id": "LIVE-CONFIG.GUARD.SEAM.scope",
|
||||
"klass": "LIVE-CONFIG",
|
||||
"value": "ownership-based, never whole-root: GSD_OWNED_ENTRIES top-level footprint + gsd--prefixed children of GSD_PREFIXED_PARENTS (dirs shared with the host agent); watching a shared root wholesale false-positives on the host's own writes and a guard that cries wolf gets disabled"
|
||||
},
|
||||
{
|
||||
"id": "LIVE-CONFIG.GUARD.SEAM.severity",
|
||||
"klass": "LIVE-CONFIG",
|
||||
"value": "reports by default; fails only under GSD_STRICT_LIVE_CONFIG_GUARD=1, skipped by GSD_SKIP_LIVE_CONFIG_GUARD=1; promote to fatal once the USERPROFILE sweep lands, mirroring local/no-source-grep warn->error (ADR 452)"
|
||||
},
|
||||
{
|
||||
"id": "LIVE-CONFIG.GUARD.SEAM.truncation",
|
||||
"klass": "LIVE-CONFIG",
|
||||
"value": "MAX_ENTRIES/MAX_DEPTH bound the walk; a bound hit sets truncated and diffLiveConfig emits kind:'unverified' — a truncated scan MUST NOT read as clean; boundary covered at {limit-1,limit,limit+1} via newestMtime's injected budget plus fast-check monotonicity, per RULESET.TESTS.boundary-coverage + RULESET.TESTS.property-based-testing"
|
||||
},
|
||||
{
|
||||
"id": "META.RULE.brief-must-cite-doc",
|
||||
"klass": "META",
|
||||
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user