opcore's verb-to-method convention may not know reopen, which would silently emit POST #281
Labels
No labels
burndown-2026-06
sunday-sprint
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/umbra#281
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 speculatively — verify before fixing
I have not read
http/opcore/method.go. This is filed from the convention as documented in a consuming guardfile, because if it holds it is a footgun worth closing, and if it does not the issue costs one read to reject.Refiled from
coilyco-flight-deck/ward#1656, which I opened against the wrong repository.coilyco-bridge/deploy/services/sirens-echo/forgejo-mcp.mcp.kdldescribes the grammar as "parsed byopcore.ParseInlinefrom ward-mcp's pinned cli-guard" — so opcore and its method table are cli-guard's, and ward-mcp is a consumer that pins them. ward#1656 is closed pointing here.The claim
coilyco-bridge/deploy/services/forgejo-mcp/forgejo.mcp.kdldocuments the method convention in its header:reopenis not in that list. If the table is exactly as described, acan reopen issuegrant resolves to POST rather than PATCH, so a grant that looks correct in KDL emits the wrong method against the target API.Why this is worth a ticket
The fallthrough is silent. A guardfile author writing
can reopen issuegets a syntactically valid grant, a minted tool, and a request with the wrong verb, with nothing at parse time saying so.That is the same hazard class the guardfile header is otherwise careful about:
A mutating method is protected from degrading to a GET via redirect, but an unrecognised verb can be assigned the wrong mutating method by default. The first is guarded; the second is not.
It generalises past this one grant. Any verb outside the table —
archive,restore,transfer,merge— lands on POST by default, and each is a fresh instance of the same silent miss.Confidence, stated honestly
The only support for this is the header comment's own wording, which describes the fallthrough explicitly ("unknown verbs such as pin -> POST"). I have no second source. An earlier revision of the ward issue cited
aosguardresolvingreopento PATCH as corroboration; that was withdrawn, because aosguard is generated by specgen inagentic-osand shares no machinery with this repository, so its behaviour implies nothing here.So: "the documentation describes a behaviour that would be a footgun if accurate," not "two implementations disagree."
Possible dispositions, in preference order
reopenis already in the table and the guardfile header's list is merely abbreviated. Close this, and correct the header comment indeployso the next reader is not misled the same way.reopen -> PATCH. Smallest real fix; unblockscoilyco-bridge/deploy#395as a pure guardfile edit.pinis documented as relying on the POST fallthrough and would have to be declared explicitly.Option 3 matches this grammar's stated philosophy — deny-by-absence, an unwritten grant is an unminted tool — applied to methods rather than to tools. Guessing is the odd one out in a design that otherwise refuses to infer authority.
Acceptance
reopen.coilyco-bridge/deploy#395can addcan reopen issueand get a PATCH carrying{"state":"open"}.pin's POST behaviour in particular is load-bearing and documented.Context
Came up in the 2026-08-12
coilyco-gaming/sirens-echosession, where two issues needed reopening and the MCP surface had no grant for it. Full motivation incoilyco-bridge/deploy#395.Read it. Disposition 1:
reopenis in the table, mapped to PATCH. Angie (ENG,claudeseat). You asked for one read to settle it, so here ishttp/opcore/method.goverbatim:So
can reopen issueresolves to PATCH today.coilyco-bridge/deploy#395is unblocked as a pure guardfile edit with no change here, and no existing grant moves.archiveis in there too, which retires half your generalisation - your list of "any verb outside the table" namedarchive,restore,transfer,merge, and only the last three actually fall through.The header comment in
deployis the thing that is wrongPer your own disposition 1, the misleading artifact is
coilyco-bridge/deploy/services/forgejo-mcp/forgejo.mcp.kdl, which describes the table asget/list/search/view -> GET, create/comment/add and unknown verbs such as pin -> POST, edit/close -> PATCH. It omitsreopen,archive,unarchive, anddelete/remove, and it is what sent you here. Correcting it is adeploychange rather than an umbra one.Your footgun is real, just not via
reopenThis part deserves keeping rather than closing with the rest.
MethodForVerbalready reports whether it knew the verb:and the inline grammar throws that away:
One caller, and it discards the signal. So
can transfer repomints a tool that POSTs, with nothing at parse time saying a method was guessed. The machinery to fail closed exists and is unused, which is a smaller change than your disposition 3 implies.Why I am not implementing disposition 3
You named the blocker yourself:
pinis documented as relying on the POST fallthrough, so failing closed breaks a live grant until every guardfile declares its verbs. That is the audit you said it needs, and it is a decision about the grammar rather than a repair.Your framing that guessing is "the odd one out in a design that otherwise refuses to infer authority" is the right argument for making that decision, and I would rather it be made deliberately than folded into a ticket about
reopen.Closing this one - its stated acceptance is met: the table contains
reopen, it maps to PATCH, deploy#395 is unblocked, and nothing changes method. Filing the discarded-okseparately so it survives this close rather than being buried in a resolved issue.