Files
StarPilot/openpilot/starpilot/flm/feedback_observation.py
T
2026-10-24 15:41:39 -05:00

653 lines
31 KiB
Python

"""Versioned observations of Controls' real consumed CO feedback.
Capture only; no native/current/profile authority. Original source and native
replay must independently verify every apply before creating a verified tape.
"""
from dataclasses import asdict, dataclass, replace, fields, Field, _FIELD
import math
import re
import struct
import uuid
from types import GetSetDescriptorType
PROTOCOL = 'original-consumed-co-feedback-v1'
MAX_ROWS = 12000
MAX_AGE_NS = 100_000_000
_VERIFIED = object()
_LOWER_HEX = re.compile('[0-9a-f]*')
def f32(value):
if type(value) not in (float, int) or not math.isfinite(value):
raise ValueError('finite feedback operand')
return struct.unpack('<f', struct.pack('<f', value))[0]
def _positive(value):
return type(value) is int and 0 < value < 2**64
def _hex(value, size=64):
return type(value) is str and len(value) == size and _LOWER_HEX.fullmatch(value) is not None
def _digest(value):
from openpilot.starpilot.flm.physical_input_observation import body_digest
return body_digest(value)
def co_body(header_ns, valid, actuators):
"""Entire semantic CO body; preserve all actuator fields and float bits."""
if type(header_ns) is not int or not 0 <= header_ns < 2**64 or type(valid) is not bool or type(actuators) is not dict:
raise ValueError('actual CO body')
return _digest({'header_ns':header_ns, 'valid':valid, 'actuators':actuators})
def applied_digest(applied):
from openpilot.starpilot.flm.fullrate_collector import AppliedEvidence
from opendbc.car.steering_projection import TorqueProjection, projection_to_dict
if type(applied) is not AppliedEvidence or type(applied.projection) is not TorqueProjection:
raise ValueError('exact typed held applied evidence')
witness = applied.projection
projection = projection_to_dict(witness)
if projection is None:
raise ValueError('bounded actual projection body')
body = {field.name: getattr(applied, field.name) for field in fields(applied) if field.name != 'projection'}
# Validated primitive projections need no discarded recursive copy. Preserve
# original deepcopy behavior for custom operands or limit-name callbacks.
if (applied.projection is not witness or any(type(row[0]) is not str for row in witness.limits) or
any(value is not None and type(value) not in (bool, int, float, str, bytes) for value in body.values())):
body = asdict(applied)
body['projection'] = projection
return _digest(body)
@dataclass(frozen=True)
class CoPublication:
version: int
session: str
sequence: int
publication_ns: int
source_epoch: str
cp_sha256: str
output_known: bool
output_control_ns: int
output_state_ns: int
output_apply_ns: int
output_carrier_sequence: int
reported_torque: float
valid: bool
co_body_sha256: str
applied_sha256: str
native_identity: str
carrier_observed_ns: int
@dataclass(frozen=True)
class CoConsumption:
version: int
control_ns: int
publication_ns: int
recv_frame: int
receipt_ns: int
seen: bool
valid: bool
co_body_sha256: str
reported_torque: float
requested_torque: float
lat_active: bool
input_limited: bool
published_limited: bool
prior_publish_ns: int
source_epoch: str
cp_sha256: str
def validate_publication(row):
if type(row) is not CoPublication or type(row.version) is not int or row.version != 1:
raise ValueError('typed feedback publication version')
if (not _hex(row.session, 32) or not all(_positive(v) for v in (row.sequence,row.publication_ns)) or
not all(_hex(v) for v in (row.source_epoch,row.cp_sha256,row.co_body_sha256)) or
not (row.native_identity == '' or _hex(row.native_identity)) or
any(type(v) is not bool for v in (row.output_known,row.valid)) or f32(row.reported_torque) != row.reported_torque):
raise ValueError('feedback publication fields')
if row.output_known:
if (not all(_positive(v) for v in (row.output_control_ns,row.output_state_ns,row.output_apply_ns,row.output_carrier_sequence,row.carrier_observed_ns)) or
not row.output_state_ns <= row.output_apply_ns <= row.carrier_observed_ns <= row.publication_ns or
row.carrier_observed_ns > row.output_apply_ns+MAX_AGE_NS or
not row.output_control_ns <= row.output_apply_ns or not _hex(row.applied_sha256)):
raise ValueError('feedback known actual apply')
elif (row.output_control_ns,row.output_state_ns,row.output_apply_ns,row.output_carrier_sequence,row.applied_sha256,row.carrier_observed_ns) != (0,0,0,0,'',0):
raise ValueError('unknown output cannot claim an apply')
return row
def validate_consumption(row):
if type(row) is not CoConsumption or type(row.version) is not int or row.version != 1:
raise ValueError('typed feedback consumption version')
if (not _positive(row.control_ns) or
any(type(v) is not int or not 0 <= v < 2**64 for v in (row.publication_ns,row.recv_frame,row.receipt_ns)) or
row.seen and (not all(_positive(v) for v in (row.publication_ns,row.recv_frame,row.receipt_ns)) or
not row.publication_ns <= row.receipt_ns <= row.control_ns <= row.publication_ns+MAX_AGE_NS) or
type(row.prior_publish_ns) is not int or not 0 <= row.prior_publish_ns < row.control_ns or
any(type(v) is not bool for v in (row.seen,row.valid,row.lat_active,row.input_limited,row.published_limited)) or
not all(_hex(v) for v in (row.co_body_sha256,row.source_epoch,row.cp_sha256)) or
any(f32(v) != v for v in (row.reported_torque,row.requested_torque))):
raise ValueError('feedback consumption fields/clock')
expected = bool(row.lat_active and abs(row.requested_torque-row.reported_torque) > .01)
if row.published_limited is not expected:
raise ValueError('original published feedback equation')
return row
class CardFeedbackCapture:
"""Owner-local association, invalidated BEFORE every output setter."""
def __init__(self, source_epoch, cp_sha256):
if not _hex(source_epoch) or not _hex(cp_sha256):
raise ValueError('feedback source context')
self.source_epoch,self.cp_sha256 = source_epoch,cp_sha256
self.session = uuid.uuid4().hex
self.sequence = self.last_header = 0
self.output = self.applied = None
self.assignment_serial = self.associated_serial = 0
def begin_assignment(self):
self.assignment_serial += 1
self.invalidate()
def invalidate(self):
self.output = self.applied = None
self.associated_serial = 0
def committed(self, actual, applied):
from openpilot.starpilot.flm.fullrate_collector import AppliedEvidence
from opendbc.car.steering_projection import TorqueProjection
# This is an observation association, never an applied/native verifier.
if (self.assignment_serial <= 0 or type(applied) is not AppliedEvidence or applied.domain != 'normalized_torque' or
type(applied.projection) is not TorqueProjection or
f32(float(actual.torque)) != f32(applied.applied) or f32(applied.projection.reported_torque) != f32(applied.applied)):
self.invalidate()
return
self.output,self.applied = actual,applied
self.associated_serial = self.assignment_serial
def publication(self, event):
header = int(event.logMonoTime)
if header <= self.last_header:
self.invalidate()
raise ValueError('nonincreasing CO owner publication')
self.last_header = header
self.sequence += 1
actual = event.carOutput.actuatorsOutput
# Object identity at setter establishes ownership; body equality only checks
# it survived assignment, never discovers which apply supplied this output.
applied = self.applied
known = self.output is not None and applied is not None and self.associated_serial == self.assignment_serial
actual_body = actual.to_dict()
if known and actual_body != self.output.to_dict():
self.invalidate()
raise ValueError('held owner output changed before CO publication')
row = CoPublication(1,self.session,self.sequence,header,self.source_epoch,self.cp_sha256,known,
0 if not known else applied.control_ns,0 if not known else applied.state_ns,
0 if not known else applied.apply_ns,0 if not known else applied.carrier_frame,
f32(float(actual.torque)),bool(event.valid),co_body(header,bool(event.valid),actual_body),
'' if not known else applied_digest(applied),'',0 if not known else applied.carrier_observed_ns)
return validate_publication(row)
def card_capture_for(owner, now_ns):
"""Only actual enabled/current settings receipt enables observational work."""
from types import SimpleNamespace
from openpilot.starpilot.flm.learning_wire import read_source_receipt
from openpilot.starpilot.flm.runtime_adapter_registry import car_params_digest
sm = owner.sm
try:
# This service is optional for native authority; all_checks deliberately
# ignores it there. Observational capture must check its REAL bits directly.
service = 'autoSteeringLearning'
stamp = int(sm.logMonoTime[service])
receipt = int(round(sm.recv_time[service]*1e9))
if (type(now_ns) is not int or not now_ns > 0 or
not all((sm.seen[service],sm.valid[service],sm.alive[service],sm.freq_ok[service])) or
not 0 < stamp <= now_ns <= stamp+500_000_000 or
not 0 < receipt <= now_ns <= receipt+500_000_000):
raise ValueError('feedback settings source/receipt invalid or stale')
digest = getattr(owner,'_feedback_cp_sha256',None)
if digest is None:
digest = owner._feedback_cp_sha256 = car_params_digest(owner.CP)
source = read_source_receipt(SimpleNamespace(valid=bool(sm.valid[service]),autoSteeringLearning=sm[service]),
now_ns=now_ns,cp_sha256=digest)
if source is None or not source.enabled or source.manual:
raise ValueError('feedback settings off/manual')
capture = getattr(owner,'learning_feedback_capture',None)
if type(capture) is not CardFeedbackCapture or (capture.source_epoch,capture.cp_sha256) != (source.source_epoch,digest):
capture = owner.learning_feedback_capture = CardFeedbackCapture(source.source_epoch,digest)
return capture
except (AttributeError,KeyError,TypeError,ValueError,OverflowError):
owner.learning_feedback_capture = None
return None
def capture_controls(owner, cc, *, control_ns, input_limited):
"""Freeze actual consumption only; no association guessed by torque equality."""
automatic = getattr(owner,'global_learning',None)
source = None if automatic is None else automatic.source
if (automatic is None or not automatic.eligible or source is None or not source.enabled or source.manual or
not source.observed_ns <= control_ns <= source.expires_ns or str(owner.CP.steerControlType) != 'torque'):
owner.learning_feedback_prior_publish_ns = 0
return None
context = (source.source_epoch,source.cp_sha256)
if getattr(owner,'learning_feedback_context',None) != context:
owner.learning_feedback_prior_publish_ns = 0
owner.learning_feedback_context = context
sm = owner.sm
header = int(sm.logMonoTime['carOutput'])
output = sm['carOutput'].actuatorsOutput
row = CoConsumption(1,control_ns,header,int(sm.recv_frame['carOutput']),int(round(sm.recv_time['carOutput']*1e9)),
bool(sm.seen['carOutput']),bool(sm.valid['carOutput']),co_body(header,bool(sm.valid['carOutput']),output.to_dict()),
f32(float(output.torque)),f32(float(cc.actuators.torque)),bool(cc.latActive),bool(input_limited),
bool(owner.steer_limited_by_safety),int(getattr(owner,'learning_feedback_prior_publish_ns',0)),
source.source_epoch,source.cp_sha256)
owner.learning_feedback_prior_publish_ns = control_ns
return validate_consumption(row)
@dataclass(frozen=True)
class FeedbackJoin:
consumption: CoConsumption
publication: CoPublication
@dataclass(frozen=True)
class VerifiedFeedbackTape:
"""Child-local result. Never decode this type from an untrusted wire."""
protocol: str
rows: tuple[FeedbackJoin, ...]
binding_digest: str
digest: str
context_only: tuple[CoConsumption, ...]
parent_digest: str
_seal: object
def join_original(publications, consumptions):
"""Pure bounded exact join. NOT independent native/source execution proof."""
if (type(publications) is not tuple or type(consumptions) is not tuple or
not 1 <= len(publications) <= MAX_ROWS or not 1 <= len(consumptions) <= MAX_ROWS):
raise ValueError('bounded complete feedback tape')
by_header = {}
prior = None
for pub in publications:
validate_publication(pub)
if pub.publication_ns in by_header or prior is not None and (
pub.session != prior.session or pub.sequence <= prior.sequence or pub.publication_ns <= prior.publication_ns or
(pub.source_epoch,pub.cp_sha256) != (prior.source_epoch,prior.cp_sha256)):
raise ValueError('ambiguous/reordered/reset CO publication')
if prior is not None and pub.output_known and prior.output_known and pub.output_apply_ns == prior.output_apply_ns and (
pub.output_carrier_sequence < prior.output_carrier_sequence or pub.carrier_observed_ns < prior.carrier_observed_ns):
raise ValueError('held publication carrier chronology')
by_header[pub.publication_ns] = pub
prior = pub
rows = []
previous = None
for row in consumptions:
validate_consumption(row)
if not row.seen or not row.valid:
raise ValueError('unseen/invalid consumed output is observation only')
pub = by_header.get(row.publication_ns)
if pub is None or not pub.output_known or (
pub.co_body_sha256,pub.reported_torque,pub.valid,pub.source_epoch,pub.cp_sha256) != (
row.co_body_sha256,row.reported_torque,row.valid,row.source_epoch,row.cp_sha256):
raise ValueError('exact consumed CO/apply provenance unavailable')
if previous is not None and (row.control_ns <= previous.control_ns or
row.recv_frame < previous.recv_frame or row.publication_ns < previous.publication_ns or
row.prior_publish_ns != previous.control_ns or row.input_limited is not previous.published_limited):
raise ValueError('original publish to next-controller feedback linkage')
rows.append(FeedbackJoin(row,pub))
previous = row
return tuple(rows)
def _plain_record_values(item, kind):
"""Read only a plain exact class's complete owned, callback-free dictionary."""
if type(item) is not kind or type(kind) is not type or kind.__bases__ != (object,):
return None
namespace = kind.__dict__
descriptor = namespace.get('__dict__')
metadata = namespace.get('__dataclass_fields__')
if ('__getattribute__' in namespace or '__getattr__' in namespace or
type(descriptor) is not GetSetDescriptorType or descriptor.__objclass__ is not kind or
type(metadata) is not dict):
return None
declared = []
for name, field in metadata.items():
if (type(name) is not str or type(field) is not Field or type(field.name) is not str or field.name != name or
field._field_type is not _FIELD or name in namespace):
return None
declared.append(name)
owned = object.__getattribute__(item, '__dict__')
if (type(owned) is not dict or any(type(key) is not str for key in owned) or
any(name not in owned for name in declared)):
return None
return tuple((name, owned[name]) for name in declared)
def _feedback_asdict(record):
"""Fresh complete record values; unknown shapes retain whole asdict order."""
def flat(item, kind):
values = _plain_record_values(item, kind)
if values is None:
return None
body = {}
for name, value in values:
if value is not None and type(value) not in (bool, int, float, str, bytes):
return None
body[name] = value
return body
kind = type(record)
if kind is CoPublication or kind is CoConsumption:
body = flat(record, kind)
if body is not None:
return body
elif kind is FeedbackJoin:
joined = _plain_record_values(record, FeedbackJoin)
if joined is not None and tuple(name for name, _ in joined) == ('consumption', 'publication'):
consumption = flat(joined[0][1], CoConsumption)
if consumption is not None:
publication = flat(joined[1][1], CoPublication)
if publication is not None:
return {'consumption': consumption, 'publication': publication}
return asdict(record)
def _tape_digest_uncached(rows, context_only, binding_digest, parent_digest):
return _digest({'binding':binding_digest,'parent':parent_digest,
'rows':[_feedback_asdict(row) for row in rows],'context_only':[_feedback_asdict(row) for row in context_only]})
# Child-local cost cache only. Fresh exact full bytes are required on EVERY hit.
from collections import OrderedDict
_TAPE_DIGEST_CACHE=OrderedDict()
_TAPE_DIGEST_CACHE_BYTES=0
_TAPE_DIGEST_MAX_ENTRIES=4
_TAPE_DIGEST_MAX_KEY=4*1024*1024
_TAPE_DIGEST_MAX_BYTES=8*1024*1024
def _tape_digest_key(rows,context_only,binding_digest,parent_digest):
if (type(rows) is not tuple or len(rows)>MAX_ROWS or type(context_only) is not tuple or len(context_only)>MAX_ROWS or
type(binding_digest) is not str or type(parent_digest) is not str or len(binding_digest)>128 or len(parent_digest)>128):
return None
def primitive_record(record,kind):
if type(record) is not kind:
return None
values=tuple(getattr(record,name) for name in kind.__dataclass_fields__)
for value in values:
leaf=type(value)
if leaf is str:
if len(value)>128:
return None
elif leaf is int:
if abs(value).bit_length()>64:
return None
elif leaf is float:
if not math.isfinite(value):
return None
elif leaf is not bool:
return None
return values
pairs=[]
for joined in rows:
if type(joined) is not FeedbackJoin:
return None
c=primitive_record(joined.consumption,CoConsumption)
p=primitive_record(joined.publication,CoPublication)
if c is None or p is None:
return None
pairs.append((c,p))
context=[]
for record in context_only:
values=primitive_record(record,CoConsumption)
if values is None:
return None
context.append(values)
import pickle
# ONLY plain native scalar tuples cross pickle. Exact known record types and
# every declared field were checked above; extra attrs/customreduce never run.
key=pickle.dumps((tuple(pairs),tuple(context),binding_digest,parent_digest),protocol=5)
return key if len(key)<=min(_TAPE_DIGEST_MAX_KEY,_TAPE_DIGEST_MAX_BYTES) else None
def _tape_digest_status(rows,context_only,binding_digest,parent_digest):
global _TAPE_DIGEST_CACHE_BYTES
key=_tape_digest_key(rows,context_only,binding_digest,parent_digest)
if key is not None and key in _TAPE_DIGEST_CACHE:
_TAPE_DIGEST_CACHE.move_to_end(key)
return _TAPE_DIGEST_CACHE[key], True
result=_tape_digest_uncached(rows,context_only,binding_digest,parent_digest)
if key is not None:
while _TAPE_DIGEST_CACHE and (len(_TAPE_DIGEST_CACHE)>=_TAPE_DIGEST_MAX_ENTRIES or
_TAPE_DIGEST_CACHE_BYTES+len(key)>_TAPE_DIGEST_MAX_BYTES):
old,_=_TAPE_DIGEST_CACHE.popitem(last=False)
_TAPE_DIGEST_CACHE_BYTES-=len(old)
_TAPE_DIGEST_CACHE[key]=result
_TAPE_DIGEST_CACHE_BYTES+=len(key)
return result, key is not None
def _tape_digest(rows,context_only,binding_digest,parent_digest):
return _tape_digest_status(rows,context_only,binding_digest,parent_digest)[0]
def _sealed_status(tape,binding_digest):
if not (type(tape) is VerifiedFeedbackTape and tape._seal is _VERIFIED and tape.protocol == PROTOCOL and
tape.binding_digest == binding_digest and _hex(binding_digest) and bool(tape.rows)):
return False, False
expected_digest = tape.digest
digest, closed = _tape_digest_status(tape.rows,tape.context_only,binding_digest,tape.parent_digest)
matched = expected_digest == digest
return matched, closed and type(tape.protocol) is str and type(expected_digest) is str
def _sealed(tape,binding_digest):
return _sealed_status(tape,binding_digest)[0]
def _control_matches(control,row,cp_digest):
from openpilot.starpilot.flm.fullrate_collector import ControlEvidence
if (type(control) is not ControlEvidence or row.cp_sha256 != cp_digest or control.source_epoch != row.source_epoch or
f32(control.requested) != row.requested_torque or bool(control.active) != row.lat_active or
bool(control.limited) != row.published_limited or dict(control.replay_inputs).get('safety_limited') != float(row.input_limited) or
not control.enabled or control.manual or not control.valid or not control.active or control.override or control.fault or
not 0 < control.source_receipt_ns <= control.control_ns <= control.source_receipt_ns+500_000_000):
raise ValueError('actual original control/source feedback mismatch')
if control.native_required:
if (not control.native_allowed or not _hex(control.native_identity) or
not 0 < control.native_observed_ns <= control.control_ns <= control.native_expires_ns <= control.native_observed_ns+200_000_000):
raise ValueError('original feedback native control lease/identity')
elif control.native_allowed or control.native_identity or (control.native_observed_ns,control.native_expires_ns) != (0,0):
raise ValueError('ordinary feedback cannot fabricate native ACK')
def verify_original(publications, consumptions, controls, outputs, engine, binding_digest, *,
expected_control_ids, context_packet, frames, allow_initial_context_only=False):
"""Complete owned original proof; optional FIRST q is explicit context only."""
from openpilot.starpilot.flm.event_controller_replay import EventControllerReplay
from openpilot.starpilot.flm.fullrate_collector import AppliedEvidence
from openpilot.starpilot.flm.torque_eligibility import consumed_sources_current
from openpilot.starpilot.flm.original_context_receipts import reuse_verified_context
from openpilot.starpilot.flm.torque_raw_fit import output_from_dict
from openpilot.starpilot.flm.runtime_adapter_registry import car_params_digest
if type(engine) is not EventControllerReplay or not _hex(binding_digest):
raise ValueError('actual original replay and owned context binding required')
verified_controls = reuse_verified_context(context_packet,engine,frames)
if verified_controls is None or type(controls) is not dict or controls != verified_controls:
raise ValueError('completed child-local exact original source/native replay proof required')
owned_outputs = {v.apply_ns:v for v in (output_from_dict(body) for body in context_packet['outputs'])}
if type(outputs) is not dict or outputs != owned_outputs:
raise ValueError('exact original applied context receipt bodies required')
_archive_records(publications,consumptions)
frame_ids = tuple(frame.control_ns for frame in frames)
if (type(expected_control_ids) is not tuple or expected_control_ids != frame_ids or
expected_control_ids != tuple(row.control_ns for row in consumptions) or type(allow_initial_context_only) is not bool):
raise ValueError('all original controller feedback membership required')
cp_digest = car_params_digest(engine.factory.cp)
for row in consumptions:
_control_matches(controls.get(row.control_ns),row,cp_digest)
by_header = {pub.publication_ns:pub for pub in publications}
first = consumptions[0]
first_pub = by_header.get(first.publication_ns)
first_unclosed = (not first.seen or not first.valid or first_pub is None or not first_pub.output_known or
first_pub.output_control_ns not in controls or first_pub.output_apply_ns not in outputs)
context_only = ()
known = consumptions
if first_unclosed:
if not allow_initial_context_only or len(consumptions) < 2 or first.control_ns != frame_ids[0]:
raise ValueError('initial original CO context is unclosed')
context_only,known = (first,),consumptions[1:]
# Retain raw archive digest, including unclosed first q and unconsumed COs.
# Only known consumed headers are joined; ALL controller rows remain required.
needed = {row.publication_ns for row in known}
used_publications = tuple(pub for pub in publications if pub.publication_ns in needed)
rows = join_original(used_publications,known)
if context_only and (known[0].prior_publish_ns != first.control_ns or known[0].input_limited is not first.published_limited):
raise ValueError('initial context to first known feedback linkage')
for joined in rows:
row,pub = joined.consumption,joined.publication
producing = controls.get(pub.output_control_ns)
output = outputs.get(pub.output_apply_ns)
if producing is None or type(output) is not AppliedEvidence:
raise ValueError('actual original producing apply unavailable')
if (pub.output_carrier_sequence < output.carrier_frame or pub.carrier_observed_ns < output.carrier_observed_ns):
raise ValueError('held original carrier receipt regressed')
held = replace(output,carrier_frame=pub.output_carrier_sequence,carrier_observed_ns=pub.carrier_observed_ns)
if (output.control_ns != pub.output_control_ns or output.state_ns != pub.output_state_ns or
output.apply_ns != pub.output_apply_ns or applied_digest(held) != pub.applied_sha256 or
not consumed_sources_current(producing,output) or not engine.applied_matches(producing,output) or
producing.source_epoch != row.source_epoch or f32(output.applied) != pub.reported_torque or
pub.native_identity and pub.native_identity != producing.native_identity or
not pub.output_apply_ns <= row.control_ns <= pub.output_apply_ns+MAX_AGE_NS or
not output.valid or not output.active or output.override or output.fault or not output.native_allowed or
producing.native_required and output.apply_ns > producing.native_expires_ns):
raise ValueError('original feedback source/native/actual CAN mismatch')
parent = _digest({'publications':[_feedback_asdict(v) for v in publications],'consumptions':[_feedback_asdict(v) for v in consumptions]})
digest = _tape_digest(rows,context_only,binding_digest,parent)
return VerifiedFeedbackTape(PROTOCOL,rows,binding_digest,digest,context_only,parent,_VERIFIED)
def _checked_subset(tape, exact_control_ids, binding_digest):
sealed, closed = _sealed_status(tape,binding_digest)
if not sealed or type(exact_control_ids) is not tuple or not exact_control_ids:
raise ValueError('owned verified feedback tape/exact window required')
stamps = tuple(row.consumption.control_ns for row in tape.rows)
try:
start = stamps.index(exact_control_ids[0])
except ValueError as error:
raise ValueError('subset cannot include unknown/context-only feedback') from error
selected = tape.rows[start:start+len(exact_control_ids)]
if tuple(row.consumption.control_ns for row in selected) != exact_control_ids:
raise ValueError('complete contiguous original feedback window required')
return selected, closed and all(type(stamp) is int for stamp in exact_control_ids)
def _mint_subset(tape, selected, binding_digest):
digest = _tape_digest(selected,(),binding_digest,tape.digest)
return VerifiedFeedbackTape(PROTOCOL,selected,binding_digest,digest,(),tape.digest,_VERIFIED)
def subset_verified(tape, exact_control_ids, *, binding_digest):
"""Owner-minted contiguous original window; no wire-created subset seal."""
selected, _ = _checked_subset(tape,exact_control_ids,binding_digest)
return _mint_subset(tape,selected,binding_digest)
def validate_subset_verified(tape, exact_control_ids, *, binding_digest):
"""Fresh validation; discard mint only for the just-checked closed domain."""
selected, closed = _checked_subset(tape,exact_control_ids,binding_digest)
if not closed:
_mint_subset(tape,selected,binding_digest)
def verify_candidate_flags(tape, candidate_requests, candidate_reported, *, activation_ns, binding_digest):
"""Narrow regime equality only. No modified inputs or native permission."""
if (not _sealed(tape,binding_digest) or not _positive(activation_ns) or
tape.rows[0].consumption.control_ns > activation_ns):
raise ValueError('owned verified feedback tape/prefix required')
return _flag_equations(tape.rows,candidate_requests,candidate_reported,activation_ns)
def _flag_equations(rows,candidate_requests,candidate_reported,activation_ns):
"""Pure arithmetic for differential tests; NEVER native/admission proof."""
if type(candidate_requests) is not dict or type(candidate_reported) is not dict:
raise ValueError('explicit candidate feedback maps')
if set(candidate_requests) != {r.consumption.control_ns for r in rows}:
raise ValueError('all candidate feedback frames required')
for joined in rows:
row,pub = joined.consumption,joined.publication
request = f32(candidate_requests[row.control_ns])
if row.control_ns < activation_ns:
if request != row.requested_torque:
raise ValueError('candidate changed original preactivation prefix')
continue
if pub.output_control_ns < activation_ns:
reported = pub.reported_torque
else:
if pub.output_apply_ns not in candidate_reported:
raise ValueError('candidate reported CO coordinate missing')
reported = f32(candidate_reported[pub.output_apply_ns])
hint = bool(row.lat_active and abs(request-reported) > .01)
if hint is not row.published_limited:
raise ValueError('candidate changed original consumed-feedback regime')
return True
def _archive_records(publications,consumptions):
if (type(publications) is not tuple or type(consumptions) is not tuple or
not 1 <= len(publications) <= MAX_ROWS or not 1 <= len(consumptions) <= MAX_ROWS):
raise ValueError('bounded complete feedback archive')
for pub in publications:
validate_publication(pub)
for row in consumptions:
validate_consumption(row)
if (len({v.publication_ns for v in publications}) != len(publications) or
any(b.publication_ns <= a.publication_ns for a,b in zip(publications,publications[1:], strict=False)) or
any(b.control_ns <= a.control_ns for a,b in zip(consumptions,consumptions[1:], strict=False))):
raise ValueError('duplicate/reordered original feedback archive')
def export_observations(publications, consumptions, *, binding_digest):
"""Separate bounded archive body; hashes bind content, never execute proof."""
if not _hex(binding_digest):
raise ValueError('explicit feedback archive binding')
# Preserve unknown/context observations too; this is NEVER a verified type.
_archive_records(publications,consumptions)
body = {'protocol':PROTOCOL,'binding_digest':binding_digest,
'publications':[_feedback_asdict(v) for v in publications],
'consumptions':[_feedback_asdict(v) for v in consumptions]}
return {**body,'digest':_digest(body)}
def decode_observations(packet, *, binding_digest):
"""Untrusted separate records only. Never returns VerifiedFeedbackTape."""
from dataclasses import fields
if type(packet) is not dict or set(packet) != {'protocol','binding_digest','publications','consumptions','digest'}:
raise ValueError('explicit feedback archive version required; old packets ineligible')
body = {k:v for k,v in packet.items() if k != 'digest'}
if (packet['protocol'] != PROTOCOL or not _hex(binding_digest) or packet['binding_digest'] != binding_digest or
not _hex(packet['digest'])):
raise ValueError('feedback archive exact binding/body')
values = []
for name,kind,validator in (('publications',CoPublication,validate_publication),('consumptions',CoConsumption,validate_consumption)):
raw = packet[name]
if type(raw) is not list or not 1 <= len(raw) <= MAX_ROWS:
raise ValueError('feedback archive row budget')
keys = {v.name for v in fields(kind)}
if any(type(v) is not dict or set(v) != keys for v in raw):
raise ValueError('feedback archive exact typed fields')
values.append(tuple(validator(kind(**v)) for v in raw))
if packet['digest'] != _digest(body):
raise ValueError('feedback archive exact binding/body')
_archive_records(*values)
return tuple(values)