Repository navigation
Every runtime loads every module, so planning can call file and platform immediately #563
Description
Epic: #530
2.4-hermeticity-guarantees.md opens with the guarantee:
Graph planning must be hermetic: given the same inputs, it produces the same graph, on any machine, every
time.
Planning does not currently have that property, and the mechanism intended to give it is present but defeated
at every call site.
Every runtime is handed the whole registry
RuntimeEnvironmentSpec.WithModules selects which providers a starlarkbridge.Runtime exposes as immediate
Starlark globals. Its own doc comment (pkg/op/runtime_environment.go:843) shows the intended shape -- a
curated subset:
WithModules(op.ReceiverRegistry().ModuleByName("file"), op.ReceiverRegistry().ModuleByName("json")).All three callers pass everything instead:
cmd/lore/lore/builder.go:111 WithModules(op.ReceiverRegistry().Modules()...)
cmd/devlore-test/devloretest/runner.go:266 WithModules(receiverRegistry.Modules()...)
cmd/star/star/application.go:80 WithModules(registry.Modules()...)builder.go:111 is the planning environment -- the one whose own comment reads "One shared
[op.RuntimeEnvironment] backs the whole build".
What that exposes at plan time
Modules() returns only RoleModule providers, so the planned-only set (shell, git, pkg, encryption,
archive, service, appnet, elevator, flow, function, powershell) is genuinely absent from immediate scope. That
part works.
What every runtime does receive is {file, json, platform, regex, template, yaml, plan, ui}. Two of those are
machine-dependent:
file-- 2.4 names it directly: "Planning currently reads secondary artifacts through ambient filesystem
access (RootReaderdelegates to liveos.*). This violates hermeticity in two ways."platform-- reading the host at plan time makes the graph depend on the machine that planned it, which
is the property 2.4 exists to guarantee against.
So the violation is reachable from the authoring surface today, not pending.
The annotation cannot express the rule
+devlore:access=[planned|immediate|both] is a property of the provider. Hermeticity is a property of the
evaluation:
| Provider | In star |
While planning |
|---|---|---|
file |
correct -- the utility should read files | hermeticity violation |
platform |
correct -- the utility should report the host | hermeticity violation |
One provider, two verdicts, decided by which runtime is asking. No per-provider annotation can say that, which
is why disciplined annotation use cannot deliver the guarantee -- and why adding a fourth annotation value would
repeat the mistake by encoding a context property on the provider.
Per-runtime module selection is the only mechanism that can state the rule, and it already exists. It is
simply never used: WithModules(registry.Modules()...) reads like a default and functions as an opt-out.
What a fix has to decide
- Which subset is hermetic.
json,regexandtemplateare pure.planis the planning surface itself.
fileandplatformare the violations.uiis the interesting one -- it prompts a human, so a plan
that branches on an answer is machine- and moment-dependent in a different way, and whether that is permitted
at plan time is a real question rather than an oversight. - How the subset is expressed. A hand-maintained list in the planning path, or a derived property. Note
that "derived from a new annotation" recreates the problem above. - Whether
starchanges at all. It should not -- it is a utility, hermeticity is not its guarantee, and
its call is correct as written. Only the planning path is wrong. - What
devlore-test's runner should do. It executes fixtures rather than planning packages, so it likely
followsstarrather than the planning path -- but that is a decision, since some fixtures build graphs.
How this was found
While asking why shell is annotated access=planned. The annotation turns out to be correct and deliberate --
it keeps a machine-dependent provider out of planning -- but tracing it surfaced that the providers which are
immediate reach the planning runtime unfiltered.
Related: test_imm_shell.star asserts immediate shell execution, contradicts both the annotation and 2.4, and
is executed by no test. test_imm_file.star and test_imm_file_join_variadic_error.star are orphans too.
Filed separately.
Activity
docs: classify provider methods, and run the fixture that proves why (#…
refactor(fsroot): delete the unconfined variants (#573)