Skip to content

fix(cli): pass child flags through and print closed native refusals - #359

Draft
roodboi wants to merge 6 commits into
nextfrom
wf/g1-cli-refusals-b17
Draft

roodboi wants to merge 6 commits into
nextfrom
wf/g1-cli-refusals-b17

Conversation

@roodboi

@roodboi roodboi commented Oct 19, 2026 •

Copy link
Copy Markdown
Contributor

Summary

This fixes four CLI parsing and refusal problems seen on the M3 with v5.0.0-next.5, plus the up --detach message. The branch is rebased onto current next (54cc4c9), which includes #331.

1. Child flags no longer reach Hack's parser

Before: hack run web --profile toolchain bun --version printed Hack's version and exited 0.

Now a positional can be marked passthrough. From the child command's first word on, every token belongs to the child. That includes --version, --help, --json, --path, --branch and any other flag.

  • A leading -- is still optional and is not passed on.
  • A later --, as in hack run web npm test -- --watch, now reaches the child unchanged. Before, it was dropped.
  • Commands marked: run, exec, host exec, env exec, session exec and x.
  • Hack options still work before the child command.
  • findPassthroughStart mirrors the parser, including options with default values.
  • A child --json no longer selects Hack's JSON error envelope. Only argv before the child command and before the first -- counts (hackOwnedArgv). So hack run --profile toolchain web tool --json and hack exec web cat --json print Hack's refusal as one human-readable line. hack --json run web tool --json still prints the envelope.
  • session exec takes its workspace command as one argument. hack session exec ws npm --version now refuses with Unexpected arguments: --version. <command> is one argument; quote the whole command, as in "npm --version". It does not print Hack's version.
  • Help shows hack run [options] <service> [cmd...] plus a one-line note. For session exec the note says to quote the command.
  • docs/reference/cli.md is regenerated, and docs/cli.md describes both rules.

MCP buildRunArgs/buildExecArgs already put -- before the service, so their behavior does not change.

2. Native refusals print one closed line, not a stack

  • The configuration refusal ("…require explicit native support…") is now HackCliError with E_NATIVE_PROJECT_UNSUPPORTED.
  • The HACK_NATIVE_SHARED_SOURCE requirement on up and restart is now E_PERMISSION, and the message says to set it and run again.
  • Malformed native HTTPS selections are now E_CONFIG_INVALID.
  • Native lifecycle preparation, readiness-hook and restart-cleanup failures are now E_LIFECYCLE_FAILED.
  • Native project input refusals are now E_NATIVE_PROJECT_UNSUPPORTED. This covers a service env_file, or a project .env without managed env. Unreviewed route labels are also E_NATIVE_PROJECT_UNSUPPORTED.
  • Branch-host, project-adaptation, AWS-adaptation and fresh-exec-environment refusals are now E_CONFIG_INVALID.
  • Other value-free native refusals are now ClosedCliError: no stack, unless HACK_DEBUG=1. This covers:
    • image-project start (pending restart, retained run changes, a missing relay artifact, HTTPS verification and the HTTPS owner, unconfirmed exit cleanup, source admission)
    • restart preflight
    • one-off run, exec, down, restart and dependency refresh
    • NativePartialShutdownError, NativeHttpsStartupError and NativeHttpsLeaseAcquisitionError
    • the invalid HACK_NATIVE_BINARY/HACK_NATIVE_HOME selection
  • Cancelling a native foreground start no longer reports the configuration-refusal text.

3. A refused run no longer prints the full help

When a handler throws a CliUsageError after parsing has succeeded, Hack now prints the message plus one line: See `hack run --help` for usage. Usage errors found while parsing still print the help. Under --json the output is still one E_USAGE envelope.

4. Authored up with the runtime stopped

  • Status check. After native review and before reservation, an authored start makes one read-only runtime status --json request. A stopped runtime (phase not running, or a dead process) refuses at stage reservation with runtime_not_running. Nothing is retained, so ps stays not_started. An inconclusive reply does not refuse.
  • Cancel during the check. The check treats a failed request as inconclusive, including one that a cancel ended. So the start checks its deadline and cancellation again after the check, before admission.reserve. A Ctrl-C during the check now ends not-started and ps stays not_started. Before this fix it ended retained and ps showed pending.
  • Error report. The CLI reports a stopped-runtime start as E_DOCKER_UNAVAILABLE (as logs already does), with a message for each outcome and the next action. Before, it reported E_STARTUP_INCOMPLETE. This now also covers fix(runtime): preserve authored startup and stopped-runtime causes #331's wrapped form: authored foreground control reports native_graph_foreground with cause runtime_not_running. The serve exit diagnostic now carries that bounded cause code to NativeAuthoredProjectStartError.nativeCauseCode. nativeCodesReportRuntimeNotRunning classifies both forms, as isNativeRuntimeNotRunning does.
  • Why pending can still be correct. The ps pending note and docs/reference/native-authored-commands.md explain the remaining case. When the intent was reserved before the runtime stopped, pending is still correct, because only the owner's cleanup proof may retire that intent.

up --detach on native

  • Image-project up with --detach, --json, --target or service names, and restart with --json, --target or service names, now refuse with a one-line E_USAGE message. (restart has no --detach option, so hack restart --detach is still an argument parse error that prints the help, as before.) It names the option and the supported form: run hack up in the foreground in its own terminal, use hack ps and hack logs from another, and press Ctrl-C to stop it.
  • Authored up --detach keeps E_NATIVE_PROJECT_UNSUPPORTED and now adds the same guidance.

Validation

At head c5b4202, based on next 54cc4c9:

  • bun run --cwd packages/cli typecheck: clean. bun run --cwd packages/cli check: 0 errors and 34 warnings, the same count as on next. Changed files lint clean with Biome.
  • docs:cli-reference is regenerated and is stable on a rerun.
  • Required: tests/integration-ownership.test.ts and tests/cli-spawn-env-isolation.test.ts pass.
  • These 29 files pass together, 486 tests and 0 failures: integration-ownership, cli-spawn-env-isolation, cli-reference-docs, cli-help, cli-closed-error-output, cli-passthrough-argv, cli-command, native-runtime-not-running-cli, native-runtime-preflight, native-authored-command, native-project-observe, native-project-start, native-project-restart, native-runtime-client, native-exec-environment, native-project-input, native-project-routing, native-project-branch, native-project-adaptation, native-aws-environment, native-project-source-preflight, native-exec-stale-env, native-project-process, native-authored-project-process, native-authored-project-restart, native-authored-command-dispatch, mcp, native-project-branch-cli and native-project-down.
  • A broader run of about 45 more CLI and native files that import the changed modules passed, apart from the two failures below.
  • tests/native-authored-project-start.test.ts: 48/48 in one run. Under host load (load average 11–13), another run cascaded through the fixture-settlement guard. The first failing test passed on its own. This is the known flakiness under load, which also happens on unchanged next.

New spawn tests use tests/helpers/private-cli-env.ts, with a private HOME and an isolated Docker client config. No real Docker, HOME or keychain is used.

Mutation proofs. Each fix was reverted, the listed tests failed, and the fix was restored.

Mutation Failing tests
Passthrough boundary disabled in parseCliArgv 47 of 51 in cli-passthrough-argv
runCli reads --json from raw argv again 3 child --json spawn tests
remaining() after the status check removed "cancel during the runtime status check refuses before the startup intent"
Handler usage error prints the full help again handler-hint test, and the spawned native run --profile refusal test
Configuration refusal back to plain Error 3 coded-configuration-refusal cases
Cancel throws the configuration refusal again "a canceled start reports cancellation, not the configuration refusal"
Shared-source refusal back to plain Error "source opt-in and occupied mapping refuse…"
Input, routing, branch, adaptation, AWS, fresh-exec (2 sites), source-admission, restart-preflight and runtime-selection refusals each back to plain Error the coded/closed assertion in each module's test file
Native up --detach refusal removed native-project-observe refusal spawn test, and the up --detach closed-line test
Authored start status check removed "a stopped runtime refuses before the startup intent…"
nativeRuntimeStatusStopped check removed 4 preflight status-reply cases, and the authored start test
Stopped-runtime start mapping removed 2 E_DOCKER_UNAVAILABLE mapping cases
Wrapped-cause mapping reverted to nativeCode === runtime_not_running the native_graph_foreground mapping case
Exit diagnostic drops nativeCauseCode "a runtime that stops during serve keeps the wrapped stopped-runtime cause"
Wrapped branch of nativeCodesReportRuntimeNotRunning removed the carried code-pair test
session exec quoting hint removed the parse test and the spawned session exec test
Text-help passthrough note removed, or single-argument note variant removed cli-help "text help says where a child command's own argv begins"
Authored detach hint removed "a detached native up names the foreground-only contract…"
NativePartialShutdownError back to Error closed-class output test
Dependency-refresh refusal back to Error "a child --version reaches the native one-off…" (stack printed)
Passthrough usage rendering removed cli-reference-docs drift test

Gaps

  • There was no live native VM run. Fake runtime binaries prove the stopped-runtime paths. One answers runtime status the way the Rust status() does for a stopped pool. Another fails serve with native_graph_foreground/runtime_not_running. The status check is advisory: if the runtime stops between the check and serve, the retained-evidence path still applies, and the CLI reports it as E_DOCKER_UNAVAILABLE with the pending explanation.
  • The wrapped cause also reaches the start error when an authored runtime request (rather than the serve process) fails with it. No test covers that request path on its own.
  • tests/native-authored-project-recovery.test.ts has 2 failures ("new no-host death…" and "new no-host recovery retains original bindings…"). They fail the same way on unchanged next on this host.
  • An unquoted session exec command is still a parse-time usage error, so it prints the root help after the quoting hint.
  • dispatch run (Beta, unsupported) was left unchanged.
  • Some other native modules (native-authored-* internals, compose adoption, DNS) still throw plain Error. This PR covers the image-project start, run, exec, down, restart (including its preflight) and dependency-refresh paths, their input/routing/branch/adaptation/AWS steps, and the authored start refusals.

Rework 2

This round fixes the independent verifier's defects at c5b4202.

Refusal classes

Every known, user-reachable refusal on the image-project up, restart, run, exec and ps paths now prints one closed line. The class follows what was refused:

  • Configuration is HackCliError with a stable code:
    • E_CONFIG_INVALID: an unbounded --profile, a malformed HACK_NATIVE_DEPENDENCIES listener selection or private selection file, HACK_NATIVE_ALLOW_HOSTS, a conflicting host-alias selection, an occupied HTTPS port, and a request over the runtime client's input or time budget (a large managed environment or a long startup timeout).
    • E_NATIVE_PROJECT_UNSUPPORTED: a service that sets init other than true with host dependencies, a Compose file outside the project, an active review with no supported service, and runtime metadata whose route labels do not match the reviewed plan.
    • E_PERMISSION: an HTTPS port that needs host permission.
  • Integrity, ownership or change is ClosedCliError. Without --json it prints the message alone. Under --json the code is E_UNEXPECTED, the existing code for a failure whose message is the only detail. This matches the down, exec, one-off and restart refusals from round 1. No existing code says "native state changed or could not be confirmed", and E_CONFIG_INVALID would wrongly tell an agent to fix its configuration. This covers:
    • a saved mapping that is unsafe or owned by another run, and the restart lock;
    • changed review, restore, retained-startup and retained-image selections;
    • invalid cache review and an unverified source publication;
    • HTTPS verification and ownership;
    • an invalid runtime control or exec completion response, and an over-budget output;
    • the finalization, frontend-recovery and cleanup-inspection refusals;
    • the foreground serve process (native-project-process.ts).

Files converted beyond the verifier's list, because they are reachable from the same paths: native-project-network.ts, native-project-host-aliases.ts, native-project-selection.ts, native-runtime-metadata.ts, native-project-finalization.ts, native-project-recovery.ts, native-project-cleanup-command.ts and native-project-process.ts.

The HTTPS port message no longer echoes the port number.

Defects

  1. Native refusal audit. Fixed for every site the verifier listed, plus the files above. The repro HACK_NATIVE_SHARED_SOURCE=1 hack up --profile <300 chars> now prints ERROR: E_CONFIG_INVALID: Native profiles require at most 64 bounded nonempty names. with no stack, and makes no runtime request.

    • New tests/native-refusal-cli.test.ts spawns the source CLI with privateCliEnv and a stub runtime. The stub answers scripted <word> <word> requests and otherwise reports a stopped runtime.
    • It asserts exactly one ERROR: line, no stack frame, no Error: and no help for these sites:
      • native-project-run (profiles, unsafe mapping)
      • native-runtime-client (unparseable reply)
      • native-project-dependencies
      • native-project-review
      • native-project-cache
      • native-project-start (dependency plan)
      • native-project-retained-startup
      • native-project-restore (through a retained up with an acknowledged finalization)
      • native-project-retained-images (through restart)
      • native-project-network
      • the serve process (whose failure the cleanup line reports)
    • A spawn cannot reach native-project-https.ts or native-https-port.ts without a live serve owner. Those refusals are raised in the foreground owner's readiness step, inside NativeHttpsStartupError, or in doctor checks that report a result instead. tests/cli-closed-error-output.test.ts renders their real errors through the top-level handler instead: one line, no stack.
  2. hack dispatch run child argv. Fixed. The command positional is passthrough: true. hack dispatch run --project p bun --version no longer prints Hack's version. Covered by the passthrough parse matrix (8 child-flag cases) and a source-CLI spawn case. docs/cli.md lists dispatch run. docs:cli-reference is unchanged, because Beta commands are not in the reference.

  3. Mutations that survived.

    • (a) Fixed. The preflight test has {phase: "initializing", process_alive: null}, so phase === "stopped" now fails it.
    • (b) Fixed. A new helper, tests/helpers/closed-refusal.ts (expectClosedRefusal and expectCodedRefusal, plus sync forms), asserts the class and code as well as the text. The restart-preflight (admission and the other closed restart refusals), down, exec, one-off, dependency-refresh and interrupted-cleanup tests now use it. A new test covers one-off argument validation.
  4. Integrity refusals in native-project-start.ts. Fixed. The shared configuration refused() is now used only for configuration. Each of these has its own closed message, and none says E_NATIVE_PROJECT_UNSUPPORTED or "cannot admit this configuration":

    • an ensure-image reply that is not a content ID, and an authoritative() receipt mismatch: "could not confirm the runtime image selection / the startup receipt";
    • an invalid dependency_plan_id: "could not confirm the host dependency plan";
    • a retireRemovedMapping owner mismatch: "Native run mapping is owned by another run; it was not removed";
    • a missing HTTPS verification response, or an unparseable redirect: Native HTTPS verification failed (NO_RESPONSE) or (REDIRECT_TARGET_REFUSED), in the same fixed form as the other verification failures, so the cleanup diagnostic keeps them.

    New tests in tests/native-project-start.test.ts cover each one.

  5. up --detach. Fixed. Both paths use nativeForegroundDetachRefusal. Authored up --detach on macOS now refuses with the image project's E_USAGE one-line message, which stands alone instead of trailing the generic sentence. Tests compare the authored refusal with the image refusal (code and full message) for up, and unit tests also pass detach to the authored restart handler directly. The CLI cannot reach that restart case: restart has no --detach option, so hack restart --detach is a parse error that prints the help (correction from verifier round 3). docs/reference/native-authored-commands.md is updated.

Also in scope: a new authored-start test covers the NativeRuntimeRequestError wrapped-cause branch in failedAdmission. The runtime status request fails with native_graph_foreground/runtime_not_running, and the start error keeps both codes at stage reservation.

Remaining plain Error sites (internal invariants)

  • native-runtime-client.ts: an argv shape that fails validExecResponseSelection/validBoundDrainSelection. Callers build these shapes, and no user input selects them. The user-reachable timeout and input bounds are now coded.
  • native-project-process.ts: "Native receipt observation must be synchronous". This is a programming contract on the injected observer.
  • native-project-exec.ts:137 is closed but cannot be reached in practice. Dependency refresh refuses an absent mapping first with its own closed "has not been started" message, so mutating this site survives. It is a defensive check for a removal between refresh and inspection.
  • Out of scope, as in round 1: native-authored-* internals and native-https-owner*. Authored start failures are wrapped by failedAdmission into coded CLI errors. HTTPS owner failures are wrapped by NativeHttpsStartupError, which is closed.

Validation (rework 2)

Head f8e823e, based on c5b4202. f8e823e fixes the six native plan CLI acceptance scripts (scripts/check-native-{env,host,routing,endpoint,process,acquisition}-plan-cli.ts), which run only in the macOS "Config compiler" CI job. On 6ec1ae2 that job failed: the scripts still expected E_NATIVE_PROJECT_UNSUPPORTED for authored up --detach. They now expect E_USAGE on macOS and keep E_NATIVE_PROJECT_UNSUPPORTED elsewhere. After bun run build, all six, check-native-config-import-cli and check-config-compiler-cli pass locally on Bun 1.4.2. All results come from Bun 1.4.2 (mise x bun@1.4.2 -- bun …) unless they say otherwise.

  • bun run --cwd packages/cli typecheck: clean. bun run --cwd packages/cli check: 0 errors and 34 warnings, the same count as next. Every changed file lints clean with Biome.
  • docs:cli-reference was rerun with no change. Beta dispatch is not in the reference.
  • gitleaks 8.30.1 over the 3 branch commits (next..HEAD): no leaks.
  • Full bun run test (1.4.2): 74 failures in a 1h18m run on a host with load average 13–32.
    • 1 was real: the authored-dispatch table still expected the generic up --detach refusal. It is now its own test that expects the shared E_USAGE line on macOS.
    • The other 15 failing files were rerun one at a time with --timeout 60000 and all passed, except native-authored-project-recovery "new no-host death…", the known HACK-1282 failure on next.
    • One 30 s source-bind adoption test also failed in its file rerun and then passed on its own with --timeout 120000.
  • Focused 1.4.2 run: the 31 changed test files plus cli-spawn-env-isolation, integration-ownership, cli-reference-docs, cli-help, native-runtime-not-running-cli and native-project-observe.
    • 608 pass. The 22 failures are the known fixture-settlement cascade in native-authored-project-start under load.
    • That file then passed 49/49 on its own on 1.4.2.
    • cli-spawn-env-isolation passed.
  • Earlier development runs and the mutation proofs below used Bun 1.4.3, the host default, before the 1.4.2 pin was required. The focused 1.4.2 run above repeats every test those mutations use.

Mutation proofs. Each was applied to the source, the listed tests failed, and the source was restored. Every mutation failed at least one test except exec.ts:137 (explained above).

Mutation Failing tests
Runtime client: invalid control response, exec completion, output budget, input/time budget back to Error (4 separate mutations) the spawn unparseable-reply case and the client tests: 2, 1, 1 and 1 tests
native-https-port.ts coded back to Error port test and handler render test
native-project-dependencies.ts coded back to Error 9 dependency, restart and spawn tests
native-project-run.ts mapping refused() / restart lock / profiles back to Error (3 mutations) 3, 1 and 2 tests (each includes the spawn case where one exists)
All closed sites back to Error in review, retained-images, retained-startup, restore, https and cache (6 mutations) 8, 6, 5, 6, 8 and 3 tests (each includes its spawn case where one exists)
Review coded sites back to Error 2 review tests
network, host-aliases, selection, runtime-metadata coded back to Error (4 mutations) 2 (including the spawn case), 1, 1 and 1 tests
finalization, recovery, cleanup-command, process closed back to Error (4 mutations) 6, 5, 1 and 3 tests
restart-preflight admission back to Error admission test
down: 4 sites, each back to Error 4, 4, 1 and 1 tests
exec: identity, argument validation back to Error 4 and 1 tests
one-off: identity, argument validation, not started back to Error 2, 1 and 1 tests
dependency-refresh: identity, not started back to Error 1 and 1 tests
interrupted-cleanup refused() back to Error; NativePartialShutdownError extends Error 4 tests; 2 tests
Each start integrity site back to the configuration refused() (6 mutations) the matching new start test
dispatch run passthrough removed 8 parse cases and the spawn case
Authored detach refusal removed 4 authored-command tests
Preflight phase === "stopped" the initializing case
failedAdmission drops the wrapped cause the new wrapped-cause test

Verifier round 3

Head ead8383, a fast-forward on 4d85f56. An independent verifier found three image-project up refusals that still printed ERROR: Error: … and a stack. next behaves the same way, so these were sites the PR missed, not regressions. Each now prints one closed line.

  1. Image admission (native-project-image-admission.ts). Three cases now print a closed line:
    • A reference the runtime refuses (registry_image), or a service with no image, gives E_NATIVE_PROJECT_UNSUPPORTED with the existing message. The message does not include the reference.
    • A malformed runtime admit-image reply (for example {}) is now a closed integrity error: "Native runtime returned an invalid image admission response; …". Before, it reused the refusal text.
    • A cancel during admission is now a closed "Native image admission was canceled" error. Before, it was reported as a reference refusal.
  2. Prepared base (native-prepared-base.ts). The three invalid HACK_NATIVE_PREPARED_BASE / _STORE selections are now E_CONFIG_INVALID. They still refuse before any runtime request.
  3. Workspace cache (native-workspace-cache.ts). refused() is now E_CONFIG_INVALID, like its sibling adaptation refusals.
  4. restart --detach. This body claimed restart --detach refuses with E_USAGE. restart has no --detach option, so it is a parse error that prints the help, and that is unchanged. The up --detach sections above are corrected.

The new spawn cases are in tests/native-refusal-cli.test.ts. The stub runtime can now also fail a request with a closed stderr code. Each case checks for exactly one ERROR: line, no stack, no Error: , no help, and the runtime calls made:

  • a refused ghcr.io/example/app:1 reference (the output does not contain ghcr.io);
  • a {} admission reply;
  • HACK_NATIVE_PREPARED_BASE=bogus, with no runtime request;
  • an adaptation file {"version":1,"workspaceCache":{"bogus":1}}, which stops after runtime check-project-share.

tests/native-prepared-base.test.ts now asserts the code with expectCodedThrow.

Mutation proofs (Bun 1.4.2). In each case the source was changed as described, the spawn file was rerun, and the source was then restored:

Mutation Failing spawn tests
native-project-image-admission.ts reverted to 4d85f56 refused reference and malformed reply (2), each showing ERROR: Error: …
only malformed() back to a plain Error malformed reply (1)
native-prepared-base.ts reverted to 4d85f56 prepared-base (1)
native-workspace-cache.ts reverted to 4d85f56 workspace cache (1)

Gates on ead8383 (Bun 1.4.2):

  • bun run --cwd packages/cli typecheck is clean. check reports 0 errors and the same 34 warnings. The changed files are formatted with Biome.
  • 495/495 pass across 44 files: every native-project-* and native-runtime-* test file, plus native-prepared-base, native-workspace-cache, native-refusal-cli (16/16), native-selection-refusals, cli-spawn-env-isolation, cli-help and cli-reference-docs.
  • After bun run build and bun run build:config-compiler, all six check-native-*-plan-cli scripts, check-native-config-import-cli and check-config-compiler-cli exit 0.
  • gitleaks 8.30.1 with .gitleaks.toml and --redact found no leaks. The agent sandbox blocks the gitleaks git subcommand, so the scan used gitleaks dir over git log -p --unified=0 origin/next..HEAD (6 commits, about 238 KB).
  • The full bun run test was not rerun this round.

🤖 Generated with Claude Code

roodboi and others added 2 commits October 19, 2026 13:54
Flags after a child command now belong to the child: `hack run web bun
--version` no longer prints Hack's version. Positionals marked
`passthrough` (run, exec, host exec, env exec, session exec, x) end Hack's
option parsing at the child's first word; a leading `--` stays optional and
a later `--` reaches the child unchanged.

Known native refusals print one closed line instead of a stack: the
configuration refusal is E_NATIVE_PROJECT_UNSUPPORTED, the shared-source
grant is E_PERMISSION, and the remaining value-free native start, run,
exec, down and restart refusals are ClosedCliError. Usage refusals thrown
by a handler print the message and a one-line help pointer instead of the
full help. Native up --detach/--json/--target/services refuse by name with
the supported foreground form.

Authored native up checks runtime status before reserving its startup
intent, so a stopped runtime refuses with E_DOCKER_UNAVAILABLE and leaves
ps at not_started instead of pending.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A child `--json` no longer selects Hack's JSON error envelope: only argv
before the passthrough child command and before the first `--` counts.

A cancel or deadline during the authored start's runtime status check now
refuses before the startup intent is reserved, so ps stays not_started.
A start that fails because authored foreground control reports a stopped
runtime wrapped in native_graph_foreground (#331) now reports
E_DOCKER_UNAVAILABLE like the direct runtime_not_running code; the serve
exit diagnostic carries the bounded cause code to the start error.

Native project input and route refusals are E_NATIVE_PROJECT_UNSUPPORTED;
branch, adaptation, AWS and fresh-exec environment refusals are
E_CONFIG_INVALID; source admission and restart preflight refusals are
closed. Each prints one line without a stack.

`session exec` keeps its single quoted command: an unquoted command now
refuses with a hint to quote it, and its help and docs say so.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@roodboi
roodboi force-pushed the wf/g1-cli-refusals-b17 branch from 75e4fe5 to c5b4202 Compare October 19, 2026 18:12
@linear-code

linear-code Bot commented Oct 20, 2026

Copy link
Copy Markdown

HACK-1269

roodboi and others added 4 commits October 20, 2026 09:12
Complete the native refusal audit on the image-project up, restart, run,
exec and ps paths. Configuration refusals carry a stable code
(E_CONFIG_INVALID, E_NATIVE_PROJECT_UNSUPPORTED or E_PERMISSION).
Integrity, ownership and change refusals are closed, so the CLI prints one
line without a stack. Start-time receipt, ownership, dependency-plan and
HTTPS verification failures no longer reuse the configuration refusal.

Mark the dispatch run command as passthrough, so a child --version reaches
the child. Give authored up/restart --detach the image project's one-line
E_USAGE refusal.

Add a CLI spawn test with a stub runtime for representative refusal sites,
class and code assertions for the round-1 conversions, a non-running phase
preflight case, and a failedAdmission wrapped-cause test.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
On macOS, authored up --detach now refuses with the image project's
one-line E_USAGE message. The native plan CLI acceptance scripts expected
E_NATIVE_PROJECT_UNSUPPORTED on every platform; expect E_USAGE on macOS
and keep E_NATIVE_PROJECT_UNSUPPORTED elsewhere.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… refusals

Three image-project `up` refusals still printed `ERROR: Error: ...` with a
stack. They now print one closed line:

- An image reference the runtime refuses (`registry_image`) or an authored
  service without an image is `E_NATIVE_PROJECT_UNSUPPORTED`. A malformed
  `runtime admit-image` reply is a closed integrity error, and a canceled
  admission no longer reports a reference refusal.
- An invalid HACK_NATIVE_PREPARED_BASE / _STORE selection is
  `E_CONFIG_INVALID`.
- An invalid workspace cache layout in HACK_NATIVE_ADAPTATION is
  `E_CONFIG_INVALID`, like its sibling adaptation refusals.

Spawn tests drive each case through the real CLI with a stub runtime.

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

This branch has not been deployed

No deployments
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