[AZ-325] C10 CacheProvisioner orchestrator

Implements the public top-level F1 build orchestrator for E-C10 per
contract v1.1.0. Composes EngineCompiler (AZ-321), DescriptorBatcher
(AZ-322), and ManifestBuilder (AZ-323) into a single idempotent
operation guarded by a fcntl-backed cache_root/.c10.lock and a
post-build coverage walk.

Adds:
- CacheProvisionerImpl + FilelockFileLockFactory (provisioner.py)
- BuildRequest/BuildReport/BuildOutcome/SectorClassification DTOs +
  FileLockFactory Protocol + replaced placeholder CacheProvisioner
  Protocol with v1.1.0 surface (interface.py)
- C10ProvisionerConfig wired into C10ProvisioningConfig (config.py)
- BuildLockHeldError + ManifestCoverageError (errors.py)
- build_cache_provisioner composition root (c10_factory.py)
- 18 tests covering AC-1..AC-16 + NFR-perf-coverage-walk
- filelock>=3.13,<4.0 (single new third-party dep)

Idempotence (CP-INV-1) reuses AZ-323's _compute_manifest_hash /
_aggregate_tile_hash so the build-identity decision agrees byte-for-
byte with the Manifest's recorded manifest_hash. Coverage rollback
uses a .prev rename snapshot. Diagnostic compile_engines_for_corpus
is lock-free per AC-10.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Oleksandr Bezdieniezhnykh
2026-05-13 05:00:16 +03:00
parent 684ec2601c
commit f7b2e70085
12 changed files with 2329 additions and 21 deletions
@@ -20,10 +20,12 @@ from typing import TYPE_CHECKING, Any
from gps_denied_onboard.components.c10_provisioning import (
BackboneSpec,
C10BatcherConfig,
CacheProvisionerImpl,
DescriptorBatcher,
DescriptorIndexRebuilder,
Ed25519ManifestSigner,
EngineCompiler,
FilelockFileLockFactory,
ManifestBuilder,
ManifestVerifierImpl,
TileBboxRecord,
@@ -46,6 +48,8 @@ from gps_denied_onboard.runtime_root.inference_factory import (
)
if TYPE_CHECKING:
from gps_denied_onboard._types.inference import PrecisionMode
from gps_denied_onboard._types.manifests import HostCapabilities
from gps_denied_onboard.clock import Clock
from gps_denied_onboard.components.c6_tile_cache import (
DescriptorIndex,
@@ -56,6 +60,7 @@ if TYPE_CHECKING:
__all__ = [
"build_backbone_specs",
"build_cache_provisioner",
"build_descriptor_batcher",
"build_engine_compiler",
"build_manifest_builder",
@@ -380,6 +385,58 @@ def c6_tile_store_to_pixel_opener(
return _C6PixelOpenerAdapter(tile_store)
def build_cache_provisioner(
config: Config,
*,
engine_compiler: EngineCompiler,
descriptor_batcher: DescriptorBatcher,
manifest_builder: ManifestBuilder,
tile_metadata_store: TileMetadataStore,
host: HostCapabilities,
precision: PrecisionMode,
clock: Clock,
) -> CacheProvisionerImpl:
"""Construct a wired :class:`CacheProvisionerImpl` (AZ-325).
The orchestrator is the public top-level seam C12 calls; the
factory composes it from the already-built phase impls so the
same engine_compiler / descriptor_batcher / manifest_builder
instances can be reused across multiple ``build_cache_artifacts``
invocations within an operator session.
``host`` + ``precision`` come from the composition root because
AZ-321's :class:`EngineCompileRequest` expects host-info threaded
in (the AZ-297 :class:`InferenceRuntime` does not introspect it),
and they participate in the build-identity hash via
:class:`EngineFilenameSchema`. Tier-1 dev workstations probe the
GPU via :mod:`pynvml`; replay / unit tests construct fixed
:class:`HostCapabilities` so AC-1..AC-16 are deterministic.
The :class:`TileMetadataStore` is wrapped in the C10
:class:`TilesByBboxQuery` cut so the orchestrator never imports
``components.c6_tile_cache``.
"""
block: C10ProvisioningConfig = config.components["c10_provisioning"]
backbones = build_backbone_specs(config)
tiles_query = c6_tile_metadata_store_to_tiles_query(tile_metadata_store)
logger = get_logger("c10_provisioning.provisioner")
return CacheProvisionerImpl(
engine_compiler=engine_compiler,
descriptor_batcher=descriptor_batcher,
manifest_builder=manifest_builder,
tile_metadata_store=tiles_query,
lock_factory=FilelockFileLockFactory(),
backbones=backbones,
host=host,
precision=precision,
workspace_mb=block.workspace_mb,
logger=logger,
clock=clock,
config=block.provisioner,
)
def c6_descriptor_index_to_rebuilder(
descriptor_index: DescriptorIndex,
) -> DescriptorIndexRebuilder: