# DD — Plan a Run in a fixed environment (3C) [Common design](dd.md) · [Tasks and completion status](adr.md). Execution Core turns an accepted saved launch into a Run and its initial Attempt. The launch chooses `environment: k8s | slurm`. There is one configured Site for each value. That value identifies the destination throughout the execution path. ## Flow 1. Load the accepted launch, including member, Project, Workload revision and environment. 2. Check current Project execution permission and load that exact immutable Workload revision. 3. Read the Project's provisioned resources through the existing provisioning query. 4. Select the single ready resource in the requested environment and check its applied limits. 5. Save the Run, initial Attempt, command receipt and existing typed Run projection atomically. 6. Later supervision builds start/cancel messages from the saved Run. Delivery routes its environment to the corresponding configured runtime under Task 4. ```mermaid flowchart TD L["Accepted launch in PostgreSQL"] --> P["Execution Core planner"] W["Exact Workload revision"] --> P A["Current Project permission"] --> P R["Provisioned resources and limits"] --> P P --> C["Check requested environment and resource"] C --> D[("PostgreSQL: Run and initial Attempt")] D --> M["Supervisor builds execution command"] M --> K["k8s runtime"] M --> S["slurm runtime"] ``` The diagram's supervisor, delivery and native runtime steps remain later tasks. Tests exercise the internal launch, planner, PostgreSQL reload and message encoder. ## Baseline and adaptations Baseline: architecture-reset `48e60e542` planning handlers, admission policies and Run construction, plus the recovered Python implementation `e34e33cfc` used by 1B. Retain explicit owner queries, current permission, exact Workload identity, resource checks, stable execution identity and transactional receipts. Replace candidate Environment/Site UUIDs and ranking with the launch's fixed environment. Provisioning supplies the Waldur resource reference, confirmed readiness and applied limits. No catalogue-generated entitlement or resource-pool UUID is invented. The Run records that opaque resource reference instead. - 3B requires and saves the environment; changed targets conflict under a reused retry key. - 3A returns an environment with each resource and validates the complete response. - 1B persists the environment, resource reference and exact execution specification. - 1C carries a single environment in the command envelope. Construction verifies it against the saved Run, configured destination and native execution reference. Starts cannot replace the saved executable intent; cancellations keep the original destination. The account query still takes member + Project only. Credentials and native account interpretation remain in their existing owner boundaries. ## Admission decisions An environment without a Project resource is rejected. A resource its provider has paused, by current evidence, returns `resource_suspended` when no other resource in the environment may still become ready. Any other unready resource or an unavailable owner postpones planning without recording a terminal outcome. Multiple ready resources in the requested environment return `resource_ambiguous`; a later resource-selection rule can extend this explicitly. Compare CPU, memory, accelerator quantities and requested ephemeral storage with confirmed limits. Unknown requested storage limits do not grant capacity. Count simultaneous distributed workers, array concurrency and service replicas when checking totals; retain per-worker quantities for execution messages. Slurm planning currently supports queued batch. Kubernetes planning also validates `reconciled-service` intent, resources and replica counts. The 5B extension requires `intent.serviceKind: application | huggingface-inference` and validates the matching command/image or model/preparation settings. Both service kinds require `environment: k8s`; the discriminator selects the native executor within that destination. Preserve it in the Run's immutable specification, command construction and retries, and reject a conflicting kind or specification. These checks and their separate PostgreSQL/codec evidence are documented under 5B; the original planning evidence predates them. Native Job, Deployment and KServe qualification belongs to 5A–5C. Session support remains technical coverage only. These are applied quota checks, not a measurement or reservation of unused CPU, memory or nodes. Concurrent runs remain subject to native quota enforcement. Current permission is checked again before a new native start through the 1C gate. ## Persistence and retry behaviour `RunPlanning.plan(PlanRunCommand(...))` loads the saved launch through its existing query and the immutable revision through `WorkloadRevisions.get_revision`. `adaptors.postgres.run_planning(...)` composes the production transaction writer; all external owner implementations must be supplied explicitly. Run, initial Attempt and placement UUIDs are deterministically derived from the original saved launch ID. Replayed or concurrent deliveries cannot create a second Run for that launch. The command's material input contains the launch reference and supplied decision time; changing material input under the same command conflicts. A repeated command returns its recorded outcome, even after provider changes or a later Attempt. A different planning command for an already saved Run is rejected. Owner reads happen before the Run transaction. The transaction rechecks receipts and versions before applying the prepared decision. Expected rejections get a receipt; provider outages and corrupt saved authority do not become terminal rejections. Encoding/storage failures roll back Run, receipt and projection together. Worker claims and durable launch retries are implemented in [3D](launch-processing.md). Run lifecycle scheduling remains Task 4. The existing baseline SQL and launch retry indexes suffice. This changes the internal snapshot and execution-message shapes; old UUID-destination snapshots are rejected rather than guessed into an environment. Disposable test databases start empty. ## Authoring and public API The Workload describes what executes; the launch supplies where. Milestone 2 defines how repository actions supply the environment. A backend entry point may create the Workload and submit its internal launch reference behind one user request. This implementation adds internal interfaces, not public launch endpoints. ## Verification evidence Verified on 10 October 2026 using the pinned tools, disposable production integration bootstrap and isolated dev-box harness. The final runs include all environment-contract and saved-specification changes. | Boundary | Evidence | | --- | --- | | Identity, admission and environment rules | Passed: 336 Execution Core cases within 354 Metallo unit tests | | PostgreSQL, restricted role, receipts and production codecs | Passed: 72 Execution Core cases; full lane has 73 including the generic persistence fixture | | Generation drift and repository verification | `pnpm verify` passed: contract drift, architecture, types, lint, Go checks, web build and deployment configuration | | Disposable broker/service/browser integration | `pnpm test:integration` passed: PostgreSQL, RabbitMQ, all service images, sessions and browser test | | Isolated dev-box cluster | Passed: 408 cases (336 Execution Core unit tests and 72 PostgreSQL cases), using the restricted runtime role and production codecs with mocked external owners | | Workload, provisioning, permissions and source credentials | Test-only doubles; real owner connections remain open | | Native Kubernetes/Slurm execution and capacity | Pending later execution tasks | The ADR tracks completed implementation/mock verification separately from the real provider and native checks. No production provider mock or execution worker is enabled. Command logs: `/tmp/metallo-3c-verify.log`, `/tmp/metallo-3c-integration.log` and `/tmp/metallo-3c-devbox.log`. The dev-box run used image `pharos-metallo/identity:bb06a7ac9319`; its private report is `.local/metallo/identity-tests/dev-dkats/identity/metallo-identity-dev-dkats-bb06a7ac9319/report.json`. The harness removed the temporary namespace and its database after success. The local harnesses also removed their disposable databases, containers and volumes. These results qualify real persistence and codecs with mocked external owners; native workload execution remains pending.