Skip to content

paths.config should govern the rest of the config chain #1842

Closed

Description

@dezren39

Relocated from dezren39/darwin-nix#5 on 2026-10-28 (placement audit): mcpx's single source lives in developing-today/code (pkgs/mcpx); re-home tracked at #309. Original body below; issue references inside it are historical (dezren39/nix numbering).

Parent: #181

Problem

paths.config is declared in the settings registry but nothing reads it. The
config search path is still the hardcoded upward walk in config.SearchPath().

Still true at 05c78b2 (#171 left it open on purpose). paths.config appears
in Go only at its declaration (internal/settings/registry.go:270) and in the
#171 guard's allowlist (internal/settings/consumed_test.go:67-70).
SearchPathFrom (internal/config/config.go:542-579) reads MCPX_CONFIG,
XDG_CONFIG_HOME and the home directory, nothing else.

One correction to what #171 recorded: the allowlist reason and
docs/declared-but-unread.md:93-96 both say config.SearchPath reads
MCPX_PATHS_CONFIG directly. It does not -- MCPX_PATHS_CONFIG occurs nowhere in
Go code outside that string. So the setting is inert through all three
channels, and docs/configuration.md:336 advertises --paths-config and
MCPX_PATHS_CONFIG, both of which parse and do nothing. The allowlist entry is
defending a mechanism that does not exist.

That is the same advertised-but-inert failure fixed for paths.scripts,
pool.* and the logging group in #4, left in one place because the fix there
is genuinely harder.

Why it is harder

Circular. To know where to look for config files you would read a setting —
which comes from a config file.

Approaches

A -- delete the setting. Honest and immediate: a knob that parses and does
nothing is the #177 bug class. Loses the "a repo config can say also look here"
capability, which nobody can use today anyway.

B -- environment and flag only. Read MCPX_PATHS_CONFIG / --paths-config
before discovery and prepend (or splice) them into the search path; ignore the
key in files. Not circular, small, and it makes the allowlist sentence true. It
does not let a file extend the chain, which is the part the rest of this issue
is about.

C -- recommended: the two-pass resolution below, with B as its first input.
The environment/flag value seeds pass 1; files found then extend the chain in
pass 2. Recommended because it is the only option where the declared setting
means the same thing from all three channels, which is the registry's promise.

Proposed resolution (Approach C)

Two passes, with the boundary stated rather than implied.

  1. Discovery pass. Walk the default locations. Read only paths.config
    from whatever is found, honouring the null splice.
  2. Load pass. Resolve that list and load everything on it, nearest last.

A file's paths.config therefore governs the rest of the chain from that
point
, not the search that found the file itself. So a repo config can say
"also look here", and a parent cannot be redirected by a child it has never
read.

Rules worth pinning

  • A paths.config found in pass 2 that differs from pass 1 is reported,
    not silently applied. Applying it means re-running discovery with different
    roots, which can not terminate.
  • A cycle (A adds B, B adds A) is refused by identity, the way the launcher
    refuses placeholder cycles.
  • MCPX_CONFIG continues to win outright and skip both passes, because "this
    file, nothing else" has to stay expressible.

Done when

  • paths.config from a discovered file changes which files load afterwards
  • a cycle is refused, naming the path that closed it
  • mcpx config --sources shows both passes distinctly
  • MCPX_CONFIG still bypasses everything

Ease · Impact · Related

Ease S-M · Impact med -- small, and #103 assumes it; also the gate on what
a project config may add to the chain before hooks (#81) and plugin directories
(#80) make that a larger grant.

Related: #103 (assumes it), #81 and #80 (a project config that declares hooks or
a plugin search path is an escalation this rule has to allow for; #173's
warnings), #177 / #129 (the inert-setting class and the guard whose allowlist
reason is wrong here).

Security/auth deferred; see tracker.

Activity

  1. developing-today commented on Oct 28, 2026

    @developing-today
    Contributor
  2. dezren39 commented on Oct 28, 2026

    @dezren39
    MemberAuthor

    History carried over from dezren39/darwin-nix#5 (verbatim, oldest first):


    @dezren39 · 2026-09-30T07:28:35Z

    Integration pass. This issue has no category tracker -- it predates the build-out and is a dependency of several parts of it. Placed in the proposed order at #181.


    @dezren39 · 2026-09-30T12:11:57Z

    Issues pass (2026-09-30, at 05c78b2).

    • Added Parent: #181, a footer (Ease S-M, Impact med, matching Phase 3: sync, blob gate, and relays #181) and Related links.
    • Confirmed still open: Phase 2: delegated Manage cannot add members #171 left paths.config unread on purpose. It appears only at internal/settings/registry.go:270 and in the guard allowlist.
    • Correction to Phase 2: delegated Manage cannot add members #171's record: the allowlist reason (internal/settings/consumed_test.go:67-70) and docs/declared-but-unread.md:93-96 say config.SearchPath reads MCPX_PATHS_CONFIG directly. It does not. SearchPathFrom (internal/config/config.go:542-579) reads only MCPX_CONFIG, XDG_CONFIG_HOME and the home dir, and MCPX_PATHS_CONFIG appears nowhere in Go. The setting is inert through all three channels, yet docs/configuration.md:336 advertises the flag and the variable.
    • Added Approaches A/B/C. A deletes the setting. B supports env/flag only, which is not circular and makes the allowlist sentence true. C, recommended, is the existing two-pass proposal with B as its first input. The existing proposal text is unchanged and now labelled Approach C. Added the design label.

    @dezren39 · 2026-10-28T19:01:27Z

    Triage verdict (task 2025): CONFIRMED, with one update since filing.

    Verified at current mains — the mcpx Go source now lives only in developing-today/code pkgs/mcpx (dezren39/nix main efd3161 has no mcpx Go source; only mcpx.config.nix, .github/workflows/mcpx-nixbuild.yml, planning/plans/mcpx-extraction.md), so citations are at developing-today/code main 35726e8e:

    • internal/settings/registry.go:349 still declares paths.config (KindPathList, Repeatable).
    • internal/config/config.go SearchPathFrom (713–776) is still the hardcoded upward walk: it reads MCPX_CONFIG (730) and XDG_CONFIG_HOME (752) and the home dir — no paths.config, no MCPX_PATHS_CONFIG.
    • MCPX_PATHS_CONFIG occurs in zero Go files (code search: only docs/configuration.md:431 and docs/declared-but-unread.md). --paths-config / MCPX_PATHS_CONFIG still parse and do nothing, and docs/declared-but-unread.md still falsely claims "config.SearchPath reads MCPX_PATHS_CONFIG directly".
    • None of the Done-when items hold yet: a discovered file's paths.config does not change which files load afterwards, there is no cycle refusal, and config --sources shows no two passes. (MCPX_CONFIG bypass does hold.)

    Update: the setting is no longer wholly unread. internal/settings/consumed_test.go:75–82 removed it from the unread allowlist because cli.adoptSettings reads it — but that read is cli/root.go:211 warnPathsConfigFile (#278), which only warns when an entry names a file. It adds nothing to the search/load chain, so the issue's core claim stands.

    Routing: follow-up fix packet enqueued to queue repo-health-nix-pilot (dedupe repo-health:v1:fix:dezren39/nix:issue:5, kind small_fix) scoped to Approach C (B as pass-1 input) in developing-today/code pkgs/mcpx, with the cycle-refusal, pass-2-divergence-report, --sources, and MCPX_CONFIG-bypass acceptance items from this issue. This issue stays the single tracking issue for the set — no per-repo code issue filed.

  3. added
    work/assignedQueue worker lifecycle state
    queue/claimedQueue worker lifecycle state
    and removed
    queue/queuedHas a queued task in the Supabase agent queue
    on Oct 29, 2026
  4. dezren39 commented on Oct 29, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · picked up

  5. dezren39 commented on Oct 29, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · triage verdict — CONFIRMED, implementation follow-up enqueued

    Verdict: CONFIRMED at current main 82b019a0. Scope stands as written, with the issue's own recommended Approach C (two-pass resolution, env/flag as its first input) as the implementation direction. No duplicate exists.

    Verified fresh (2026-10-29 ~04:15Z):

    1. The setting is still inert through all channels. pkgs/mcpx/internal/settings/registry.go ~L349 declares paths.config (KindPathList, Repeatable). Nothing consumes it to build the chain: SearchPathFrom (pkgs/mcpx/internal/config/config.go ~L713-763) honours only MCPX_CONFIG outright, then the upward walk, XDG/home fallbacks and /etc/mcpx/config.json. Code search: MCPX_PATHS_CONFIG occurs in no Go file — only docs/configuration.md and docs/declared-but-unread.md, both of which advertise a mechanism that does not exist; the consumed_test.go allowlist reason repeats the same false claim. (One nuance for the implementer: the comment at config.go ~L728 says "paths.configFile. Read by name because it decides which files the settings are resolved from" — that names the internal constant for the MCPX_CONFIG env var, not the paths.config setting; do not mistake it for consumption. A warnPathsConfigFile helper in internal/cli/root.go ~L211-230 does exist — it warns when an entry names a file — but warning is not governing.)
    2. Dedupe: issue search for paths.config / the config chain returns this issue as the only one scoped to it. The other hits are trackers that reference it (mcpx: extensibility -- plugins, hooks, tool sources, embedding (tracker) #1885, mcpx: a promise and a behaviour that disagree — every declared surface needs a guard that walks it (tracker) #1893, mcpx: the backlog build-out — every theme, in one order, with the disagreements between them (super tracker) #1900, mcpx testing: guard tests that close a whole bug class #1971, mcpx docs: level-2 page map, and the configuration, modes and transport pages #1848, mcpx: the sources the reference would be generated from are incomplete, and several docs say what the code does not #1883) or different work (mcpx: where a script's packages come from -- npm/deno/bun dependency configuration chain #1913 dependency chain; closed mcpx daemons: dead records listed forever, custom-state daemons missed, paths.config file entry silently ignored #278 was the daemon-side "file entry silently ignored" bug, a different defect). Nothing to close as a duplicate; no competing PR or branch owns this.
    3. Approach: the issue records the analysis and the recommendation — C: two-pass resolution (discovery pass reads only paths.config from the default locations, honouring the null splice; load pass resolves that list, nearest last), with Approach B's env/flag value (MCPX_PATHS_CONFIG / --paths-config) seeding pass 1. That makes the declared setting mean the same thing from file, env and flag — the registry's promise. Rules pinned by the issue and carried into the follow-up intact: a differing paths.config found in pass 2 is reported, not applied; a cycle is refused by identity, naming the path that closed it; MCPX_CONFIG keeps winning outright and skips both passes.

    Follow-up: implementation packet enqueued to repo-health-code-pilot (small_fix) with the issue's four "Done when" bullets as its acceptance criteria, plus the allowlist/docs truth-up (consumed_test.go allowlist reason, docs/declared-but-unread.md, docs/configuration.md) so the guard stops defending a mechanism that does not exist. Task ID recorded in the completion note below / queue.

  6. dezren39 commented on Oct 29, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · triage complete

    • Agent: queue worker (repo-worker-code), Lane D shift
    • Session / ID: queue task 2736 → follow-up task 3059
    • Outcome: Triage CONFIRMED (verdict above). Implementation follow-up enqueued to repo-health-code-pilot as task 3059 (small_fix, dedupe_key repo-health:v1:fix:developing-today/code:issue:1842) with the issue's four "Done when" bullets intact plus the allowlist/docs truth-up. This issue now carries queue/queued for task 3059.
  7. 21 remaining items

  8. added
    queue/parkedQueue task is parked (waiting on CI, time, or an event)
    status/parkedDeliberately paused with a recorded resume condition
    and removed
    queue/claimedQueue worker lifecycle state
    on Oct 30, 2026
  9. dezren39 commented on Oct 30, 2026

    @dezren39
    MemberAuthor

    agent-note:v1
    event: parked
    task: 3059 (queue repo-health-code-pilot, lane D)
    worker: repo-worker-code
    summary: Implemented Approach C and opened PR #2477 (branch queue/3059-1842-paths-config-chain): config.ResolveChainFrom two-pass resolution, env/global-flag seeding, cycle refusal naming the closing path, pass-2 divergence reported via mcpx config --sources, MCPX_CONFIG bypass, consumed_test/docs truth-ups. 6 new tests in internal/config/chain_test.go; config, settings and (isolated) cli packages pass on the laptop; go vet clean.
    next: Parked for CI on PR #2477 and the merge-queue gate #2403. Next lane: read PR checks (incl. a clean internal/daemon verdict — one termination was seen under parallel-suite contention and did not reproduce isolated) and Codex findings, merge when green and #2403 clears, then complete task 3059.
    pr: #2477

  10. dezren39 commented on Oct 30, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · parked

  11. dezren39 commented on Oct 30, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · handed off

    • Agent: queue worker (repo-worker-code), Lane A
    • Session / ID: queue task 3059 follow-up note, 2026-10-30T01:17Z
    • Found via: fresh GitHub check after parking task 3059 on the Codex gate
    • Task: Correction to my park note above: PR mcpx: paths.config governs the config chain (two-pass, #1842) #2477 was merged at 01:09:11Z by Drew (merge 0b06b27) while the task was parked. The merge is done and not mine to undo — but the 6 Codex P2 findings listed in my park note remain undispositioned on the merged PR. They still warrant a follow-up pass (fix forward or reply with rationale on each thread).
    • Expectation: whoever completes task 3059 records outcome fixed_merged (merge 0b06b27); the Codex findings follow-up should be filed/tracked separately rather than silently dropped.
    • Links: PR mcpx: paths.config governs the config chain (two-pass, #1842) #2477
  12. dezren39 commented on Oct 30, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · done

  13. removed
    status/parkedDeliberately paused with a recorded resume condition
    queue/parkedQueue task is parked (waiting on CI, time, or an event)
    work/assignedQueue worker lifecycle state
    on Oct 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions