Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ All notable changes to this project are documented here. Format follows
- Planned-facility evidence now reuses the semantic-relationship channel with
`lw_plans_to_operate` (ADR 0142). The relationship is retained only when the
same source span names a matching R&R actor and project-backed facility; it
never represents an already-operating facility.
never represents an already-operating facility. Migration 0138 keeps the
database write constraint aligned with the closed predicate vocabulary.
- Event Lineage now reports why a post has no DAG (ADR 0143):
"no_relation_found" when reconstruct compared it against real
candidates and found no relation, or "no_comparison_group" when it was
Expand Down
7 changes: 6 additions & 1 deletion lineageweave/post_summary.py
Original file line number Diff line number Diff line change
Expand Up @@ -1848,12 +1848,17 @@ def _optional_text(*keys: str, _entry: dict[str, object] = entry) -> str | None:
for entry in raw_relationships:
if not isinstance(entry, dict):
continue
predicate_code = str(entry.get("predicate_code", "")).strip()
# The legacy JSON contract has no source text to re-check against
# ADR 0142, so it cannot safely admit a planned-facility claim.
if predicate_code == "lw_plans_to_operate":
continue
Comment thread
seonghobae marked this conversation as resolved.
try:
semantic_relationships.append(
SemanticRelationship(
subject_name=str(entry.get("subject_name", "")).strip(),
subject_type=str(entry.get("subject_type", "")).strip().casefold(),
predicate_code=str(entry.get("predicate_code", "")).strip(),
predicate_code=predicate_code,
object_name=str(entry.get("object_name", "")).strip(),
object_type=str(entry.get("object_type", "")).strip().casefold(),
evidence_text=str(entry.get("evidence_text", "")).strip(),
Expand Down
14 changes: 14 additions & 0 deletions tests/test_post_summary.py
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,20 @@ def test_parses_allow_list_semantic_relationships_with_evidence() -> None:
)


def test_legacy_json_parser_drops_planned_facility_relation_without_source_context() -> None:
summary = parse_summary_response(
'{"korean_summary":"요약", "semantic_relationships":['
'{"subject_name":"Synthetic Utility", "subject_type":"organization", '
'"predicate_code":"lw_plans_to_operate", '
'"object_name":"Aurora Charging Hub", "object_type":"industrial_asset", '
'"evidence_text":"Synthetic Utility plans to operate Aurora Charging Hub", '
'"confidence":0.93}]}'
)

assert summary is not None
assert summary.semantic_relationships == ()


def test_parses_standard_profile_relation_for_industrial_why_path() -> None:
summary = parse_summary_response(
'{"korean_summary":"요약", "key_events":[], "semantic_relationships":['
Expand Down
70 changes: 70 additions & 0 deletions tests/test_schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,11 @@
/ "migrations"
/ "0114_semantic_relationship_standard_predicates.sql"
)
_PLANNED_FACILITY_RELATIONSHIP_PREDICATE_MIGRATION = (
Path(__file__).resolve().parents[1]
/ "migrations"
/ "0138_planned_facility_relation_predicate.sql"
)


def _postgres_available() -> bool:
Expand Down Expand Up @@ -149,6 +154,11 @@ def schema_db():
cur.execute(_EVENT_CLUE_MIGRATION.read_text())
cur.execute(_BROAD_FACT_TYPES_MIGRATION.read_text())
cur.execute(_SEMANTIC_RELATIONSHIP_PREDICATES_MIGRATION.read_text())
planned_predicate_migration = (
_PLANNED_FACILITY_RELATIONSHIP_PREDICATE_MIGRATION.read_text()
)
cur.execute(planned_predicate_migration)
cur.execute(planned_predicate_migration)
conn.commit()
yield conn
finally:
Expand Down Expand Up @@ -207,6 +217,66 @@ def test_migration_applies_cleanly(schema_db) -> None:
assert expected <= tables


def test_planned_facility_relationship_predicate_persists(schema_db) -> None:
"""Migration 0138 must admit the source-backed ADR 0142 relationship."""
with schema_db.cursor() as cur:
cur.execute(
"""
insert into common_lookup_value (
lookup_category, lookup_code, lookup_label
) values
('corporate_entity_level', 'company', 'Company'),
('voc_type', 'voc', 'Voice of Customer'),
('post_visibility', 'public', 'Public')
"""
)
cur.execute(
"""
with synthetic_entity as (
insert into corporate_entity (
corporate_entity_code, entity_name, entity_level_code
) values ('SYNTHETIC-PLAN-ORG', 'Synthetic Planning Org', 'company')
returning corporate_entity_id
), synthetic_account as (
insert into user_account (
external_subject_id, display_name, email_address
) values (
'synthetic-plan-account', 'Synthetic Planner',
'synthetic.planner@example.test'
) returning user_account_id
), synthetic_post as (
insert into source_post (
author_account_id, corporate_entity_id, post_title, post_body,
voc_type_code, visibility_code
)
select user_account_id, corporate_entity_id,
'Synthetic facility plan',
'Synthetic Planning Org plans to operate Aurora Charging Hub',
'voc', 'public'
from synthetic_account cross join synthetic_entity
returning post_id
), synthetic_summary as (
insert into post_summary_result (post_id, korean_summary)
select post_id, '합성 계획 요약입니다.' from synthetic_post
returning post_id
)
insert into post_summary_semantic_relationship (
post_id, relation_ordinal, subject_name, subject_type,
predicate_code, object_name, object_type, evidence_text,
relation_confidence
)
select post_id, 0, 'Synthetic Planning Org', 'organization',
'lw_plans_to_operate', 'Aurora Charging Hub',
'industrial_asset',
'Synthetic Planning Org plans to operate Aurora Charging Hub',
0.93
from synthetic_summary
returning predicate_code
"""
)
assert cur.fetchone() == ("lw_plans_to_operate",)


def test_major_event_action_project_reference_is_normalized(schema_db) -> None:
with schema_db.cursor() as cur:
cur.execute(
Expand Down