Skip to content

feat: same refusal code and detail on CLI and MCP, blocking-assets lookup, named change-log actor - #907

Merged
JArmandoAnaya merged 1 commit into
mainfrom
feat/surface-error-and-actor-parity
Oct 9, 2026
Merged

JArmandoAnaya merged 1 commit into
mainfrom
feat/surface-error-and-actor-parity

Conversation

@JArmandoAnaya

Copy link
Copy Markdown
Contributor

What

A refusal now says the same thing on every surface, the assets that block a schema change can be listed from the CLI and MCP, and the dataset change log names the surface that made each change.

  • Refusal code and detail: the kernel owns the error code and the plain-data detail (kernel/error_codes.py); the server keeps only the HTTP status and Retry-After. REST bodies are unchanged. MCP errors now carry code and detail. Under --json, a CLI refusal prints {"error": {"code", "message", "detail"}} on stdout (it printed nothing before); the message stays on stderr and the exit code stays 1.
  • Blocking assets: new MCP tool list_blocking_assets and CLI command visionset schema blocking-assets, the counterparts of POST /projects/{id}/schema/blocking-assets, with paging and a wire projection. The tool count in the docs is now 61 offered by default and 65 in all.
  • Change-log actor: one DatasetActor definition in the kernel (rest, cli, mcp). REST now writes rest where it wrote null. A direct SDK call that passes no actor still writes null, and existing rows are unchanged.

Addresses findings 1, 4 and 5 of #884; the rest of that tracker is untouched.

Notes for review

  • The detail builder reproduces the REST bodies exactly; the existing tests that pin the code table and the docs table still apply, and a new test compares the kernel's detail with the server's response models.
  • The CLI records --json in a context variable that is reset at the start of every invocation, so a usage error cannot leak it into the next command.
  • No credential is written to the log: REST has no token identity (the auth port answers yes or no), so the actor names the surface, not a person.
  • On CLI and MCP the message is the full error text; REST still sends only the reason for a media error.
  • export --check --json prints its report inside opened_workspace; if closing the workspace raised a refusal there, stdout would carry a second document. No current path does.

Verification

  • tests/kernel, tests/server, tests/mcp, tests/cli, tests/architecture, tests/examples on the rebased branch: 3957 passed, 14 skipped.
  • Full Python suite on both halves of the inference matrix before the rebase: 4966 passed with local-inference, 4960 passed without; mypy src/visionset clean on a base install.
  • ruff check and ruff format --check clean; the four import contracts kept; scripts/export_mcp_tools.py --check passes; the docs link and sidebar tests pass.
  • CI and the browser suites were not run locally.

…e blocking-assets lookup, name the actor

- kernel: own the error code and detail mapping in kernel/error_codes.py; the
  server keeps only the HTTP status and retry-after, REST bodies are unchanged
- mcp: the error envelope carries code and detail
- cli: a refusal under --json prints {error: {code, message, detail}} on stdout
- mcp, cli: list_blocking_assets and 'schema blocking-assets' for the assets
  that stop a schema change
- datasets: the change log names the surface that made the change (rest, cli,
  mcp) from one definition
@JArmandoAnaya
JArmandoAnaya merged commit 5514d2e into main Oct 9, 2026
31 checks passed
@JArmandoAnaya
JArmandoAnaya deleted the feat/surface-error-and-actor-parity branch October 9, 2026 18:38
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.

1 participant