Repository navigation
feat(runnable): a REST read over GET is an operation, and Swagger 2.0 is read as itself - #852
Merged
Merged
Conversation
… is read as itself A solution's tool-worthy routes are its GET reads, and openAPIOperationMethods admitted only POST and PUT. A GET is now admitted as a read only — recompute, a read-only tool, invoke scopes requiring nothing but read — with its query parameters as its input object and its operationId as the recorded input identity. Mutations keep their body, receipt and POST/PUT. ParseOpenAPIDocument reads Swagger 2.0, the dialect solution-runtime-go, protoc-gen-openapiv2 and core's OpenAPICombinator publish, by moving its body parameter, response schemas, consumes/produces and definitions into the OpenAPI 3 places; the same operation in either dialect derives a byte-identical package. DefaultRouteOperation is DefaultOperation's REST twin: the marker an owner writes from a route's authority policy, so it states core's defaults. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…he policy JSON its owner publishes Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…r holds it to being a read HTTPRoute.verb admits GET (Go and Python regenerated through the proto companion; buf.lock untouched). VerifyPrepared refuses a GET whose policy is not a read, the rule the derivation applies. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
antoinetoussaint-byte
added a commit
to codefly-dev/cli
that referenced
this pull request
Oct 27, 2026
…s a module's methods do (#1184) `generate runnables` derives every route a module's OpenAPI contract marks x-codefly-operation through the same location, file and index writers a method goes through (deriveOpenAPIEndpoint / deriveRoute), one directory per route named by its operationId. solution-runtime-go marks each read a solution backend serves, so its GET reads become read-only Runnables whose query is their input. `generate runnable-bindings` prepares them keyed SOLUTION__OPERATION with a rest route; callTarget now calls an http endpoint that publishes OpenAPI exactly as it calls a rest one. Core pinned to the codefly-dev/core#852 head (GET operations, Swagger 2.0, RouteMarker). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
crisfiorini-oss
pushed a commit
to crisfiorini-oss/cli
that referenced
this pull request
Oct 27, 2026
…s a module's methods do (codefly-dev#1184) (codefly-dev#1185) * feat(generate): a solution's routes become Runnables, and so tools, as a module's methods do (codefly-dev#1184) `generate runnables` derives every route a module's OpenAPI contract marks x-codefly-operation through the same location, file and index writers a method goes through (deriveOpenAPIEndpoint / deriveRoute), one directory per route named by its operationId. solution-runtime-go marks each read a solution backend serves, so its GET reads become read-only Runnables whose query is their input. `generate runnable-bindings` prepares them keyed SOLUTION__OPERATION with a rest route; callTarget now calls an http endpoint that publishes OpenAPI exactly as it calls a rest one. Core pinned to the codefly-dev/core#852 head (GET operations, Swagger 2.0, RouteMarker). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * test(generate): gate a solution's committed artifact end to end; name the InterfaceDocument trap TestTheCommittedArtifactBecomesTools runs generate contracts, runnables and runnable-bindings on the releases backend's artifact exactly as solution-runtime-go's Server.InterfaceArtifact renders it. A document that marks no route although its routes declare read-only policies now names each such read as not an operation. Core pinned to 518714d0, core#852's merge commit. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Antoine Toussaint <312536060+antoinetoussaint-byte@users.noreply.github.com> Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
antoinetoussaint-byte
added a commit
to gael-obin/core
that referenced
this pull request
Oct 27, 2026
… clock (codefly-dev#802) Bump version/info.codefly.yaml 0.19.6 → 0.19.7; version-tag.yml cuts the tag from the merged commit once the suite is green. Carries codefly-dev#802 (kern.bootsessionuuid BootID, which service-postgres#199 needs as a release), codefly-dev#806, codefly-dev#820/codefly-dev#821, codefly-dev#824, codefly-dev#829, codefly-dev#830, codefly-dev#835–codefly-dev#852, codefly-dev#856. Agent contract: protocol 1 / startup 2 unchanged; adds the optional operation contract runtime-backend-declaration/v1. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
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.
Summary
First of three PRs for codefly-dev/cli#1184 — every gRPC method of a module and every REST route of a solution becomes a tool by becoming a Runnable. The module half is already automatic; this makes a solution's routes derivable at all.
1. A REST read over GET is an operation.
openAPIOperationMethodsadmitted only POST and PUT ("an operation applies an effect and is retried under a declared policy, which GET and DELETE do not describe"), while the module side already derives read-only operations ("a policy requiring only 'read' derives a read-only tool that is safe to re-run and carries no receipt"). A read is the safest operation to re-run, so GET is now admitted as a read only (readOnlyRoute):RECOVERY_RECOMPUTE, a read-only tool, and invoke scopes requiring nothing butread. Mutations keep their body, their receipt rules (untouched) and POST/PUT; DELETE and PATCH stay refused.queryPayload): one object whose members are itsqueryparameters, each a scalar, optional exactly when the parameter is; a GET with no parameter takes{}. Arrays, objects, nullables, a body, path parameters and path templates are refused by name.input_messageis required by the package schema (min_len: 1). No component describes a query, so a GET records the identity the document publishes it under, itsoperationId; a GET without one is refused. (I chose this over relaxing the validated field, which would be a schema change.)HTTPRoute.verbinproto/codefly/runnable/v0/prepared.protoadmitted only POST/PUT too, so a derived GET could not be prepared. It now admits GET (Go and Python regenerated withcodefly generate proto … --localand--template buf.gen.python.yaml;proto/buf.lockrestored, since onlymake buf-dep-updatemoves it).VerifyPreparedholds a delivered GET binding to the same read rule, so an installer does not trust that a generator applied it.2. Dialect: core reads Swagger 2.0. I took the "core reads what exists" option. Evidence:
solution-runtime-go/operations.goInterfaceDocumentdeliberately renders Swagger 2.0 — "the dialect the platform's proto-generated modules emit, so one reader handles every repository's artifact".OpenAPICombinatorwrites 2.0 (this file's previous comment said so), and protoc-gen-openapiv2 output is 2.0.solutions/{proposals,wiki}/contracts/api/backend/http/openapi.jsonon chore(deps): bump the docker-major group across 2 directories with 2 updates #451) are 2.0, and the CLI's route-policy reader (pkg/methodpolicy) already reads them as they are. Migrating to OpenAPI 3 would churn every solution's committed contract and collide with chore(deps): bump the docker-major group across 2 directories with 2 updates #451, for no change in what the document says.ParseOpenAPIDocumentnow moves what Swagger spells differently — thein: bodyparameter, a response'sschema,consumes/produces, typed parameters,#/definitions/— into the OpenAPI 3 places before anything reads the document (fromSwagger). Every rule after that reads both alike, andTestTheTwoDialectsDeriveOneOperationholds the same operation in both dialects to a byte-identical package. Any otherswaggerversion is still refused by name.3.
DefaultRouteOperationandRouteMarker.DefaultRouteOperation(method, path, authority, audience, name, description)isDefaultOperation's REST twin (core's default bounds,"503"as the HTTP spelling ofUNAVAILABLE).RouteMarker(method, path, policyJSON, …)writes it as thex-codefly-operationmarker from thex-codefly-authority-policyJSON an owner already publishes, byte-stably. That is how solution-runtime-go marks a route without inventing a bound — and without constructing core's wire messages, which its typed-boundary gates refuse in that package. A policy requiring nothing, a mutation over GET or a path template isErrNotDerivable.Classification
Fix at the owner: core owns the derivation, the bounded profile, the prepared-binding schema and the defaults. No stopgap.
Docs
docs/runnable.md(the two-builders table, "The REST reader": GET as a read, its query as input, both dialects),docs/runnable-binding-delivery.md(restcall verbs, the installer's GET rule).Test plan
go test -race ./runnable/... ./internal/ciguard/...— green; the existingTestPackageFromOpenAPIOperationIsByteStabledigest is unchanged.runnable/operation_openapi_route_test.go— dialect drift gate, Swagger held to the same refusals, GET read derivation (/historyquery → input,/recorded→{}), every way a GET is refused,DefaultRouteOperation/RouteMarker(marker round-trips to the hand-written fixture's digest), prepared GET held to being a read. I removed theVerifyPreparedGET guard and watchedTestAPreparedGetIsHeldToBeingAReadfail, then restored it.make buf-lint,make buf-breaking(no breaking change against origin/main), and the Python contract tests with CI's exact command — green."object"(the projection beside it spells it the same way).Not verified
go test ./...of core: I ran./runnable/...,./internal/ciguard/...,./generated/...andgo build ./....pkg/runnable/transport.gobodiedMethods(POST/PUT/PATCH/DELETE), and obin-ai/module-robinrunnable_catalog.go:94skips every binding whose call is not Connect (prepared.GetCall().GetConnect() == nil), andtoolowner/operation.goalways POSTs a Connect procedure. Reported on feat(generate): a solution's routes become Runnables, and so tools, as a module's methods do (#1184) cli#1185; no issue filed without the owner's go-ahead.Order
Merge this first. codefly-dev/solution-runtime-go#77 and codefly-dev/cli#1185 pin this branch's head
d2cf8206, and re-pin to this PR's merge commit before they land (a squash would orphand2cf8206).Part of codefly-dev/cli#1184.
🤖 Generated with Claude Code