Expand description
Server-side {workspace_root} expansion for declared action bodies (#139).
{workspace_root} expansion — for declared action bodies, and for the
path-valued settings of a worker document’s harness section.
The two consumers differ in one way that matters and are otherwise the same
act. A declared BODY is a command string that gets parsed into an argv, so
the splice must not change how it parses (WorkspaceRoot::expand). A
harness SETTING is one whole path that nothing parses, so those rules do not
apply to it and are not imposed on it (WorkspaceRoot::expand_setting);
what does apply is the root being resolvable, absolute, spellable and
spawnable. Both read the ONE resolved root, so a body and a setting in the
same document can never disagree about where this box’s workspaces live.
A declared body runs with its environment cleared to PATH only, so it
cannot expand ~ or read a variable to learn where session workspaces
live. The workflow’s start inputs cannot carry the location either — the
operator’s start contract is deliberately minimal, and the workspace root
is a property of the SERVER, not of any one run. The server therefore
states it: a declared command may carry the literal placeholder
WORKSPACE_ROOT_PLACEHOLDER, and the dispatch path replaces every
occurrence with the server’s own workspace root before the command is
parsed.
The root is the aion home’s clones/ directory
(crate::config::aion_home → <home>/clones) — the same location the
crate worker’s provision handlers established (#175): durable history
records workspace paths, so they must live somewhere that survives a host
reboot, never the OS temp dir. There is no separate configurable value;
the home is already the operator’s one answer to “where does this
server’s state live” (#113), and resolving a second answer here is how
two components come to disagree about one path.
Resolution happens ONCE, at server-state construction, and every consumer — the declared-body dispatcher, the startup banner — reads that one value. A resolution failure is carried, not raised: boot proceeds, and the failure surfaces as a terminal dispatch refusal when (and only when) a placeholder-bearing body is dispatched. Bodies that do not use the placeholder are untouched by resolution failure.
Expansion happens on the raw command STRING, before
aion_worker::shell::ShellAction parses it into an argv. A root whose
text would change that parse — whitespace splits a word, { can pair
with a following { to open an interpolation, a quote opens a quoted
region, NUL cannot cross execve — is refused rather than spliced,
because a silent reshape of
the declared command is exactly what the template layer exists to
prevent. The root is server-controlled, so the refusal is theoretical;
it is checked because “theoretical” is not “impossible”.
The COMMAND is held to the same standard: every placeholder occurrence
must stand alone as one whole, unquoted argv word of the command as the
template parses it. An occurrence inside a quoted region or glued to
adjacent text would make the spliced root a FRAGMENT of some larger
word, so what executes would not be the path the server resolved — the
dispatch is refused by name instead (WorkspaceRootError::PlaceholderMisplaced).
Structs§
- Expanded
Command - A declared command with its workspace-root placeholder expanded.
- Workspace
Root - The server’s one workspace root, resolved once and read everywhere.
Enums§
- Workspace
Root Error - Why the workspace root could not be resolved or spliced into a declared command.
Constants§
- WORKSPACE_
ROOT_ PLACEHOLDER - The literal placeholder a declared command carries where the server’s workspace root belongs.