affaan-m/ECC · error · ContractError
CV effect must fail closed on anchor loss
Error message
CV effect {event.get('effect')} must fail closed on anchor loss What it means
ContractError (f-string) raised when the anchor's lost_policy is not exactly 'disable_effect_until_track_recovers'. The contract mandates fail-closed behavior: when the subject track is lost, the CV effect must be disabled until the track recovers, rather than continuing or guessing.
Solutions
- Set lost_policy to exactly "disable_effect_until_track_recovers".
- Remove custom loss-handling fields and rely on the contract's single supported policy.
- Update recipe templates/generators to hardcode the required policy string.
- Catch ContractError and log the offending policy value for the recipe author.
Example fix
// before
anchor = {..., "lost_policy": "keep_last_position"}
// after
anchor = {..., "lost_policy": "disable_effect_until_track_recovers"} Defensive patterns
Strategy: validation
Validate before calling
LOST_POLICY = "disable_effect_until_track_recovers"
if anchor.get("lost_policy") != LOST_POLICY:
raise ValueError(f"lost_policy must be {LOST_POLICY!r}") Type guard
def fails_closed_on_anchor_loss(anchor) -> bool:
return isinstance(anchor, dict) and anchor.get("lost_policy") == "disable_effect_until_track_recovers" Try / catch
try:
validate_effect_recipe(recipe, reference_durations)
except ContractError as exc:
if "fail closed on anchor loss" in str(exc):
anchor["lost_policy"] = "disable_effect_until_track_recovers"
else:
raise Prevention
- Hardcode the single supported policy string in your anchor constructor
- Never accept free-form loss policy strings from upstream systems
- Template anchors with the policy prefilled
- Add a contract-conformance test over all shipped recipes
When it happens
Trigger: Calling validate_effect_recipe with an anchor whose lost_policy is e.g. "keep_last_known", "continue", "ignore", "drop_event", or missing/null.
Common situations: Copying anchor configs from systems with lenient loss handling; assuming any descriptive policy string is valid; older drafts of the recipe format that allowed multiple policies.
Understand the failure class
Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.
Related errors
- anchor evidence source duration is not bound to its receipt…
- CV effect has an invalid subject anchor
- CV effect lacks a valid subject anchor
- CV effect must require a subject anchor
- effect lacks placement constraints
AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16).
Data as JSON: /api/errors/2e7ef9dc6f98f09e.
Report an issue: GitHub.
Appendix: source
Thrown at skills/taste-application/scripts/tasteforge/contract.py:242
raise ContractError("stochastic schedule is periodic; repeating interval cycle")
if recipe.get("periodic") is not False:
raise ContractError("effect recipe must explicitly declare periodic=false")
for event in events:
cv_effect = str(event.get("effect", "")).startswith("cv_")
if cv_effect and event.get("requires_subject_anchor") is not True:
raise ContractError(f"CV effect {event.get('effect')} must require a subject anchor")
if event.get("requires_subject_anchor"):
anchor = event.get("subject_anchor")
required = {
"mode", "target", "source_ref_sha256", "evidence_time",
"source_duration", "lost_policy",
}
if not isinstance(anchor, dict) or not required.issubset(anchor):
raise ContractError(f"CV effect {event.get('effect')} lacks a valid subject anchor")
if anchor.get("mode") not in {"object_track", "point_track", "segmentation_track"}:
raise ContractError(f"CV effect {event.get('effect')} has an invalid subject anchor")
if anchor.get("lost_policy") != "disable_effect_until_track_recovers":
raise ContractError(f"CV effect {event.get('effect')} must fail closed on anchor loss")
_validate_media_time(
anchor.get("evidence_time"), anchor.get("source_duration"),
label="anchor evidence time",
)
if reference_durations is not None:
digest = anchor.get("source_ref_sha256")
expected_duration = reference_durations.get(digest) if isinstance(digest, str) else None
if expected_duration is None or anchor.get("source_duration") != expected_duration:
raise ContractError("anchor evidence source duration is not bound to its receipt reference")
for event in events:
placement = event.get("placement")
if not isinstance(placement, dict) or not {"safe_area", "max_coverage", "occlusion_policy"}.issubset(placement):
raise ContractError(f"effect {event.get('effect')} lacks placement constraints")
def validate_provenance(payload: dict[str, Any]) -> None:
"""Require every declared rule to cite immutable, timestamped evidence."""
rules = payload.get("rules")View on GitHub (pinned to 8321021c54)