Files
StarPilot/openpilot/starpilot/flm/fullrate_collector.py
T
Dom 487dfc4bf4 FLM: preserve fresh evidence across paired queue drains
Merge bounded control/output FIFO heads using original publisher headers. Preserve original age, native, source, overflow and malformed-input checks; retain producer order after joins.

Validated with actual pinned cloud dependencies and fresh-head regression tests.
2026-10-27 17:01:24 -05:00

962 lines
38 KiB
Python

"""Bounded fullrate command ownership and independent physical response join.
Runs in a separate learning process, never inside Controls/Card or torqued.
Inputs are decoded custom evidence produced by actual owners; no Params/default
controller selection is inferred here. Domain adapters qualify response inverse.
"""
from typing import TypeGuard, cast
from collections import Counter, OrderedDict, deque
from openpilot.starpilot.flm.torque_eligibility import asynchronous_hint, bounded_context_output, exact_unclipped_pair, consumed_sources_current
from openpilot.starpilot.flm.native_refinement_wire import valid_inputs
from dataclasses import dataclass, replace
import math
import re
import uuid
from openpilot.starpilot.flm.adaptive_profile import Block, Sample, Result, evaluate, replay_accepts, readmit_profile
_IDENTITY_HEX64 = re.compile(r'[0-9a-f]{64}')
MAX_PENDING = 128
MAX_DRAIN = 32
MAX_POINTS = 240
MAX_RAW_POINTS = 80 # 16*80/20Hz*100Hz +16*100 warmup frames <=8160.
MAX_BLOCKS = 24
MAX_AGE_NS = 100_000_000
JOIN_NS = 30_000_000
ACTIVE_NS = 2_000_000_000
EXCLUSION_NS = 1_000_000_000
MAX_WIRE_BYTES = 32768
MAX_SNAPSHOT_WIRE_BYTES = 131072
def finite(value: object) -> TypeGuard[int | float]:
return (type(value) is int or type(value) is float) and math.isfinite(value)
def replay_values(value, bound):
return bool(
type(value) is tuple
and len(value) <= bound
and len({name for name, _ in value}) == len(value)
and all(type(name) is str and 0 < len(name) <= 96 and (type(item) is bool or finite(item) or type(item) is str and len(item) <= 96) for name, item in value)
)
def identity(value):
return type(value) is str and len(value) == 64 and _IDENTITY_HEX64.fullmatch(value) is not None
@dataclass(frozen=True)
class ControlEvidence:
identity: str
generation: int
control_ns: int
state_ns: int
domain: str
stage_revision: str
response_revision: str
requested: float
features: tuple[float, ...]
baseline_prediction: float
enabled: bool
manual: bool
active: bool
valid: bool
override: bool
fault: bool
saturated: bool
limited: bool
model_wobble: bool
controller_chatter: bool
stage_schema_revision: str = ''
stage_values: tuple[tuple[str, float], ...] = ()
applied_coordinates: tuple[float, ...] = ()
source_epoch: str = ''
source_receipt_ns: int = 0
controller_mode: str = ''
policy: str = ''
baseline_revision: str = ''
baseline_values: tuple[float, ...] = ()
controller_revision: str = ''
replay_snapshot: tuple[tuple[str, object], ...] = ()
replay_inputs: tuple[tuple[str, object], ...] = ()
snapshot_sequence: int = 0
turn_assist: bool = False
applied_parameter_names: tuple[str, ...] = ()
native_required: bool = False
native_observed_ns: int = 0
native_expires_ns: int = 0
native_allowed: bool = False
native_identity: str = ''
applied_profile_sequence: int = 0
applied_profile_observed_ns: int = 0
applied_profile_expires_ns: int = 0
effect_trace: object | None = None
effect_prepare_ns: int = 0
vehicle_model_anchor: tuple[float, ...] = ()
live_applied_coordinates: tuple[float, ...] = ()
@dataclass(frozen=True)
class AppliedEvidence:
control_ns: int
state_ns: int
apply_ns: int
domain: str
applied: float
valid: bool
active: bool
override: bool
fault: bool
limited: bool
native_allowed: bool
projection: object = None
carrier_frame: int = 0
carrier_observed_ns: int = 0
@dataclass(frozen=True)
class PhysicalEvidence:
mono_ns: int
received_ns: int
calibration: str
model_generation: str
lag_generation: str
lag_ns: int
speed_mps: float
yaw_rate: float
roll_rad: float
steering_angle_deg: float
valid: bool
override: bool
fault: bool
# Current physical and authority witnesses, not historical healthy booleans.
native_allowed: bool
source_boot_ns: int = 0
clock_offset_ns: int = 0
clock_uncertainty_ns: int = 0
@dataclass(frozen=True)
class RawPoint:
control_ns: int
apply_ns: int
mono_ns: int
control: ControlEvidence
output: AppliedEvidence
physical: dict
physical_context: tuple
@dataclass(frozen=True)
class RawBlock:
identity: str
block_id: str
cohort: str
stage_revision: str
response_revision: str
samples: tuple[RawPoint, ...]
class FullrateCollector:
def __init__(self, adapter):
self.adapter = adapter
self.live_tracking = None
self.live_response_pair = None
self._last_live_ingest_ns = 0
self.session = uuid.uuid4().hex
self.sequence = self.block_sequence = 0
self.controls = OrderedDict()
self.applied = OrderedDict()
self.recent_controls = OrderedDict()
self.recent_applied = OrderedDict()
self.ready = deque(maxlen=MAX_PENDING)
# Historical NUMERICAL inputs only. Pending/live joins keep MAX_PENDING;
# the actor still enforces original2s age, source/native identity and expiry.
self.probe_ready = deque(maxlen=256)
self.last_carrier_frame = 0
self.blocks = deque(maxlen=MAX_BLOCKS)
self.points = []
self.raw_points = []
self.context = self.physical_context = self.cohort = None
self.active_since = self.last_apply = self.last_response = 0
self.excluded_until = 0
self.last_qualified_response = 0
self.last_fit = 0
self.fit_result = self.fit_validation = self.last_validation = None
self.prior_coefficients = None
self.live_profile_sequence = 0
self.fit_block_sequence = 0
self.result = None
self.reason = 'initializing'
self.training_interruptions = Counter()
self.dropped = 0
self.sealed = False
self.model_block_sequence = self.model_points = 0
self.model_sealed = False
def enable_original_source_capture(self, *, clock_contract=None):
"""Explicit private experiment; never called by the production parent."""
from openpilot.starpilot.flm.original_source_capture import OriginalSourceCapture, OriginalSourceClockContract
if getattr(self, 'original_source_capture', None) is not None:
raise ValueError('original source capture already enabled')
if clock_contract is None:
from openpilot.starpilot.flm.producer_clock_equivalence import pinned_default_contract
clock_contract = pinned_default_contract()
if not isinstance(clock_contract, OriginalSourceClockContract):
raise ValueError('independently pinned original producer-clock contract required')
clock_contract.validate()
enable_context = getattr(self.adapter, 'enable_original_context_capture', None)
if enable_context is None:
raise ValueError('actual original context-only archive required')
enable_context()
self.original_source_clock_contract = clock_contract
self.original_source_capture = OriginalSourceCapture()
def begin_original_source_experiment(self, receipt):
capture = getattr(self, 'original_source_capture', None)
if capture is None:
raise ValueError('original source capture not enabled')
capture.begin_epoch(receipt)
def reset_original_source_capture(self, reason, *, hard=False):
capture = getattr(self, 'original_source_capture', None)
if capture is None:
return
pending = getattr(self, '_original_source_pose_queue', ())
if hard:
# Revoke every previously seen/pending source publication. Clearing seen
# alone would recapture the same old KF publication after OFF/ON.
floor = max((getattr(self, '_original_source_revoked_before_ns', 0),
getattr(self, '_original_source_seen_pose', 0),
*(row.mono_ns for row in pending), *(row.mono_ns for row in capture.rows[-1:])))
self._original_source_revoked_before_ns = floor
for name in ('_original_source_pose_context', '_original_source_clock',
'_original_source_calibrator', '_original_source_vm_anchor', '_original_source_equivalence'):
self.__dict__.pop(name, None)
self._original_source_seen_pose = 0
self._original_source_clock_generation = getattr(self, '_original_source_clock_generation', 0) + 1
self._original_source_pose_queue = ()
capture.reset(reason, hard=hard)
def original_source_pose(self, value, now_ns):
capture = getattr(self, 'original_source_capture', None)
if capture is None:
return False
# The 5120 raw-row cap includes legacy retained rows and the <=4 original
# pending poses. No second 5120-row allowance is created by this opt-in.
retained = len(self.raw_points) + sum(len(block.samples) for block in self.blocks)
pending = len(getattr(self, '_original_source_pose_queue', ()))
return capture.add(value, now_ns, retained_raw_rows=retained + pending)
def split(self, reason, *, reset=False):
self.reset_original_source_capture(reason, hard=reset)
if self.live_tracking is not None:
self.live_tracking.interrupt(reason, context_changed=reset)
self.live_response_pair = None
if reason in self.training_interruptions or len(self.training_interruptions) < 24:
self.training_interruptions[reason] += 1
self.controls.clear()
self.applied.clear()
self.recent_controls.clear()
self.recent_applied.clear()
self.ready.clear()
self.probe_ready.clear()
self.last_carrier_frame = 0
self.points.clear()
self.raw_points.clear()
self.active_since = self.last_apply = self.last_response = self.last_qualified_response = 0
self.cohort = None
self.sealed = False
self.model_block_sequence += 1
self.model_points = 0
self.model_sealed = False
self.reason = reason
self.result = self.last_validation = None
if reset:
self.blocks.clear()
self.result = self.fit_result = self.fit_validation = None
self.physical_context = None
self.fit_block_sequence = 0
def _retain_original_pair(self, command, output):
# Called only AFTER existing source/receiver/native admission above.
# Keep the exact same objects and clocks; this supplies no new proof.
pair=(command,output)
self.ready.append(pair)
self.probe_ready.append(pair)
def overrun(self):
self.dropped += 1
self.split('fullrate_overrun')
def _retains_controller_chatter(self, value):
# Legacy/custom collection never opts into the event-only trial contract.
return False
def control(self, value, now_ns):
if isinstance(value, ControlEvidence) and (value.manual or not value.enabled):
self.reset_original_source_capture('original_source_disabled_or_manual', hard=True)
if isinstance(value, ControlEvidence) and value.effect_trace is not None:
try:
from openpilot.starpilot.flm.effect_trace import FullEffectTrace
trace = value.effect_trace
if not isinstance(trace, FullEffectTrace):
raise ValueError('typed full effect trace')
trace.validate()
if (trace.control_ns != value.effect_prepare_ns or trace.envelope.source_epoch != value.source_epoch or
trace.envelope.selected_baseline_revision != value.baseline_revision or
trace.envelope.controller_revision != value.controller_revision or any(value.applied_coordinates)):
raise ValueError('full effect trace source mismatch')
if trace.qualified and (value.applied_profile_sequence <= 0 or not
0 < value.applied_profile_observed_ns <= value.control_ns <= value.applied_profile_expires_ns <=
value.applied_profile_observed_ns + 500_000_000):
raise ValueError('applied full30 lacks original profile lease')
except (AttributeError, KeyError, TypeError, ValueError, OverflowError):
self.split('full_effect_trace_invalid')
return
if (
not isinstance(value, ControlEvidence)
or not identity(value.identity)
or type(value.generation) is not int
or value.generation < 0
or type(value.control_ns) is not int
or type(value.state_ns) is not int
or not 0 < value.state_ns <= value.control_ns <= now_ns
or value.domain != 'normalized_torque' and value.control_ns - value.state_ns > JOIN_NS
or not 1 <= len(value.features) <= 8
or not all(finite(v) for v in (value.requested, value.baseline_prediction, *value.features, *value.applied_coordinates))
or len(value.stage_values) > 40
or not value.stage_schema_revision
or len({name for name, _ in value.stage_values}) != len(value.stage_values)
or any(not isinstance(name, str) or not 0 < len(name) <= 64 or not finite(v) for name, v in value.stage_values)
or len(value.applied_coordinates) != len(value.features)
or not identity(value.source_epoch)
or not identity(value.baseline_revision)
or type(value.source_receipt_ns) is not int
or not 0 < value.source_receipt_ns <= value.control_ns
or value.control_ns - value.source_receipt_ns > 500_000_000
or not value.controller_mode
or not value.policy
or not value.controller_revision
or not replay_values(value.replay_snapshot, 1024)
or not valid_inputs(value.replay_inputs)
or type(value.snapshot_sequence) is not int
or value.snapshot_sequence < 0
or type(value.turn_assist) is not bool
or type(value.native_required) is not bool
or type(value.native_allowed) is not bool
or type(value.native_observed_ns) is not int
or type(value.native_expires_ns) is not int
or any(type(v) is not int or v < 0 for v in (value.applied_profile_sequence, value.applied_profile_observed_ns, value.applied_profile_expires_ns))
or type(value.native_identity) is not str
or value.native_identity
and not identity(value.native_identity)
or len(value.applied_parameter_names) > 8
or len(set(value.applied_parameter_names)) != len(value.applied_parameter_names)
or (
value.applied_parameter_names
and (
value.applied_profile_sequence <= 0
or not 0
< value.applied_profile_observed_ns
<= value.control_ns
<= value.applied_profile_expires_ns
<= value.applied_profile_observed_ns + 500_000_000
)
)
or any(type(name) is not str or not 0 < len(name) <= 96 for name in value.applied_parameter_names)
or not 1 <= len(value.baseline_values) <= 32
or not all(finite(v) for v in value.baseline_values)
or not value.stage_revision
or not value.response_revision
):
self.split('invalid_control')
return False
context = (
value.identity,
value.generation,
value.domain,
value.stage_revision,
value.response_revision,
value.source_epoch,
value.controller_mode,
value.policy,
value.baseline_revision,
value.controller_revision,
value.turn_assist,
)
if self.context != context:
self.split('actual_controller_identity_changed', reset=True)
self.context = context
if value.override:
self.excluded_until = now_ns + EXCLUSION_NS
if (
not value.enabled
or value.manual
or not value.active
or not value.valid
or value.override
or value.fault
or value.saturated
or value.limited and not (getattr(self.adapter, 'raw_collection', False) and asynchronous_hint(value))
or value.model_wobble
or value.controller_chatter and not self._retains_controller_chatter(value)
or now_ns < self.excluded_until
):
self.split('ineligible_control')
return False
if now_ns - value.control_ns > MAX_AGE_NS or value.control_ns - value.state_ns > JOIN_NS:
# Receiver or normalized source-state delay still rejects this row.
# Only inert study data may survive; native refusal is not a timing gap.
if value.native_required and (not value.native_allowed or not identity(value.native_identity) or
not 0 < value.native_observed_ns <= value.control_ns <= value.native_expires_ns <= value.native_observed_ns + 200_000_000):
self.split('original_native_admission_unavailable')
return False
self.split('stale_control')
return False
previous = self.recent_controls.get(value.control_ns)
if previous is not None:
if previous != value:
self.split('changed_duplicate_control', reset=True)
return False
return True
# A joined command leaves controls but remains part of this producer tape.
# Cross-stream ingestion must not hide its ordering boundary after a join.
if self.recent_controls and value.control_ns <= next(reversed(self.recent_controls)):
self.split('reordered_control')
return False
self._last_live_ingest_ns = now_ns
if self.live_tracking is not None:
self.live_tracking.observe_source_control(value, now_ns=now_ns,
current_native=getattr(self, '_learning_current_native_allowed', False))
self.controls[value.control_ns] = value
self.recent_controls[value.control_ns] = value
while len(self.recent_controls) > MAX_PENDING:
self.recent_controls.popitem(last=False)
while len(self.controls) > MAX_PENDING:
self.controls.popitem(last=False)
self._join(value.control_ns)
return True
def output(self, value, now_ns):
context_only = getattr(self.adapter, 'observe_original_applied', None)
if context_only is not None:
context_only(value) # Original owner receipt, never ready/plant permission.
if (
not isinstance(value, AppliedEvidence)
or not finite(value.applied)
or any(type(n) is not int for n in (value.control_ns, value.state_ns, value.apply_ns))
or not 0 < value.control_ns <= value.apply_ns <= now_ns
or not 0 < value.state_ns <= value.apply_ns
or value.apply_ns - value.control_ns > MAX_AGE_NS
):
self.split('invalid_applied_output')
return False
if value.override:
self.excluded_until = now_ns + EXCLUSION_NS
if (not value.valid or not value.active or value.override or value.fault or
value.limited and not (getattr(self.adapter, 'raw_collection', False) and bounded_context_output(value)) or
now_ns < self.excluded_until):
self.split('ineligible_applied_output')
return False
if value.domain == 'normalized_torque':
if (
type(value.carrier_frame) is not int
or value.carrier_frame <= 0
or type(value.carrier_observed_ns) is not int
or not value.apply_ns <= value.carrier_observed_ns <= now_ns
or self.last_carrier_frame
and value.carrier_frame not in (self.last_carrier_frame, self.last_carrier_frame + 1)
):
self.split('actual_carrier_gap_or_clock', reset=True)
return False
record = getattr(self.adapter, 'record_actual_carrier', None)
if record is None or not record(value):
self.split('actual_carrier_unavailable', reset=True)
return False
self.last_carrier_frame = value.carrier_frame
if now_ns - value.apply_ns > MAX_AGE_NS:
if value.domain != self.adapter.command_domain:
self.split('consumed_source_mismatch', reset=True)
return False
self.split('stale_applied_output')
return False
key = (value.control_ns, value.apply_ns)
previous = self.recent_applied.get(key)
if previous is not None:
if replace(value, carrier_frame=previous.carrier_frame, carrier_observed_ns=previous.carrier_observed_ns) != previous:
self.split('changed_duplicate_output', reset=True)
return False
return True
self._last_live_ingest_ns = now_ns
self.applied[key] = value
self.recent_applied[key] = value
while len(self.recent_applied) > MAX_PENDING:
self.recent_applied.popitem(last=False)
while len(self.applied) > MAX_PENDING:
self.applied.popitem(last=False)
self._join(value.control_ns)
return True
def _join(self, stamp):
command = self.controls.get(stamp, self.recent_controls.get(stamp))
if command is None:
return
for key in tuple(self.applied):
if key[0] == stamp:
output = self.applied.pop(key)
self.controls.pop(stamp, None)
self._join_emission(command, output)
def _join_emission(self, command, output):
if output.domain != self.adapter.command_domain:
self.split('consumed_source_mismatch', reset=True)
return
current_sources = (consumed_sources_current(command, output) if command.domain == 'normalized_torque' else
command.state_ns <= output.state_ns <= output.apply_ns and output.state_ns - command.state_ns <= JOIN_NS)
if not current_sources:
from openpilot.starpilot.flm.unchanged_output import redundant_late_output
if redundant_late_output(self, command, output):
# The original on-time pair remains untouched. This repeat creates no
# ready row, sample, application time, physical witness or permission.
return
# This pair is unusable, but it does not change the identity/provenance
# of independently sealed historical samples. Withdraw current admission
# and discard the partial window; real context changes still hard-reset.
self.split('consumed_source_mismatch', reset=command.domain != 'normalized_torque')
return
if command.domain == 'normalized_torque':
projection = output.projection
if (
projection is None or projection.requested_torque != command.requested or projection.reported_torque != output.applied or not projection.steer_requested
):
self.split('actual_encoder_projection_unavailable')
return
if command.native_required:
if (
not command.native_allowed
or not identity(command.native_identity)
or not 0 < command.native_observed_ns <= command.control_ns <= output.apply_ns <= command.native_expires_ns
or command.native_expires_ns - command.native_observed_ns > 200_000_000
):
self.split('original_native_admission_unavailable')
return
# Evidence-only reconstructed permission is bound to this exact consumed
# CC and original validated native lease, never another newer grant.
output = replace(output, native_allowed=True)
if not output.native_allowed:
self.split('applied_native_witness_unavailable')
return
if self.last_apply and (output.apply_ns <= self.last_apply or output.apply_ns - self.last_apply > MAX_AGE_NS):
self.split('applied_gap_or_reorder')
if self.active_since == 0:
self.active_since = output.apply_ns
self.last_apply = output.apply_ns
if command.domain == 'normalized_torque':
record = getattr(self.adapter, 'record_actual_emission', None)
if record is None or not record(command, output):
self.split('actual_emission_recorder_unavailable', reset=True)
return
self._retain_original_pair(command, output)
if self.live_tracking is not None:
try:
profile = self.live_tracking.profile(command)
self.live_tracking.observe_control(command, output, profile_sha256=profile,
now_ns=self._last_live_ingest_ns, current_native=getattr(self, '_learning_current_native_allowed', False))
except (AttributeError, KeyError, TypeError, ValueError):
self.live_tracking.interrupt('actual_tracking_native_pair_unqualified')
def physical(self, value, now_ns):
if (
not isinstance(value, PhysicalEvidence)
or type(value.mono_ns) is not int
or type(value.received_ns) is not int
or type(value.lag_ns) is not int
or not 0 < value.mono_ns <= value.received_ns <= now_ns
or now_ns - value.mono_ns > MAX_AGE_NS
or not 0 <= value.lag_ns <= 500_000_000
or not value.calibration
or not value.model_generation
or not value.lag_generation
or not all(finite(v) for v in (value.speed_mps, value.yaw_rate, value.roll_rad, value.steering_angle_deg))
or not self.adapter.physical_observable(value)
or not value.valid
or value.override
or value.fault
or not value.native_allowed
):
if isinstance(value, PhysicalEvidence) and value.override:
self.excluded_until = now_ns + EXCLUSION_NS
self.split('ineligible_physical_response')
return False
physical_context = (value.calibration, value.model_generation, value.lag_generation, value.lag_ns)
if self.physical_context is None:
self.physical_context = physical_context
elif physical_context != self.physical_context:
self.split('physical_generation_changed', reset=True)
self.physical_context = physical_context
return False
if value.mono_ns <= self.last_response:
return False
if self.last_response and value.mono_ns - self.last_response > MAX_AGE_NS:
self.split('physical_response_gap')
return False
self.last_response = value.mono_ns
target = value.mono_ns - value.lag_ns
if not self.active_since or target - self.active_since < ACTIVE_NS or now_ns < self.excluded_until:
return False
eligible = [(control, output) for control, output in self.ready if output.apply_ns <= target]
if not eligible:
return False
command, output = eligible[-1]
if target - output.apply_ns > JOIN_NS:
self.split('unmatched_physical_response')
return False
# Actual adapter independently converts physical data back into its applied
# request domain, checking exact frozen model/stage identity. Never P/I error.
applied_command = output.applied
if output.domain == 'normalized_torque':
from openpilot.starpilot.flm.torque_emission_replay import delivered
try:
applied_command = delivered(output)
except (AttributeError, TypeError, ValueError, OverflowError):
self.split('actual_delivered_coordinate_unavailable')
return False
physical = {
'yaw_rate': value.yaw_rate,
'roll_rad': value.roll_rad,
'lateral_accel': value.speed_mps * value.yaw_rate - 9.81 * math.sin(value.roll_rad),
'curvature': value.yaw_rate / value.speed_mps if value.speed_mps > 0 else None,
'steering_angle_deg': value.steering_angle_deg,
'speed_mps': value.speed_mps,
'physical_context': physical_context,
'applied_command': applied_command,
'response_ns': value.mono_ns,
'source_boot_ns': value.source_boot_ns,
'clock_offset_ns': value.clock_offset_ns,
'clock_uncertainty_ns': value.clock_uncertainty_ns,
}
raw = bool(getattr(self.adapter, 'raw_collection', False))
cohort = self.adapter.cohort(command, physical)
if not cohort or not isinstance(cohort, str) or len(cohort) > 96:
complete = getattr(self.adapter, 'raw_maneuver_complete', None)
if (cohort is None and raw and complete is not None and complete(command, physical)):
self._seal_raw()
self.raw_points.clear()
self.cohort, self.sealed = None, False
self.reason = 'waiting_for_excited_maneuver'
return False
self.split('response_cohort_unqualified')
return False
if getattr(self.adapter, 'raw_collection', False):
if self.cohort is not None and self.cohort != cohort:
self._seal_raw()
self.raw_points.clear()
self.sealed = False
self.cohort = cohort
if output.limited or command.limited and not exact_unclipped_pair(command, output):
self.reason = 'waiting_for_unclipped_estimation'
return False
if not self.sealed:
self.raw_points.append(RawPoint(command.control_ns, output.apply_ns, value.mono_ns, command, output, physical, physical_context))
if len(self.raw_points) == MAX_RAW_POINTS:
self._seal_raw()
self.sealed = True
# Raw healthy response supports only live metadata freshness. All model
# fitting/inversion/stage normalization/heldout replay belongs to child.
self.last_qualified_response = value.mono_ns
return True
if self.cohort is not None and self.cohort != cohort:
self.split('maneuver_cohort_changed')
return False
self.cohort = cohort
if not self.model_sealed:
self.adapter.observe_model(
command,
physical,
output.applied,
physical_context,
command_ns=output.apply_ns,
response_ns=value.mono_ns,
block_id=f'{self.session}:model:{self.model_block_sequence}',
)
self.model_points += 1
self.model_sealed = self.model_points >= MAX_POINTS
target_value = self.adapter.response_target(command, physical, output.applied, physical_context)
if not finite(target_value):
self.reason = 'independent_physical_model_collecting'
return False
self.last_qualified_response = value.mono_ns
if self.sealed:
return False
self.points.append(Sample(value.mono_ns, command.control_ns, output.apply_ns, command.features, target_value - command.baseline_prediction, 1.0))
if len(self.points) == MAX_POINTS:
self.blocks.append(
Block(command.identity, f'{self.session}:{self.block_sequence}', cohort, command.stage_revision, command.response_revision, tuple(self.points))
)
self.block_sequence += 1
self.points.clear()
self.sealed = True
return True
def _seal_raw(self):
if 40 <= len(self.raw_points) <= MAX_RAW_POINTS and self.context is not None:
control = self.raw_points[0].control
self.blocks.append(
RawBlock(
control.identity, f'{self.session}:{self.block_sequence}', cast(str, self.cohort),
control.stage_revision, control.response_revision, tuple(self.raw_points)
)
)
self.block_sequence += 1
self.raw_points.clear()
def fit(self, now_ns):
# This method belongs only to the separate learning process. Finite evidence
# and<=8 coefficients bound work. An owner worker must enforce hard joblimits.
if (
self.context is None
or self.block_sequence == self.fit_block_sequence
or len(self.blocks) < 8
or self.last_fit
and now_ns - self.last_fit < 60_000_000_000
):
return None
self.sequence += 1
self.fit_result = evaluate(
self.context[0],
tuple(self.adapter.parameters()),
tuple(self.blocks),
now_ns=now_ns,
sequence=self.sequence,
response_revision=self.context[4],
required_cohorts=tuple(self.adapter.required_cohorts()),
prior=self.prior_coefficients,
)
self.fit_block_sequence, self.last_fit = self.block_sequence, now_ns
if self.fit_result.profile is not None and self.ready:
control, output = self.ready[-1]
self.fit_validation = self.adapter.revalidate_fit(self.fit_result.profile, control, output, self.physical_context, tuple(self.blocks))
return self.fit_result
def restore_prior(self, coefficients):
parameters = tuple(self.adapter.parameters())
if coefficients is None:
self.prior_coefficients = None
return
if (
type(coefficients) is not tuple
or len(coefficients) != len(parameters)
or not all(finite(v) and p.low <= v <= p.high and abs(v) <= p.max_step for p, v in zip(parameters, coefficients, strict=True))
):
raise ValueError('historical coefficient bounds')
self.prior_coefficients = coefficients
def job_snapshot(self, now_ns):
if (
self.context is None
or self.block_sequence == self.fit_block_sequence
or len(self.blocks) < (16 if getattr(self.adapter, 'raw_collection', False) else 8)
or self.last_fit
and now_ns - self.last_fit < 60_000_000_000
):
return None
if not self.ready or self.physical_context is None:
return None
control, output = self.ready[-1]
self.sequence += 1
try:
snapshot = self.adapter.fit_job_snapshot(
tuple(self.blocks),
now_ns=now_ns,
sequence=self.sequence,
prior=self.prior_coefficients,
control=control,
output=output,
physical_context=self.physical_context,
)
except (ValueError, OverflowError, MemoryError):
# Oversized whole chronology is rejected, never thinned. Throttle this
# failed serialization attempt without consuming the sealed block cursor.
self.reason = 'fit_snapshot_unavailable'
self.last_fit = now_ns
return None
if snapshot is None:
return None
return snapshot
def mark_job_submitted(self, now_ns):
self.fit_block_sequence, self.last_fit = self.block_sequence, now_ns
def install_fit(self, result, validation):
if (
not isinstance(result, Result)
or result.profile is None
or self.context is None
or result.profile.identity != self.context[0]
or result.profile.parameters != tuple(self.adapter.parameters())
or not replay_accepts(validation, result.profile)
):
return False
self.fit_result, self.fit_validation = result, validation
return True
def revalidate_fit(self, now_ns):
# Renew LIVE admission only with fresh exact source/response/model context.
# Original train/heldout IDs and candidate coefficients stay immutable.
fit = self.fit_result
if (
fit is None
or fit.profile is None
or self.context is None
or not self.ready
or not 0 < self.last_apply <= now_ns
or now_ns - self.last_apply > MAX_AGE_NS
or not 0 < self.last_qualified_response <= now_ns
or now_ns - self.last_qualified_response > MAX_AGE_NS
or now_ns < self.excluded_until
or self.physical_context is None
or fit.profile.identity != self.context[0]
):
self.result = self.last_validation = None
return None
control, output = self.ready[-1]
if (
(
control.identity,
control.generation,
control.domain,
control.stage_revision,
control.response_revision,
control.source_epoch,
control.controller_mode,
control.policy,
control.baseline_revision,
control.controller_revision,
control.turn_assist,
)
!= self.context
or not 0 < control.source_receipt_ns <= now_ns <= control.source_receipt_ns + 500_000_000
or (control.native_required and (not control.native_allowed or not 0 < control.native_observed_ns <= now_ns <= control.native_expires_ns))
or not control.enabled
or control.manual
or not control.active
or not control.valid
or control.override
or control.fault
or control.saturated
or control.limited and not exact_unclipped_pair(control, output)
or control.model_wobble
or control.controller_chatter
or not output.active
or not output.valid
or output.override
or output.fault
or output.limited
or not output.native_allowed
):
self.result = self.last_validation = None
return None
self.live_profile_sequence = max(self.live_profile_sequence, fit.profile.sequence) + 1
# Only the registered event adapter accepts the collector's trusted clock;
# legacy/custom adapter signatures and conservative calls stay unchanged.
from openpilot.starpilot.flm.event_collection import EventCollectionAdapter
admission_clock = {'now_ns': now_ns} if isinstance(self.adapter, EventCollectionAdapter) else {}
admission = self.adapter.current_admission(fit.profile, control, output, self.physical_context, **admission_clock)
admitted = readmit_profile(fit.profile, self.fit_validation, admission, now_ns=now_ns, sequence=self.live_profile_sequence)
if admitted is None:
self.result = self.last_validation = None
return None
profile, validation = admitted
self.last_validation = validation
self.result = Result('qualified', fit.reason, profile)
return self.result
def _check_evidence_wire(event):
wire_bytes = len(event.as_builder().to_bytes())
if wire_bytes > MAX_SNAPSHOT_WIRE_BYTES:
raise ValueError('wire_bound')
if wire_bytes > MAX_WIRE_BYTES:
kind = event.which()
control_snapshot = kind == 'starpilotLateralState' and bool(len(event.starpilotLateralState.learningEvidence.replaySnapshot))
ford_events = (
kind == 'starpilotCarState'
and event.starpilotCarState.fordLearningEvidence.version == 1
and 0 < len(event.starpilotCarState.fordLearningEvidence.rows) <= 4
)
if not (control_snapshot or ford_events):
raise ValueError('non_snapshot_wire_bound')
def drain(socket, decode, receive, collector, now_ns):
"""Nonblocking bounded existing transport; overflow rejects whole maneuver."""
for _ in range(MAX_DRAIN):
event = receive(socket)
if event is None:
return True
try:
_check_evidence_wire(event)
decode(event, collector, now_ns)
except (AttributeError, KeyError, TypeError, ValueError, OverflowError):
collector.split('malformed_evidence', reset=True)
return False
# The bounded lookahead is observation only; an overrun cannot silently pass.
if receive(socket) is not None:
collector.overrun()
return False
return True
class _DrainOverrun(Exception):
pass
def drain_pair(control_socket, control, applied_socket, applied, receive, collector, now_ns):
"""Merge two bounded FIFO tapes by their original publisher headers.
Only the two queue heads compete; never sort a producer's own tape. A held
command can be republished by Card, so embedded control/apply clocks are not
transport ordering keys. Headers choose order only: the original callbacks
still decode the untouched event and resample source/native/receiver clocks.
Equal headers put control first, matching the previous causal preference.
Malformed input or either stream overrunning remains a maneuver boundary.
"""
sockets, callbacks = (control_socket, applied_socket), (control, applied)
counts = [0, 0]
def head(index):
event = receive(sockets[index])
if event is None:
return None
# This is the same one-message bounded lookahead as the single-stream drain.
if counts[index] == MAX_DRAIN:
raise _DrainOverrun
_check_evidence_wire(event)
stamp = event.logMonoTime
if type(stamp) is not int or stamp <= 0:
raise ValueError('invalid_publisher_header')
return event, stamp
try:
pending = [head(0), head(1)]
while pending[0] is not None or pending[1] is not None:
index = 0 if pending[1] is None or (pending[0] is not None and pending[0][1] <= pending[1][1]) else 1
event, _stamp = pending[index]
callbacks[index](event, collector, now_ns)
counts[index] += 1
pending[index] = head(index)
except _DrainOverrun:
collector.overrun()
return False
except (AttributeError, KeyError, TypeError, ValueError, OverflowError):
collector.split('malformed_evidence', reset=True)
return False
return True