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
¶
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,...]}.