Skip to content

An answer with no code says whether waiting will help - #112

Merged
enesismail merged 1 commit into
mainfrom
an-answer-that-can-clear-says-wait
Oct 10, 2026
Merged

enesismail merged 1 commit into
mainfrom
an-answer-that-can-clear-says-wait

Conversation

@enesismail

Copy link
Copy Markdown
Contributor

What this changes

A refusal whose body is not the wire envelope carries no code. The service's own handlers always write the envelope, so such an answer came from somewhere else: a proxy in front of the service while it restarts, a router answering for a route or method it does not serve, a captive portal, or a CURIOUS_API_URL pointing elsewhere.

Until now it was answered as a code this build does not know. It gave up, said "Updating curious may help: this build may be older than the server.", and quoted the client's own "could not parse" sentence as if the server had written it. A proxy's 502 passes on its own, and updating changes nothing about it.

Each of the six handler switches now meets the empty code in a case "": of its own. The HTTP status decides between two new failure ids:

id action status
server-error-unexplained Wait any 5xx, and 408, 425, 429
server-request-unserved GiveUp every other status, including a redirect, which curious never follows

Neither answer quotes anything, and neither claims the build is older or newer than the server. Both show the HTTP status. The GiveUp answer names CURIOUS_API_URL and anything in between as the things to check.

Each site says what it can and cannot tell about what had already happened:

site Wait GiveUp
capacity check, create nothing has been uploaded or deployed same
login a code already entered may be spent; start the login again nothing added
publish the deploy may or may not have got an address, with its id same
start the build may be running anyway nothing added
build log curious cannot tell whether the build is still running the build itself is not affected

The build log also gains a case for internal: server-fault, Wait, and the server's message quoted, in the shape of the start's own internal case. Two comments that said a refusal "will say the same thing next time" now say only that a refusal stops rather than reconnects.

unrecognisedAnswer loses its empty-code branch, and its guard exception goes with it. catalog.json and the README gain the two ids, and server-fault gains a build-log line.

The guards

  • TestEveryCodeSwitchAnswersAnAnswerWithNoCode (new, beside the dispatch guard). Every handler switch over wire.ErrorCode must have a case "": that names the empty code alone. Every return in that case must be one of the two new answers, and the case must reach both.
  • The failure-contract checker requires a verified summary for both helpers. The census lists both.
  • The settings guard requires a setting named in a failure's next-step words to be named in its Why. So the GiveUp Why says "The address comes from CURIOUS_API_URL." Both Whys are constants at the construction, so that guard can see them.

Rows

New, each red on main first:

  • TestACodelessAnswerThatCanClearSaysWait: a 502 at all six handlers.
  • TestACodelessAnswerThatCannotClearGivesUp: a 404 at all six handlers, and a 307 at the capacity check.
  • TestTheStatusDecidesWhetherACodelessAnswerCanClear: at the create, 408, 425, 429 and 500 take Wait; 302, 405, 409 and 499 take GiveUp.
  • TestACodelessAnswerAtTheCapacityCheckIsRetriedThenSaysWait: over httptest. An empty 502 takes 3 attempts; a text/plain 405 takes 1.
  • TestACodelessAnswerAtTheLoginStopsAndSaysWait: an empty 502 through LoginStart and LoginVerify, over httptest.
  • TestALoginRefusalWithNoCodeIsRenderedAsTheFailure: both MCP login tools render the failure, not the "can be recovered from" answer.
  • TestTheBuildLogsInternalSaysWait: a full deploy whose build log is refused with a 500 internal.
  • TestEveryCodeSwitchAnswersAnAnswerWithNoCode: the guard row above.

A control, green on both trees: TestTheBuildLogsRateLimitStaysWithTheSharedAnswer.

Existing rows edited:

  • TestAnAnswerWithNoCodeIsNotSaidToHaveOne. It pinned the old Why and that the client's sentence was quoted. It now asserts the reverse.
  • TestACodelessAnswerThatCannotClearGivesUp, after its red. Its expected Why gained the CURIOUS_API_URL sentence the settings guard requires.

The test servers can now send a refusal with no envelope. It is honoured everywhere a scripted answer is written or checked. The build-log server can refuse before it streams.

Required mutations, each run and reverted:

  • delete the six case "": clauses: every code-less row reds;
  • delete the build log's internal case: its row reds;
  • the status predicate always "clears": the GiveUp rows red;
  • it never "clears": the Wait rows red;
  • delete one case "":: the guard reds.

Not changed

  • Any other known code's copy, including rate_limited and unauthorized on the build log.
  • Reconnecting on a code-less answer at the build log.
  • The waitlist signup.
  • MCP deploy_status.
  • No release.

A refusal whose body is not the wire envelope carries no code. The
service's own handlers always write the envelope, so such an answer came
from something else: a proxy in front of the service while it restarts,
a router answering for a route it does not serve, a captive portal, or an
address that points elsewhere. It was answered as a code this build does
not know: it gave up, said updating curious may help, and quoted the
client's own "could not parse" sentence as the server's words.

Each of the six handler switches now meets the empty code in a case of
its own, and the HTTP status decides between two new answers:

- server-error-unexplained (Wait) for any 5xx, 408, 425 and 429, which
  pass on their own;
- server-request-unserved (GiveUp) for every other status, including a
  redirect, which curious never follows. It says what to check.

Neither quotes anything or claims the build is older or newer than the
server. Each site says what it can and cannot tell about what had
already happened: a publish or a start may have been acted on, a login
code may be spent, and a build log answered this way may mean the build
ended with the service.

The build log also gains a case for internal, the server's own fault
while reading the deploy: server-fault, Wait, the message quoted.

The dispatch guard now requires every handler switch to answer the empty
code with the two new answers, and the shared answer's own empty-code
branch and its exception are gone. The catalog and the README move with
the ids. The test servers gain a refusal with no envelope, honoured
everywhere a scripted answer is written or tested, and the build-log
server can refuse before it streams.
@enesismail
enesismail added this pull request to the merge queue Oct 10, 2026
Merged via the queue into main with commit e9d0280 Oct 10, 2026
13 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