PtcRunner.Kernel.ProviderAcquisition (PtcRunner v0.14.0)

Copy Markdown View Source

Acquires one prepared run's selected providers through its active session.

The acquisition barrier prepares the planned providers, completes local preflight, and then acquires them in dependency order. Each acquired provider is committed to its provisional registrar immediately, before the next provider can run.

acquire/6 is the entry every provider-acquiring run uses and also serves acquisition-mode occurrences under doctor --connect. Connectivity has its own sealed completion while sharing the surrounding active-session ownership. Acquisition plans from sealed evidence: the preparation phase 5 produced and the exact catalog it was validated against, which together supply the dependency graph that decides the closure and the whole-application judgements already made over the complete selection. Nothing about which callbacks run is derived from what a callback reported.

Credentials are supplied, not resolved here. An active command resolves them once at phase-8 step 5 from its sealed declarations, before any provider callback runs, and hands the map down. Each provider receives only the names its own sealed declaration names, because a preparation that reports anything else — including a name a different selected provider declared — fails closed before the supplied map is consulted at all.

For an active command, provider preparation, preflight, and acquisition run in owner-linked bounded work using the remaining shared run deadline and provider heap limit. Preflight releases use one shared provider-cleanup budget.

acquire_embedded/5 is the direct embedding entry. It has no preparation, no catalog, and no operation deadline, so it has no sealed declaration to compare a preparation against and no union to resolve before one runs: it decides the whole-application judgements from the preparations themselves and lets the registry resolve credentials synchronously, which is the contract ProviderRegistry documents for that caller.

This module does not own the provider session. Its caller closes that session after any error and retains it with a successful acquisition result.

Summary

Functions

Acquires the sealed acquisition targets of one prepared run, and nothing else.

Acquires every selected provider of a direct embedding build.

Types

artifact_preflight()

@type artifact_preflight() :: (input_class() -> :ok | {:error, term()})

input_class()

@type input_class() :: :normal | :private_inspection

occurrence()

@type occurrence() :: %{destination: :workflow | :mission, index: non_neg_integer()}

result()

@type result() ::
  {:ok, map()}
  | {:error, term()}
  | {:unregistered_provider_close, term(),
     PtcRunner.Kernel.ProviderRegistry.close()}

targets()

@type targets() :: [occurrence()] | :all | map()

Functions

acquire(prepared, catalog, registry, session, targets, credentials)

Acquires the sealed acquisition targets of one prepared run, and nothing else.

A provider the sealed declarations did not name — directly or as a dependency — stays completely callback-inert: not prepared, not preflighted, not asked for credentials, not acquired. Preparation is provider work, not a lookup. A prepare callback can fail the whole operation, block until the deadline, spend the budget a real target needed, and register provisional roots that outlive it, so "prepare everything and then narrow" narrows nothing that matters.

The plan is therefore projected here from sealed evidence rather than handed in: prepared and catalog must be the pair phase 5 validated together, and session must be the one opened for that preparation. Those three checks are what bind the plan to the operation it runs under; a preparation and catalog legitimately sealed for a different operation cannot decide which callbacks run under this one, even when both applications share a package digest. Deriving the closure from callback-reported requires/provides instead would make the authority to invoke a callback depend on invoking callbacks, and would let executable code redirect which executable code runs.

targets is :all for a run, which acquires the whole selection, or the {destination, index} occurrences connectivity answers for — the same identity the sealed declarations and ConnectivityResult use. They are checked against the sealed occurrences before any callback runs, so an unknown or empty target set costs nothing.

Inside the closure, each preparation is compared with its sealed declaration and drift fails closed. Dependency-only providers are support work: acquired and cleaned up like any other, and never reported as a caller's own result.

The whole-application judgements need no re-derivation. Phase 5 decided dependency validity, cycles, workflow-LLM default uniqueness, the effective data class, and the providers' acceptance of it inertly over the complete selection, and sealed the result — an application whose classes disagree never becomes a preparation at all.

credentials is the map phase-8 step 5 resolved for the whole selection. It is deliberately wider than this closure: connectivity must answer for every selected occurrence, including ones no closure reaches.

acquire_embedded(package, registry, session, input_class, artifact_preflight)

Acquires every selected provider of a direct embedding build.

An embedding never crossed phases 4 and 5, so this entry has no preparation to plan from and no catalog to read a descriptor out of. The whole-application judgements are therefore derived from the preparations themselves, the effective data class is folded from the caller's input class, and credentials are resolved synchronously by the registry once every provider has preflighted.

What tells an embedding apart from an active command is that its session carries no operation identity and no operation deadline, and that is asked once, here, before any callback runs. An active command reaching this entry would otherwise spend its budget preparing and preflighting every selected provider — outside the sealed preparation, catalog, and session binding acquire/6 checks — and only be refused when it reached credential resolution.

artifact_preflight is called with the derived effective class, after preparation and before any provider is preflighted, because an embedding owns the artifact destinations its own build is about to write.