{"record":{"id":"ec6e7c85c22797e3","repo":"affaan-m/ECC","slug":"cv-effect-event-get-effect-has-an-invalid-subject-anchor","errorCode":null,"errorMessage":"CV effect {event.get('effect')} has an invalid subject anchor","messagePattern":"CV effect (.+?) has an invalid subject anchor","errorType":"validation","errorClass":"ContractError","httpStatus":null,"severity":"error","filePath":"skills/taste-application/scripts/tasteforge/contract.py","lineNumber":240,"sourceCode":"    for period in range(1, len(intervals) // 2 + 1):\n        if all(intervals[index] == intervals[index % period] for index in range(len(intervals))):\n            raise ContractError(\"stochastic schedule is periodic; repeating interval cycle\")\n    if recipe.get(\"periodic\") is not False:\n        raise ContractError(\"effect recipe must explicitly declare periodic=false\")\n    for event in events:\n        cv_effect = str(event.get(\"effect\", \"\")).startswith(\"cv_\")\n        if cv_effect and event.get(\"requires_subject_anchor\") is not True:\n            raise ContractError(f\"CV effect {event.get('effect')} must require a subject anchor\")\n        if event.get(\"requires_subject_anchor\"):\n            anchor = event.get(\"subject_anchor\")\n            required = {\n                \"mode\", \"target\", \"source_ref_sha256\", \"evidence_time\",\n                \"source_duration\", \"lost_policy\",\n            }\n            if not isinstance(anchor, dict) or not required.issubset(anchor):\n                raise ContractError(f\"CV effect {event.get('effect')} lacks a valid subject anchor\")\n            if anchor.get(\"mode\") not in {\"object_track\", \"point_track\", \"segmentation_track\"}:\n                raise ContractError(f\"CV effect {event.get('effect')} has an invalid subject anchor\")\n            if anchor.get(\"lost_policy\") != \"disable_effect_until_track_recovers\":\n                raise ContractError(f\"CV effect {event.get('effect')} must fail closed on anchor loss\")\n            _validate_media_time(\n                anchor.get(\"evidence_time\"), anchor.get(\"source_duration\"),\n                label=\"anchor evidence time\",\n            )\n            if reference_durations is not None:\n                digest = anchor.get(\"source_ref_sha256\")\n                expected_duration = reference_durations.get(digest) if isinstance(digest, str) else None\n                if expected_duration is None or anchor.get(\"source_duration\") != expected_duration:\n                    raise ContractError(\"anchor evidence source duration is not bound to its receipt reference\")\n    for event in events:\n        placement = event.get(\"placement\")\n        if not isinstance(placement, dict) or not {\"safe_area\", \"max_coverage\", \"occlusion_policy\"}.issubset(placement):\n            raise ContractError(f\"effect {event.get('effect')} lacks placement constraints\")\n\n\ndef validate_provenance(payload: dict[str, Any]) -> None:","sourceCodeStart":222,"sourceCodeEnd":258,"githubUrl":"https://github.com/affaan-m/ECC/blob/8321021c54d670126ce3b2969d5deb880b4b0c2a/skills/taste-application/scripts/tasteforge/contract.py#L222-L258","documentation":"ContractError (f-string) raised when the subject anchor dict is structurally complete but its 'mode' value is not one of the allowed tracking modes: object_track, point_track, or segmentation_track. The contract restricts anchors to these three track types.","triggerScenarios":"Calling validate_effect_recipe with an anchor whose mode is e.g. \"bbox\", \"face\", \"object\", \"tracking\", or a typo like \"object_tracks\". Any value outside the three-element set fails.","commonSituations":"Using mode names from a different tracking library's vocabulary; typos or pluralization mistakes; older recipe formats that used a different mode enum before the contract standardized the three values.","solutions":["Set mode to exactly one of: object_track, point_track, segmentation_track.","Map your tracker's output type to the closest contract mode before validating.","Add an enum check in your generator against the same set the contract uses.","Catch ContractError and print the invalid mode value to speed up authoring fixes."],"exampleFix":"// before\nanchor = {..., \"mode\": \"bounding_box\", ...}\n// after\nanchor = {..., \"mode\": \"object_track\", ...}","handlingStrategy":"validation","validationCode":"VALID_MODES = {\"object_track\", \"point_track\", \"segmentation_track\"}\nif anchor.get(\"mode\") not in VALID_MODES:\n    raise ValueError(f\"anchor mode must be one of {sorted(VALID_MODES)}\")","typeGuard":"def has_valid_track_mode(anchor) -> bool:\n    return isinstance(anchor, dict) and anchor.get(\"mode\") in {\"object_track\", \"point_track\", \"segmentation_track\"}","tryCatchPattern":"try:\n    validate_effect_recipe(recipe, reference_durations)\nexcept ContractError as exc:\n    if \"invalid subject anchor\" in str(exc):\n        anchor[\"mode\"] = normalize_track_mode(anchor[\"mode\"])\n    else:\n        raise","preventionTips":["Define the three valid modes as an enum shared by generator and validator","Map external tracker type names to contract modes at ingestion","Add an enum membership test to your recipe CI","Reject mode aliases (e.g. bbox, face) at authoring time"],"tags":["validation","contract","enum"],"backgroundTag":"invalid-enum-value","analyzedSha":"8321021c54d670126ce3b2969d5deb880b4b0c2a","analyzedAt":"2026-09-16T10:08:13.343Z","contentChangedAt":"2026-09-16T10:08:13.343Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}