Skip to content

feat: a scaffolded solution serves a route, and ships the document that says so - #3

Merged
antoinetoussaint-byte merged 2 commits into
mainfrom
feat/base-serves-an-operation
Oct 29, 2026
Merged

antoinetoussaint-byte merged 2 commits into
mainfrom
feat/base-serves-an-operation

Conversation

@antoinetoussaint-byte

Copy link
Copy Markdown
Contributor

base/operations.go returned nil, so every solution this agent scaffolds served nothing of its own. The owner's bar is: create a solution with the CLI, then run it against the local dev authority — and an inert backend makes that unprovable.

What it serves

One documented route, GET /v1/<id>/overview, answering the solution's id and the as name of every module it relays.

The answer is derived from consumed() — the declarations the runtime actually booted with — not from constants. That is the point: a page rendering it has proven the whole path (host mounts the remote, edge routes /v1/<id>, the authority checks the viewer's Work Context against the policy, the runtime dispatches). A fixed string renders identically with nothing behind it and proves none of that.

Its policy is solution.Requires(solutionID+".page", "read") — exactly the scope_ceiling and installer role codefly add solution writes for that name (codefly-dev/cli#1216), so the two halves interlock: the CLI declares the vocabulary, the route requires it.

The bug it exposed

writeInterfaceArtifact rendered the interface document from a server with no operations registered. That was invisible while base served none; with one route, a scaffolded tree shipped a document saying it serves nothing while its code served /v1/<id>/overview.

Not cosmetic: the CLI publishes that document as the http endpoint's contract and the authority derives its route checks from it (cli#1104), so a served route missing from it is a route the authority was never told to check. The scaffolded tree's own TestInterfaceArtifactIsCurrent caught it.

scaffoldedOperations declares the routes in the agent module so they can be rendered without compiling the scaffolded tree — base/ is a separate Go module. The duplication is guarded: TestBaseInterfaceDocumentIsTheRuntimesRender renders this declaration and compares it byte for byte against base/openapi/api.swagger.json, which base's own go generate produces from base/operations.go.

The alternative, and why not here

Delete writeInterfaceArtifact and template base's rendered document instead — one mechanism rather than two, and the recorded objection ("the template's bytes are not the renderer's") stops holding once base's copy is the renderer's output. It needs a Codefly-base → {{ .OperationPrefix }} replacement for the operationId, and it touches builder.go, scaffold_test.go, base_test.go and the generation ignores. Better shape, separate change.

Verified

go test ./... green at the root, including TestBaseCompilesAndPassesItsOwnSuite, TestFactoryTemplatesAreGeneratedFromBase, TestAScaffoldedSolutionBuildsAndPassesItsOwnGates and the shape tests.

Not verified

No scaffolded backend has been booted from this branch yet. That is the next step and the owner's actual bar — scaffold with the CLI, run against the local dev authority — and it needs a release of this agent first.

Note: base/'s own TestTheGeneratedConsumptionMatchesTheManifest fails on a bare clone because it reads ../../solution.codefly.yaml; that is pre-existing and reproduces on an unmodified branch.

🤖 Generated with Claude Code

antoinetoussaint-byte and others added 2 commits October 28, 2026 22:19
base/operations.go returned nil, so a scaffolded solution served nothing
and its page could show nothing — correct-looking and inert.

overviewOperation is one route with a required policy on this solution's
own kind (solutionID + ".page", which is exactly the scope_ceiling and
installer role `codefly add solution` writes, cli#1216), answering from
the DECLARATIONS the runtime booted with rather than from constants, so
a page that renders it has proven the whole path: host mounts the
remote, edge routes /v1/<id>, authority checks the viewer against the
policy, runtime dispatches.

INCOMPLETE — pushing the diagnosis with the change.

Adding any operation to base/ breaks the agent's "a scaffolded tree's
first interface document is already current" guarantee:
writeInterfaceArtifact (scaffold.go:216) renders from
solution.New(Manifest{...}) with NO operations registered, so the
committed document has "paths": {} while the scaffolded code serves
/v1/<id>/overview. Two tests catch it, both now red:

  TestBaseInterfaceDocumentIsTheRuntimesRender
  TestAScaffoldedSolutionBuildsAndPassesItsOwnGates
      -> notes/backend: TestInterfaceArtifactIsCurrent

See the PR discussion for the two ways to close it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
base/operations.go now serves one route, so the interface document the
agent writes at Create had to list it — and did not. writeInterfaceArtifact
rendered from a server with NO operations registered, so a scaffolded tree
shipped a document saying it serves nothing while its code served
/v1/<id>/overview.

That is not cosmetic. The CLI publishes this document as the http
endpoint's contract and the authority derives its route checks from it
(cli#1104), so a served route missing from it is a route the authority
was never told to check. The scaffolded tree's own
TestInterfaceArtifactIsCurrent caught it, which is how it was found.

scaffoldedOperations declares the routes in THIS module so they can be
rendered without compiling the scaffolded tree — base/ is a different Go
module and cannot be imported from here. The duplication is tolerable
only because the drift is guarded:
TestBaseInterfaceDocumentIsTheRuntimesRender renders this declaration and
compares it byte for byte against base/openapi/api.swagger.json, which
base's own `go generate` produces from base/operations.go. Change one and
not the other and that test fails.

The alternative was to delete writeInterfaceArtifact and template base's
rendered document instead — one mechanism rather than two. It is the
better shape and it touches builder.go, scaffold_test.go, base_test.go
and the generation ignores, so it is not this change.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@antoinetoussaint-byte
antoinetoussaint-byte force-pushed the feat/base-serves-an-operation branch from adb8786 to a9d855e Compare October 29, 2026 02:20
@antoinetoussaint-byte
antoinetoussaint-byte merged commit 5000777 into main Oct 29, 2026
2 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