Preflight and freezing
Everything that happens between task creation and sandbox creation: re-authorisation, deterministic compilation, capacity and risk assessment, digest computation, and the fail-closed boundary.
Why preflight exists
Preflight solves one specific problem: a conclusion reached during planning cannot be treated as authorisation.
Planning is model-driven; it retrieves and evaluates the available flows and capabilities. But the model sees the candidates it is entitled to see, whereas what execution actually requires is the authorisation held by the current user and current workspace at the moment the sandbox is created. Those two can differ — permissions may have been revoked, a version withdrawn, a connector address changed.
So preflight does not "trust the planning result". It re-checks under the same identity and then fixes the outcome. That makes it both a security boundary and the source of reproducibility.
The seven steps of preflight
One, resolve the inputs. Resolve identity, workspace, requirement sources, repository, baseline branch and currently available capabilities.
Two, determine the flow. Freeze the existing version the user chose, or run retrieval, evaluation, adaptation and generation.
Three, deterministic compilation. Normalise the flow through the shared compiler. The compiler checks at least that:
- every required input has exactly one legitimate source;
- there are no circular dependencies, duplicate node identifiers or illegal rework targets;
- artefact types and format contracts are compatible;
- inputs use qualified references and do not create implicit dependency edges.
Four, risk assessment. Assess and persist the risk classification, confidence and whether approval is required. This data serves explanation, audit, later policy analysis and reproduction; it is not itself a manual blocking condition on the flow plan, though a node requiring approval still has to be approved before that node executes.
Five, re-authorisation and validation. Re-authorise every exact reference against the current user and workspace, and validate repository and branch, compatibility, budget and risk. Preflight does not resolve floating tags again, does not substitute candidates by scope, and does not add any built-in capability.
Six, freeze. Freeze the initial execution flow snapshot, the execution specification and the exact capability lock. The snapshot records whether it came from an existing version or was generated by an agent.
Seven, compute the digest. Compute a normalised content digest over the whole specification. This is the proof of immutability at execution time.
Re-validation inside the sandbox
Only after preflight completes is the specification passed to the runner. On start-up the runner re-validates the frozen plan against the same compiler and the same digest; it does not reinterpret natural language and does not resolve floating references.
Using the same logic in both places is deliberate: if preflight were the only check, problems introduced while passing the specification along would never be caught; if run time were the only check, failures would arrive after resources had already been created.
Failing closed
When preflight fails:
- no runtime environment is created;
- no Pod, service or task secret is created;
- the task keeps structured check results and a repair entry point;
- there is no silent fallback to broader permissions.
The most common causes of failure were listed earlier. The preflight UI shows the progress of flow retrieval, generation, risk and freezing, so the point of failure can usually be located directly.
The execution manifest
Preflight generates a secret-free execution manifest with a fixed digest for each task. It is the task's only execution configuration, and must contain in full the repository URL and baseline branch, the location information for every requirement source, the flow policy, and — for each node — the final prompt, skills, extensions, sub-agents, main agent model and runtime configuration.
The execution specification carries only content references into the manifest and its digest. The sandbox mounts it read-only, and the runner re-validates it.
A single configuration does not mean inlining every external body. The runner materialises requirements locally for each task from all the source location information, and each node uses that local result; skills, hooks and runtime files are materialised from configuration; credential environment variables are pre-injected into the sandbox. None of these payloads may form a second, parallel execution configuration, and none require the runner to recompute domain configuration.
All requirement sources are materialised exactly once per task. The runner preserves source identity and produces a unified requirement index, so retries, rework and every node reuse the same local result. This is a platform invariant, and no refresh policy is exposed in configuration. To refresh external requirements, create a new task or an explicit new execution revision, rather than letting an ordinary node read floating text mid-run.
What is projected into the UI
When the control plane assembles a task snapshot, it projects each node's secret-free agent evidence from the same frozen manifest: the main agent model and runtime, the node prompt, sub-agent names and their inheritance relationships, and the exact skill and extension versions.
Gateway addresses, credential references, extension authentication and platform system prompts do not enter the snapshot. For system prompts the UI shows an explicit note about the private execution layer; it does not reverse-engineer them from session text, directories or test fixtures.