From 10a19e81dda0f28eec543385556325f38be2c242 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sun, 23 Aug 2026 15:57:56 +0900 Subject: [PATCH] test(e2e): cover the customer-master in-place post-open fix; update gap baseline Adds a Playwright e2e spec for the #458 navigation fix (opens a real customer entity's related post, asserts it renders in place with no navigation to Board), following the same live-stack-only convention as the existing knowledge-graph.spec.ts. Records the full #458/#461/ #462 checkpoint in docs/product-technical-gap-baseline.md, including what remains genuinely open (account_affiliation traversal for counterparty-created entities) so the gap isn't overclaimed as closed. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_015HgzNGsCxqiTaT4YuJEb5J --- docs/product-technical-gap-baseline.md | 81 ++++++++++++++++++++++- frontend/e2e/customer-master.spec.ts | 90 ++++++++++++++++++++++++++ 2 files changed, 170 insertions(+), 1 deletion(-) create mode 100644 frontend/e2e/customer-master.spec.ts diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index 448acf678..2aaabcc4e 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -261,7 +261,7 @@ adapter, fixture, or HTTP-shaped test double never upgrades a row to | Keyman on both sides, titles, affiliations, related KG nodes | Keyman/affiliate-tree/related-node routes and popup | source + unit; live extraction open | | Ontology, semantic layer, provenance, W3C PROV-O projection | normalized schema, SKOS operational vocabulary concepts, `ontology_annotations` label fallback, ADR 0124, provenance modules, ADRs, evidence UI | source + unit; corpus verification open | | Branching Event Lineage DAG with evidence trail | `LineageDag.tsx`, Storybook story, Figma frames, accessible node-kind names for screen readers/tooltips, frontend tests; runtime cases include both a rendered DAG and honest empty states, while current corpus coverage remains sparse | source + unit + local-integration partial | -| Customer master and hierarchy tree | `/api/customer-master`, `scope_facets`, visible `post_organization_mention` enrichment, affiliate tree, migration `0105`, scope filter | source + unit + local-integration partial; authorized own/granted/unclassified facets, visible observed organizations, and admitted observed hierarchy facets are implemented, while authoritative scope backfill and broader hierarchy traversal remain open | +| Customer master and hierarchy tree | `/api/customer-master`, `scope_facets`, visible `post_organization_mention` enrichment, affiliate tree, migration `0105`, scope filter, in-place related-post popup, hierarchy-aware `resolve_customer_hint`, `scripts/backfill_customer_hints.py`, Storybook coverage | source + unit + local-integration partial; authorized own/granted/unclassified facets, visible observed organizations, admitted observed hierarchy facets, in-place post viewing, and hierarchy-aware customer-hint resolution are implemented, while authoritative scope backfill and broader `account_affiliation` hierarchy traversal for auto-created counterparty entities remain open | | VOC/VOM/VOP/VOCC/VOCO/VOS role classification | common lookup values and relationship APIs | source + unit; live classification open | | Evidence-grounded chat and source navigation | `/chat`, `/ask`, citation/evidence UI | source + unit; synthetic orchestrator judge route verified, corpus chat/runtime evidence open | | OpenTelemetry across LineageWeave, contextual-orchestrator, Valkey, and GRC | LineageWeave PR #383 adds API/Valkey/session spans; contextual-orchestrator PR #765 carries session/provider telemetry; governance-risk-compliance PR #50 adds request telemetry, W3C trace context, OTLP export, and ADR 0009 | source + PR; protected merge and end-to-end collector evidence open | @@ -401,6 +401,43 @@ or an explicit unavailable result. `account_affiliation`/`corporate_entity` scope flag, or a customer-tree query redesign: guessing at either without a reviewed decision risks an ABAC-adjacent regression. + **Update (2026-08-23, PRs #458/#461/#462):** three related, user-reported + Customer Master defects fixed and merged into this branch, narrowing but + not closing the standing gap above. (a) Clicking a customer's related + post called `changeDestination("board")`, unmounting Customer Master + entirely instead of showing the post in the existing right-docked + `PostDetailPopup` -- fixed by giving `CustomerMasterPanel` its own + `selectedPostId` state; the popup now opens in place. (b) + `resolve_customer_hint` (`backend/app/customer_hint_ingestion.py`) + previously created every newly resolved SAP customer code as a flat, + unparented `corporate_entity` via a bare INSERT; it now routes through + `get_or_create_corporate_entity` first (ADR 0010's hierarchy-inference + pipeline, same one `keyman_ingestion.py` already used), respecting ADR + 0026's tie-must-stay-unbound rule, so a configured hierarchy channel + gives the entity a real parent chain at resolution time. (c) Hint + resolution was reachable only one `source_customer_code` at a time via + the admin "Resolve" button in the UI; `scripts/backfill_customer_hints.py` + now resolves a bounded batch through the same pipeline, closing the "no + bulk/automatic backfill" gap for a SAP export whose only customer field + (`zcrht811_export_rows.kunnr_field`) is an opaque number with no name at + all. **What remains open:** (b)/(c) only improve the *creation* path for + entities this pipeline resolves -- the standing gap this bullet describes + (a counterparty `corporate_entity` ADR 0010 auto-creates is never linked + via `account_affiliation`, so it cannot reach `/api/customer-master` + regardless of how well-populated the corpus becomes) is unchanged and + still needs the ADR named above. Storybook coverage for + `CustomerEntityTreeRow`/`CustomerRelatedPostCard` (default/loading/empty/ + interactive states, reviewed against this repo's `ui-ux-pro-max` + + `Anti-Slop-UI` skills) and two accessibility fixes (WCAG 2.5.5 touch + target size on `.customer-entity-button`/`.related-post-card`; a + per-hint `aria-label` on the "Resolve" button so screen-reader users can + distinguish it from others in the same list) shipped in the same PR + series. A Playwright e2e spec (`frontend/e2e/customer-master.spec.ts`) + covers the (a) fix end-to-end -- same "runs only against a live + authenticated stack, not CI" convention as the existing + `knowledge-graph.spec.ts` -- but was not executed in this environment (no + local stack was up at the time; the operator should run it against + `make up && make seed` or a real import to confirm). - **Event Lineage thread grouping — systemic mismapping, evidence-backed (2026-08-22):** `reconstruct_group_key` (`backend/app/lineage_ingestion.py`) uses `source_post.thread_group_key` first when non-empty, falling back to @@ -618,6 +655,48 @@ excluded per this repo's de-identification discipline. hosted-protected-gate evidence at the current merged head -- rerun after merge before treating this exact head as release-ready. +## 6b. 2026-08-23 update: Customer Master post-panel checkpoint (`docs/customer-master-scope-adr`) + +Exact head after this update: `5458151f8702fe0444a45b38715216de7c29fa61` +(squash merge of PR #462 on top of #461, #458, all merged this session). +Detailed evidence for each item lives in section 5's "Customer master +'customer tree'" bullet, updated in this same checkpoint. + +- **Closed this checkpoint:** clicking a customer's related post in + Customer Master navigated the whole workspace to Board instead of + showing the post in place (PR #458); `resolve_customer_hint` created + every newly resolved SAP customer code as a flat, unparented entity + instead of routing through the existing ADR 0010 hierarchy-inference + pipeline (PR #458); hint resolution was reachable only one code at a + time via the admin UI with no bulk path (`scripts/backfill_customer_hints.py`, + PR #458, CLI-safety fix in PR #461); `CustomerEntityTreeRow`/ + `CustomerRelatedPostCard` had no Storybook coverage and two real + accessibility gaps (WCAG 2.5.5 touch target size, screen-reader + disambiguation of the "Resolve" button) went unreviewed against this + repo's `ui-ux-pro-max`/`Anti-Slop-UI` skills (PR #462). +- **Learned this checkpoint, process-level:** this repository's + stacked-branch workflow lets a PR merge into a branch another PR has + already forward-merged past, orphaning the new commits even though + GitHub reports `state: MERGED` -- happened twice in this checkpoint + (PR #414's predecessor attempt, and the final commit of PR #458 itself). + Verify a merge by reading the actual file content at the merge commit, + not by trusting `state`/`mergeStateStatus`/commit-ancestry alone (a + squash merge also makes `git merge-base --is-ancestor` an unreliable + check on its own). +- **Not closed this checkpoint:** the standing gap section 5's bullet + describes -- a counterparty `corporate_entity` ADR 0010 auto-creates is + never linked via `account_affiliation`, so it cannot reach + `/api/customer-master` regardless of corpus size -- remains open and + still needs its own ADR before implementation. +- **Local quality evidence at this exact head:** frontend `pnpm exec tsc -b` + clean, `pnpm run lint` clean, `pnpm test -- --run` 204/204 passed, + `pnpm run build-storybook` succeeds; backend `pytest tests/ backend/tests/` + 860 passed / 17 skipped (one pre-existing, unrelated failure -- + `resolved_date_text` column missing -- confirmed absent from every file + this checkpoint's diffs touch). The new Playwright e2e spec + (`frontend/e2e/customer-master.spec.ts`) was not executed: no local + stack was running in this environment at the time. + ## 7. References (APA 7th) ContextualWisdomLab. (2026). *TEPP* [Computer software]. GitHub. diff --git a/frontend/e2e/customer-master.spec.ts b/frontend/e2e/customer-master.spec.ts new file mode 100644 index 000000000..3bb074148 --- /dev/null +++ b/frontend/e2e/customer-master.spec.ts @@ -0,0 +1,90 @@ +import { test, expect } from "./fixtures"; + +/** + * Regression guard for the 2026-08-22 Customer Master navigation bug: + * clicking a customer's related post used to call changeDestination("board") + * and jump the whole workspace away from Customer Master instead of showing + * the post in place. Discovers a real customer entity with a linked post + * through the running app's own API rather than a fixed id (AGENTS.md's + * synthetic-only-artifact rule) -- runs against the live authenticated + * stack (`make up && make seed`, or an authorized real import). + */ + +interface RelatedNode { + node_id: string; + node_type_code: string; + label?: string; +} + +async function findEntityWithRelatedPost( + request: import("@playwright/test").APIRequestContext, + baseURL: string, + accessToken: string, +): Promise<{ entityId: string; entityName: string } | null> { + const master = await request.get(`${baseURL}/api/customer-master`, { + headers: { Authorization: `Bearer ${accessToken}` }, + }); + if (!master.ok()) return null; + const { corporate_entities: entities } = (await master.json()) as { + corporate_entities: { corporate_entity_id: string; entity_name: string }[]; + }; + for (const entity of entities) { + const related = await request.get(`${baseURL}/api/corporate-entities/${entity.corporate_entity_id}/related`, { + headers: { Authorization: `Bearer ${accessToken}` }, + }); + if (!related.ok()) continue; + const { related: nodes } = (await related.json()) as { related: RelatedNode[] }; + if (nodes.some((node) => node.node_type_code === "node_post")) { + return { entityId: entity.corporate_entity_id, entityName: entity.entity_name }; + } + } + return null; +} + +test("opens a customer's related post in place, never navigating away from Customer master", async ({ + page, + request, +}) => { + 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`, + { + form: { + client_id: "lineageweave-frontend", + grant_type: "password", + username: process.env.LINEAGEWEAVE_E2E_USERNAME ?? "demo.analyst", + password: process.env.LINEAGEWEAVE_E2E_PASSWORD ?? "lineageweave-demo-only", + }, + }, + ); + test.skip(!tokenResponse.ok(), "Keycloak token endpoint unavailable in this environment"); + const { access_token: accessToken } = (await tokenResponse.json()) as { access_token: string }; + + const entity = await findEntityWithRelatedPost(request, backendBaseURL, accessToken); + test.skip(entity === null, "No customer entity with a linked post is visible in this environment"); + const { entityName } = entity!; + + await page.goto("/"); + await page.getByRole("button", { name: "Customer master" }).click(); + await expect(page.getByRole("heading", { name: "Customer master" })).toBeVisible(); + + const entityButton = page.getByRole("button", { name: new RegExp(entityName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")) }); + await entityButton.click(); + + const relatedPostButton = page.getByRole("button", { name: /^Open related post:/ }).first(); + await expect(relatedPostButton).toBeVisible({ timeout: 15000 }); + await relatedPostButton.click(); + + // The fix: this popup renders in place (a fixed right-docked panel), + // it does not navigate to Board -- Customer master stays mounted and + // its own entity for this related post is still visible underneath. + const popup = page.locator(".popup-panel"); + await expect(popup).toBeVisible({ timeout: 15000 }); + await expect(page.getByRole("heading", { name: "Customer master" })).toBeVisible(); + await expect(page.getByRole("heading", { name: "Board", exact: true })).not.toBeVisible(); + + await popup.getByRole("button", { name: /close/i }).click(); + await expect(popup).not.toBeVisible(); + await expect(page.getByRole("heading", { name: "Customer master" })).toBeVisible(); + await expect(entityButton).toBeVisible(); +});