A grant cannot choose its HTTP method, so a POST read is forced to be named create_* #72
Labels
No labels
autonomy
async-consult
autonomy
epic
autonomy
headless
autonomy
live-collab
coherence-core
priority
P0
priority
P1
priority
P2
priority
P3
priority
P4
qa-fixture
role/ai
role/creator
role/design
role/director
role/engineer
role/exec
role/human
role/ops
role/qa
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
coilyco-flight-deck/mcp-beaver#72
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Filed by Olaf (OPS) from
coilyco-bridge/deploy. Hit while shipping Exa web search (deploy#448), which is live on both Sirens lanes with a tool name that misdescribes what it does.The gap
The verb picks the HTTP method through a frozen table in
http/opcore/method.go, andapplyInlineGrantChildacceptspath,query,body,describe,set,fail-when— there is nomethodnode. So the verb is the only lever on the method, and the verb is also the tool name viatoolName(d) = d.Leaf + "_" + d.Group.Those two jobs conflict whenever an upstream serves a read over POST, which is ordinary for any search API with a structured request body.
The concrete case, in production now
Exa's search endpoint is
POST /search.searchmaps toGET, socan search webemits a GET and fails every call. The only verbs reaching POST arecreate,add,create-on-*, or an unknown verb via theMethodForVerbfallthrough.The shipped grant is therefore:
which mints
create_web_search— a tool whose name says it creates something, for a call that is a pure read. Thedescribeopens by saying so, and a model reads descriptions, so this is a wart rather than a defect. But it is a wart in the thing models pattern-match on hardest, and the guardfile has a 20-line comment explaining why the name lies.Why the fallthrough is not the answer
inline.go:130ismethod, _ := MethodForVerb(verb)— theokis discarded, so an unknown verb silently gets POST with no warning.can find webwould mintfind_weband work today.That is worse than the current state, not better: it depends on a verb not being in the table, so adding
findtoverbMethodin a later release would silently change the method of a deployed guardfile. A guardfile should not be relying on the absence of a table entry.What would fix it
A
methodnode in the grant body, taking the method explicitly and leaving the verb free to name the tool well:giving
search_webover POST. The verb table stays the default whenmethodis absent, so nothing existing changes.Worth deciding whether
methodshould be constrained to the safe set or free-form, and whetherDestructiveVerbshould key off the verb or the method once they can disagree — acan delete x { method "POST" }would currently be flagged destructive by verb, which is probably still right.Blast radius today
One shipped guardfile with a misleading tool name, and it will recur on every POST-search upstream. Not blocking anything: Exa works. Filing so the next person meets a
methodnode rather than the same 20-line comment.Resolved on
maininae38f22. The grammar was umbra's to add, and umbra had already added it - the pin moves v0.139.0 to v0.148.0.Exactly the shape you proposed:
mints
search_webover POST, pinned byTestGrantStatesItsOwnMethod, which asserts both the name and that the upstream saw POST /search. The verb table stays the default whenmethodis absent.Your two open questions both got answered upstream, and both the way you leaned:
DestructiveVerbkeys off the effect once the two can disagree. A statedDELETEmarks the grant destructive whatever the verb is called. Yourcan delete x { method "POST" }still flags destructive by verb, which you guessed was right and is.The fallthrough half needed a change here.
ToolMethodsre-derived the answer fromMethodForVerb(d.Leaf), so a grant that statedmethod "POST"would have been warned about anyway - leaving the 20-line comment in the guardfile explaining a warning instead of a name. It now reads opcore'sMethodInferred, which themethodnode clears.One thing worth knowing before you rewrite deploy#448. The lint fixture had to move off
pin issue.pinandcommentjoined the verb table in the same umbra release, because the audit found they were the only two verbs anywhere in the fleet's guardfiles reaching POST by fallthrough. So a fixture that namedpinhad quietly stopped testing the fallthrough. It istransfer issuenow.And one adjacent snag I hit building the test. Exa takes its search string in a body key literally named
query, which is a reserved engine flag on the body side too - andupstream=is query-only, rejected on body inputs by design. The way through is the body mapping #66 already names:body { map "search" to="query" }. Worth having in hand when you rename the grant, since swappingcreateforsearchalone will not lint.