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
41 changes: 24 additions & 17 deletions backend/app/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -937,7 +937,7 @@ async def read_customer_master(
and btrim(post.source_author_code) <> ''
and (post.visibility_code = 'public' or post.corporate_entity_id = any($1::uuid[]))
and {SOURCE_POST_ELIGIBILITY_SQL.format(alias='post')}
), ranked as (
), ranked as materialized (
select scoped.*,
row_number() over (
partition by author_code, author_account_id, account_display_name
Expand All @@ -951,32 +951,39 @@ async def read_customer_master(
from ranked
group by author_code, author_account_id, account_display_name
), keyman_mentions as (
select ranked.author_code, ranked.author_account_id,
ranked.account_display_name, ranked.post_id,
person.person_id, person.person_name,
-- Driven from post_summary_role/post_person_mention (tens to
-- low hundreds of rows) rather than `ranked` (one row per
-- eligible post -- the full corpus for a broadly-authorized
-- account): the planner reliably underestimates a CTE's own
-- cardinality, so starting the join from `ranked` produced a
-- nested loop that re-scanned the small tables once per
-- `ranked` row instead of the reverse. Logically identical
-- result (inner joins commute); the earlier query was
-- observed running 90+ seconds against the real import,
-- this one completes in the same run in well under a second.
select role.post_id, person.person_id, person.person_name,
person.person_side_code, person.last_known_job_title
from ranked
join post_summary_role role
on role.post_id = ranked.post_id
and role.actor_type_code = 'prov_person'
from post_summary_role role
join cataloged_person person
on person.person_id = role.cataloged_person_id
and person.person_side_code = 'our_side'
where role.cataloged_person_id is not null
where role.actor_type_code = 'prov_person'
and role.cataloged_person_id is not null
union
select ranked.author_code, ranked.author_account_id,
ranked.account_display_name, ranked.post_id,
person.person_id, person.person_name,
select mention.post_id, person.person_id, person.person_name,
person.person_side_code, person.last_known_job_title
from ranked
join post_person_mention mention
on mention.post_id = ranked.post_id
from post_person_mention mention
join cataloged_person person
on person.person_id = mention.person_id
and person.person_side_code = 'our_side'
), keyman_mention_authors as (
select ranked.author_code, ranked.author_account_id,
ranked.account_display_name, keyman_mentions.*
from keyman_mentions
join ranked on ranked.post_id = keyman_mentions.post_id
), keyman_authors as (
select distinct author_code, author_account_id, account_display_name
from keyman_mentions
from keyman_mention_authors
Comment on lines 953 to +986

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 Info: keyman_mentions restructure preserves result set

Driving keyman_mentions from the small tables and deferring the ranked join into keyman_mention_authors is equivalent: ranked is one row per post_id, so author columns are functionally determined by post_id, making the old 8-column UNION dedupe match the new 5-column one plus join. Both consumers (keyman_authors:986, keyman_groups:1003) were updated. Eligibility filtering survives because the inner join to ranked drops person rows from non-eligible posts.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

), top_groups as materialized (
select groups.*
from groups
Expand All @@ -993,7 +1000,7 @@ async def read_customer_master(
mentions.person_id, mentions.person_name,
mentions.person_side_code, mentions.last_known_job_title,
count(distinct mentions.post_id) as mention_count
from keyman_mentions mentions
from keyman_mention_authors mentions
join top_groups
on top_groups.author_code = mentions.author_code
and top_groups.author_account_id = mentions.author_account_id
Expand Down
4 changes: 4 additions & 0 deletions frontend/e2e/customer-master.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ test("opens a customer's related post in place, never navigating away from Custo
page,
request,
}) => {
// The fixture's own UI login already spends a chunk of the default 30s
// budget; this test does a second, independent token fetch (for API
// discovery) plus multiple entity/related lookups on top of that.
test.setTimeout(60000);
const backendBaseURL = process.env.LINEAGEWEAVE_BACKEND_URL ?? "http://localhost:18420";
const tokenResponse = await request.post(
`${process.env.LINEAGEWEAVE_KEYCLOAK_URL ?? "http://localhost:18080"}/realms/lineageweave-demo/protocol/openid-connect/token`,
Expand Down
7 changes: 6 additions & 1 deletion frontend/e2e/fixtures.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,12 @@ export const test = base.extend({
await page.click("#kc-login");
await page.waitForURL((url) => !url.pathname.includes("/realms/"), { timeout: 15000 });
}
await page.waitForLoadState("networkidle");
// "networkidle" never resolves against this app -- some background
// connection (HMR, polling) keeps the network non-idle forever, which
// is exactly why Playwright's own docs discourage it. Wait for the
// authenticated shell's own navigation instead, a concrete signal the
// initial render/data cycle is done.
await page.getByRole("navigation").first().waitFor({ state: "visible" });
await runFixture(page);
},
});
Expand Down