Relationship inference

Opt-in contract

Inference is opt-in and records its evidence. Imports apply candidates only with --infer-relationships; pure-junction collapse additionally needs --many-to-many.

Name/type matching

Candidates use complete primary keys with dialect-equivalent types. Single keys match parent_key or singular_parent_id; composite keys match every key column in order.

Unique indexes

When a unique index exactly covers a valid child tuple, the inferred child cardinality is zero-or-one with unique_index_primary_key evidence. Otherwise it is many with column_name_primary_key evidence.

Junction recognition

Pure junction recognition requires exactly two foreign keys whose union is the complete primary key, without payload columns or unrelated constraints. The physical table remains while the logical entity becomes an association.

Evidence

Every candidate has an evidence kind, exact reason and confidence from 0 to 100. Text and JSON import reports include every accepted inference.

Ambiguity

Only a unique highest-scoring candidate is inferred. Equal best candidates produce a sorted ambiguity note and no relationship.

Pull acceptance

Pull plans mark inferred items with [?] inferred: and leave them unchecked even with --yes. Use --accept-inferred-relationships to select them; edited plan files still require that flag.

Reports

Reports carry accepted evidence plus relevant ambiguity and non-pure notes. Callers can inspect an inference report without mutating the logical model.

CLI examples

For example: bluep import ddl schema.sql --dialect postgresql --out model --infer-relationships --many-to-many --report inference.json.

Safety

Inference never mutates a model without an explicit option. It does not profile data, make fuzzy guesses, infer ternary relationships or apply suggestions on ordinary commands.