Skip to content

doctor: resolve the harness credential check on the same AdapterHost as the agent preset check (#1015) - #1018

Open
maxie-agent wants to merge 1 commit into
MakePrisms:mainfrom
maxie-agent:fix/1015-doctor-harness-cred-warn
Open

maxie-agent wants to merge 1 commit into
MakePrisms:mainfrom
maxie-agent:fix/1015-doctor-harness-cred-warn

Conversation

@maxie-agent

Copy link
Copy Markdown
Collaborator

Fixes #1015.

The defect

maxplayer doctor contradicted itself in a single run — on every run, both seats, both versions, including seats that then worked fine:

PASS agent preset — registry resolves: codex (preferred argv0=codex-acp)
WARN harness credential permissions — harness registry did not resolve
     (fix: fix the agent preset check first)

The remedy pointed at a check that had just passed, so the operator had nothing to act on.

Root cause

The issue posed the question as "either the two checks pass different inputs to resolve, or the Host-side resolve fails for a docker-mode seat for a reason the message hides". It is the first one.

The two checks are documented to be one seller_agents::resolve on one config, but they were not given the same inputs:

  • build_checks (doctor.rs:2383) derives let agent_host = AdapterHost::for_sandbox(sandbox.as_ref()) and hands it to check_agent_registry.
  • check_harness_credential_permissions (doctor.rs:1983 on the base) hardcoded AdapterHost::Host and never received that value.

Those differ under [sandbox] mode = "docker", which is exactly what AdapterHost exists to distinguish:

  • Container keeps argv0 bare for the image's PATH and never consults the host PATH — the sandbox Dockerfile bakes the adapters in, so there is nothing to probe.
  • Host resolves argv0 against this machine's PATH and fails fast when it is absent.

A docker seat bakes its adapters into the image and installs nothing host-side. So the preset check resolved via Container and PASSed, while the credential check resolved via Host, got RegistryError::AllFailed, and WARNed — on precisely the seats that were working. That is the every-run, both-seats, both-versions signature in the field report.

Why threading the host through is only half the fix

Under docker the host $HOME credential directory is not the surface in use at all. The job container inherits nothing from the host; the credential arrives through the daemon's own environment or the #647 credential proxy — docs/SELLER-QUICKSTART.md, "An environment credential does not cross the container boundary".

So simply passing agent_host in would have made a docker seat inspect host paths its container cannot read and report PASS on them. That is #715's inspected-the-wrong-directory-and-passed defect, arrived at from the container side. The docker arm therefore reports what it is and measures nothing.

Changes

  • check_harness_credential_permissions takes host: AdapterHost and resolves with it. build_checks passes the same value the preset check gets, so the contradiction cannot recur by construction.

  • New Status::Skip (SKIP) for not applicable / not verified. Non-blocking exactly like Warnexit_code and readiness_ok still gate on Fail alone — but distinct from Pass in the report, and rendered (why: …) rather than (fix: …), because a skip has nothing to repair. Counted separately from warnings in both summary lines.

    This is the "skip cleanly" the issue asked for, done without letting a skip read as a clean bill of health: a check that inspected nothing has not passed, and saying PASS would be the doctor: permission checks stop at MAXPLAYER_HOME and never look at the harness credential directory #715 failure mode in reverse.

  • Docker seats skip with a line that states plainly that it makes no claim about the credential the jobs actually use, and that it does not inspect the host files [sandbox.codex_chatgpt] and [[sandbox.file_credentials]] read when those are configured. Those are real host-side credential surfaces under docker; this check does not cover them and does not pretend to.

  • The resolve-failure arm carries the real resolver error. With identical inputs this arm now implies the preset check failed too and has already told the operator what to repair, so the message never again cross-references a check that passed.

What is deliberately unchanged

Real credential-permission findings are preserved exactly:

  • group/world-writable credential directories and settings.json still WARN with their chmod go-w remedy;
  • an unlinked harness (no credential directory at any known location) still WARNs with its remedy, including when an unresolvable label rides along in the same result — only the unresolvable-label-alone case became a skip. Downgrading the unlinked finding too would bury a real finding behind the new label, which is this issue's defect inverted.

Tests

Five regression tests, each red on the base:

Test Holds
docker_seat_does_not_get_a_pass_and_a_did_not_resolve_warn_in_one_run The reported defect. Uses a built-in preset with no [agents] override so the real resolver runs; deterministic on CI, where claude-agent-acp is absent.
both_checks_agree_about_whether_the_registry_resolved The invariant, as a property over both AdapterHost values.
a_docker_seat_does_not_inspect_host_credential_directories_but_a_host_seat_still_does One 0777 ~/.claude, two hosts, two individually correct verdicts. Red in both directions: inspect host paths under docker and the skip assertions go red; silence the check for everyone and the Host WARN goes red.
a_skip_is_reported_distinctly_and_blocks_nothing SKIP is a reporting distinction, not a severity — visible in output, no effect on exit code or the boot gate.
existing harness_credential_check_absent_directory_is_warn_not_silent_skip Kept asserting Warn, with a comment on why it must not be swept into Skip.

Verified with cargo test -p maxplayer --no-default-features --features wallet,acp: 204 unit + 19 integration tests pass, 0 failures; the doctor module is 85 passed / 0 failed.

Scope

Touches one file, crates/maxplayer/src/doctor.rs. No overlap with #1013 (probe naming) or #996 (sandbox). Does not revisit #689, and does not address #770 (credential check PASSing on a still-writable surface), which is a different defect in the same check.

⚠️ Please do not merge or enable auto-merge — opened for team review.

…as the agent preset check (MakePrisms#1015)

`maxplayer doctor` contradicted itself in a single run, on every run, on both
seats and both versions, including seats that then worked fine:

    PASS agent preset — registry resolves: codex (preferred argv0=codex-acp)
    WARN harness credential permissions — harness registry did not resolve
         (fix: fix the agent preset check first)

The remedy named a check that had just passed, so the operator had nothing to
act on.

Root cause: the two checks are documented to be one `seller_agents::resolve` on
one config, but they were NOT given the same inputs. `build_checks` derives
`AdapterHost::for_sandbox(sandbox)` and hands it to `check_agent_registry`;
`check_harness_credential_permissions` hardcoded `AdapterHost::Host` and never
received it. Under `[sandbox] mode = "docker"` those differ: `Container` keeps
argv0 bare for the image's PATH and never consults the host, while `Host`
requires the adapter on THIS machine's PATH. A docker seat bakes its adapters
into the sandbox image and installs nothing host-side, so the preset check
resolved and passed while the credential check took the Err arm — on precisely
the seats that were working.

Threading the host through is only half of it. Under docker the host `$HOME`
credential directory is not the surface in use at all: the job container
inherits nothing, and the credential arrives through the daemon's environment
or the MakePrisms#647 proxy (docs/SELLER-QUICKSTART.md, "An environment credential does
not cross the container boundary"). Inspecting host paths for a docker seat and
reporting PASS would be MakePrisms#715's inspected-the-wrong-directory-and-passed defect
arrived at from the container side, so the docker arm reports what it is and
measures nothing.

- `check_harness_credential_permissions` takes `host: AdapterHost` and resolves
  with it; `build_checks` passes the same value the preset check gets.
- New `Status::Skip` (`SKIP`) for not applicable / not verified: non-blocking
  like `Warn`, distinct from `Pass` in the report, and rendered `(why: …)`
  rather than `(fix: …)` because a skip has nothing to repair. Counted
  separately from warnings in both summary lines.
- Docker seats skip with a line that states it makes no claim about the
  credential the jobs actually use, and does not cover the host files
  `[sandbox.codex_chatgpt]` / `[[sandbox.file_credentials]]` read.
- The Err arm carries the real resolver error instead of the circular remedy.
- Real findings are untouched: group/world-writable directories and
  `settings.json` still WARN with their remedy, and an unlinked harness still
  WARNs even when an unresolvable label rides along with it.

Regression tests (each red on the base):
- `docker_seat_does_not_get_a_pass_and_a_did_not_resolve_warn_in_one_run` —
  the reported defect, reproduced on a built-in preset so the real resolver runs.
- `both_checks_agree_about_whether_the_registry_resolved` — the invariant, over
  both hosts.
- `a_docker_seat_does_not_inspect_host_credential_directories_but_a_host_seat_still_does`
  — one 0777 directory, two hosts, two individually correct verdicts; red in
  both directions.
- `a_skip_is_reported_distinctly_and_blocks_nothing` — SKIP is a reporting
  distinction, not a severity.
@vercel

vercel Bot commented Sep 17, 2026

Copy link
Copy Markdown

@maxie-agent is attempting to deploy a commit to the MakePrisms Team on Vercel.

A member of the Team first needs to authorize it.

@vercel

vercel Bot commented Sep 17, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
mobee Ready Ready Preview Sep 17, 2026 7:09pm UTC

Request Review

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

doctor: harness credential check WARNs 'fix the agent preset check first' while the agent preset check PASSes

1 participant