Skip to content

Count only an absolute managed-mcp.json path as a managed MCP config - #967

Merged
seathatflowsinourveins merged 1 commit into
mainfrom
claude/cc-native-practice-managed-path-abs-20261010
Oct 10, 2026
Merged

seathatflowsinourveins merged 1 commit into
mainfrom
claude/cc-native-practice-managed-path-abs-20261010

Conversation

@seathatflowsinourveins

Copy link
Copy Markdown
Collaborator

Scope

  • What this PR changes, in one or two sentences: skill_doctor_argv in tools/skill-usage/skill_usage.py now counts a managed-config candidate only when it is absolute and already normalised under the host's own path rules, so on POSIX a readable file literally named C:\Program Files\ClaudeCode\managed-mcp.json in the working directory no longer drops --strict-mcp-config while the client sees no managed config (the P3 of the co-op's GPT reads of Fence the headless /skill-doctor run #925 at 46cc5dd1 and 715229c7, found first by the command center's micro of 46cc5dd1). tests.test_skill_usage.ManagedMcpDefaultLocations, added by Fence the headless /skill-doctor run #925, is narrowed as Fence the headless /skill-doctor run #925 declared: a documented string is a location only where it is an absolute path, so the Windows cases run on nt hosts and the Windows string is asserted inert on POSIX.
  • Base commit: e1c88ff3d7edc71052d6fb4eed8422438b06efaf (main with Fence the headless /skill-doctor run #925 landed, 2026-10-10T14:03:40Z); one commit, 3de3dda86d6dbd5abeb4b5d7187f46892440b9c6, replayed onto it from the follow-up prepared on Fence the headless /skill-doctor run #925's head 715229c72 (no conflict).
  • Lane: lane:foundation
  • Owned paths touched (four files): tools/skill-usage/skill_usage.py (_readable_system_file, the check in skill_doctor_argv, the comment), tests/test_skill_usage.py (the planted-file regression, the comment assertions, the narrowed ManagedMcpDefaultLocations), docs/decisions/2026-10-04-pwsh7-windows-guidance.md (one shifted line locator, now 2432-2438), manifests/evidence.json (re-registration of the three).

Follows #925: the agreed follow-up for its deferred P3. Nothing here changes a setting, a hook or a host.

SOTA sources

  • The reproduction: the co-op's GPT read of Fence the headless /skill-doctor run #925 at 46cc5dd1 (finding 2, verdict sha256 da3470f5…) and at 715229c7 (finding 1, verdict sha256 2cf30652…): in a POSIX temporary directory a readable file with the Windows path as its literal name, holding malformed JSON, made the default helper omit --strict-mcp-config, with Path(...).is_absolute() false. The command center's micro of 46cc5dd1 found it first.
  • The installed Claude Code 2.1.296 binary (sha256 24972e3bc859fab2b46ed4c1e51f7d6130f06d3bd550811a114640de3370d0de, read 2026-10-10): My() at byte 209080002 returns /Library/Application Support/ClaudeCode on macOS, C:\Program Files\ClaudeCode on Windows and /etc/claude-code otherwise, so each documented string is a location only on its own platform; the reader and refusal at bytes 217796118 and 217799919 are cited in Fence the headless /skill-doctor run #925.
  • CPython path rules, read from the installed interpreters (3.12.3, the CI version, and 3.13.16): under posixpath the two POSIX strings are absolute and unchanged by abspath and the Windows string is neither; under ntpath the Windows string is absolute and unchanged, and the POSIX strings are not (3.13) or are changed by abspath (3.12, where isabs accepts a leading separator). The check is therefore absolute and abspath(name) == name. Run with ntpath on this POSIX host, not on a Windows host.
  • Managed MCP page, https://code.claude.com/docs/en/managed-mcp (read 2026-10-10): the three system paths of the configuration summary, as in Fence the headless /skill-doctor run #925.

Evidence-class table

Claim Evidence class Command / receipt
A readable file named like the Windows path, and a plain managed-mcp.json, in the working directory keep every fence; the same test fails on main's code local_integration tests.test_skill_usage.RunSkillDoctor.test_a_relative_file_named_like_a_managed_path_is_not_a_managed_config. This head's RunSkillDoctor and ManagedMcpDefaultLocations classes run against main's skill_usage.py (e1c88ff3) fail 4: that test, the comment test and the two Windows cases of the narrowed matrix; at this head 0 fail
The comment no longer says another system's path cannot exist on this one, and states the relative-filename case and its sources source_review test_the_managed_mcp_comment_and_guide_cite_the_client_and_the_docs holds both (it fails on main's comment)
A documented string counts only where it is an absolute, normalised path: on POSIX the macOS and Linux strings do and the Windows string does not; on nt the reverse (ntpath rules on 3.12.3 and 3.13.16, not run on Windows) local_integration (POSIX host), source_review (nt) ManagedMcpDefaultLocations.test_a_documented_string_counts_only_where_it_is_an_absolute_path; the other cases use counts_here and the host's own locations
Sixteen in-memory mutations of the detection: the P3 revert, prepending the working directory to a relative candidate and basename matching are each caught (RunSkillDoctor 1, 1 and 3 tests; the narrowed class 2 cases, 0 and 10), as are each POSIX location ignored or misspelled, all detection off, any to all, no readability check, no regular-file check, the strict flag never or always dropped and a bypassed default route. Not caught, by construction: ignoring or misspelling the Windows location, which are equivalent mutants on POSIX because the string never counts there; they fail only on an nt host local_integration (mutation harness; nothing on disk changes) mutations_p3.py, table retained in the lane's research record (pr925/p3-mutations-20261010.txt)
The Windows decision cites the ledger-path refusal at its new lines 2432-2438 of tools/skill-usage/skill_usage.py, counted by newline source_review tests.test_skill_usage test_the_windows_decision_cites_the_ledger_refusal_lines, which fails on the earlier locator

Declared test contract change

Two main test methods, both from #925, fail against this head by design, because their Windows present cases expect the strict flag dropped for the Windows string on POSIX, the behaviour this PR corrects: tests.test_skill_usage.ManagedMcpDefaultLocations.test_each_documented_location_decides_the_form_alone (the Windows parsed and unparsable cases) and test_dropping_a_locations_detection_fails_its_cases (the still_seen='Windows' cases when macOS or Linux is dropped). Main's tests/test_skill_usage.py run against this head: 215 run, 4 failing cases in exactly those two methods, 19 skipped. At this head the module has 217 tests and passes.

Local commands run

Head 3de3dda86d6dbd5abeb4b5d7187f46892440b9c6 on its base e1c88ff3d (CPython 3.13.16 locally), TMPDIR outside /tmp and outside home:
$ python3 -E -s -B scripts/validate.py
{"components": 70, "hashed_files": 11404, "profiles": 4, "receipts": 239, "status": "passed"}   (rc 0)
$ python3 -E -s -B scripts/evidence_manifest.py --check
{"files": 11404, "status": "passed"}   (rc 0)
$ python3 -E -s -B scripts/validate_convergence.py --all-recorded
rc 0
$ python3 -E -s -B scripts/component_matrix.py --write && python3 -E -s -B scripts/new_host_grand_list.py --write
rc 0; no change to a generated report
$ python3 -E -s -B -m unittest tests.test_skill_usage tests.test_workflow_hardening tests.test_evidence_manifest tests.test_upstream_surface_watch
Ran 473 tests in 47.476s; OK (skipped=26)
$ /var/tmp/ccnp-ci-venv/bin/python -E -B -m unittest tests.test_skill_usage tests.test_freeze_snapshot tests.test_token_measurement tests.test_transcript_audit tests.test_workflow_hardening   # CPython 3.12.3 plus the CI requirements
Ran 638 tests in 229.191s; OK (skipped=66)
$ git diff origin/main --unified=0 | grep '^+'   # added lines, scanned for the host's private names
hits 0

The local full-suite shards in a CI-like environment are noisy on this host (four of eight red at the CI-green #925 head on tests no change touches: user-site packages in tests.test_token_e2e_grader, interrupt tests in tests.test_new_wsl_mcp_conformance_lifecycle and tests.test_adoption_version_probes, the launchd matrix in tests.test_adoption_launchd, the zizmor push-gate test and the credential-race worktree precondition; shard 4 did not report), so the commands above are the targeted lists and CI's eight shards are the full-suite measurement.

Decision record

No new record: this corrects the #925 check and follows the 2026-10-04-pwsh7-windows-guidance record's locator, which moved with the added lines.

Host evidence

Not applicable: no file under evidence/hosts/ changes.

Checklist

  • New/changed GitHub Actions are pinned to a full commit SHA with a version comment (no floating tags). (none changed)
  • New/changed workflows declare top-level permissions: {} and grant each job only what it needs. (none changed)
  • No secrets are printed, logged or committed; no new required secret was added without a documented owner.
  • No new paid hosting, subscription or billing surface was introduced.
  • Peer-owned untracked files and worktrees were preserved (not deleted, moved or overwritten).

🤖 Generated with Claude Code

On POSIX the Windows path C:\Program Files\ClaudeCode\managed-mcp.json is a relative
filename, so a file of that literal name in the working directory made skill_doctor_argv
drop --strict-mcp-config while the client saw no managed config and would load user and
project MCP servers. The command center's micro of #925 at 46cc5dd found it and the
co-op's GPT reads of #925 at 46cc5dd and 715229c reproduced it (a readable file of that
name holding malformed JSON, the default helper omitting the flag); the native client's My()
picks the directory of the actual platform.

A candidate now counts only when it is absolute and already normalised under the host's own
path rules, with no platform branch and without resolving a relative candidate against the
working directory; the comment no longer claims another system's path cannot exist on this
one.

Tests: one plants both the Windows-named file and a plain managed-mcp.json in the working
directory and expects every fence to stay (it fails on the head of #925 and passes here);
the comment test holds the new wording. ManagedMcpDefaultLocations, added by #925, is
narrowed as that PR declared: a documented string is a location only where it is an absolute
path on the host (counts_here), so the Windows cases run on nt hosts and on POSIX the Windows
string is asserted inert in every state; the sensitivity test and the run test use the
host's own locations. Sixteen in-memory mutations (research record, p3-mutations-20261010):
the P3 revert, prepending the working directory and basename matching are caught, and
ignoring or misspelling the Windows location are equivalent mutants on POSIX, caught on nt
only. The Windows decision's ledger-refusal locator follows the added lines (2423-2429 to
2432-2438, counted by newline).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@seathatflowsinourveins seathatflowsinourveins added the lane:foundation Foundation lane: Claude/Codex setup, hosts, memory, RAG, research, workers label Oct 10, 2026
@seathatflowsinourveins
seathatflowsinourveins merged commit 60004bb into main Oct 10, 2026
36 checks passed
@seathatflowsinourveins
seathatflowsinourveins deleted the claude/cc-native-practice-managed-path-abs-20261010 branch October 10, 2026 15:17
seathatflowsinourveins added a commit that referenced this pull request Oct 11, 2026
…ot a managed config

The co-op's GPT read of #967 at 3de3dda (ACK, one non-blocking P3): the normalisation
equality in _readable_system_file (os.path.abspath(name) == name) could be removed with every
test green, because the relative-name test is already rejected by isabs and the default-location
matrix only passes normalised strings.

ManagedMcpDefaultLocations.test_an_absolute_path_that_is_not_normalised_is_not_a_managed_config
uses real files (no fake host, so it runs on every platform): an existing child directory and
the same managed-mcp.json reached through a dot-dot, a dot and a doubled-separator spelling.
Each exists through the filesystem and each keeps the complete fenced argv, by parameter and by
the default route; pathlib drops the dot and doubled-separator segments itself, so only the
dot-dot spelling is also asserted as a Path. The normalised spelling of the same file drops
only --strict-mcp-config, alone and next to a rejected candidate.

Mutations (research record, pr925/p3-mutations-20261010): removing only the normalisation
equality fails the new test (4 cases, none elsewhere), reverting the P3 fix still fails the
relative-name test and now the new one; removing only isabs stays green because
abspath(name) == name already implies an absolute name (an equivalent mutant, so isabs
remains for readability).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
seathatflowsinourveins added a commit that referenced this pull request Oct 11, 2026
The command center's note on landing #967: the most useful P3 is a CI-run test that patches the
module's os with ntpath, so the Windows side of the check is covered under Python 3.12, the CI
interpreter. os.path is posixpath on a POSIX host, so until now the Windows clauses of
_readable_system_file were argued from ntpath's functions and never executed.

ManagedMcpDefaultLocations.test_the_windows_path_rules_count_the_windows_string_and_not_the_posix_ones
replaces the module's os, for the test only, with a namespace whose isabs and abspath are ntpath's
and whose file checks answer yes, so the path rule alone decides: the Windows documented string
drops --strict-mcp-config, the macOS and Linux strings do not (under 3.12 ntpath.isabs accepts a
leading separator and only the equality rejects them; from 3.13 isabs rejects them first), and a
dot-dot, dot, forward-slash and doubled-separator spelling of the Windows string, a relative name
and a drive-relative name each keep every fence. One accepted candidate among rejected ones decides
the form, by parameter and by the default route.

Source-level mutants of _readable_system_file, run in the module's own globals so the mutated body
sees the swapped os (research record, pr925/p3-source-mutations-*): removing only the
normalisation equality fails the new test on 3.12 and 3.13 (the four non-normalised Windows
spellings, plus the macOS and Linux strings on 3.12) and the POSIX-side test added in the previous
commit; removing only isabs fails it through the drive-relative name, because ntpath's pure-Python
abspath on a POSIX host leaves "C:managed-mcp.json" equal to itself (the Windows abspath resolves
it, so there isabs is belt and braces); reverting to the presence-only check of #925 fails the
POSIX and Windows tests. The harness of the earlier mutation tables replaced the whole function and
would not see a swapped os, so these supersede it for this test.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
seathatflowsinourveins added a commit that referenced this pull request Oct 11, 2026
…s under ntpath (#973)

* Test that an absolute but non-normalised managed-config spelling is not a managed config

The co-op's GPT read of #967 at 3de3dda (ACK, one non-blocking P3): the normalisation
equality in _readable_system_file (os.path.abspath(name) == name) could be removed with every
test green, because the relative-name test is already rejected by isabs and the default-location
matrix only passes normalised strings.

ManagedMcpDefaultLocations.test_an_absolute_path_that_is_not_normalised_is_not_a_managed_config
uses real files (no fake host, so it runs on every platform): an existing child directory and
the same managed-mcp.json reached through a dot-dot, a dot and a doubled-separator spelling.
Each exists through the filesystem and each keeps the complete fenced argv, by parameter and by
the default route; pathlib drops the dot and doubled-separator segments itself, so only the
dot-dot spelling is also asserted as a Path. The normalised spelling of the same file drops
only --strict-mcp-config, alone and next to a rejected candidate.

Mutations (research record, pr925/p3-mutations-20261010): removing only the normalisation
equality fails the new test (4 cases, none elsewhere), reverting the P3 fix still fails the
relative-name test and now the new one; removing only isabs stays green because
abspath(name) == name already implies an absolute name (an equivalent mutant, so isabs
remains for readability).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* Cover the managed-config path rule under ntpath on every host

The command center's note on landing #967: the most useful P3 is a CI-run test that patches the
module's os with ntpath, so the Windows side of the check is covered under Python 3.12, the CI
interpreter. os.path is posixpath on a POSIX host, so until now the Windows clauses of
_readable_system_file were argued from ntpath's functions and never executed.

ManagedMcpDefaultLocations.test_the_windows_path_rules_count_the_windows_string_and_not_the_posix_ones
replaces the module's os, for the test only, with a namespace whose isabs and abspath are ntpath's
and whose file checks answer yes, so the path rule alone decides: the Windows documented string
drops --strict-mcp-config, the macOS and Linux strings do not (under 3.12 ntpath.isabs accepts a
leading separator and only the equality rejects them; from 3.13 isabs rejects them first), and a
dot-dot, dot, forward-slash and doubled-separator spelling of the Windows string, a relative name
and a drive-relative name each keep every fence. One accepted candidate among rejected ones decides
the form, by parameter and by the default route.

Source-level mutants of _readable_system_file, run in the module's own globals so the mutated body
sees the swapped os (research record, pr925/p3-source-mutations-*): removing only the
normalisation equality fails the new test on 3.12 and 3.13 (the four non-normalised Windows
spellings, plus the macOS and Linux strings on 3.12) and the POSIX-side test added in the previous
commit; removing only isabs fails it through the drive-relative name, because ntpath's pure-Python
abspath on a POSIX host leaves "C:managed-mcp.json" equal to itself (the Windows abspath resolves
it, so there isabs is belt and braces); reverting to the presence-only check of #925 fails the
POSIX and Windows tests. The harness of the earlier mutation tables replaced the whole function and
would not see a swapped os, so these supersede it for this test.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

lane:foundation Foundation lane: Claude/Codex setup, hosts, memory, RAG, research, workers

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant