Skip to content

tdfs4ds.migration.conflicts

tdfs4ds.migration.conflicts

Conflict detection + the lab→production replace safety gate for cross-store migration (v0.3.1.150).

Promoting objects from a lab store into a production store is governed: any name collision (feature or object) must be surfaced for approval, and a request to replace an existing production object must prove that no direct dependent in production loses a feature it consumes (a downstream dataset/process must not silently lose a column).

The scoring logic here is pure (sets / dicts) so it is unit-testable without a Teradata connection; the planner builds the inputs (existing keys, dependents, required-feature maps) from the primary catalogs + persisted lineage graph.

norm_name

norm_name(name: Optional[str]) -> str

Uppercase, de-quoted, stripped — the canonical comparison form.

feature_conflicts

feature_conflicts(incoming: List[Dict[str, str]], existing_keys: Set[Tuple[str, str, str]]) -> List[Dict[str, Any]]

Return the incoming features whose (DATA_DOMAIN, ENTITY, FEATURE) triplet already exists in the primary.

Parameters

incoming : list of dict Each {'data_domain','entity','feature', ...} — already scoped to the target data domain (so a target_data_domain re-route is reflected). existing_keys : set of (DOMAIN_UP, ENTITY_UP, FEATURE_UP) The primary feature catalog's triplet set.

object_conflicts

object_conflicts(incoming_objects: List[Dict[str, str]], existing_object_keys: Set[Tuple[str, str]]) -> List[Dict[str, Any]]

Return the incoming objects whose (DST_DB, OBJECT) already exists in the primary as a (potentially different) object.

Parameters

incoming_objects : list of dict Each {'dst_database','object','object_type', ...} — the destination placement in the primary (so the collision is checked where the object would actually land). existing_object_keys : set of (DB_UP, OBJ_UP) Objects already present in the primary (from DBC.TablesV / catalogs).

downstream_feature_loss

downstream_feature_loss(incoming_features: Set[str], existing_features: Set[str], dependents_required: Dict[str, Set[str]]) -> Dict[str, Any]

Decide whether replacing an existing primary object is safe.

Parameters

incoming_features : set[str] Features the incoming (lab) version of the object exposes. existing_features : set[str] Features the current (primary) version exposes. dependents_required : dict[str, set[str]] For each direct primary dependent (node id), the set of features it consumes from this object. For a dataset dependent this is the intersection of the dataset's features with the object's; for a process/plain-view dependent, conservatively the whole existing feature set (any column could be referenced). Feature names are compared case-insensitively.

Returns

dict {'lost_features', 'blocking', 'impacted':[{'dependent','needs'}]}. blocking is True when a dependent needs a feature that the incoming version drops.

validate_approvals

validate_approvals(conflicts: List[Dict[str, Any]], approvals: Optional[Dict[str, str]]) -> Dict[str, Any]

Check that an approvals map covers every conflict and that no approved replace is still blocking.

Parameters

conflicts : list of dict The manifest's conflicts list. Each carries a key (stable id), resolution_options and, for replaceable objects, a downstream block with blocking. approvals : dict[str, str] | None {conflict_key: 'skip'|'replace'}.

Returns

dict {'ok': bool, 'unapproved':[key,...], 'invalid':[{key,reason}], 'blocked':[key,...]}.