-
Notifications
You must be signed in to change notification settings - Fork 1
feat: focus Keyman after GNB Event Lineage names it next (v2.19.0) #266
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Closed
seonghobae
wants to merge
65
commits into
feat/event-lineage-node-keeps-gnb-focus-v2170
from
feat/gnb-event-lineage-focus-keyman-v2190
Closed
Changes from all commits
Commits
Show all changes
65 commits
Select commit
Hold shift + click to select a range
ce4663c
feat: name Weekly VOC and focus Event Lineage (v2.13.0)
seonghobae 03a1167
feat: open Calendar commitments onto Event Lineage (v2.14.0)
seonghobae d25eeda
feat: open Customer master related posts onto Event Lineage (v2.15.0)
seonghobae 0aaf992
feat: open Ask Agent cited posts onto Event Lineage (v2.16.0)
seonghobae 3e5bfca
feat: keep GNB Event Lineage focus on a linked DAG node (v2.17.0)
seonghobae 8966294
ci: repair analysis-run DAG cutoff context
seonghobae cad7327
feat: focus Keyman after GNB Event Lineage names it next (v2.19.0)
seonghobae 8ed5015
feat: name Weekly VOC and focus Event Lineage (v2.13.0)
seonghobae 3990fc9
feat: open Calendar commitments onto Event Lineage (v2.14.0)
seonghobae f9b86fc
docs: assign Calendar focus ADR a unique number
seonghobae 609b61d
fix: stop auto-drilled Keyman panel from stealing Event Lineage focus
seonghobae a5831c0
feat: open Customer master related posts onto Event Lineage (v2.15.0)
seonghobae 73887c9
fix: preserve Event Lineage focus after related loads
seonghobae cbdcc6f
feat: open Ask Agent cited posts onto Event Lineage (v2.16.0)
seonghobae 1eeac6b
feat: keep GNB Event Lineage focus on a linked DAG node (v2.17.0)
seonghobae b5caf7c
fix(ui): preserve analysis-run cutoff across DAG navigation
seonghobae 36ef783
feat: open Customer master related posts onto Event Lineage (v2.15.0)
seonghobae 29c9732
test: keep customer master router specific
seonghobae 1c37126
test(red): reproduce stale post detail navigation
seonghobae b39fd35
feat: open Ask Agent cited posts onto Event Lineage (v2.16.0)
seonghobae 48461d0
merge: restack onto feat/ask-agent-open-focus-event-lineage-v2160
seonghobae bd08c68
merge: restack onto feat/event-lineage-node-keeps-gnb-focus-v2170
seonghobae c910478
feat: name Weekly VOC and focus Event Lineage (v2.13.0)
seonghobae 85db4e1
fix: reject impossible Weekly VOC dates
seonghobae 8daa419
feat: open Calendar commitments onto Event Lineage (v2.14.0)
seonghobae 156a507
fix: stop auto-drilled Keyman panel from stealing Event Lineage focus
seonghobae 5267614
fix: keep Calendar scroll with Event Lineage
seonghobae dc00316
feat: open Customer master related posts onto Event Lineage (v2.15.0)
seonghobae 15c82c7
test: keep customer master router specific
seonghobae 8fb0fea
feat: open Ask Agent cited posts onto Event Lineage (v2.16.0)
seonghobae 7f36683
feat: keep GNB Event Lineage focus on a linked DAG node (v2.17.0)
seonghobae a731551
fix(ui): preserve analysis-run cutoff across DAG navigation
seonghobae 4d6494d
fix: ignore stale post detail responses
seonghobae a7f3c12
merge: restack onto latest feat/event-lineage-node-keeps-gnb-focus-v2170
seonghobae d789c30
merge: restack onto latest feat/event-lineage-node-keeps-gnb-focus-v2170
seonghobae 8bbc2ed
chore: restack Keyman focus on current Event Lineage head
seonghobae 5e3e241
chore: reconcile remote Keyman restack with verified tree
seonghobae 251efe1
chore: restack Keyman focus on current Event Lineage head
seonghobae 4506f26
fix: align static SQL contract with safe composition
seonghobae b333958
chore: restack Keyman focus on current Event Lineage head
seonghobae 7d881db
chore: restack Keyman focus on final Event Lineage
seonghobae 4ff6fa2
chore: restack Keyman focus on final Event Lineage
seonghobae 387427e
chore: restack Keyman focus on final Event Lineage
seonghobae afe8c2d
Merge remote-tracking branch 'origin/feat/event-lineage-node-keeps-gn…
seonghobae 0229c4b
test: align embedded image accessibility expectation
seonghobae dc15a23
Merge commit '85013814fd65114c5a75d04297f04e342129b8d1' of https://gi…
seonghobae 86c5f88
fix: avoid keyman ADR number collision
seonghobae 95f19d0
Merge remote-tracking branch 'origin/feat/event-lineage-node-keeps-gn…
seonghobae eb4594d
docs: assign unique ADR number to Valkey events
seonghobae 74c2234
Merge remote-tracking branch 'origin/feat/event-lineage-node-keeps-gn…
seonghobae e44f1a6
Merge remote-tracking branch 'origin/feat/event-lineage-node-keeps-gn…
seonghobae a005e7e
Merge current event-lineage base into GNB lineage
seonghobae 60b44c4
merge: propagate current protected Event Lineage base
seonghobae 75cdf43
merge: propagate current Event Lineage branch head
seonghobae 26a6d9c
merge: propagate current semantic-source Event Lineage base
seonghobae 4a76186
Merge remote-tracking branch 'origin/feat/event-lineage-node-keeps-gn…
seonghobae bbbe734
Merge remote-tracking branch 'origin/feat/event-lineage-node-keeps-gn…
seonghobae 259b3b0
Merge remote-tracking branch 'origin/feat/event-lineage-node-keeps-gn…
seonghobae 0beb110
Merge remote-tracking branch 'origin/feat/event-lineage-node-keeps-gn…
seonghobae 8a6a1b6
Merge remote-tracking branch 'origin/feat/event-lineage-node-keeps-gn…
seonghobae c8b7445
fix: remove self-modifying repair artifacts
seonghobae d0ecc3d
feat: verify Global Ask semantic claims with public evidence (#276)
seonghobae d1b181f
fix: fail closed on malformed claim verification
seonghobae 73621d1
chore: restack keyman focus on current parent
seonghobae 1a8f926
chore: preserve exact keyman focus repair
seonghobae File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| # 2.20.0 — Global Ask public semantic verification | ||
|
|
||
| - Global Ask may nominate source posts from persisted semantic, ontology, and Knowledge Graph evidence instead of requiring the buyer's term to appear in raw post text. | ||
| - Multilingual contains-search uses one indexable predicate per semantic field and migration 0054 adds matching `pg_trgm` GIN indexes; concatenated expression scans are regression-tested out. | ||
| - An explicit public-verification boundary uses SearXNG retrieval and contextual-orchestrator verification while keeping external URLs separate from internal post citations. | ||
| - Private source evidence, Keyman/person facts, TEPP measurement artifacts, and fast-mlsirm measurement data are ineligible for public-search egress. | ||
| - Public corroboration remains review evidence and never authority-promotes an inferred graph or ontology assertion. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| # 2.20.0 Project-history response contract | ||
|
|
||
| Project-history storage projections now emit the same strict evidence-bound | ||
| shape that the HTTP response validates. Project identity display names retain | ||
| their authoritative code/key, event source IDs and time basis are explicit, | ||
| and the endpoint no longer fails with a validation error for an authorized | ||
| timeline. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,240 @@ | ||
| """Semantic and Knowledge-Graph candidate nomination for Global Ask. | ||
|
|
||
| Candidate nomination is deliberately non-authoritative. This module returns | ||
| post identifiers only. The caller must re-run the normal source-post visibility | ||
| predicate before exposing body text or evidence. | ||
| """ | ||
|
|
||
| from __future__ import annotations | ||
|
|
||
| import re | ||
| from typing import Any | ||
|
|
||
| import asyncpg | ||
|
|
||
| from lineageweave.claim_verification import ontology_lookup_codes_for_question | ||
|
|
||
| _STOP_WORDS = frozenset( | ||
| { | ||
| "which", | ||
| "what", | ||
| "where", | ||
| "when", | ||
| "who", | ||
| "why", | ||
| "how", | ||
| "the", | ||
| "this", | ||
| "that", | ||
| "posts", | ||
| "post", | ||
| "글", | ||
| "게시글", | ||
| "질문", | ||
| "관련", | ||
| "확인되는", | ||
| "핵심", | ||
| "사실", | ||
| "무엇", | ||
| "무엇인가요", | ||
| "인가요", | ||
| } | ||
| ) | ||
| _TOKEN = re.compile(r"[^\W_]+(?:-[^\W_]+)*", re.UNICODE) | ||
| _EVIDENCE_POST_IDS = re.compile(r"\[evidence_post_id=([^]]+)\]") | ||
|
|
||
|
|
||
| def global_ask_query_terms(question: str | None, *, maximum_terms: int = 8) -> tuple[str, ...]: | ||
| """Return bounded, de-duplicated lexical terms from a Global Ask query.""" | ||
|
|
||
| if maximum_terms <= 0: | ||
| return () | ||
| return tuple( | ||
| dict.fromkeys( | ||
| token.casefold() | ||
| for token in _TOKEN.findall(question or "") | ||
| if len(token) >= 2 and token.casefold() not in _STOP_WORDS | ||
| ) | ||
| )[:maximum_terms] | ||
|
|
||
|
|
||
| async def semantic_candidate_post_ids( | ||
| conn: asyncpg.Connection, | ||
| question: str | None, | ||
| *, | ||
| maximum_candidates: int = 128, | ||
| ) -> list[str]: | ||
| """Nominate posts from persisted semantic and Knowledge-Graph evidence. | ||
|
|
||
| Project mentions, responsibility/affiliation evidence, Keyman names, and | ||
| organization/team catalogs use one ``ILIKE`` predicate per indexed column. | ||
| Search-corroborated raw/canonical organization-name pairs additionally | ||
| nominate direct organization mentions and affiliated people's posts; pending | ||
| or uncorroborated aliases do not. This preserves multilingual substring lookup | ||
| without wrapping indexed fields in an expression that forces a sequential | ||
| scan. Ontology lookup codes are applied only to graph lookup-code columns. | ||
| The function never returns source text and nomination never grants access. | ||
| """ | ||
|
|
||
| if maximum_candidates <= 0: | ||
| return [] | ||
| terms = global_ask_query_terms(question) | ||
| ontology_codes = ontology_lookup_codes_for_question(question or "") | ||
| if not terms and not ontology_codes: | ||
| return [] | ||
| rows = await conn.fetch( | ||
| """ | ||
| with query_terms as ( | ||
| select unnest($1::text[]) as term | ||
| ), verified_organization as ( | ||
| select distinct entity.corporate_entity_id | ||
| from organization_name_resolution resolution | ||
| join corporate_entity entity | ||
| on entity.entity_name = resolution.resolved_organization_name | ||
| join query_terms term | ||
| on resolution.raw_organization_name ilike '%' || term.term || '%' | ||
| or resolution.resolved_organization_name ilike '%' || term.term || '%' | ||
| where resolution.verification_status_code = 'verify_corroborated' | ||
| ), candidate_post as ( | ||
| select mention.post_id, post.created_at | ||
| from post_project_mention mention | ||
| join source_post post on post.post_id = mention.post_id | ||
| where exists ( | ||
| select 1 from query_terms term | ||
| where mention.project_name ilike '%' || term.term || '%' | ||
| or mention.evidence_text ilike '%' || term.term || '%' | ||
| or mention.ontology_iri ilike '%' || term.term || '%' | ||
| ) | ||
| union all | ||
| select role.post_id, post.created_at | ||
| from post_summary_role role | ||
| join source_post post on post.post_id = role.post_id | ||
| where exists ( | ||
| select 1 from query_terms term | ||
| where role.actor_name ilike '%' || term.term || '%' | ||
| or role.responsibility ilike '%' || term.term || '%' | ||
| or role.affiliated_organization_name ilike '%' || term.term || '%' | ||
| ) | ||
| union all | ||
| select mention.post_id, post.created_at | ||
| from post_person_mention mention | ||
| join cataloged_person person on person.person_id = mention.person_id | ||
| join source_post post on post.post_id = mention.post_id | ||
| where exists ( | ||
| select 1 from query_terms term | ||
| where person.person_name ilike '%' || term.term || '%' | ||
| or person.last_known_job_title ilike '%' || term.term || '%' | ||
| or mention.mention_context ilike '%' || term.term || '%' | ||
| ) | ||
| union all | ||
| select mention.post_id, post.created_at | ||
| from post_organization_mention mention | ||
| join corporate_entity entity | ||
| on entity.corporate_entity_id = mention.corporate_entity_id | ||
| join source_post post on post.post_id = mention.post_id | ||
| where exists ( | ||
| select 1 from query_terms term | ||
| where entity.entity_name ilike '%' || term.term || '%' | ||
| ) | ||
| union all | ||
| select mention.post_id, post.created_at | ||
| from post_organization_mention mention | ||
| join verified_organization organization | ||
| on organization.corporate_entity_id = mention.corporate_entity_id | ||
| join source_post post on post.post_id = mention.post_id | ||
| union all | ||
| select mention.post_id, post.created_at | ||
| from post_person_mention mention | ||
| join person_affiliation affiliation | ||
| on affiliation.person_id = mention.person_id | ||
| join verified_organization organization | ||
| on organization.corporate_entity_id = affiliation.affiliated_corporate_entity_id | ||
| join source_post post on post.post_id = mention.post_id | ||
| union all | ||
| select mention.post_id, post.created_at | ||
| from post_team_mention mention | ||
| join cataloged_team team on team.team_id = mention.team_id | ||
| join source_post post on post.post_id = mention.post_id | ||
| where exists ( | ||
| select 1 from query_terms term | ||
| where team.team_name ilike '%' || term.term || '%' | ||
| or team.affiliated_organization_name ilike '%' || term.term || '%' | ||
| ) | ||
| union all | ||
| select evidence.evidence_post_id as post_id, post.created_at | ||
| from knowledge_graph_edge edge | ||
| join knowledge_graph_edge_evidence evidence | ||
| on evidence.knowledge_graph_edge_id = edge.knowledge_graph_edge_id | ||
| join source_post post on post.post_id = evidence.evidence_post_id | ||
| where edge.edge_type_code = any($2::text[]) | ||
| or edge.source_node_type_code = any($2::text[]) | ||
| or edge.target_node_type_code = any($2::text[]) | ||
| ) | ||
| select post_id::text as post_id | ||
| from candidate_post | ||
| group by post_id | ||
| order by max(created_at) desc, post_id desc | ||
| limit $3 | ||
| """, | ||
| list(terms), | ||
| list(ontology_codes), | ||
| maximum_candidates, | ||
| ) | ||
| return list(dict.fromkeys(str(row["post_id"]) for row in rows)) | ||
|
|
||
|
|
||
| def graph_fact_evidence_post_ids(fact: str) -> frozenset[str]: | ||
| """Extract all persisted evidence-post identifiers named by one graph fact.""" | ||
|
|
||
| match = _EVIDENCE_POST_IDS.search(fact) | ||
| if match is None: | ||
| return frozenset() | ||
| return frozenset( | ||
| value.strip() for value in match.group(1).split(",") if value.strip() | ||
| ) | ||
|
|
||
|
|
||
| def public_external_claim_facts( | ||
| row: Any, | ||
| semantic_facts: tuple[str, ...], | ||
| graph_facts: tuple[str, ...], | ||
| public_post_ids: frozenset[str], | ||
| ) -> tuple[str, ...]: | ||
| """Return externally searchable facts only for a public source post. | ||
|
|
||
| Source hints, people/Keyman facts, TEPP results, and fast-mlsirm reports are | ||
| absent by construction. A graph fact is eligible only if every persisted | ||
| evidence post named by that edge is public in the authorized result set. | ||
| """ | ||
|
|
||
| if row.get("visibility_code") != "public": | ||
| return () | ||
| public_graph_facts = tuple( | ||
| fact | ||
| for fact in graph_facts | ||
| if (evidence_ids := graph_fact_evidence_post_ids(fact)) | ||
| and evidence_ids.issubset(public_post_ids) | ||
| and "node_person" not in fact | ||
| ) | ||
| public_semantic_facts = tuple( | ||
| _public_semantic_fact(fact) | ||
| for fact in semantic_facts | ||
| if fact.startswith("project:") | ||
| and "node_person" not in fact | ||
| and not fact.startswith(("actor:", "Keyman mention:")) | ||
| ) | ||
| return tuple(dict.fromkeys(public_semantic_facts + public_graph_facts)) | ||
|
|
||
|
|
||
| def _public_semantic_fact(fact: str) -> str: | ||
| """Keep only the assertion, never the internal project evidence excerpt.""" | ||
|
|
||
| return fact.split(" | evidence:", 1)[0].strip() | ||
|
|
||
|
|
||
| __all__ = [ | ||
| "global_ask_query_terms", | ||
| "graph_fact_evidence_post_ids", | ||
| "public_external_claim_facts", | ||
| "semantic_candidate_post_ids", | ||
| ] | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🟨 Graph relations backed partly by private posts reach external web search
public_external_claim_factstreats a graph relation as public-egress eligible when every evidence id inside the fact string is public (evidence_ids.issubset(public_post_ids)). But_graph_facts_for_postsfilters evidence withwhere evidence.evidence_post_id = any($1)beforearray_agg(post_chat_ingestion.py), so the fact only names evidence posts within the bounded visible set. A private evidence post on the same edge is dropped, so the check passes and, whenverify_externalis on, the relation is sent to SearXNG. ADR 0106 requires every persisted evidence post of the edge to be public; this only checks the visible subset.Was this helpful? React with 👍 or 👎 to provide feedback.