Repository navigation
Fence the headless /skill-doctor run - #925
Merged
seathatflowsinourveins merged 7 commits intoOct 10, 2026
Merged
seathatflowsinourveins merged 7 commits into
seathatflowsinourveins merged 7 commits into
Conversation
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 40d25bebc9
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
seathatflowsinourveins
added a commit
that referenced
this pull request
Oct 10, 2026
…al locator The co-op's GPT read of #925 at 2c8fc61 asked for three forward fixes, each with a test that fails without it: - The --claude-skill-doctor help still showed the bare command, and the drift test searched the whole --help output, so the correct --run-skill-doctor entry hid the stale one. Both entries now print shlex.join(SKILL_DOCTOR_ARGV), checked per option through build_parser() (main's parser, split out unchanged). - The fence comment credited `claude --help` for every flag, but 2.1.295 and 2.1.296 hide --max-turns from --help. The comment now names the flags --help lists, cites the CLI reference for --max-turns and PERM-03 for the no-prompting rule; a test rejects the 2c8fc61 comment and any unlanded-record source. - The Windows decision's locator: by newline count (editors, grep -n, GitHub) 2381-2386 did hold the def and the work-tree refusal at 2c8fc61; the read's probe used str.splitlines(), which also breaks at the U+2028 and U+2029 this module holds in one line, two lines off. This commit's insertions move the function to 2389-2395, so the decision cites that, and a test (splitting on "\n") fails whenever the cited lines stop holding the refusal. Measured on 2026-10-10 from this branch: /skill-doctor returns, per client, a sha256-identical table at $0 and 0 turns with the b2189ba fences and with these (2.1.295 and 2.1.296). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
skill_usage.py ran `claude -p "/skill-doctor"` with no fences, so the run inherited the host's default permission mode (bypassPermissions here), its MCP servers and every tool. /skill-doctor is a local command (0 turns, $0), so fences change nothing while the client recognises it; they keep an unrecognised prompt from reaching a model with tools or spending: --permission-mode dontAsk, --tools "", --strict-mcp-config, --max-turns 1 and --max-budget-usd 0.05. Measured on 2.1.295: the fenced and unfenced runs return the same table byte for byte, at cost 0 and 0 turns. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The test compared the captured argv with SKILL_DOCTOR_ARGV, the same list the code passes, so a mutated constant still passed. It now compares with a complete literal list; the co-op's three mutations (an added --tools Read, --dangerously-skip-permissions, a second --max-turns) each fail. The pwsh7 record's locator for ledger_path_issue moves from 2372-2377 to 2381-2386, the same six lines after the constant inserted above them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ommand to the argv Blind judging of the review-gate run confirmed five defects that were still present at b2189ba: - the argv lacked --permission-prompts none, which the adopted rule PERM-03 requires (docs/harness-rules-convergence-20260922.md); - tools/skill-usage/README.md, adoption/update.md and blueprints/native-skill-practice/README.md still gave the bare, unfenced command, and no test tied those hand copies to SKILL_DOCTOR_ARGV; - the --run-skill-doctor help named the Python constant instead of the command it runs; - the fence comment cited an unlanded record with no repository, pin or path. The argv gains --permission-prompts none; the docstring, both READMEs and the update guide carry the exact fenced command; the help prints shlex.join(SKILL_DOCTOR_ARGV); a new test fails when any copy drifts from the argv; the comment names the PERM-03 rule and the measured result. Measured on Claude Code 2.1.295: /skill-doctor returns the same table (identical sha256) at $0 and 0 turns with and without the new flag. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…al locator The co-op's GPT read of #925 at 2c8fc61 asked for three forward fixes, each with a test that fails without it: - The --claude-skill-doctor help still showed the bare command, and the drift test searched the whole --help output, so the correct --run-skill-doctor entry hid the stale one. Both entries now print shlex.join(SKILL_DOCTOR_ARGV), checked per option through build_parser() (main's parser, split out unchanged). - The fence comment credited `claude --help` for every flag, but 2.1.295 and 2.1.296 hide --max-turns from --help. The comment now names the flags --help lists, cites the CLI reference for --max-turns and PERM-03 for the no-prompting rule; a test rejects the 2c8fc61 comment and any unlanded-record source. - The Windows decision's locator: by newline count (editors, grep -n, GitHub) 2381-2386 did hold the def and the work-tree refusal at 2c8fc61; the read's probe used str.splitlines(), which also breaks at the U+2028 and U+2029 this module holds in one line, two lines off. This commit's insertions move the function to 2389-2395, so the decision cites that, and a test (splitting on "\n") fails whenever the cited lines stop holding the refusal. Measured on 2026-10-10 from this branch: /skill-doctor returns, per client, a sha256-identical table at $0 and 0 turns with the b2189ba fences and with these (2.1.295 and 2.1.296). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
seathatflowsinourveins
force-pushed
the
claude/cc-native-practice-skill-doctor-fence-20261009
branch
from
October 10, 2026 07:38
c955581 to
9403588
Compare
Claude Code refuses --strict-mcp-config while managed-mcp.json is deployed: 2.1.296 prints "You cannot use --strict-mcp-config when an enterprise MCP config is present", and https://code.claude.com/docs/en/managed-mcp says the client "exits at startup" when the flag is passed with that file deployed. So --run-skill-doctor failed on enterprise-managed hosts (the Codex review thread on #925, P2). skill_doctor_argv now drops only that flag when a readable managed-mcp.json exists at the documented system path (macOS, Linux and WSL, Windows) and keeps every other fence; the documented command is unchanged. Five new tests, each failing on the previous code (the new function, the keyword, the path table and the comment and guide citations did not exist); the existing RunSkillDoctor tests no longer depend on a managed-mcp.json that may exist on the host running them. The README, adoption/update.md and the blueprint README say when to drop the flag, and the Windows decision's locator follows the inserted lines (2389-2395 to 2421-2427, counted by newline). Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…form The macOS drift guard (tests.test_workflow_hardening.MacosPatternsTests) flagged the platform branch that chose the managed-mcp.json path, a failure the targeted run missed and CI's shard 0 found. Another system's documented path cannot exist on this one, so skill_doctor_argv now checks all three (/Library/Application Support/ClaudeCode/, /etc/claude-code/, and C:\Program Files\ClaudeCode\ from the managed MCP page's configuration summary) and the module has no platform branch. The run tests are hermetic by patching the path tuple, the path test pins the three documented paths, and the Windows decision's locator follows the removed lines (2421-2427 to 2417-2423, counted by newline). Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
… default route The co-op's GPT read of 46cc5dd (CHANGES_REQUESTED, P2): RunSkillDoctor empties MANAGED_MCP_CONFIG_PATHS and injects one temporary path, so ignoring the macOS, Linux or Windows location, or all default detection, still passed 15/15. ManagedMcpDefaultLocations answers it. For each documented location alone, a fake filesystem (a real file backs each present state) reports the location absent, present and parsed, present and unparsable, present but unreadable, or a directory, and the full ordered argv is compared with independent literals: the strict flag kept or dropped, the other fences unchanged. A sensitivity test removes each location from the tuple and shows that its present cases then keep --strict-mcp-config while the other locations still decide the form; run_skill_doctor takes the same default route. Thirteen in-memory mutations (each location ignored or misspelled, all detection off, any->all, no readability check, no regular-file check, strict never or always dropped, run_skill_doctor ignoring the default) fail the new class; RunSkillDoctor alone fails three of them. The Windows cases model a host that reports a readable file at the documented string. Whether that string is a location on a POSIX host is the separate P3 (a Windows-shaped filename in the working directory), which stays in its follow-up and narrows these cases to nt hosts. The source comment and the README now record what the pinned client does (2.1.296 binary, sha256 24972e3b..., read 2026-10-10): the refusal applies only to a present file that loads without a read, JSON or schema error (reader at byte 217796118, refusal at 217799919), and its own plugin eval init launcher drops the flag on presence alone (byte 247738504). A test holds the comment and README to that wording. The six added comment lines move the ledger-refusal locator in the pwsh7 decision from 2417-2423 to 2423-2429. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
5 tasks done
seathatflowsinourveins
deleted the
claude/cc-native-practice-skill-doctor-fence-20261009
branch
October 10, 2026 14:03
This was referenced Oct 10, 2026
seathatflowsinourveins
added a commit
that referenced
this pull request
Oct 10, 2026
…967) 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: seathatflowsinourveins <234074349+seathatflowsinourveins@users.noreply.github.com> Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
This was referenced Oct 10, 2026
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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Scope
tools/skill-usage/skill_usage.pynow runs the headless/skill-doctorcall with the headless fences (--permission-mode dontAsk,--permission-prompts none,--tools "",--strict-mcp-config,--max-turns 1,--max-budget-usd 0.05) instead of inheriting the host's permission mode, MCP servers and tools; both CLI help entries and every documented copy of the command say the same, and a test ties each copy to the argv. On a host with a readablemanaged-mcp.jsonthe run drops--strict-mcp-config, because the client refuses that flag there (skill_doctor_argv; a forward commit that answers the Codex review thread on enterprise-managed clients). A third forward commit (715229c72fcb5e4afe7e86969798c7b1e189b21a) tests the three documented locations through that default route, answering the co-op's GPT read of46cc5dd1(CHANGES_REQUESTED, P2).4d345267866403d75edece400fde6cd35ec4d05c(one landing rebase onto it, 2026-10-10: four commits replayed with no conflict, all seven per-file patch-ids unchanged; first opened on22e3ef6ffd53b09f3cb335c46f7c696093521274); three forward commits sit on top of the rebased head940358882b906cb9fcc4df65c8a1c20052f1404d:d7c7ef24ad07a800b1cddd1780e7eb49e1a4d463(the managed-config behaviour),46cc5dd15ff56deb2c2283e739c1a91e4185737d(it removes a platform branch that CI's macOS drift guard flagged) and715229c72fcb5e4afe7e86969798c7b1e189b21a(tests for each documented location through the default route; the source comment and README record what the pinned client checks)lane:foundationtools/skill-usage/skill_usage.py(the argv constant with its sourced comment,skill_doctor_argvand the three documented managed-config paths (all checked on every system, so the module has no platform branch), the call, both CLI help entries built from the constant),tests/test_skill_usage.py(the exact-argv test pins each fence with a literal; new tests tie every documented copy, each help entry, the comment's sources and the Windows decision's locator to the code, and five more cover the managed-config case; the run tests no longer depend on a managed file existing on the host; the new classManagedMcpDefaultLocationstests each documented location through the default route in three tests, and the comment test also holds the pinned-client wording),tools/skill-usage/README.md,adoption/update.mdandblueprints/native-skill-practice/README.md(the documented manual command, now the fenced form, with when to drop--strict-mcp-config),docs/decisions/2026-10-04-pwsh7-windows-guidance.md(one shifted line locator, now 2423-2429),manifests/evidence.json(re-registration). Record Codex native skill-event overturn condition #898 also changes themanifests/evidence.jsonentry fortools/skill-usage/README.md(its text does not overlap), so whichever lands second re-hashes it.Closes the
headless-sdkgap the Claude Code native practice record of 2026-10-09 lists ("two call sites lack fences (skill_usage.py)", #923).SOTA sources
claude --help(the installed clients, read 2026-10-10):--tools("Use "" to disable all tools"),--permission-mode,--permission-prompts,--strict-mcp-config,--max-budget-usd;--max-turnsis accepted but hidden from--helpand documented at https://code.claude.com/docs/en/cli-reference (read 2026-10-09).managed-mcp.jsonholds exclusive control of the MCP servers; "If a user passes it [--strict-mcp-config] while such a file is deployed, Claude Code exits at startup on a workstation and in a cloud session alike"; system paths/Library/Application Support/ClaudeCode/,/etc/claude-code/andC:\Program Files\ClaudeCode\(the configuration summary).24972e3bc859fab2b46ed4c1e51f7d6130f06d3bd550811a114640de3370d0de, 2026-10-10; the co-op's GPT read reached the same offsets independently): the managed-config reader at 217796118, the refusal function at 217799919 (if(!D_())continue,if(rTe()===null){if(n)refuse: only a present file with no read, JSON or schema error), theplugin eval initlauncher at 247738504 (...D_()?[]:["--strict-mcp-config"]: presence alone), andMy()at 209080002, which picks/Library/Application Support/ClaudeCode,C:\Program Files\ClaudeCodeor/etc/claude-codeby platform.docs/harness-rules-convergence-20260922.md): deny anything not pre-approved without prompting, which--permission-mode dontAskwith--permission-prompts nonedoes.dontAskruns only reads and pre-approved tools and denies anything that would prompt (with--tools ""no tool is offered at all); a session with no--permission-modestarts in the settings'permissions.defaultMode, which isbypassPermissionsin this host's user settings.headless-sdk): every fence on the command line for unattended runs.Evidence-class table
b2189ba0) and these return the same table byte for byte (2.1.295: sha256 prefixb8cd3fe63acb; 2.1.296:0d593d5aaa82; 6,086 characters each), allsuccess,total_cost_usd0,num_turns0; the two clients' tables differ from each otherlocal_integrationskill-doctor-paired-receipt-20261010.json, sha256ee0c2ebd0d6e8652463a532a90de3c6e10d8487e93a3d374d59409161db347d4); an earlier unfenced-versus-fenced run on 2.1.295 gave the same table (2026-10-09)measured: true,origin: run, cost 0, 0 turnslocal_integrationpython3 tools/skill-usage/skill_usage.py --run-skill-doctor --out <scratch>--tools Read, an added--dangerously-skip-permissionsand a second--max-turnseach fail the test; each of the other copies (both help entries, the three documents, the module docstring) is tied to the argv by a testlocal_integrationtests.test_skill_usage.RunSkillDoctor.test_runs_exact_argv_with_devnull_stdin_and_timeout,test_every_documented_copy_of_the_command_matches_the_argv,test_each_cli_help_entry_names_the_exact_command,test_the_fence_comment_names_its_sources; mutation runs in a scratch interpretermanaged-mcp.jsonthe argv drops only--strict-mcp-configand keeps every other fence; with none it is unchanged; the client refuses the flag where the file is deployedlocal_integrationfor the drop (a fake managed path),source_reviewfor the client behaviourtests.test_skill_usage.RunSkillDoctor:test_a_deployed_managed_mcp_config_drops_only_the_strict_flag,test_run_skill_doctor_runs_the_managed_form_on_a_managed_host,test_without_a_readable_managed_file_every_fence_stays,test_the_default_paths_are_the_documented_system_paths,test_the_managed_mcp_comment_and_guide_cite_the_client_and_the_docs(all five error on940358882);tests.test_workflow_hardening.MacosPatternsTestspasses at the head; the 2.1.296 binary strings and the docs page above. Not run live: this host has nomanaged-mcp.jsonrun_skill_doctortakes the same routelocal_integration(a fake filesystem for the documented strings, a real file behind each present state)tests.test_skill_usage.ManagedMcpDefaultLocations:test_each_documented_location_decides_the_form_alone,test_dropping_a_locations_detection_fails_its_cases,test_run_skill_doctor_takes_the_default_route(3 tests, 32 cases)anytoall, no readability check, no regular-file check, the strict flag never or always dropped,run_skill_doctorignoring the default) each fail the new class;RunSkillDoctoralone fails three of themlocal_integration(mutation harness, nothing on disk changes)mutations925.pyover the committed tests, table retained in the lane's research record (pr925/mutations-20261010.txt)--strict-mcp-configonly for a present file that loads without error, and its own launcher drops the flag on presence alone, so a readable file drops it here and an absent, unreadable or non-regular file keeps itsource_review(the 2.1.296 binary, offsets above)test_the_managed_mcp_comment_and_guide_cite_the_client_and_the_docsholds the comment and the README to that wordingnthostssource_review46cc5dd1, finding 2docs/decisions/2026-10-04-pwsh7-windows-guidance.mdcites the ledger-path refusal at its new lines 2423-2429 oftools/skill-usage/skill_usage.py, counted by newline (str.splitlines()also breaks at the U+2028 and U+2029 on line 768 and is the wrong counter here)source_reviewtests.test_skill_usagetest_the_windows_decision_cites_the_ledger_refusal_lines, which fails on an inserted line and on the earlier locatorDeclared test contract change
tests.test_skill_usage.RunSkillDoctor.test_runs_exact_argv_with_devnull_stdin_and_timeoutkeeps its exact-argv pin; the pinned argv gains flags and loses none. At the merge base it asserts["claude", "-p", "/skill-doctor", "--output-format", "json"], so that version fails against this head by design (the co-op's pre-cue read: 203 run, 1 failure). The added flags, in order afterjson:--permission-mode dontAsk--permission-prompts none--tools ""--strict-mcp-config--max-turns 1--max-budget-usd 0.05The first five elements are unchanged, and the added flags are six. On a host with a readable
managed-mcp.jsonthe argv has five of them, without--strict-mcp-config(test_a_deployed_managed_mcp_config_drops_only_the_strict_flagpins that literal), because the client refuses the flag there. The test compares the captured argv with a complete literal list, independent ofSKILL_DOCTOR_ARGV(the co-op's read showed that comparing with the constant pinned nothing); an added--tools Read, an added--dangerously-skip-permissionsand a second--max-turnseach fail it.Local commands run
The hosted CI at the first forward commit (
d7c7ef24) failed one test,tests.test_workflow_hardening.MacosPatternsTests.test_drift_guard_every_flagged_file_is_listed_or_excluded, which flagged a platform branch inskill_usage.py; my targeted list had not included it, and the second forward commit removes the branch (the module now checks all three documented paths on every system). The hosted CI that ran before this rebase tested the merge of the earlier head onto the old main (30aa2fa7), where the evidence row fortests/test_local_pages_fleet_regressions.pywas stale (fixed on main by #923); this head is rebuilt on the current main, so the hosted run at this head is the first measurement of the real merge.The co-op's GPT read of
46cc5dd1found thatRunSkillDoctorempties the module's paths and injects one, so ignoring a location or all default detection still passed; the third forward commit answers it with the default-route class and the mutation table above. The local full-suite shards in a CI-like environment are noisy on this host (four of eight red at the CI-green46cc5dd1on tests no change touches), so the commands above are the targeted lists, and the hosted CI at the head is the full-suite measurement.Decision record
No new record: this applies the
headless-sdkdefault of the 2026-10-09 native practice record (#923). The slot's note is updated in the follow-up to that PR once both land.Host evidence
Not applicable: no file under
evidence/hosts/changes.Checklist
permissions: {}and grant each job only what it needs. (none changed)🤖 Generated with Claude Code