Skip to content

fix(web): mint PROVIDER_NOT_FOUND; push refusals reach the caller - #345

Merged
cvince merged 1 commit into
feat/portabilityfrom
claude/provider-not-found-and-exitprompt-audit
Aug 28, 2026
Merged

fix(web): mint PROVIDER_NOT_FOUND; push refusals reach the caller#345
cvince merged 1 commit into
feat/portabilityfrom
claude/provider-not-found-and-exitprompt-audit

Conversation

@cvince

@cvince cvince commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

Two things, one a correction to my own code in #344.

PROVIDER_NOT_FOUND

I used INVALID_FORMAT for an unknown provider. Wrong: that is a not-found condition, not a malformed one, and the remedies differ"pick from the list" versus "correct your syntax". A caller branching on the code cannot tell those apart, and the code is the contract; that is the whole reason we do not parse prose. Minted at the point the condition is first known, alongside the existing not-found family.

push

Found by running commands under --web with no TTY, not by reading them. capy push --web refused with exit 1 and no URL anywhere. It was on nobody's list — not mine, not the audit's.

Both guards now throw into the catch execute() already routes to displayErrorAndExit. push takes no web option and needs none: that function reads web mode itself.

Verified by running:

$ capy push --web        # clean HOME
  exit code: 1
  url line : http://127.0.0.1:60064/s/G5BjAmn9Owi7-uZY9PR3pPqnL85M8tIprJ96XX3qne0

Before this it printed the refusal and nothing else.

Suite

1851 pass, 0 fail. A first run exited 1 on tests/auth/authServiceKeepScreens.test.ts; that file passes in isolation on this tree and a second full run was clean, so it is order-dependent flake rather than this change — the diff touches only push, connect and the code table. Flagging it rather than quietly re-running until green.

Two things, one of them a correction to my own code in #344.

PROVIDER_NOT_FOUND. I used INVALID_FORMAT for an unknown provider, which is
wrong: that is a not-found condition, not a malformed one, and the remedies
differ — "pick from the list" versus "correct your syntax". A caller branching
on the code cannot tell those apart, and the code is the contract; that is the
whole reason we do not parse the prose. Minted at the point the condition is
first known, per the rule KEY_NOT_ON_DEVICE's own comment states, and
alongside the existing not-found family.

push. Found by RUNNING commands under --web with no TTY rather than reading
them: `capy push --web` refused with exit 1 and no URL anywhere. It was on
nobody's list. Both its guards now throw into the catch that execute() already
routes to displayErrorAndExit. push takes no `web` option and needs none —
that function reads web mode itself.

Verified by running, not inferred:

    $ capy push --web        # clean HOME
      exit code: 1
      url line : http://127.0.0.1:60064/s/G5BjAmn9Owi7-uZY9PR3pPqnL85M8tIprJ96XX3qne0

Before this it printed the refusal and nothing else.

Suite: 1851 pass, 0 fail. A first run exited 1 on
tests/auth/authServiceKeepScreens.test.ts; that file passes in isolation on
this tree and a second full run was clean, so it is order-dependent flake,
not this change — the diff touches only push, connect and the code table.
@cvince

cvince commented Aug 28, 2026

Copy link
Copy Markdown
Contributor Author

ExitPromptError audit — answer to "which sites can be reached with no TTY under --web"

Answer: none that I can demonstrate, and I probed rather than read.

What I ran

Every command reachable from a clean HOME, under --web with stdin at /dev/null, fetching the served page so the process exits for a real code rather than being killed:

command exit URL
deploy 1 yes
decrypt 1 yes
branch 1 yes
checkout somebranch 1 yes
redeem serves page yes
byoc serves page yes
kick <email>, org auth path yes
push 1 NO — fixed in this PR
flow cancel <id> 3 NO — see below

Not one exits 0 with no URL. The silent-success class you described is real in shape, but I cannot reach it on any path a clean HOME can produce. The ExitPromptError handlers only fire once an interactive prompt is actually reached, and every command I can invoke refuses at auth or project state before prompting. Reaching them needs a signed-in session with a project — which I cannot construct here.

The site inventory, for when someone can reach them

Three handlings, as you said:

  • exit 0 directly: errorScreen.ts:117, deployTokenCommand.ts:645, index.ts ×2, index-dev.ts ×2, decryptCommand.ts:301
  • rethrow (correct — lets the outer handler decide): kickCommand:44, orgCommand:72
  • pre-empted upstream: capyCommand.ts:686-700, which detects no-TTY before the keypress read. Its comment is right that catching at the read is already too late.

Candidate files where a prompt exists with little or no web-awareness, i.e. where an unguarded read could still fire: githubActionsConnector.ts (4 prompts, 0 web checks), orgCreation.ts, redeemCommand.ts, flowCancelCommand.ts, byocCommand.ts (10 prompts, 1 check), deployCommand.ts (18 prompts, 3 checks). I am not reporting these as defects — a file having no web check does not mean the path is reachable under --web, and tonight has repeatedly shown source sweeps over-report.

One genuine finding I am not fixing unilaterally

capy flow cancel <id> --web exits 3 with no URL. That is not the silent class — it refuses loudly and names the remedy (--yes), which is the correct non-interactive pattern. But under --web the refusal still reaches nobody. Fixing it means deciding whether a refusal that already behaves correctly for a terminal also owes a page. Your call.

capy deploy --web, run again just now

COMMAND:   capy-staging deploy --web
EXIT CODE: 1
URL LINE:  http://127.0.0.1:64892/s/y7W5k7l8HQbcK_YkVbdDSTX1e4hjZIdRIJNULodWCag

Nothing blocks it. That is the 10th run.

@cvince
cvince merged commit 6a7c3a4 into feat/portability Aug 28, 2026
2 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.

1 participant