mirror of
https://github.com/semantica-agi/semantica.git
synced 2026-09-08 04:00:15 +00:00
* fix(kg): promote synthetic relation endpoints into the graph Relation extraction synthesizes an UNKNOWN Entity for a relationship endpoint that is absent from the NER entity list (metadata synthetic=True), but GraphBuilder kept only the endpoint string, so the synthetic object never reached the entity collection. GraphValidator then reported DANGLING_EDGE, breaking the native NER -> relation -> graph -> validation pipeline. The relation branch now collects synthetic endpoint entities and promotes them into the entity collection (deduplicated by id, keeping confidence=0.8 and the synthetic metadata). A new unknown_relation_endpoint option defaults to include; set it to "reject" to drop relationships whose endpoints are synthetic instead. Closes #1463 * fix(kg): reconcile synthetic endpoints after resolution Address Qodo review feedback on #1464: - Read unknown_relation_endpoint through the nested "config" mapping the orchestrator passes (GraphBuilder(config=...)), so the policy actually takes effect end to end. - Prefer a real entity over an earlier-promoted synthetic one with the same id, deduplicating at build tail (unhashable ids are skipped defensively). - Tag LLM triple endpoints that match no extracted entity and promote them too, so triplet relationships no longer leave dangling edges. - Log when the reject policy drops a relationship. Closes #1463 * fix(kg): key dedup on both id and entity_id; tag HF triple endpoints Follow-up hardening on #1464's synthetic-endpoint reconcile: - Dedup promoted endpoints against both `id` and `entity_id` (the canonical keys the builder itself recognizes), in both the relation branch and the build-tail reconciliation. The build-tail pass now also skips unhashable ids defensively. - Tag HuggingFace REBEL endpoint texts that match no extracted entity, same as the LLM typed path, so HF triplets no longer leave dangling edges. - Tests: use a real `Triplet`, cover the `entity_id` dedup case, exercise `merge_entities=True` explicitly (the prior test mislabeled the default), and lock in the dict-relationship out-of-scope contract. * fix(kg): guard metadata=None and gate endpoint promotion scan _real_ids and the reconcile filter both did .get("metadata", {}).get(...), which returns None (not {}) when the key is present with a None value and raised on entities carrying metadata=None. The synthetic-endpoint promotion block in _process_item rebuilt existing_ids by scanning all_entities for every relationship, making build() quadratic on dense relation inputs. Gate it on if synthetic_endpoints so ordinary relationships pay nothing (6000+6000 no-synthetic builds in 0.018s vs 9.04s). * config(kg): home unknown_relation_endpoint in build config and document it The option now has a default in the per-module build method config (kg_methods.build.unknown_relation_endpoint) and kg_usage.md documents both values. __init__ folds a config= dict into the option mapping once, which also fixes entity_resolution/conflict_detection being silently dropped on the orchestrator path; every option reads the same way now. * fix(extract): thread entities into HF REBEL triplet path extract_triplets_huggingface read entities from kwargs.get("entities") which is always empty on this path, making the synthetic-endpoint tag a no-op comparison. Declare entities as a parameter so it matches the real NER list TripletExtractor already forwards. * fix(kg): finalize synthetic relation endpoint handling - Add concrete Python API (kg_config.set_method_config) and YAML config file example to kg_usage.md; the previous text referenced only an opaque config-file key path with no runnable code. - Add three targeted tests to test_dangling_synthetic_endpoint.py: * test_real_entity_with_entity_id_only_wins_over_prior_synthetic: covers the _real_ids dedup pass when the real entity carries its id under entity_id only (no 'id' field). * test_llm_relation_synthetic_endpoints_promoted: exercises the full _parse_relation_result → Relation → GraphBuilder promotion path end-to-end. * test_reject_policy_emits_warning_when_all_rels_dropped: verifies that the 'all relationships were dropped' warning fires correctly when the reject policy drops every relationship from a dict-style source. - Add import pytest (required for caplog fixture used in the new test). - Fix missing EOF newline in the test file. * fix(kg): make reject-policy edge drops observable The reject policy logged at INFO and returned no machine-readable count, making it effectively silent at WARNING-level logging thresholds. Issue #1463 requires that rejected relationships are 'reported explicitly'. Changes: - Elevate the per-rejection log from INFO to WARNING so it is visible without debug logging enabled. - Add self._rejected_relationships counter (reset per build() call, incremented per dropped edge). - Expose the count in graph['metadata']['rejected_relationships'] so callers can check the outcome programmatically without log parsing. - Document both observability mechanisms in kg_usage.md. - Add four focused regression tests: * rejected count matches number of dropped edges * include policy always yields count=0 * WARNING log is emitted once per dropped edge (not just INFO) * counter resets between successive build() calls on the same builder --------- Co-authored-by: Sameer Kadam <sskadam6305@gmail.com> Co-authored-by: Sameer Kadam <sameerkadam@Mac-11.lan>