How-to: Add a new safety filter
A safety filter consumes a nominal action and an observation and returns a projected action that lies in the safe set (ADR-004 §Decision). The public surface for third-party filters is split by mode — pick the Protocol that matches the filter's intended deployment shape (ADR-004 §Public API; spike_004A §Three-mode taxonomy).
Pick a Protocol
There are two filter Protocols in concerto.safety.api:
EgoOnlySafetyFilter— deployment / ad-hoc / black-box-partner. The QP decides the ego agent's action only; the partner's motion enters as a predicted disturbance on the constraint RHS.filter()takes a singleFloatArrayego action plusego_uidandpartner_predicted_states, and returns aFloatArray. This is the Protocol every ADR-009 partner-zoo evaluation uses.JointSafetyFilter— oracle / ablation baseline (CENTRALIZED) and lab-only co-control (SHARED_CONTROL). The QP decides every uid's action;filter()takes adict[uid, FloatArray]and returns a dict of the same shape.SHARED_CONTROLadditionally requirespartner_action_boundat call time.
The pre-refactor single SafetyFilter alias still resolves (as
Union[EgoOnlySafetyFilter, JointSafetyFilter]) but emits a
DeprecationWarning on first use. New code targets the typed
Protocols directly; the alias will be removed in 0.3.0.
Steps
- Implement either
EgoOnlySafetyFilterorJointSafetyFilterfromconcerto.safety.api. Both are@runtime_checkable, so a duck- typed class that definesresetandfilterwith the matching signature is accepted. - If you are wrapping the built-in exp CBF-QP backbone, construct it via the mode-specific typed classmethod so static checkers narrow the return type to the right Protocol:
from concerto.safety.cbf_qp import ExpCBFQP
ego_filter = ExpCBFQP.ego_only(control_models=models)
oracle_filter = ExpCBFQP.centralized(control_models=models)
shared_filter = ExpCBFQP.shared_control(control_models=models)
- Register the filter in
concerto.safety.__init__if it is shipped as part of the method package; third-party plugins live in their own packages and depend onconcerto.safety.apionly. - Write a property test verifying the feasibility / objective-bound
invariant (see
plan/08-quality-and-process.md §3and the existingtests/property/test_cbf_qp.py).
The CBF formulation is encapsulated behind the QP constraint-generation module per ADR-004 §Reversibility; swapping in HO-CBF or MPC in Phase 3 only requires reimplementing the per-pair row builder, not the Protocol surface.