Skip to content

run: --output-env carries a structured document, naming the run environment its reader derives the key from - #1206

Merged
antoinetoussaint-byte merged 2 commits into
mainfrom
fix/output-env-carries-documents
Oct 28, 2026
Merged

antoinetoussaint-byte merged 2 commits into
mainfrom
fix/output-env-carries-documents

Conversation

@antoinetoussaint-byte

@antoinetoussaint-byte antoinetoussaint-byte commented Oct 27, 2026 •

Copy link
Copy Markdown
Contributor

The bug

platform-core's composition gate fails on 0.1.219 at codefly run … --output-env, first Init:

Runner.Init: cannot write environment variables to file: resources.AppendServiceProcessConfigurationsToFile:
cannot get service process environment variables: configuration document requires origin, name and environment

A configuration document — a workspace group that is one YAML/JSON document rather than key/value pairs — is carried under a key that hashes its origin, its name and the environment (resources.ConfigurationDocumentKey); that is how the SDK finds it again. The two --output-env writers (AppendServiceProcessConfigurationsToFile, AppendEnvironmentVariablesToFile) built their EnvironmentVariableManager without SetEnvironment, so core's carrier refused. The agent's own Init request has always carried the environment, which is why no run without --output-env ever met this.

What surfaced it: the composition root's merged fixture-composition.yaml (codefly generate fixture-composition, #1197) is a root-owned document and so is handed to every service of the run. platform-core#117 (b514028c) added that generation and passes --output-env for saas/auth-gateway; the whole run refused at the first Init. Diagnosed, not inferred: the failing call is runner.go:375 → AppendServiceProcessConfigurationsToFile → core configurationAsEnvironmentVariables(conf, holder.environment.GetName(), …) with a nil holder.environment.

Core's contract is right. A document without its environment is unreadable by the SDK, so inventing an origin in the composition (the question the coordinator asked) would not have worked either; the writer was the owner.

The fix

The writers take the run's environment from the world (runner.world.Env.Proto(), exactly what the Init request carries) and set it on the manager. A writer handed no environment refuses by name before writing anything, instead of failing on the first document with the contract's generic error. Three call sites (Init, Start, excluded root) updated.

Evidence

  • Reproduced on the released 0.1.219, on the gate's shape: a one-module workspace whose root configurations/local/fixture-composition.yaml is the schema line, run service gateway/edge --init-only --output-env … → configuration document requires origin, name and environment, no file written.
  • Same run with this branch: gateway/edge: Stopped cleanly, and the file carries CODEFLY__CONFIGURATION_DOCUMENT_V1__5023386cb168… whose carrier reads "origin":"_workspace_origin","name":"fixture-composition","environment":"local".
  • Tests: the existing output-env test now also hands a root document and asserts the key ConfigurationDocumentKey(workspace, fixture-composition, local) is written and that DecodeConfigurationDocument reads it back for local; a new test proves a writer with no environment refuses by name and leaves no file.
  • go test ./pkg/orchestration/ ./cmd/run/ green; golangci-lint run ./pkg/orchestration/... clean.

Fix or hack

Fix at the owner (the CLI's writer). Goes in v0.1.220 with #1205.

🤖 Generated with Claude Code

Docs (same PR)

docs/commands.md, under codefly run: what --output-env writes (own, runtime, workspace groups; dependencies once at Start after the barrier), its owner-only mode and the secrets in it, and that a structured configuration document is carried under a key hashing origin, name and the selected run environment — the key the SDK derives — for the normal and the excluded-root file alike; a writer handed no environment refuses by name.

…environment its reader derives the key from

A configuration document — a workspace group that is one YAML or JSON document
rather than key/value pairs — is carried under a key that hashes its origin,
its name AND the environment (resources.ConfigurationDocumentKey), which is how
the SDK finds it again. The two --output-env writers built their
EnvironmentVariableManager without SetEnvironment, so core's carrier refused:
"configuration document requires origin, name and environment". The agent's
own Init request has always carried the environment, which is why no run
without --output-env ever met this.

What surfaced it: the composition root's merged fixture-composition.yaml
(`codefly generate fixture-composition`, cli#1197) is a root-owned document
and so is handed to EVERY service of the run; platform-core's composition gate
passes --output-env for saas/auth-gateway and refused at the first Init on
0.1.219 (platform-core#117, b514028c). Reproduced on 0.1.219 with a one-module
workspace carrying a root fixture-composition.yaml; the same run passes with
this change and the file carries the document under
CODEFLY__CONFIGURATION_DOCUMENT_V1__… with origin, name and environment
"local", read back by resources.DecodeConfigurationDocument.

The writers now take the run's environment from the world (runner.world.Env,
as the Init request does) and refuse by name when they are handed none, rather
than failing on the first document with the contract's generic error. Core's
contract is right: a document without its environment is unreadable by the
SDK, so inventing an origin in the composition would not have worked either.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ments are keyed on

Same-PR docs for the writer fix: the file's contents, its owner-only mode and
the secrets in it, the Start-only dependency write, and that a structured
configuration document is carried under a key hashing origin, name and the
selected run environment — the key the SDK derives — for the normal and the
excluded-root file alike.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@antoinetoussaint-byte
antoinetoussaint-byte added this pull request to the merge queue Oct 27, 2026
Merged via the queue into main with commit 616897d Oct 28, 2026
23 of 26 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