-
Notifications
You must be signed in to change notification settings - Fork 1
feat(dashboard): complete governed semantic evidence paths #614
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
Changes from all commits
b65ee74
9e830ad
f2da8d3
4af4ba0
506ffb8
f40ecef
e9ca1d0
f61c146
61fd631
f8ad49d
0700943
353d39b
bc182f1
83c817a
e9763ed
34414c1
d89e448
8c7d39b
e844aaa
5c2a430
b73243a
002d1d5
08a689a
409e9b3
fcbe697
425f398
718aa1f
43f0751
ec1ea32
fe9573d
f0b9602
416fd19
6e486e8
70bda1d
82fd36f
a6f3183
5abc5dd
801f6aa
64cf83b
e6a18b2
cbb5911
3e3b3ee
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -87,6 +87,7 @@ | |
| from lineageweave.post_summary import ContextualOrchestratorPostSummaryClient, NullPostSummaryClient | ||
| from lineageweave.relation_verification import NullRelationVerificationClient, SearxngRelationVerificationClient | ||
| from lineageweave.semantic_hints import customer_hint_trust, format_semantic_hints | ||
| from lineageweave.similar_voc import ContextualOrchestratorSimilarVocAnalysisClient | ||
| from lineageweave.ontology import LW | ||
| from lineageweave.rankweave_client import build_rankweave_client | ||
| from lineageweave.naruon_calendar_workspace import ( | ||
|
|
@@ -220,6 +221,8 @@ | |
|
|
||
| _POST_READ = "post_read" | ||
| _POST_ADMIN = "post_admin" | ||
| _SIMILAR_VOC_PAGE_SIZE = 8 | ||
| _SIMILAR_VOC_REQUEST_TIMEOUT_SECONDS = 180.0 | ||
|
|
||
|
|
||
| @asynccontextmanager | ||
|
|
@@ -272,6 +275,7 @@ | |
| chat_factory=lambda: _post_chat_client( | ||
| timeout=load_settings().orchestrator_answer_timeout_seconds | ||
| ), | ||
| embedding_factory=_embedding_client, | ||
| ) | ||
| ) | ||
| app.state.global_ask_worker = global_ask_worker | ||
|
|
@@ -482,6 +486,18 @@ | |
| ) | ||
|
|
||
|
|
||
| def _similar_voc_client(): | ||
| """Live semantic-pair client, or ``None`` when inference is unavailable.""" | ||
| settings = load_settings() | ||
| if not (settings.orchestrator_base_url and settings.orchestrator_api_key): | ||
| return None | ||
| return ContextualOrchestratorSimilarVocAnalysisClient( | ||
| base_url=settings.orchestrator_base_url, | ||
| api_key=settings.orchestrator_api_key, | ||
| timeout=_SIMILAR_VOC_REQUEST_TIMEOUT_SECONDS, | ||
| ) | ||
|
|
||
|
|
||
| def _rankweave_client(): | ||
| """In-process RankWeave unless RANKWEAVE_DISABLED=1 (ADR 0024).""" | ||
| return build_rankweave_client(disabled=load_settings().rankweave_disabled) | ||
|
|
@@ -756,7 +772,11 @@ | |
| async with pool.acquire() as conn: | ||
| try: | ||
| return await fetch_operations_dashboard( | ||
| conn, account.corporate_entity_ids, period_start, period_end | ||
| conn, | ||
| account.corporate_entity_ids, | ||
| account.process_unit_ids, | ||
| period_start, | ||
| period_end, | ||
| ) | ||
| except ValueError as exc: | ||
| raise HTTPException(status.HTTP_422_UNPROCESSABLE_CONTENT, str(exc)) from exc | ||
|
|
@@ -1754,7 +1774,8 @@ | |
| # Safe SQL: the eligibility predicate is an immutable schema fragment; post id is bound. | ||
| row = await conn.fetchrow( # nosemgrep: python.lang.security.audit.sqli.asyncpg-sqli.asyncpg-sqli | ||
| """ | ||
| select source_post.post_id, source_post.post_title, source_post.voc_type_code, | ||
| select source_post.post_id, source_post.post_title, source_post.post_body, | ||
| source_post.voc_type_code, | ||
| source_post.visibility_code, source_post.corporate_entity_id, | ||
| source_post.process_unit_id, source_post.created_at, source_post.author_account_id, | ||
| source_post.source_process_unit_code, source_post.source_author_code, | ||
|
|
@@ -1776,6 +1797,95 @@ | |
| return row | ||
|
|
||
|
|
||
| @app.get("/api/posts/{post_id}/similar-voc") | ||
| async def read_similar_voc( | ||
| post_id: str, | ||
| offset: int = Query(0, ge=0), | ||
| account: CurrentAccount = Depends(get_current_account), | ||
|
Comment on lines
+1800
to
+1804
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 📝 Info: Similar VOC fires orchestrator work on every post open Opening any post detail auto-calls Was this helpful? React with 👍 or 👎 to provide feedback. |
||
| pool: asyncpg.Pool = Depends(get_pool), | ||
| ) -> dict[str, Any]: | ||
| """Return authorized, semantically adjudicated prior VOC evidence. | ||
|
|
||
| Persisted ``repeat_issue`` classifications narrow the candidate corpus | ||
| without lexical matching. contextual-orchestrator then establishes each | ||
| pair; event time orders the display and is not a relevance score. | ||
| """ | ||
| focal = await _load_visible_post(post_id, account, pool) | ||
| client = _similar_voc_client() | ||
| if client is None: | ||
| raise HTTPException( | ||
| status.HTTP_503_SERVICE_UNAVAILABLE, | ||
| "similar VOC inference is unavailable; configure contextual-orchestrator and retry", | ||
| ) | ||
| async with pool.acquire() as conn: | ||
| rows = await conn.fetch( | ||
| f""" | ||
| select post.post_id, post.post_title, post.post_body, | ||
| post.visibility_code, post.corporate_entity_id, post.process_unit_id, | ||
| coalesce(post.event_occurred_at, post.created_at) as occurred_at | ||
|
seonghobae marked this conversation as resolved.
|
||
| from operations_case_classification classification | ||
| join source_post post on post.post_id = classification.post_id | ||
| where classification.case_kind_code = 'repeat_issue' | ||
| and post.post_id <> $1 | ||
| and post.post_body <> '' | ||
| and (post.visibility_code = 'public' | ||
| or (post.corporate_entity_id::text = any($2::text[]) | ||
| and (cardinality($3::text[]) = 0 | ||
| or post.process_unit_id::text = any($3::text[])))) | ||
| and {SOURCE_POST_ELIGIBILITY_SQL.format(alias='post')} | ||
| order by coalesce(post.event_occurred_at, post.created_at) desc, post.post_id | ||
| offset $4 limit $5 | ||
| """, | ||
| post_id, | ||
| list(account.corporate_entity_ids), | ||
| list(account.process_unit_ids), | ||
| offset, | ||
| _SIMILAR_VOC_PAGE_SIZE + 1, | ||
| ) | ||
|
github-advanced-security[bot] marked this conversation as resolved.
Fixed
github-advanced-security[bot] marked this conversation as resolved.
Fixed
Comment on lines
+1821
to
+1844
Comment on lines
+1821
to
+1844
|
||
| candidates = [row for row in rows[:_SIMILAR_VOC_PAGE_SIZE] if _can_see_post(account, row)] | ||
|
|
||
| async def _adjudicate(candidate: asyncpg.Record): | ||
| with use_llm_metadata(build_post_llm_metadata(post_id, focal)): | ||
| return await asyncio.to_thread( | ||
| client.analyze, | ||
| focal["post_title"], | ||
| focal["post_body"], | ||
| str(candidate["post_id"]), | ||
| candidate["post_title"], | ||
| candidate["post_body"], | ||
| ) | ||
|
|
||
| try: | ||
| results = await asyncio.wait_for( | ||
| asyncio.gather(*(_adjudicate(candidate) for candidate in candidates), return_exceptions=True), | ||
| timeout=_SIMILAR_VOC_REQUEST_TIMEOUT_SECONDS, | ||
| ) | ||
| except TimeoutError: | ||
| results = () | ||
|
Comment on lines
+1858
to
+1864
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 📝 Info: Batch timeout discards completed Similar VOC results On Was this helpful? React with 👍 or 👎 to provide feedback. |
||
| items = [] | ||
| for candidate, evidence in zip(candidates, results): | ||
| if evidence is None or isinstance(evidence, BaseException): | ||
| continue | ||
| items.append( | ||
| { | ||
| "post_id": evidence.candidate_post_id, | ||
| "post_title": candidate["post_title"], | ||
| "issue_summary": evidence.issue_summary, | ||
| "focal_evidence_text": evidence.focal_evidence_text, | ||
| "candidate_evidence_text": evidence.candidate_evidence_text, | ||
| "customer_cohort_text": evidence.customer_cohort_text, | ||
| "action_history": evidence.action_history, | ||
| "occurred_at": candidate["occurred_at"].isoformat(), | ||
| } | ||
| ) | ||
| return { | ||
| "items": items, | ||
| "next_offset": offset + _SIMILAR_VOC_PAGE_SIZE | ||
| if len(rows) > _SIMILAR_VOC_PAGE_SIZE | ||
| else None, | ||
| } | ||
|
seonghobae marked this conversation as resolved.
|
||
|
|
||
|
|
||
| async def _load_post_semantic_hints(conn: asyncpg.Connection, post_id: str) -> str: | ||
| """Render author, business-unit, sales-pool, and customer hints without treating them as proof.""" | ||
| rows = await conn.fetch( | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.