videoflow.backends package
Backend contracts: the responsibility boundaries behind a running flow.
Videoflow builds a graph on one machine and executes it on many. Between the graph and the workers sit a handful of backends — a message transport, a payload store, an accelerator allocator, an execution environment — and a runtime that decides what correct processing means regardless of which concrete backend is underneath. This package holds the contracts for those boundaries, the truthful outcome types they share, and reference in-memory implementations that double as the executable specification every real adapter is tested against.
MessagingBackend(messaging): how does an envelope reach its required consumers?PayloadStore(payload): where are the image bytes, and how long must they survive?AcceleratorAllocationBackend(allocation): which accelerators may this workload use, under what guarantees? (Implemented bydeploy.allocation_localforrun-local,deploy.allocation_kubernetesover the GPU strategies, and render-onlydeploy.allocation_dra.)FlowRuntime(runtime): what constitutes correct processing and recovery?the composition planner (
capabilities): can this graph meet its requested contract?
Two rules run through all of it. Policy lives above adapters: an adapter reports
what it can guarantee, and the planner rejects a request it cannot meet instead
of quietly weakening it. And observations are truthful: a read that failed is
Unknown, never zero, never empty, never complete.
Nothing here imports a broker, a store or a cluster client at module scope, so the contracts can be imported wherever the graph can.
Subpackages
- videoflow.backends.memory package
- Submodules
- videoflow.backends.memory.allocation module
MemoryAllocationBackendMemoryAllocationBackend.apply_pending_geometry()MemoryAllocationBackend.bind_workload()MemoryAllocationBackend.bindings()MemoryAllocationBackend.capabilities()MemoryAllocationBackend.fail_geometry()MemoryAllocationBackend.fail_reads()MemoryAllocationBackend.inventory()MemoryAllocationBackend.mark_workload_ready()MemoryAllocationBackend.mutations()MemoryAllocationBackend.node()MemoryAllocationBackend.observe()MemoryAllocationBackend.plan()MemoryAllocationBackend.pointer()MemoryAllocationBackend.reconcile()MemoryAllocationBackend.release()MemoryAllocationBackend.reserve()MemoryAllocationBackend.shared_config()MemoryAllocationBackend.unbind_workload()
NodeFixtureNodeFixture.classification()NodeFixture.gpu_countNodeFixture.labelsNodeFixture.memory_gibNodeFixture.mig_configNodeFixture.mig_layoutNodeFixture.mig_stateNodeFixture.mig_state_generationNodeFixture.nameNodeFixture.ownerNodeFixture.owner_epochNodeFixture.productNodeFixture.resource_versionNodeFixture.restore_recordNodeFixture.workloads
pack_whole_devices()
- videoflow.backends.memory.clock module
- videoflow.backends.memory.messaging module
MemoryMessagingBackendMemoryMessagingBackend.cancel_publication()MemoryMessagingBackend.capabilities()MemoryMessagingBackend.channel_ids()MemoryMessagingBackend.close()MemoryMessagingBackend.commit_control()MemoryMessagingBackend.control_state()MemoryMessagingBackend.ensure_channel()MemoryMessagingBackend.ensure_subscription()MemoryMessagingBackend.fail_observation()MemoryMessagingBackend.observe_ack_floor()MemoryMessagingBackend.observe_channel()MemoryMessagingBackend.observe_publication()MemoryMessagingBackend.observe_subscription()MemoryMessagingBackend.pause_acceptance()MemoryMessagingBackend.publish()MemoryMessagingBackend.receive()MemoryMessagingBackend.renew()MemoryMessagingBackend.replay()MemoryMessagingBackend.resume_acceptance()MemoryMessagingBackend.settle()MemoryMessagingBackend.stored()MemoryMessagingBackend.subscription_ids()
make_channel()make_envelope()make_subscription()
- videoflow.backends.memory.mig_geometry module
- videoflow.backends.memory.payload module
MemoryPayloadStoreMemoryPayloadStore.acquire_obligation()MemoryPayloadStore.capabilities()MemoryPayloadStore.corrupt()MemoryPayloadStore.delete()MemoryPayloadStore.expire_obligation()MemoryPayloadStore.expire_obligation_set()MemoryPayloadStore.fail_inventory()MemoryPayloadStore.fail_reads()MemoryPayloadStore.inventory()MemoryPayloadStore.object_count()MemoryPayloadStore.obligations()MemoryPayloadStore.put()MemoryPayloadStore.read()MemoryPayloadStore.reconcile()MemoryPayloadStore.ref_for_key()MemoryPayloadStore.release_obligation()MemoryPayloadStore.renew_obligation()MemoryPayloadStore.stored_bytes()MemoryPayloadStore.truncate()
StaticLedger
- videoflow.backends.memory.runtime_store module
Submodules
videoflow.backends.allocation module
The AcceleratorAllocationBackend contract: which accelerator resources may a
workload use, and under what guarantees.
Named for what it decides, not for one mechanism: a Kubernetes DRA driver, the
device plugin, videoflow’s managed MIG geometry and a local nvidia-smi walk
are all implementations. What every implementation must share:
Inventory and plans are advisory. A feasible plan is a snapshot, never a reservation; authoritative allocation must survive concurrent demand.
Reservation is a compare-and-swap. Ownership is written under a server enforced precondition (a Kubernetes
resourceVersionor a JSON-patchtestop), and a stale rollback cannot remove a newer owner.Readiness is observed, not inferred. “Allocated”, “prepared” and “application-ready” are different states; a historical
successlabel is not evidence for a new operation.Reads that failed are Unknown. An occupancy listing the API refused does not prove a device idle.
Release is idempotent and generation-fenced, and a retained workload keeps its allocation until an explicit later release.
Memory is expressed in bytes with separate meanings — usable minimum, reserved,
hard limit, declared peak — because one gpu_memory_gb with three meanings
was how a scheduler reservation got mistaken for isolation.
- class videoflow.backends.allocation.AcceleratorAllocationBackend[source]
Bases:
ABC- abstractmethod bindings(claim_id: str, workload_id: str) WorkloadBindings[source]
- abstractmethod capabilities(environment: Mapping[str, Any]) AllocationCapabilities[source]
- abstractmethod inventory(scope: Mapping[str, Any]) Known[InventorySnapshot] | Unknown[source]
- abstractmethod observe(claim_id: str) Known[ClaimObservation] | Unknown[source]
- abstractmethod plan(requests: Sequence[WorkloadRequest], snapshot: InventorySnapshot) FeasiblePlan | Infeasible[source]
- abstractmethod reconcile(claim_id: str, desired: str, expected_generation: str) ClaimObservation[source]
- abstractmethod release(claim_id: str, operation_id: str, expected_generation: str, keep_workloads: bool = False) ReleaseObservation[source]
- abstractmethod reserve(plan: FeasiblePlan, operation_id: str, expected_generation: str | None) ClaimObservation[source]
- class videoflow.backends.allocation.ClaimObservation(claim_id: str, owner: str, desired_generation: str, observed_generation: str | None, status: str, grant: tuple[videoflow.backends.allocation.DeviceIdentity, ...] | None, evidence: Mapping[str, Any]=<factory>)[source]
Bases:
object- claim_id: str
- desired_generation: str
- evidence: Mapping[str, Any]
- grant: tuple[DeviceIdentity, ...] | None
- observed_generation: str | None
- owner: str
- status: str
- class videoflow.backends.allocation.Constraint(key: str, operator: str, values: tuple[str, ...], hard: bool = True)[source]
Bases:
objectA hard requirement or a soft preference on device or node attributes.
- hard: bool = True
- key: str
- operator: str
- values: tuple[str, ...]
- class videoflow.backends.allocation.DeliveredGrant(workload_id: str, devices: tuple[DeviceIdentity, ...], exclusive: bool, requested: int, policy: str, host: str = 'observed')[source]
Bases:
objectWhat a workload actually received, distinct from what it requested.
- devices: tuple[DeviceIdentity, ...]
- exclusive: bool
- static from_dict(d: Mapping[str, Any]) DeliveredGrant[source]
- host: str = 'observed'
observedwhen the grant reflects a successful host read;unobservedwhen discovery failed and the launcher went ahead without one — an empty device list then means “could not tell”, never “a zero-GPU machine”.
- policy: str
- requested: int
- workload_id: str
- class videoflow.backends.allocation.DeviceIdentity(node: str | None, ordinal: int | None, uuid: str | None, mig_uuid: str | None, product: str, memory_bytes: int | None, mig_profile: str | None = None)[source]
Bases:
objectOne accelerator as three different identifier spaces: a host ordinal, a physical GPU UUID, and (for a slice) a MIG UUID. They are not interchangeable; a worker maps whatever it was granted onto CUDA-local ordinals itself.
- memory_bytes: int | None
- mig_profile: str | None = None
- mig_uuid: str | None
- node: str | None
- ordinal: int | None
- product: str
- uuid: str | None
- videoflow.backends.allocation.EXCLUSIVE_FEATURE_PAIRS = (('mps', 'dynamic-mig'), ('mps', 'consumable-capacity'))
MPS shares a device between clients while dynamic MIG re-partitions it, and consumable shares already carve it.
- Type:
Combinations no backend can serve at once
- videoflow.backends.allocation.FEATURE_DYNAMIC_MIG = 'dynamic-mig'
Feature vocabulary a request may name (
WorkloadRequest.features); each is admitted only when the backend’s version matrix lists it as available — a request for dynamic MIG on hardware or a driver that cannot partition is rejected by name, never by a blanket “impossible” (ALLOC-023).
- class videoflow.backends.allocation.FeasiblePlan(assignments: Mapping[str, tuple[DeviceIdentity, ...]], geometry: Mapping[str, str], snapshot_generation: str, plan_id: str, notes: tuple[str, ...] = ())[source]
Bases:
objectAdvisory.
plan_idandsnapshot_generationtie a later reservation to the inventory it was planned on.- assignments: Mapping[str, tuple[DeviceIdentity, ...]]
- geometry: Mapping[str, str]
- notes: tuple[str, ...] = ()
- plan_id: str
- snapshot_generation: str
- class videoflow.backends.allocation.Infeasible(reasons: tuple[str, ...])[source]
Bases:
object- reasons: tuple[str, ...]
- class videoflow.backends.allocation.InventorySnapshot(devices: tuple[DeviceIdentity, ...], occupancy: Mapping[str, int], sharing: Mapping[str, str], owners: Mapping[str, str], completeness: str, observed_at: float, generation: str)[source]
Bases:
object- Arguments:
occupancy: device key -> units in use, as far as the reads could see.
sharing: node -> classification (
physical,mig,time-sliced,mps,unknown).owners: node -> owner recorded on it (videoflow’s own stamp), if any.
completeness:
completewhen every read succeeded,partialwhen some read failed — a partial snapshot may plan but may not admit.
- completeness: str
- devices: tuple[DeviceIdentity, ...]
- generation: str
- observed_at: float
- occupancy: Mapping[str, int]
- owners: Mapping[str, str]
- sharing: Mapping[str, str]
- class videoflow.backends.allocation.ReleaseObservation(claim_id: str, status: str, remaining: tuple[str, ...] = (), reason: str = '')[source]
Bases:
object- claim_id: str
- reason: str = ''
- remaining: tuple[str, ...] = ()
- status: str
- class videoflow.backends.allocation.WorkloadBindings(env: ~typing.Mapping[str, str], pod_fragment: dict, container_fragment: dict, claim_manifests: list[dict] = <factory>, node_constraints: dict = <factory>)[source]
Bases:
objectHow a granted claim reaches a workload: environment for a process, and Kubernetes fragments (plain dicts — external API schema) for a pod.
- claim_manifests: list[dict]
- container_fragment: dict
- env: Mapping[str, str]
- node_constraints: dict
- pod_fragment: dict
- class videoflow.backends.allocation.WorkloadRequest(flow_id: str, run_id: str, workload_id: str, device_count: int, sharing: str, minimum_usable_memory_bytes: int | None = None, reserved_memory_bytes: int | None = None, hard_memory_limit_bytes: int | None = None, declared_peak_memory_bytes: int | None = None, features: frozenset[str] = frozenset(), constraints: tuple[videoflow.backends.allocation.Constraint, ...]=(), elasticity: str = 'fixed', host_cpu: str | None = None, host_memory: str | None = None, provenance: Mapping[str, str]=<factory>)[source]
Bases:
object- constraints: tuple[Constraint, ...] = ()
- declared_peak_memory_bytes: int | None = None
- device_count: int
- elasticity: str = 'fixed'
- features: frozenset[str] = frozenset({})
- flow_id: str
- hard_memory_limit_bytes: int | None = None
- host_cpu: str | None = None
- host_memory: str | None = None
- minimum_usable_memory_bytes: int | None = None
- provenance: Mapping[str, str]
- reserved_memory_bytes: int | None = None
- run_id: str
- sharing: str
- workload_id: str
- videoflow.backends.allocation.allocation_rejections(requests: Sequence[WorkloadRequest], capabilities: AllocationCapabilities) list[str][source]
Why the backend cannot serve these requests, before anything is planned or written — the validation-before-write boundary. Empty means admitted. Each reason names the request, the feature/policy/sharing kind it needs and what the backend (
adapter/authority) actually offers, so the operator can tell “this driver version lacks the gate” from “this hardware cannot do it”.
videoflow.backends.capabilities module
Capability profiles and the composition planner.
A backend’s name is not a guarantee. “JetStream” can be a single server on an emptyDir or a three-replica cluster on persistent disks; “Redis” can be an evictable cache or an append-only durable store; “GPU” can be a whole device, a MIG slice with hardware isolation, or a time-share that only the scheduler accounts for. So every adapter reports a versioned capabilities record, the flow (or its defaults) states what it requires as profiles, and the planner compares the two before a single stream is provisioned, a single worker starts, or a single label is written. A requirement the composition cannot meet is rejected with the channel, the profile and the missing guarantee named; it is never quietly downgraded to whatever the backend does offer.
Messaging profiles (ARCHITECTURE §2):
live_latest: bounded backlog and age, explicit drop policy and scope (latest per key versus global), observable gaps; no offline replay promise.reliable_work: every accepted item stays recoverable for each required logical consumer until committed or durably failed; overflow backpressures, rejects before acceptance, or records a terminal outcome — never evicts.durable_control: reconciled run state and durable terminal records across controller and worker restarts; a transient notification may wake workers but cannot be the sole record of stop, abort or completion.replay_archive: retention independent of working consumers, with payloads and provenance; a replay is a new execution with explicit recipients.
Allocation guarantees name the mechanism behind a promise, because “reserved”
means three different things: enforcement says whether a memory bound is
enforced by hardware (MIG), by a runtime cap (MPS pinned memory), by scheduler
accounting only (a consumable capacity or a whole-device count), or not at all.
FlowRequirements is deliberately not a field of NodeSpec: the spec is
serialised with asdict into every specs ConfigMap, so a new field changes
bytes for every existing flow. Requirements travel as a separate document beside
the specs and as environment variables that are emitted only when set.
- videoflow.backends.capabilities.ADMISSION_TIMEOUT_ENV = 'VF_ADMISSION_TIMEOUT_SECONDS'
How long the in-container admission checks (the provision entrypoint before it creates anything, a worker before it opens its node) give the broker and the payload store to answer a read-back, connect included. Unset ⇒ the default; the answer past the deadline is
Unknown('timeout'), never a guess.
- class videoflow.backends.capabilities.AllocationCapabilities(adapter: str, authority: str, exclusive_device: bool, isolated_mig: bool, cooperative_sharing: bool, memory_enforcement: str, multi_device: bool, topology_verification: bool, elastic: bool, admission_boundary: bool, version_matrix: Mapping[str, Any]=<factory>)[source]
Bases:
object- adapter: str
- admission_boundary: bool
- authority: str
- cooperative_sharing: bool
- elastic: bool
- exclusive_device: bool
- isolated_mig: bool
- memory_enforcement: str
- multi_device: bool
- topology_verification: bool
- version_matrix: Mapping[str, Any]
version(a string),features(theallocation.FEATURE_*names available) and whatever else the adapter records (feature-gate states, the API group served).- Type:
What the adapter’s version can do, keyed by name
- class videoflow.backends.capabilities.CompositionPlan(channel_profiles: Mapping[str, str], channel_retention: Mapping[str, str], restart_safe: bool, notes: tuple[str, ...] = ())[source]
Bases:
objectThe admitted composition: which profile each channel got, the retention class it compiles to, and the notes a human reads to see why. An instance exists only if nothing was rejected — a rejection is an exception, not a field.
- channel_profiles: Mapping[str, str]
- channel_retention: Mapping[str, str]
- notes: tuple[str, ...] = ()
- restart_safe: bool
- videoflow.backends.capabilities.EFFECT_AT_LEAST_ONCE = 'at_least_once'
What a sink can promise about its external effects (
ConsumerNode.effect_guarantee).
- class videoflow.backends.capabilities.ExecutionCapabilities(engine: str, restart_supervision: bool, readiness_states: tuple[str, ...], pvc_mounts: bool, autoscaling_controllers: tuple[str, ...] = (), execution_groups: bool = False, dynamic_batching: bool = False)[source]
Bases:
objectWhat an execution engine advertises.
execution_groups(fused groups whose internal edges never touch the broker, RUN-035) anddynamic_batching(a runtime batching contract distinct from transport fetch batching, RUN-036) are declared False by both shipped engines: a flow that declares either is refused at admission rather than run as ordinary nodes.- autoscaling_controllers: tuple[str, ...] = ()
- dynamic_batching: bool = False
- engine: str
- execution_groups: bool = False
- pvc_mounts: bool
- readiness_states: tuple[str, ...]
- restart_supervision: bool
- class videoflow.backends.capabilities.FlowRequirements(profiles: tuple[~videoflow.backends.capabilities.ProfileRequest, ...]=(), restart_safe: bool = False, exactly_once_effects: tuple[str, ...]=(), resources: Mapping[str, ~typing.Mapping[str, str]]=<factory>, priority_class: str | None = None, rollout_policy: str | None = None, tolerated_failures: int = 0, sink_guarantees: Mapping[str, str]=<factory>, effect_retention_seconds: float | None = None, replay_horizon_seconds: float | None = None, execution_groups: Mapping[str, tuple[str, ...]]=<factory>, batching: Mapping[str, ~typing.Mapping[str, ~typing.Any]]=<factory>)[source]
Bases:
objectEverything a flow asks of its backends beyond the graph itself. Serialised beside the specs (
compile_to_dict()['requirements']) only when non-empty, so flows that never touch it produce byte-identical documents.- batching: Mapping[str, Mapping[str, Any]]
Dynamic-batching contracts the nodes declare (
Node.batching_policy): node -> policy. Admitted only againstdynamic_batching(RUN-036).
- effect_retention_seconds: float | None = None
a marker that expires inside the replay horizon cannot certify exactly-once.
- Type:
How long effect markers are kept, and how far back a replay may reach
- exactly_once_effects: tuple[str, ...] = ()
- execution_groups: Mapping[str, tuple[str, ...]]
group name -> member nodes. Admitted only against an engine advertising
execution_groups(RUN-035); none does today.- Type:
Fused execution groups the nodes declare (
Node.execution_group)
- static from_dict(d: Mapping[str, Any] | None) FlowRequirements[source]
- priority_class: str | None = None
- profiles: tuple[ProfileRequest, ...] = ()
- replay_horizon_seconds: float | None = None
- resources: Mapping[str, Mapping[str, str]]
- restart_safe: bool = False
- rollout_policy: str | None = None
- sink_guarantees: Mapping[str, str]
What each sink declares about its external effects (
ConsumerNode.effect_guarantee, only the non-defaultidempotent_keydeclarations): the one thing that can admitexactly_once_effectsfor it (RUN-017).
- tolerated_failures: int = 0
Broker pod losses accepted work must survive (the deployment’s declared fault model, MSG-021):
fneeds persistent storage and2f + 1stream copies, read back — never inferred from durable names or pod counts.
- videoflow.backends.capabilities.LEDGER_NONE = 'none'
What a backend knows about the fate of a publication after the fact.
- videoflow.backends.capabilities.MAX_STREAMS_ENV = 'VF_MAX_STREAMS'
the measured limit a benchmark (MSG-026) established on the deployment’s hardware, so a graph beyond it is refused at admission instead of partially provisioned.
- Type:
Operator-declared supported graph size for the JetStream adapter
- class videoflow.backends.capabilities.MessagingCapabilities(adapter: str, version: str, retained_backlog: bool, recoverable_delivery: bool, latest_per_key: bool, dedup_window_seconds: int | None, publication_ledger: str, replication_factor: Known[int] | Unknown, persistent_storage: Known[bool] | Unknown, max_payload_bytes: Known[int] | Unknown, credit_resizable: bool, control_shares_data_slot: bool, durable_control: bool = False, archive: bool = False, mixed_retention_per_channel: bool = False, max_streams: Known[int] | Unknown | None = None, max_consumers: Known[int] | Unknown | None = None)[source]
Bases:
objectWhat a messaging adapter, as configured, can guarantee. Observations that depend on the deployed broker (replication, storage, payload limit) are
Observationvalues: an adapter that could not read them says so, and the planner treats that as a reason to reject a profile that depends on them.- adapter: str
- archive: bool = False
- credit_resizable: bool
- dedup_window_seconds: int | None
- durable_control: bool = False
- latest_per_key: bool
- max_streams: Known[int] | Unknown | None = None
The largest graph the adapter supports, as streams and consumers (MSG-026): the broker account’s limits read back (
-1= unlimited) capped by the operator’s declared supported size (VF_MAX_STREAMS/VF_MAX_CONSUMERS,graph_limits_from_env);Nonewhen the adapter declares nothing.
- mixed_retention_per_channel: bool = False
- publication_ledger: str
- recoverable_delivery: bool
- retained_backlog: bool
- version: str
- videoflow.backends.capabilities.PARENT_REPLICAS_ENV = 'VF_PARENT_REPLICAS'
The per-parent replica counts (ENV-11), positionally aligned with VF_PARENT_NAMES.
- videoflow.backends.capabilities.PROFILE_REQUESTS_ENV = 'VF_PROFILE_REQUESTS_JSON'
The environment variable carrying an operator’s explicit channel-profile requests to a worker (
deploy --require-profile); absent when none were made, so the default worker environment is unchanged (D8).
- class videoflow.backends.capabilities.PayloadCapabilities(adapter: str, durable: Known[bool] | Unknown, evictable: Known[bool] | Unknown, atomic_multikey: Known[bool] | Unknown, max_object_bytes: int | None, reader_identities: bool, reference_forwarding: bool = False, persistent_storage: Known[bool] | Unknown = <factory>)[source]
Bases:
objectdurable: an accepted object outlives a restart of the store’s process (persistence on) and is never dropped while a reader holds it (noeviction) — whatreliable_workasks.persistent_storage: the data lives on a volume that outlives the store’s pod — what surviving a pod loss (tolerated_failures) additionally asks; a dev Redis writes its append-only file to an emptyDir and is durable without being that. The wire cannot tell the two apart (CONFIG GET dirnames a path, not what backs it), so a read-back leaves itUnknownand the profile record on the Service (or the operator) declares it.reference_forwarding: a stage that republishes an unchanged payload shares the canonical object instead of writing a copy per hop (PAY-017). Neither shipped store declares it; every hop writes its own copy, which the benchmark measures as a copy amplification of one object per frame-bearing stage — declared, never hidden.- adapter: str
- max_object_bytes: int | None
- reader_identities: bool
- reference_forwarding: bool = False
- class videoflow.backends.capabilities.ProfileRequest(channel: str, profile: str, options: Mapping[str, ~typing.Any]=<factory>)[source]
Bases:
object- Arguments:
channel: the producing node whose output channel the profile applies to.
profile: one of
MESSAGING_PROFILES.options: profile-specific knobs —
latest_per_key(bool),horizon_seconds(int, the recovery/replay horizon),key(str).
- channel: str
- static from_dict(d: Mapping[str, Any]) ProfileRequest[source]
- options: Mapping[str, Any]
- profile: str
- videoflow.backends.capabilities.RETENTION_LIMITS = 'limits'
Retention classes a channel can be compiled to. A channel has exactly one.
- videoflow.backends.capabilities.RUNTIME_STORE_ENV = 'VF_RUNTIME_STORE_URL'
the ledger every worker of the run keeps its records in.
- Type:
The runtime store’s URL (RFC 0006 ENV-10)
- class videoflow.backends.capabilities.RuntimeCapabilities(store: str, durable: videoflow.backends.outcomes.Known[bool] | videoflow.backends.outcomes.Unknown, shared_across_processes: bool, restart_safe_joins: bool, elastic_state: bool)[source]
Bases:
object- elastic_state: bool
- restart_safe_joins: bool
- store: str
- videoflow.backends.capabilities.admission_timeout_from_env(value: str | None) float[source]
VF_ADMISSION_TIMEOUT_SECONDSas seconds: the default when unset.- Raises:
ConfigError: a value that is not a positive number.
- videoflow.backends.capabilities.combined_limit(account: Known[int] | Unknown | None, declared: int | None) Known[int] | Unknown | None[source]
The tighter of an account limit (
-1unlimited) and a declared cap; None when neither says anything.
- videoflow.backends.capabilities.default_requirements(flow_type: str, specs: Sequence[NodeSpec]) FlowRequirements[source]
The requirements a flow makes without saying anything: one profile request per edge, derived from the flow type and each consuming node’s delivery override. Two consumers of one channel may therefore ask for different profiles; whether one channel can serve both is the planner’s decision.
- videoflow.backends.capabilities.graph_limits_from_env(environ: Mapping[str, str]) tuple[int | None, int | None][source]
(max_streams, max_consumers)declared in the environment, or None each; a non-integer is a ConfigError.
- videoflow.backends.capabilities.kubernetes_execution_capabilities(autoscaling: bool = False) ExecutionCapabilities[source]
The Kubernetes engine: kubelet restarts, PVC mounts, KEDA when asked for; no fusion or batching.
- videoflow.backends.capabilities.local_execution_capabilities() ExecutionCapabilities[source]
The local engine: subprocess supervision, no claims, no controllers, no fusion or batching.
- videoflow.backends.capabilities.plan_composition(requirements: FlowRequirements, messaging: MessagingCapabilities, payload: PayloadCapabilities | None = None, runtime: RuntimeCapabilities | None = None, allocation: AllocationCapabilities | None = None, execution: ExecutionCapabilities | None = None, payload_refs_in_use: bool = False) CompositionPlan[source]
Admit the composition or reject it — never downgrade it.
- Arguments:
requirements: what the flow asks for (
default_requirementswhen it says nothing).messaging / payload / runtime / allocation / execution: what the composed backends advertise.
Nonemeans that backend is not part of the composition; a profile needing it is then rejected.payload_refs_in_use: whether any channel offloads payloads to the store, which makes the store’s durability part of the messaging guarantee.
- Raises:
IncompatibleProfile: a requested guarantee is definitely not provided; the diagnostics list every one.
UnobservableState: a requested guarantee depends on a capability the adapter could not observe (replication, persistence, store durability). Unknown is not a pass.
- videoflow.backends.capabilities.profile_for_edge(flow_type: str, delivery: Mapping[str, Any] | None) str[source]
The profile an edge requests under today’s presets: BATCH is reliable work, REALTIME is live-latest, and a node’s
deliveryoverride flips its own inputs (an at-least-once sink inside a REALTIME flow asks for reliable work).
- videoflow.backends.capabilities.realtime_default_capabilities_note(flow_type: str) str[source]
One line for videoflow explain: what the flow type’s preset implies.
- videoflow.backends.capabilities.requests_env(explicit: Sequence[ProfileRequest]) dict[str, str][source]
The worker environment entry for explicit requests — empty when there are none.
- videoflow.backends.capabilities.requests_from_env(value: str | None) list[ProfileRequest][source]
The inverse of
requests_envon the worker side;[]when unset.
videoflow.backends.faults module
Named fault barriers for deterministic failure injection.
A conformance case is a story with a fault in the middle: “crash after the group
is persisted but before its outputs are published”, “drop the acknowledgment of
the settlement”, “let a second owner write between the read and the update”.
Repeating a happy-path test many times does not reach those interleavings; a
barrier does. Adapters and the runtime call barrier(name, **context) at each
named point; in production nothing is installed and the call is one attribute
read. A test installs a FaultSchedule mapping barrier names to actions, and
afterwards asks which barriers actually fired — a scheduled fault that never
fired makes the test INVALID_TEST, not PASS.
Barriers reach worker subprocesses too: FaultSchedule.to_env() serialises the
schedule into VF_FAULT_SCHEDULE_JSON and names a marker directory in
VF_FAULT_MARKER_DIR; videoflow.runtime.worker installs it from the
environment, and every hit appends a marker file the parent can count.
Actions:
Crash(exit_code): write the marker, thenos._exit— nofinally, no atexit, exactly the death a kill produces.RaiseError(factory)/RaiseError.typed(code, message, disposition): raise.Delay(seconds): sleep, then continue.DropResponse: continue, but the adapter reports the call’s outcome asUnknown— the lost-receipt model at the adapter boundary.Pause(name): block untilFaultSchedule.release(name)(or the marker<dir>/<name>.releaseappears), so two processes can be interleaved by hand.Nth(n, action): applyactionon the n-th hit only.
- class videoflow.backends.faults.Crash(exit_code: int = 137)[source]
Bases:
object- exit_code: int = 137
- class videoflow.backends.faults.FaultSchedule(actions: Mapping[str, Crash | RaiseError | Delay | DropResponse | Pause | Nth], marker_dir: str | None = None)[source]
Bases:
object- Arguments:
actions: barrier name -> action.
marker_dir: directory for cross-process markers; created on install.
- fired() dict[str, int][source]
Hit counts per barrier: in-process hits plus marker files written by other processes.
- classmethod from_env(environ: Mapping[str, str] | None = None) FaultSchedule | None[source]
- install() FaultSchedule[source]
- release(name: str) None[source]
Let a
Pause(name)continue, in this process and in any process sharing the marker dir.
- class videoflow.backends.faults.Hit(fired: bool, drop_response: bool = False)[source]
Bases:
objectWhat
barrier()returns: whether the adapter must report this call’s outcome as unknown.- drop_response: bool = False
- fired: bool
- class videoflow.backends.faults.Nth(n: int, action: Any)[source]
Bases:
object- action: Any
- n: int
- class videoflow.backends.faults.Pause(name: str, timeout_seconds: float = 60.0)[source]
Bases:
object- name: str
- timeout_seconds: float = 60.0
- class videoflow.backends.faults.RaiseError(factory: Callable[[], BaseException], spec: Mapping[str, str] | None = None)[source]
Bases:
object- factory: Callable[[], BaseException]
- spec: Mapping[str, str] | None = None
Serialisable form for cross-process schedules (see
typed); None when the factory is an in-process callable that cannot travel.
- static typed(code: str, message: str, disposition: str = 'transient') RaiseError[source]
A raise action built from the error taxonomy, serialisable into a worker’s env.
- exception videoflow.backends.faults.UnknownBarrier[source]
Bases:
ValueErrorA schedule or a call named a barrier that is not in
BARRIERS.
- videoflow.backends.faults.barrier(name: str, **context: Any) Hit[source]
The production-side call. One set lookup when no schedule is installed; otherwise delegates to it. Adapters check
.drop_responsewhere the lost-receipt model applies, and letRaiseError/Crashpropagate.
- videoflow.backends.faults.installed() FaultSchedule | None[source]
videoflow.backends.identity module
Collision-resistant logical identities over today’s physical names.
Every broker subject, stream, durable and Kubernetes resource is derived from
user-chosen strings — flow ids, run ids, node names — through two lossy encodings:
topology.sanitize (any run of characters outside [A-Za-z0-9_-] becomes a
single _) and manifests.k8s_name (lower-case, non-DNS characters to -,
truncated to 63). Lossy means collisions: a.b and a_b share a stream;
Node and node share a Deployment; two long names can truncate onto each
other. And hyphen-joined tuples collide across positions: stream vf-a-b-c-n
is the same string for (flow='a-b', run='c') and (flow='a', run='b-c').
The design package asks for identities that are reversible or tied to exact owner metadata. This module does the second without renaming anything (a rename is an RFC): it enumerates every physical name a compiled flow will use, rejects the flow at compile time when two distinct logical identities map to one physical name, and produces the owner labels that provisioning writes into stream and consumer metadata (RFC 0006) so teardown can match exactly instead of by prefix.
The naming functions themselves stay where they are (messaging/topology.py,
deploy/manifests.py): this module only calls them, so there is still one
source of truth for every name.
- class videoflow.backends.identity.Collision(physical: str, identities: tuple[videoflow.backends.identity.LogicalIdentity, ...])[source]
Bases:
object- identities: tuple[LogicalIdentity, ...]
- physical: str
- class videoflow.backends.identity.LogicalIdentity(kind: str, parts: tuple[str, ...])[source]
Bases:
objectWhat a physical name means: its kind and the exact logical parts it encodes.
- kind: str
- parts: tuple[str, ...]
- videoflow.backends.identity.collisions(specs: Sequence[NodeSpec], flow_id: str, run_id: str) list[Collision][source]
Physical names that two distinct logical identities of the same kind map to. Different kinds may legitimately share a string (a subject and a stream never occupy the same namespace), so only same-kind clashes count.
- videoflow.backends.identity.collisions_across_runs(specs: Sequence[NodeSpec], flow_id: str, run_ids: Iterable[str]) list[Collision][source]
Collisions between two runs of one flow (
rvsr-x), for teardown safety checks.
- videoflow.backends.identity.derived_names(specs: Sequence[NodeSpec], flow_id: str, run_id: str, instance_ids: Mapping[str, Sequence[str]] | None = None) dict[str, list[LogicalIdentity]][source]
Every physical name a compiled flow will create or bind, mapped to the logical identities that produce it. The exact set — not a prefix — that a teardown may delete, and the corpus the collision check runs over.
- Arguments:
instance_ids: per-node EOS instance ids when known (the per-process uuid-suffixed durables are minted at worker start, so provisioning cannot enumerate them; pass what a test or a running flow knows).
- videoflow.backends.identity.flow_labels(flow_id: str, kind: str) dict[str, str][source]
Ownership metadata for a flow-scoped resource — the dead-letter stream, which outlives every run. It carries no run label on purpose:
ownsis False for it under every run id, so no run’s teardown can match it.
- videoflow.backends.identity.has_owner_labels(metadata: Mapping[str, str] | None) bool[source]
Whether a resource carries videoflow ownership metadata at all — labelled (RFC 0006) versus legacy.
- videoflow.backends.identity.node_name_collisions(names: Sequence[str]) list[Collision][source]
Node names that encode to one physical name under either encoder — the check the graph validator runs before a flow is ever compiled. Flow and run ids are constant across a flow’s nodes, so within one flow only the node part can collide.
- videoflow.backends.identity.owner_labels(flow_id: str, run_id: str, node: str | None = None, kind: str | None = None, generation: str | None = None) dict[str, str][source]
Exact-ownership metadata for a broker resource. Written as JetStream stream / consumer
metadata(RFC 0006) and compared verbatim by teardown, which is what makesrandr-xdistinguishable when their names share a prefix.
videoflow.backends.messaging module
The MessagingBackend contract: how an envelope reaches its required consumers.
A messaging backend owns channels, publication outcomes, logical subscriptions, delivery leases, settlement semantics, transport retention and replay capabilities. It does not own joining inputs, GPU reservations, application effects or whole-run completion — those belong to the runtime, which composes a backend with a payload store and a durable ledger.
The vocabulary that matters:
A subscription is a logical consumer. Ten replicas serving one consumer compete for its work; two distinct downstream consumers each have their own obligations. Fan-out and competing delivery are never interchangeable defaults.
A delivery token names the run, the subscription, the message, the attempt and the ownership generation. A stale attempt cannot decide a newer attempt’s outcome:
settleon a superseded token returnsSettleStalewithout a broker call.Terminalsettlement requires a reference to a durable record (a dead-letter acceptance, a ledger entry). An adapter must refuse to terminate a message whose only trace would be its own disappearance.Observations distinguish zero from unknown. A subscription observation that could not be made is
Unknown; queue counters are metrics, not a completion protocol.
- class videoflow.backends.messaging.ChannelId(flow_id: str, run_id: str, node: str)[source]
Bases:
object- flow_id: str
- node: str
- run_id: str
- class videoflow.backends.messaging.ChannelObservation(first_seq: int, last_seq: int, messages: int, retention: str, observed_at: float)[source]
Bases:
objectWhat a channel retains right now: the first and last stream sequences it holds and how many messages — the eviction facts a reconciler needs (
BLOB-14step 4: a publication belowfirst_seqwas evicted and its readers will never take it).- first_seq: int
- last_seq: int
- messages: int
- observed_at: float
- retention: str
- class videoflow.backends.messaging.ChannelSpec(id: ~videoflow.backends.messaging.ChannelId, profile: str, retention: str, max_msgs: int, max_bytes: int | None, max_age_seconds: float | None, overflow: str, dedup_window_seconds: int, replicas: int, persistence: bool, required_subscriptions: tuple[~videoflow.backends.messaging.SubscriptionId, ...], owner_labels: ~typing.Mapping[str, str] = <factory>, per_subject_limits: bool = False)[source]
Bases:
objectWhat a channel must provide, verified against the broker before production starts.
owner_labelsis the exact-ownership metadata teardown matches on.- dedup_window_seconds: int
- max_age_seconds: float | None
- max_bytes: int | None
- max_msgs: int
- overflow: str
- owner_labels: Mapping[str, str]
- per_subject_limits: bool = False
- persistence: bool
- profile: str
- replicas: int
- required_subscriptions: tuple[SubscriptionId, ...]
- retention: str
- class videoflow.backends.messaging.Delivery(token: videoflow.backends.messaging.DeliveryToken, envelope_bytes: bytes, size: int, received_at: float, headers: Mapping[str, str]=<factory>)[source]
Bases:
object- envelope_bytes: bytes
- headers: Mapping[str, str]
- received_at: float
- size: int
- token: DeliveryToken
- class videoflow.backends.messaging.DeliveryToken(subscription: videoflow.backends.messaging.SubscriptionId, message_id: str, stream_sequence: int | None, attempt: int, generation: str)[source]
Bases:
object- attempt: int
- generation: str
- message_id: str
- stream_sequence: int | None
- subscription: SubscriptionId
- class videoflow.backends.messaging.Envelope(channel: ChannelId, publication_id: str, headers: Mapping[str, str], body: bytes, size: int, event_id: str, partition_key: str | None, event_ts: float | None, source_epoch: str | None, source_offset: int | None, schema_version: int, payload_refs: tuple[ImmutablePayloadRef, ...] = (), kind: str = 'data')[source]
Bases:
objectA publication.
publication_idis the stable operation identity a retry re-uses (it becomes the broker’s dedup key);event_idis the logical event identity the runtime reasons about. Physical stream sequences are diagnostics, not identity.- body: bytes
- event_id: str
- event_ts: float | None
- headers: Mapping[str, str]
- kind: str = 'data'
- partition_key: str | None
- payload_refs: tuple[ImmutablePayloadRef, ...] = ()
- publication_id: str
- schema_version: int
- size: int
- source_epoch: str | None
- source_offset: int | None
- videoflow.backends.messaging.KIND_DATA = 'data'
what the bytes are, which decides the subject they ride and what a receiver does with them.
dlqis a dead-letter publication of raw wire bytes (DELIV-8), addressed by the origin node’s channel.- Type:
Envelope.kindvalues
- class videoflow.backends.messaging.LeaseObservation(token: videoflow.backends.messaging.DeliveryToken, renewed: bool, expires_at: float | None, reason: str = '')[source]
Bases:
object- expires_at: float | None
- reason: str = ''
- renewed: bool
- token: DeliveryToken
- class videoflow.backends.messaging.MessagingBackend[source]
Bases:
ABCThe transport contract. Every method returns an outcome type rather than raising for the expected failure modes; exceptions are for programming errors and for faults the caller could not have anticipated.
- abstractmethod capabilities() MessagingCapabilities[source]
- abstractmethod close(owned: Sequence[ChannelId], expected_generation: str) CleanupObservation[source]
Remove exactly the owned channels; report what could not be confirmed removed.
- abstractmethod ensure_channel(spec: ChannelSpec, operation_id: str) VerifiedChannel[source]
Create or reconcile the channel and read back its effective configuration. An immutable mismatch (retention, replicas) raises
IncompatibleProfile; “already exists” is never accepted without inspection.
- abstractmethod ensure_subscription(spec: SubscriptionSpec, operation_id: str) VerifiedSubscription[source]
- observe_ack_floor(subscription: SubscriptionId) Known[int] | Unknown[source]
The stream sequence up to which
subscriptionhas settled everything (its ack floor), for any subscription of the run — bound by this process or not: a reconciler evaluates other readers’ progress through it. Unknown when the adapter cannot read it, which a reconciler treats as “still required”, never as settled.
- observe_channel(channel: ChannelId) Known[ChannelObservation] | Unknown[source]
The channel’s retained range (
ChannelObservation); Unknown when the adapter cannot read it.
- abstractmethod observe_publication(envelope: Envelope) Accepted | Rejected | PublicationUnknown | PublicationUnresolvable[source]
What the backend can say later about
envelope.publication_id;Unresolvablewhen it keeps no ledger.
- abstractmethod observe_subscription(subscription: SubscriptionId) Known[SubscriptionObservation] | Unknown[source]
- prefetched(subscription: SubscriptionId) int[source]
Deliveries fetched from the broker and parked locally for
subscription(0 when the backend keeps none).
- abstractmethod publish(envelope: Envelope, deadline: float) Accepted | Rejected | PublicationUnknown | PublicationUnresolvable[source]
Publish with a monotonic deadline; on expiry the outcome is
PublicationUnknown, never a guess.
- abstractmethod receive(subscription: SubscriptionId, item_credit: int, byte_credit: int, deadline: float) list[Delivery][source]
- receive_any(subscriptions: Sequence[SubscriptionId], item_credit: int, byte_credit: int, deadline: float) list[tuple[SubscriptionId, Delivery]][source]
Deliveries from whichever of
subscriptionshas any, waiting untildeadline(monotonic) for at least one. The default polls each subscription in turn; an adapter that can wait on all of them at once overrides it. Returns[]at the deadline, so a caller can re-check its own termination conditions rather than block forever.
- abstractmethod renew(token: DeliveryToken) LeaseObservation[source]
- set_admission(subscription: SubscriptionId, admit: Callable[[Delivery], bool], on_skip: Callable[[Delivery], None] | None = None) bool[source]
Ask the backend to run
admiton every delivery ofsubscriptionbefore it is parked forreceive: a delivery it refuses is settledCompletedby the backend at once — so a message this consumer will never process does not occupy its ack window — and, once that settlement is confirmed, handed toon_skipoff the backend’s own threads.admitruns on the backend’s thread and must be cheap and must not block. Returns False when the backend keeps no such filter; the caller then decides on the receiving side.
- abstractmethod settle(token: DeliveryToken, outcome: Completed | Retry | Terminal, settlement_id: str) SettleConfirmed | SettleUnknown | SettleStale[source]
- subscribe_control(callback: Callable[[], None]) None[source]
Invoke
callbackwhen the run’s flow-wide stop is published; a backend without a control channel ignores it.
- supersede(token: DeliveryToken) bool[source]
Retire a delivery token locally — the receiver now holds a newer attempt of the same logical message — without any broker settlement. Returns whether the token was live. A later
settleof the retired token isSettleStale. The default is a no-op for adapters whose tokens are already fenced by attempt and generation.
- class videoflow.backends.messaging.Retry(delay_seconds: float | None = None)[source]
Bases:
object- delay_seconds: float | None = None
- class videoflow.backends.messaging.SubscriptionId(channel: ChannelId, consumer_node: str, partition: int | None, kind: str = 'data', instance: str | None = None)[source]
Bases:
object- Arguments:
partition: the replica index of a partitioned consumer (every replica has its own logical subscription); None for a competing subscription shared by all replicas.
kind:
dataoreos.instance: a per-process observer instance — end-of-stream markers are observed by every replica through its own subscription, named by the process that created it. None for the logical work subscription.
- consumer_node: str
- instance: str | None = None
- kind: str = 'data'
- partition: int | None
- class videoflow.backends.messaging.SubscriptionObservation(available: int, leased: int, unresolved: int, dropped: int, rejected_publications: int, observed_at: float, generation: str | None = None)[source]
Bases:
objectCounts are for this observation only;
unresolvedis work the broker holds but can no longer deliver.- available: int
- dropped: int
- generation: str | None = None
- leased: int
- observed_at: float
- rejected_publications: int
- unresolved: int
- class videoflow.backends.messaging.SubscriptionSpec(id: SubscriptionId, competing: bool, ack_wait_seconds: float, max_deliver: int, item_credit: int, byte_credit: int, owner_labels: Mapping[str, str]=<factory>)[source]
Bases:
objectmax_deliver == -1means the broker never strands a message; the runtime’s ledger budgets attempts.- ack_wait_seconds: float
- byte_credit: int
- competing: bool
- id: SubscriptionId
- item_credit: int
- max_deliver: int
- owner_labels: Mapping[str, str]
- class videoflow.backends.messaging.Terminal(record_ref: str)[source]
Bases:
objectrecord_refnames the durable record (DLQ acceptance, ledger id) that outlives the message.- record_ref: str
- class videoflow.backends.messaging.VerifiedChannel(spec: videoflow.backends.messaging.ChannelSpec, effective: Mapping[str, Any], mismatches: tuple[str, ...] = ())[source]
Bases:
object- effective: Mapping[str, Any]
- mismatches: tuple[str, ...] = ()
- spec: ChannelSpec
- class videoflow.backends.messaging.VerifiedSubscription(spec: videoflow.backends.messaging.SubscriptionSpec, effective: Mapping[str, Any], mismatches: tuple[str, ...] = ())[source]
Bases:
object- effective: Mapping[str, Any]
- mismatches: tuple[str, ...] = ()
- spec: SubscriptionSpec
videoflow.backends.observation module
An append-only observation log — the independent evidence a conformance oracle reads instead of trusting a provider’s own counters.
The design package asks every adapter and the runtime to record, for each logical operation, the identities that let a failure be attributed: the operation id, the source epoch and offset, the event or group id, the logical consumer, the delivery attempt, the ownership generation, the payload digest or obligation, the claim and pod UIDs, the device ids, and a monotonic timestamp. Image bytes are never logged. This module is deliberately tiny: a list of frozen records, a lock, and JSONL in/out, so it can be attached to a worker subprocess through a file path and merged back in the test that spawned it.
- class videoflow.backends.observation.Event(kind: str, monotonic: float, wall: float, fields: Mapping[str, ~typing.Any]=<factory>)[source]
Bases:
objectOne observation.
kindnames what happened ('publish','settle','claim'…).- fields: Mapping[str, Any]
- kind: str
- monotonic: float
- wall: float
- videoflow.backends.observation.FIELDS = ('op_id', 'source_epoch', 'source_offset', 'event_id', 'group_id', 'consumer', 'attempt', 'generation', 'payload_digest', 'obligation_id', 'claim_uid', 'pod_uid', 'device_ids', 'status', 'reason')
Field names every record may carry; adapters use these keys so logs from different backends line up in one oracle.
- class videoflow.backends.observation.ObservationLog(path: str | None = None, clock: Any = <built-in function monotonic>)[source]
Bases:
objectThread-safe, append-only, replayable.
- Arguments:
path: when given, every event is also appended as one JSON line, so a subprocess can keep writing while its parent still reads.
clock: monotonic clock, injectable for deterministic tests.
- events(kind: str | None = None, **match: Any) list[Event][source]
Events of
kind(any kind when None) whose fields equal everymatchitem.
videoflow.backends.outcomes module
Truthful outcome types shared by every backend contract.
The failure that motivates this module is quiet: a broker query that raised was reported as “zero pending”, a lost acknowledgment as “acknowledged”, a node list the API refused as “no GPUs in use”. Each of those turned an unobservable state into a confident answer, and the code above it then made a destructive decision (declared a drain complete, reclaimed a payload, repartitioned a card). The types here make the distinction unavoidable in the type system:
Known[T]/Unknown: an observation either carries a value with the time and generation it was observed at, or says why it could not be made. Nothing coercesUnknownto a default.Accepted/Rejected/PublicationUnknown/PublicationUnresolvable: what happened to a publication.Unknownmeans the side effect may have happened (a lost receipt);Unresolvablemeans the backend has no ledger to ask, so the runtime must reconcile through its own durable intent.SettleConfirmed/SettleUnknown/SettleStale: what happened to a settlement. A stale settlement is one issued from a delivery attempt that a newer attempt has superseded; it is refused before it reaches the broker.CleanupObservation: what a teardown actually removed, and what it could not — never a silent return on a failed listing.
- class videoflow.backends.outcomes.Accepted(publication_id: str, sequence: int | None, duplicate: bool, durability_boundary: str)[source]
Bases:
objectThe backend durably took the envelope.
duplicateis True when it deduplicated a retry.- duplicate: bool
- durability_boundary: str
- publication_id: str
- sequence: int | None
- class videoflow.backends.outcomes.CleanupObservation(complete: bool, removed: tuple[str, ...], remaining: tuple[str, ...], reason: str = '')[source]
Bases:
objectWhat a teardown did.
completeis False when anything owned could not be confirmed removed — including when the inventory itself could not be read, which is not “nothing to remove”.- complete: bool
- reason: str = ''
- remaining: tuple[str, ...]
- removed: tuple[str, ...]
- videoflow.backends.outcomes.DURABILITY_MEMORY = 'memory'
Durability boundaries an
Acceptedpublication can report having crossed.
- class videoflow.backends.outcomes.Known(value: T, observed_at: float, generation: str | None = None)[source]
Bases:
Generic[T]A successful observation.
- Arguments:
value: what was observed.
observed_at: monotonic time of the observation, so two observations can be ordered without trusting wall clocks.
generation: the provider’s version of the observed state when it has one (a Kubernetes
resourceVersion, a consumer info sequence, a ledger version).Nonewhen the provider offers nothing comparable.
- generation: str | None = None
- observed_at: float
- value: T
- class videoflow.backends.outcomes.PublicationUnknown(publication_id: str, reason: str)[source]
Bases:
objectA response was lost or a deadline expired after the send; the envelope may be stored.
- publication_id: str
- reason: str
- class videoflow.backends.outcomes.PublicationUnresolvable(publication_id: str, reason: str)[source]
Bases:
objectThe backend keeps no queryable publication history for this id; only the runtime’s own intent can reconcile it.
- publication_id: str
- reason: str
- class videoflow.backends.outcomes.Rejected(publication_id: str, reason: str, retryable: bool)[source]
Bases:
objectThe backend definitely did not take the envelope.
retryablesays whether waiting can help.- publication_id: str
- reason: str
- retryable: bool
- class videoflow.backends.outcomes.SettleConfirmed(token: 'DeliveryToken', settlement_id: str)[source]
Bases:
object- settlement_id: str
- token: DeliveryToken
- class videoflow.backends.outcomes.SettleStale(token: DeliveryToken, current_attempt: int, current_generation: str)[source]
Bases:
objectRefused before reaching the broker: a newer attempt owns this logical message.
- current_attempt: int
- current_generation: str
- token: DeliveryToken
- class videoflow.backends.outcomes.SettleUnknown(token: DeliveryToken, reason: str)[source]
Bases:
objectThe settlement was sent but not confirmed; the delivery may still be leased or may redeliver.
- reason: str
- token: DeliveryToken
- class videoflow.backends.outcomes.Unknown(reason: str, observed_at: float, detail: str = '')[source]
Bases:
objectAn observation that could not be made.
reasonis a short machine-readable category ('timeout','auth','malformed','unreachable','unsupported');detailis the human-readable why.- detail: str = ''
- observed_at: float
- reason: str
videoflow.backends.payload module
The PayloadStore contract: where the image bytes are, and how long they must
survive.
The reviewed implementation kept one decrement-only counter per blob and deleted
the blob when it reached zero. Two deliveries of the same message to the same
reader decremented twice; a counter that expired between EXISTS and DECR
deleted a blob another reader still needed; a crash after the acknowledgment but
before the release leaked the blob until its TTL. The contract here replaces the
counter with obligations: named, idempotent, generation-fenced claims by
logical readers. A payload is reclaimable only when no obligation names it; a
release is idempotent by (obligation_id, generation); a TTL is an expiry
policy or a final safety net, never proof that every consumer finished.
Read outcomes are typed: transient failures retry, a missing object is a
durable data-loss outcome, a digest mismatch is corruption. None of them is a
silent None.
- class videoflow.backends.payload.Corrupt(ref: videoflow.backends.payload.ImmutablePayloadRef, expected_digest: str, actual_digest: str)[source]
Bases:
object- actual_digest: str
- expected_digest: str
- ref: ImmutablePayloadRef
- class videoflow.backends.payload.DurableReceipt(ref: videoflow.backends.payload.ImmutablePayloadRef, obligation_id: str, deadline: float)[source]
Bases:
object- deadline: float
- obligation_id: str
- ref: ImmutablePayloadRef
- class videoflow.backends.payload.ImmutablePayloadRef(store: str, key: str, size: int, digest: str, generation: str, content_id: str)[source]
Bases:
object- Arguments:
store: the store identity the ref belongs to (
'redis','memory').key: the store-local key (the wire
BlobRef.ref).size: byte length of the object.
digest: hex SHA-256 of the object, verified on read when the store keeps it.
generation: the ownership generation minted at
put; a release from an older generation is stale and cannot delete a newer object at the same key.content_id: the logical content identity (event id + producer), so an unchanged frame forwarded through metadata stages can share one object.
- content_id: str
- digest: str
- generation: str
- key: str
- size: int
- store: str
- class videoflow.backends.payload.Missing(ref: videoflow.backends.payload.ImmutablePayloadRef)[source]
Bases:
object- ref: ImmutablePayloadRef
- class videoflow.backends.payload.ObligationLedger[source]
Bases:
ABCWhat the runtime knows about obligations, for reconciliation: which readers are still required for which refs. A store reconciles its objects against it.
A ledger speaks for the obligation families it is authoritative for and no other: the runtime ledger knows its flow’s readers and publishers’ intents, not an archive’s or a dead-letter pin’s (
BLOB-13familiesarchive/*,dlq/*), so a store cancels an obligation the ledger does not require only when the ledger is authoritative for it. The default — everything — is the whole-truth ledger a flow-wide reconciler or a test builds.
- class videoflow.backends.payload.PayloadBytes(ref: videoflow.backends.payload.ImmutablePayloadRef, data: bytes, digest_verified: bool)[source]
Bases:
object- data: bytes
- digest_verified: bool
- ref: ImmutablePayloadRef
- class videoflow.backends.payload.PayloadStore[source]
Bases:
ABC- abstractmethod acquire_obligation(ref: ImmutablePayloadRef, obligation_id: str, deadline: float) DurableReceipt[source]
- abstractmethod capabilities() PayloadCapabilities[source]
- abstractmethod inventory() Known[tuple[ImmutablePayloadRef, ...]] | Unknown[source]
- abstractmethod put(data: bytes, content_id: str, contract: RetentionContract) ImmutablePayloadRef[source]
- abstractmethod read(ref: ImmutablePayloadRef) PayloadBytes | TransientFailure | Missing | Corrupt[source]
- abstractmethod reconcile(ledger: ObligationLedger, operation_id: str) ReclamationObservation[source]
- ref_for_key(key: str) ImmutablePayloadRef[source]
The ref for a wire key (
BlobRef.ref), completed from the store’s own metadata when it keeps any: size, digest and generation as recorded atput, so a reader that only has the key can still verify what it reads and release against the right generation. A store without metadata for the key (an RFC 0002 publisher, or metadata that expired) returns a ref with empty digest and generation — readable, unverifiable, and released against nothing.
- abstractmethod release_obligation(ref: ImmutablePayloadRef, obligation_id: str, completion_receipt: str) ReleaseReceipt[source]
- abstractmethod renew_obligation(ref: ImmutablePayloadRef, obligation_id: str, deadline: float) DurableReceipt[source]
- class videoflow.backends.payload.ReclamationObservation(reclaimed: tuple[str, ...], retained: tuple[str, ...], unknown: tuple[str, ...])[source]
Bases:
object- reclaimed: tuple[str, ...]
- retained: tuple[str, ...]
- unknown: tuple[str, ...]
- class videoflow.backends.payload.ReleaseReceipt(ref: ImmutablePayloadRef, obligation_id: str, remaining: int | None, reclaimed: bool, stale: bool, unknown: bool = False)[source]
Bases:
objectstalemeans the release named an older generation and touched nothing;unknownmeans the store applied (or may have applied) the release but the response was lost — the caller retries, which is safe because a release is idempotent by(obligation_id, generation).- obligation_id: str
- reclaimed: bool
- ref: ImmutablePayloadRef
- remaining: int | None
- stale: bool
- unknown: bool = False
- class videoflow.backends.payload.RetentionContract(ttl_seconds: int, horizon_seconds: int, durable_required: bool, obligations: tuple[str, ...] = ())[source]
Bases:
object- Arguments:
ttl_seconds: the store-side expiry backstop.
horizon_seconds: the recovery/replay horizon the flow promised; a TTL shorter than it is rejected at admission unless obligations pin the object for the whole horizon.
durable_required: whether the profile needs the object to survive the store’s own failure model (reliable work) or tolerates loss (live).
obligations: the logical readers that will claim the object up front.
- durable_required: bool
- horizon_seconds: int
- obligations: tuple[str, ...] = ()
- ttl_seconds: int
- class videoflow.backends.payload.TransientFailure(ref: ImmutablePayloadRef, reason: str)[source]
Bases:
objectThe store was unreachable or slow; the bytes may still exist. Retry. (An outcome, not the core error.)
- reason: str
- ref: ImmutablePayloadRef
- videoflow.backends.payload.admit_retention(contract: RetentionContract) None[source]
Admit a retention contract before a byte is written (
BLOB-14step 5, PAY-009): adurable_requiredcontract whose TTL is shorter than the recovery horizon it promises is rejected unless obligations pin the object for the whole horizon. Both reference stores extend a pinned object’s life to the horizon, so with obligations the TTL is a backstop rather than the bound; without them it is the bound, and a horizon it cannot cover is a promise nobody keeps.- Raises:
IncompatibleProfile: the contract promises a horizon its TTL cannot cover and no obligation pins the object.
videoflow.backends.payload_bridge module
A BlobStore façade over a PayloadStore, so the wire codec’s offload path
(encode_envelope(blob_store = ...) / hydrate_message(decoded, blob_store))
can drive an obligation-keeping store without the codec learning about
obligations, contracts or typed read outcomes.
The codec sees the RFC 0002 interface it always has: put_with_readers returns
the wire key, get returns bytes or raises. Behind it the bridge translates:
a put becomes
PayloadStore.putunder aRetentionContractnaming the reader obligations the publisher acquires up front (BLOB-14step 1) plus the publisher’s ownintent/<publication_id>for the send in flight; the ref of the last put is kept so the messenger can release that intent once the publication’s outcome is known. The reader set is the bridge’s (VF_BLOB_READER_IDS), whichever of the codec’s two put paths is taken: the RFC 0002 reader count chooses between them and means nothing here. With no reader ids at all the object is TTL-only — no obligations, not even the intent — because a lone intent released on the PubAck would reclaim an object its (unidentified) readers have yet to fetch (ENV-12: ids unset ⇒ count semantics, else TTL-only);a read’s typed outcome becomes the error the messenger’s ladder already understands:
TransientFailure(retry — never malformed bytes,BLOB-15), andDecodeErrorforMissing/Corrupt(terminal for that delivery, dead-lettered with aVF-Errornaming the ref and the reason);releaseis a no-op — obligations are released by reader id through the store, after a confirmed settlement, which is the messenger’s decision.
- class videoflow.backends.payload_bridge.PayloadStoreBlobBridge(store: ~videoflow.backends.payload.PayloadStore, obligations: ~typing.Sequence[str], horizon_seconds: int, durable_required: bool, content_id: ~typing.Callable[[], str], intent: ~typing.Callable[[], str | None] = <function PayloadStoreBlobBridge.<lambda>>)[source]
Bases:
BlobStore- Arguments:
store: the obligation-keeping store.
- obligations: the reader obligation ids every put acquires up front
(
VF_BLOB_READER_IDS:<child>per competing child,<child>/p<i>per partitioned replica).
- horizon_seconds: the recovery horizon the flow promised; a shorter
TTL is the admission’s problem, recorded on the contract here.
- durable_required: whether the channel’s profile needs the bytes to
survive the store’s own failure model.
- content_id: the logical content identity of the message being
published, evaluated at put time.
- intent: the
intent/<publication_id>obligation for the send in flight, evaluated at put time; None when there is none.
- intent: the
- last_ref: ImmutablePayloadRef | None
The ref of the most recent put — what the publisher releases its intent on.
- put(data: bytes, ttl_seconds: int = 3600) str[source]
Stores
dataand returns an opaque reference string thatget()can resolve later.
- put_with_readers(data: bytes, readers: int, ttl_seconds: int = 3600) str[source]
Stores
dataexpecting exactlyreadersdownstream reads, enabling the store to reclaim the blob once every reader has released it (BLOB-5).Default implementation ignores
readersand delegates toput()— a store with no reclamation support degrades to plain TTL expiry.
- release(ref: str) None[source]
One downstream reader is finished with
ref(its message was acked, BLOB-6). Default no-op.
- property store: PayloadStore
videoflow.backends.runtime module
Runtime contracts: the durable state that makes processing correct across restarts, independent of the transport underneath.
RuntimeStore is a small versioned key-value store with compare-and-swap;
three implementations exist (memory for tests, a file directory for the local
engine, Redis for clusters) and the planner reads their capabilities to decide
whether a restart-safe profile can be admitted at all. The FlowRuntime built
on it (Phase 3 of the backend plan) owns the group ledger, ownership epochs,
completion barriers, the publication outbox and source epochs.
This module also carries the one identity rule that must be pure and stable
across languages: group_identity — the id of a time-aligned input group is
derived from its members, not from a rounded timestamp, so two distinct groups
whose event times round to the same microsecond never collide, and a replay of
the same members yields the same id.
- class videoflow.backends.runtime.CommitReceipt(group_id: str, state_version: str, output_intents: tuple[str, ...], effect_intents: tuple[str, ...])[source]
Bases:
object- effect_intents: tuple[str, ...]
- group_id: str
- output_intents: tuple[str, ...]
- state_version: str
- class videoflow.backends.runtime.CompletionReceipt(partition_id: str, epoch: int, final_sequence: int, version: str)[source]
Bases:
object- epoch: int
- final_sequence: int
- partition_id: str
- version: str
- videoflow.backends.runtime.DEFAULT_PARTITION_LEASE_SECONDS = 10.0
How many times a compare-and-swap is retried against a concurrent writer before the caller is told the store would not take the update. How long a partition lease lasts without renewal (
VF_PARTITION_LEASE_SECONDS): a crashed holder’s replacement waits at most this long; a live holder renews every third of it from its own thread. Long enough that a scheduler hiccup does not usurp a paused process, short enough that a crash is not a long outage.
- videoflow.backends.runtime.DEFAULT_RECONCILE_INTERVAL_SECONDS = 60.0
How often a running worker reconciles payload obligations (
BLOB-14step 4);0disables the periodic pass (the start pass always runs).
- class videoflow.backends.runtime.FlowRuntime(store: ~videoflow.backends.runtime.RuntimeStore, flow_id: str, run_id: str, node: str, replica_id: int = 0, nb_tasks: int = 1, partition_by: str | None = None, parent_replicas: ~typing.Mapping[str, int] | None = None, clock: ~typing.Callable[[], float] = <built-in function time>, lease_seconds: float = 10.0, sleep: ~typing.Callable[[float], None] = <built-in function sleep>)[source]
Bases:
objectThe per-node runtime ledger of RFC 0006
CTRL-4, over anyRuntimeStore: terminators and received sets (theEOS-7completion barrier), ownership epochs with fencing, the publication outbox, attempt counts, the terminal log, pending dead-letter handoffs, open join groups, checkpoints and sink-effect markers. Every mutation is a compare-and-swap on one key; every read is what the store holds, so a replacement process starts from the same facts.What it never does: decide policy. The messenger asks it questions (
completion_state,attempts_for) and records facts; the answers hold only as far as the store’s owncapabilities()— a memory store makes every record process-local, and the callers know it (durable_shared()).- Arguments:
store: the
RuntimeStore(VF_RUNTIME_STORE_URL).flow_id / run_id / node: the ledger’s namespace,
vf/{flow}/{run}/{node}/.replica_id / nb_tasks / partition_by: this replica’s identity within the node.
parent_replicas:
{parent: nb_tasks}fromVF_PARENT_REPLICAS(ENV-11); a parent absent from it has no completion barrier.clock: epoch seconds, injectable for tests.
completion_statetakes the durable’s(num_pending, num_ack_pending)observation as the messenger reads it (_consumer_pending).- aborted_parents() dict[str, Mapping[str, Any]][source]
Parents with a recorded ABORT, with the error each carried — an ABORT outranks a clean EOS (ABORT-3).
- acquire_partition(partition_id: str | None = None, expected_epoch: int | None = None, wait: bool = True) OwnershipToken[source]
Take (or retake) ownership of a partition: the epoch is CAS-incremented and a fresh fencing token minted.
expected_epochrefuses the acquisition when someone else has moved the epoch since the caller last saw it.A partition is leased: the record names its holder and a
lease_untilthe holder renews (renew_partition) and clears on a graceful close (release_partition). Another process asking for a partition whose lease is live waits for it to lapse — at most one lease length — and is refused the moment the holder renews it (a renewal proves the holder alive): a singleton scaled out by adding replicas fails explicitly at bind time instead of two owners fencing each other in turns (RUN-018, RUN-019), while the replacement for a crashed holder takes over as soon as its lease lapses, and at once after a graceful close.wait = Falserefuses a live lease at once instead of waiting for it to lapse (claim_replica_slotprobes the free slots that way first).- Raises:
StaleAuthority:
expected_epochno longer matches (another owner took over), or the store would not take the update.OwnershipConflict: another live process holds the partition’s lease.
- attempts_for(message_id: str) int[source]
Failed attempts of
message_idthat count against its budget (neverworker_fatal).
- capabilities() RuntimeCapabilities[source]
- check_authority(token: OwnershipToken) None[source]
Refuse a commit under a superseded epoch: the store’s epoch and token must be the caller’s.
- checkpoint(state: bytes, replay_position: Mapping[str, Any]) str[source]
One CAS write: state and position describe the same committed prefix.
replay_positionis the node’s own vocabulary ({'offset': 42}for a replayable source,{'group': <input key>}for a stateful node, plus theoutputcommitted with it). Returns the new version.
- commit_completion(parent: str, token: OwnershipToken | None = None) CompletionReceipt[source]
Record that
parentis complete for this replica’s partition; refused under a superseded epoch of that partition (StaleAuthority). Partitions are independent authorities — a sibling replica’s epoch says nothing about this one’s — so the record is keyed by partition id.
- completed_parents(partition_id: str | None = None) set[str][source]
Parents this replica’s partition (or
partition_id) has committed complete.
- completion_state(parent: str, durable: str, observation: Known[tuple[int, int]] | Unknown, pending_halves: bool = False) str[source]
Where
parentstands for this node (EOS-7):openuntil every expected replica’s terminator is recorded;abortedonce an ABORT is recorded and the parent is drained;drainingwhile the received count is short of the terminators’ final counts, a join still holds a half, or the broker still reports deliveries;unknownwhile the broker cannot be observed — nevercompleteon evidence that was never obtained.
Whether records here outlive this process and are seen by sibling replicas: the EOS-7 and D11 gate.
- property flow_id: str
- held_partition(partition_id: str | None = None) OwnershipToken | None[source]
The token this process holds for the partition, if it acquired it already (
claim_replica_slot).
- intend_publication(publication_id: str, digest: str, payload_refs: Sequence[str] = (), kind: str = 'data', readers: Sequence[str] = ()) str[source]
Record the intent to publish before the send; returns the key’s version (an existing intent is kept).
readersare the reader obligations the put acquired (VF_BLOB_READER_IDS), kept with the refs so a reconciler can tell which readers still owe a release (RuntimeObligationLedger).
- property lease_seconds: float
- mark_effect(key: str, retention_seconds: float) bool[source]
Mark an effect as applied; False when it already was (within its retention).
- property node: str
- open_groups() list[RecoveryRecord][source]
- outbox_entry(publication_id: str) OutboxEntry | None[source]
- outbox_of(node: str) list[dict[str, Any]][source]
Every outbox document of
nodein this run (a parent’s, for a reader reconciling the obligations it and its siblings owe): the raw records —refs,readers,outcome,seqwhen accepted.
- property parent_replicas: Mapping[str, int]
- pending_handoffs() list[PendingHandoff][source]
- persist_group(group_id: str, members: Mapping[str, tuple[str, str, int]], tokens: Mapping[str, str]) RecoveryRecord[source]
Record a group’s members by logical id as they arrive (idempotent; a redelivered member replaces its token).
- published_count() int[source]
Distinct DATA ids this replica published (accepted or deduplicated): a terminator’s
seq(EOS-7).
- received_ids(parent: str, durable: str) set[str][source]
The union over this node’s replicas of the distinct ids delivered from
parentondurable.
- record_attempt(message_id: str, disposition: str) int[source]
One failed attempt of
message_idunderdisposition;worker_fatalnever counts. Returns the budgeted count.
- record_pending_handoff(record_id: str, headers: Mapping[str, str], raw: bytes) None[source]
A dead letter the broker did not accept: kept so a later attempt (or a restart) re-publishes it under the same id.
- record_received(parent: str, durable: str, message_id: str) bool[source]
Note a distinct DATA id delivered from
parentondurableto this replica; False when already noted.
- record_terminal(record: Mapping[str, Any]) str[source]
Append a terminal record (a delivery ended without a dead letter) and return its reference.
- record_terminator(parent: str, replica_id: int, kind: str, seq: int, error: Mapping[str, Any] | None = None) bool[source]
Record a parent replica’s terminator before it is acked. Idempotent by
(parent, replica_id, kind): returns False when that fact was already recorded (a duplicate marker), True when it is new.
- release_partition(token: OwnershipToken) None[source]
Clear the lease on a graceful close so a replacement takes over at once; a superseded token releases nothing.
- renew_partition(token: OwnershipToken) float[source]
Extend the lease of a partition this process holds; returns the new
lease_until. A record that no longer carries the token belongs to another owner:StaleAuthority.
- property replica_id: int
- resolve_publication(publication_id: str, outcome: Accepted | Rejected | PublicationUnknown | PublicationUnresolvable) None[source]
Record the send’s outcome; an
Accepted(duplicate included) DATA id counts once for EOS-7.
- property run_id: str
- property store: RuntimeStore
- terminators(parent: str) list[TerminatorRecord][source]
- unresolved_publications() list[OutboxEntry][source]
Intents whose send was never confirmed (
intentorunknown): what a restart must reconcile first.
- videoflow.backends.runtime.LEASE_POLL_SECONDS = 0.5
How often a would-be owner re-reads a held lease while waiting for it to lapse.
- class videoflow.backends.runtime.OutboxEntry(publication_id: str, digest: str, payload_refs: tuple[str, ...], outcome: str, kind: str, replica_id: int)[source]
Bases:
object- digest: str
- kind: str
- outcome: str
- payload_refs: tuple[str, ...]
- publication_id: str
- replica_id: int
- class videoflow.backends.runtime.OwnershipToken(partition_id: str, epoch: int, fencing_token: str)[source]
Bases:
objectA fencing token: commits carry it, and a commit under a superseded epoch is refused.
- epoch: int
- fencing_token: str
- partition_id: str
- class videoflow.backends.runtime.PendingHandoff(record_id: str, headers: Mapping[str, str], raw: bytes, attempts: int)[source]
Bases:
object- attempts: int
- headers: Mapping[str, str]
- raw: bytes
- record_id: str
- class videoflow.backends.runtime.RecoveryRecord(group_id: str, members: Mapping[str, str], version: str)[source]
Bases:
object- group_id: str
- members: Mapping[str, str]
- version: str
- class videoflow.backends.runtime.RuntimeStore[source]
Bases:
ABCVersioned KV.
cassucceeds only when the key’s current version equalsexpected_version(None= must not exist). Versions are opaque strings the store mints; callers never fabricate one.- abstractmethod capabilities() RuntimeCapabilities[source]
- class videoflow.backends.runtime.TerminatorRecord(parent: str, replica_id: int, kind: str, seq: int, error: Mapping[str, Any] | None)[source]
Bases:
object- error: Mapping[str, Any] | None
- kind: str
- parent: str
- replica_id: int
- seq: int
- videoflow.backends.runtime.claim_replica_slot(store: ~videoflow.backends.runtime.RuntimeStore, flow_id: str, run_id: str, node: str, nb_tasks: int, partition_by: str | None = None, parent_replicas: ~typing.Mapping[str, int] | None = None, slots: int | None = None, clock: ~typing.Callable[[], float] = <built-in function time>, lease_seconds: float = 10.0, sleep: ~typing.Callable[[float], None] = <built-in function sleep>) FlowRuntime[source]
A replica id for a process that was given none (ENV-5 step 3): the lowest slot
0..slots-1whose partition lease is free or lapsed, claimed through the ledger, and theFlowRuntimethat holds it. A Kubernetes Deployment pod has no ordinal, so its competing replicas would all report as replica 0 — one terminator where the barrier expects N, one lease fought over by N pods; claiming a slot gives the live pods distinct, stable identities, and the replacement for a crashed pod resumes that pod’s slot (and its ledger: unresolved intents, terminators) once its lease lapses.Free and lapsed slots are taken at once; when none is, each live slot is waited on in turn for at most one lease length (a renewal proves its holder alive). A process that finds every slot held is an extra replica, refused the way a scaled-out singleton is (RUN-018).
- Arguments:
nb_tasks: the node’s declared replica count (what the runtime is built with).
slots: how many identities may be claimed —
nb_tasksunless a scaler may run more pods (VF_REPLICA_SLOTS, its ceiling), which are wanted replicas rather than extras.
- Raises:
OwnershipConflict: every slot is held under a live lease.
- videoflow.backends.runtime.group_identity(members: Mapping[str, tuple[str, str, int]], window_id: str | None, rounded_micros: int | None = None) str[source]
Canonical identity of an input group.
- Arguments:
members: parent name -> (producer, trace_id, seq) of the member it contributed.
window_id: the join window or namespace the group formed in (
Nonefor trace joins).rounded_micros: the legacy
tw-<µs>prefix component, kept so ids stay sortable by time; distinctness comes from the member hash.
- videoflow.backends.runtime.partition_lease_from_env(value: str | None) float[source]
VF_PARTITION_LEASE_SECONDSparsed: absent means the default; a non-positive or non-numeric value fails fast.
- videoflow.backends.runtime.reconcile_interval_from_env(value: str | None) float[source]
VF_RECONCILE_INTERVAL_SECONDSparsed: absent means the default; negative or non-numeric fails fast.
- videoflow.backends.runtime.replayable_trace_id(node: str, offset: int, analysis_version: str | None = None) str[source]
Trace id of a replayable source’s frame at
offset; a new analysis version is a new namespace.
- videoflow.backends.runtime.source_epoch_trace_id(node: str, epoch: str, sequence: int) str[source]
Trace id of a live source’s
sequence-th capture within capture epochepoch.
Whether a store’s records outlive one process and are seen by sibling replicas (what makes a ledger a ledger).