Skip to content

feat(runtime): authorized Server Diagnose entry with a CLI provider diagnostic (#994) - #1329

Merged
yyjeqhc merged 2 commits into
yyjeqhc:mainfrom
skygunner:contrib/acp-diagnose-server-entry
Oct 28, 2026
Merged

yyjeqhc merged 2 commits into
yyjeqhc:mainfrom
skygunner:contrib/acp-diagnose-server-entry

Conversation

@skygunner

@skygunner skygunner commented Oct 27, 2026 •

Copy link
Copy Markdown
Contributor

Context

Follow-up to #994 and the merged Runner-side primitive #1129. This implements the remaining scope endorsed by @swjnxyf in the issue thread: the canonical Server/ToolRuntime Diagnose entry first, with a small CLI diagnostic command as its first consumer. No Desktop surface in this round; the same authorized entry is what Desktop can reuse later.

Design notes: docs/design/issue-994-server-diagnose-entry-design.md.

What this adds

diagnose_coding_agent — one canonical Server/ToolRuntime entry (model-visible, next to observe_coding_agent):

  • Static authority identical to observe_coding_agent: OAuth policy Require(coding_agent:run), effect Observe, approval None, idempotency PureRead, Runner capability CodingAgentRuns.
  • The no-spawn presence check and the live probe stay distinct. include_live_acp=true escalates at runtime — before any resolution, observation, or dispatch — to the exact start_coding_agent scope policy (check_runtime_tool_scope) plus a fresh per-Project PermissionEvaluator decision attached to the result. Presence-only never launches a process; observation authority never implies launch authority.
  • Fail-closed resolution order: input validation → live-flag authority gate → Project resolution for the caller → exact Runner semantic view for the caller (coding_agent_runner_unavailable when offline/unauthorized) → current provider generation looked up from the Runner's advertised inventory (never caller-supplied) → typed forwarding through the existing enqueue_coding_agent fence, which independently re-verifies Runner identity, provider generation, online window, and access. Stale identities are rejected with bounded reason codes.
  • Server-side bound re-verification of the Runner response before projection: option/choice counts, identity byte bounds, the stable select|boolean kind vocabulary, the options-only-on-success invariant, and the env-presence map bound. Violations collapse into invalid_runner_response. CODING_AGENT_MAX_ENV_MAPPINGS moves to core and is now shared with the Runner's ACP config validation, so the output schema can never disagree with what was admitted.
  • Bounded 45 s response wait (> the Runner's 30 s probe budget). Projection is project, provider_id, env_presence (booleans only), and live_acp (the bounded typed diagnostic, null unless requested). The provider instance id never crosses to callers, matching safe_provider_inventory.

CLI consumer — webcodex ops diagnose-provider --project <id> --provider <id> [--include-live-acp]:

  • Calls the same authorized Server entry through the existing /api/tools/call bridge with the operator credential (token/env-file precedence shared with the other ops commands). No separate ACP client, no new HTTP endpoint, no self-inspected CLI environment.
  • Renders presence lines (present / ABSENT), live option identities when requested, and an ops verdict (warn for absent env sources — the Windows-propagation case from Support: official ACP Codex model allowlist approval and runner:manage verification #990; fail for bounded server-side failures). --strict maps FAIL to exit 2. Values, provider stderr, instance ids, and credentials never reach the output.

Boundaries preserved (per the review checklist)

  • Exact Runner instance, provider generation, and authorized Project/cwd are resolved and re-verified before forwarding; stale/replaced identities fail closed (stale_coding_agent_provider, stale_coding_agent_project pass through from the Runner fence; the registry independently re-checks).
  • The live probe reuses the Runner-owned ACP lifecycle, deadline/cancellation, one-probe-per-Runner busy contract, and process-tree cleanup from feat(acp): add bounded read-only provider diagnostics (#994) #1129 — no prompts, no provider tools, no configuration writes, no raw stderr, no environment values.
  • No automatic retry anywhere: bounded failures carry reason codes and recovery hints; the CLI surfaces them as an ops verdict.

Tests

New coverage:

  • Authority: live probe refused for coding_agent:run-only and project:write-only tokens (coding_agent_live_probe_authority_required); presence-only needs no start authority; the gate holds through the full dispatch path (router pre-resolution included); restricted authority mode denies the live probe per Project while presence-only stays permission-free.
  • Resolution: unsupported Runner, unadvertised provider with safe inventory + schema-validated recovery suggestion.
  • Response mapping: mismatched provider identity, oversized env map, option/choice/identity bound violations, non-success-with-options, missing payload → closed reason codes; stale-provider failure passthrough.
  • Non-disclosure: projection contains no provider instance id, no environment values, no executable identity; the full success payload validates against the registered output schema.
  • OAuth catalog: diagnose_coding_agent hidden from under-scoped catalogs and kept behind call_runtime_tool like its siblings.
  • CLI: canonical entry call shape (tool name + typed params), presence rendering, FAIL/strict mapping, flag parsing, help.

Suites run on this branch (all green):

Suite Result
cargo test -p webcodex --lib 3833 passed, 0 failed (13 ignored)
cargo test -p webcodex-runner 1188 passed, 0 failed (11 ignored)
cargo test -p webcodex-tool-contracts 342 passed, 0 failed
cargo test -p webcodex-tool-runtime-contracts 61 passed, 0 failed
cargo test -p webcodex-cli 549 passed, 0 failed
cargo fmt --all --check clean
cargo clippy --workspace --all-targets -- -D clippy::correctness exit 0

Out of scope (unchanged)

Desktop "Diagnose" action, real-operator ACP verification against a commercial provider binary, and any change to the #1129 Runner contracts. #994 stays open per the review guidance until the authorized entry and at least one usable surface are verified — this PR is exactly that pairing.

Refs #994. Built on #1129.

…iagnostic

Implements the remaining yyjeqhc#994 scope endorsed in the issue thread: one
canonical Server/ToolRuntime entry that independently authorizes the exact
Runner, provider generation, and authorized Project before forwarding the
typed Runner Diagnose request from yyjeqhc#1129, plus a CLI operator command as
its first consumer.

- diagnose_coding_agent: model-visible runtime tool with observe-level
  static authority (Require(coding_agent:run), PureRead). The optional
  include_live_acp flag escalates at runtime to the exact start_coding_agent
  scope policy plus a fresh per-Project permission decision before any
  provider process is launched; presence-only stays spawn-free.
- Resolution order is fail-closed: validate input, gate the live flag,
  resolve the Project for the caller, require the exact Runner semantic
  view and CodingAgentRuns capability, look up the current provider
  generation from the Runner inventory, then forward through the existing
  enqueue_coding_agent fence (which re-verifies identity, generation,
  online window, and access).
- The Server re-verifies Runner response bounds (option/choice counts,
  identity byte bounds, stable kind vocabulary, options-only-on-success,
  env map bound) before projecting; violations collapse into
  invalid_runner_response. CODING_AGENT_MAX_ENV_MAPPINGS moves to core and
  is shared with the Runner's ACP config validation so the output schema
  can never disagree with what was admitted.
- Projection is project/provider_id/env_presence/live_acp only; the
  provider instance id never crosses to callers.
- CLI: webcodex ops diagnose-provider (--project, --provider,
  --include-live-acp) calls the same entry through the existing
  /api/tools/call bridge and renders presence booleans, live option
  identities, and an ops verdict; values, stderr, and credentials never
  reach the output.

@yyjeqhc yyjeqhc left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed the canonical Server/ToolRuntime Diagnose path and CLI consumer against #994, including the live-probe scope/Project authorization, Runner/provider fencing, bounded response projection, and non-disclosure. Added review commit 47193b0 to fix rustfmt plus live-response mode, bounded environment names, allowlisted current values, and uncertain launch semantics on lost responses. Focused validation: 14 server Diagnose tests and 4 CLI Diagnose tests passed; CI is being verified separately.

@yyjeqhc
yyjeqhc merged commit f69dd40 into yyjeqhc:main Oct 28, 2026
18 checks passed
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.

2 participants