docs: the failure shapes a client cannot learn from the routes - #676
Merged
Conversation
Three things a client had to discover by hitting them. All three cost real
debugging time during helm's port, and in two cases the wrong guess had
already shipped before the payload proved it wrong.
An empty `changedFiles` is not always "clean". The list is never absent —
`git` is what is optional — so "not measured" is `git` missing, and the state
that catches people is the third one: `worktree-status.ts` captures git
failures as data (`error?: string`, "NEVER thrown") and leaves the list empty
when it fires. helm-migration.md told clients to derive collisions from that
list and never mentioned `error`, so a client following it would state
confidently that a kild collides with nothing at the exact moment it cannot
tell — feeding a land gate.
`POST /land` answers 409 from two places with different bodies: a refused
merge returns the whole report, and a target `resolveKild` refused returns a
bare `{error, code}`. Both carry `error`, so that field cannot discriminate
them; `wouldMerge` can. A client decoding every 409 as a report throws on the
bare one and replaces a message that names the fix ("address its tree as
'sidebar-observe'") with an opaque decode failure — which makes a
correctly-behaving engine look broken.
The transcript route refuses for an attached agent rather than returning an
empty transcript. `ownership` decides the source, not the fidelity: there is
no pi session behind a harness kild does not own, and empty would assert the
agent had done nothing when the truth is the question has no answer. Also
noted: an assistant turn that only calls tools has `text: ""`, so a renderer
reading `text` alone drops exactly the turns that acted.
No behaviour changes. Each of these is a real distinction the wire makes; the
documentation simply did not make it.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Documentation only — no behaviour changes. Three distinctions the wire makes that the docs did not, all found by helm porting against the merged surface, and in two cases only after the wrong guess had shipped.
An empty
changedFilesis not always "clean"helm-migration.mdtells clients to derivecollidesWithfromgit.changedFilesand never mentionedgit.error. There are three states, not two:gitabsentgitpresent,changedFiles: [], noerrorgitpresent,changedFiles: [],errorsetworktree-status.tscaptures git failures as data (error?: string, documented there as "any git failure captured here, NEVER thrown") and leaves the list empty when that fires. A client following the doc as written would report "collides with nothing" at exactly the moment it cannot tell — and that answer feeds a land gate.The list itself is not optional;
gitis. A client guarding an optionalchangedFilesis guarding a state that never occurs while leaving the real one unguarded.POST /landreturns 409 from two places, with different bodieskildResultStatusmaps every non-not_foundfailure to 409, so an archived or orphaned target answers with a bare{error, code}while a merge that would not apply answers with the entire report — which also contains anerror. That field therefore cannot discriminate them;wouldMergecan.A client decoding every 409 as a report throws on the bare one and replaces a message that names the fix with an opaque decode error:
{ "error": "kild c8971dd5 is archived (its agents are gone) — address its tree as 'sidebar-observe'", "code": "invalid_state" }Losing that makes a correctly-behaving engine look broken. Documented rather than changed: the two really are different kinds of failure, and helm is mid-port against this surface.
The transcript route refuses for an attached agent
ownershipdecides the source, not the fidelity. Refusing is correct — an empty transcript would assert the agent had done nothing, when the truth is the question has no answer for a harness kild does not own. Those agents' history is the kild message log, a different source rather than a thinner view.Also noted: an assistant turn that only calls tools has
text: ""with the calls intoolCalls, so a renderer readingtextalone silently drops precisely the turns that acted.Verification
Every claim was checked against the source rather than transcribed from the report that raised it —
server.ts:907-923andkildResultStatusfor the dual 409,server.ts:257-271for the transcript refusal,worktree-status.tsfor theerrorsemantics.