diff --git a/.github/workflows/ask-agent-workspace-integration.yml b/.github/workflows/ask-agent-workspace-integration.yml deleted file mode 100644 index a012f5dad..000000000 --- a/.github/workflows/ask-agent-workspace-integration.yml +++ /dev/null @@ -1,139 +0,0 @@ -name: Apply Ask Agent evidence workspace - -on: - push: - branches: - - feat/ask-agent-evidence-workspace-v2180-r2 - paths: - - .github/workflows/ask-agent-workspace-integration.yml - pull_request: - branches: - - feat/event-lineage-node-keeps-gnb-focus-v2170 - types: - - opened - - reopened - - synchronize - workflow_dispatch: - -permissions: - contents: write - pull-requests: write - -concurrency: - group: ask-agent-workspace-${{ github.event.pull_request.number || github.ref }} - cancel-in-progress: true - -jobs: - integrate-and-verify: - if: >- - github.event_name != 'pull_request' || - (github.event.pull_request.head.repo.full_name == github.repository && - github.event.pull_request.head.ref == 'feat/ask-agent-evidence-workspace-v2180-r2') - runs-on: ubuntu-24.04-arm - steps: - - name: Checkout exact branch head - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # actions/checkout@v7 - with: - ref: feat/ask-agent-evidence-workspace-v2180-r2 - fetch-depth: 0 - - - name: Set up Python - uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # actions/setup-python@v6 - with: - python-version: "3.12" - - - name: Apply bounded integration patch - env: - PR_NUMBER: "353" - run: python scripts/patch_ask_agent_workspace.py - - - name: Verify patch shape - run: | - git diff --check - test -f frontend/src/components/AskAgentWorkspace.tsx - test -f docs/adr/0126-ask-agent-evidence-workspace.md - grep -F 'AskAgentWorkspace as AskAgentPanel' frontend/src/App.tsx - grep -F '| #353 | Ask Agent evidence workspace' docs/product-technical-gap-baseline.md - grep -F '`Ask/AskAgentWorkspace`' docs/storybook-inventory.md - if grep -F 'function AskAgentPanel({' frontend/src/App.tsx; then - echo 'Legacy inline AskAgentPanel remains' >&2 - exit 1 - fi - - - name: Set up Node - uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # actions/setup-node@v5 - with: - node-version: "24" - - - name: Pin and enable pnpm - run: | - corepack enable - corepack prepare pnpm@9.15.9 --activate - test "$(pnpm --version)" = "9.15.9" - - - name: Install locked frontend dependencies - working-directory: frontend - run: pnpm install --frozen-lockfile - - - name: Run focused Ask Agent tests - working-directory: frontend - run: pnpm run test -- src/components/AskAgentWorkspace.test.tsx src/components/AskAgentWorkspace.styles.test.ts - - - name: Run frontend lint - working-directory: frontend - run: pnpm run lint - - - name: Run full frontend tests - working-directory: frontend - run: pnpm run test - - - name: Build frontend - working-directory: frontend - run: pnpm run build - - - name: Build Storybook state inventory - working-directory: frontend - run: pnpm run build-storybook - - - name: Materialize verified integration commit and bundle - run: | - rm -rf frontend/dist frontend/storybook-static - rm -f scripts/patch_ask_agent_workspace.py - rm -f .github/workflows/ask-agent-workspace-integration.yml - git diff --check - git config user.name 'github-actions[bot]' - git config user.email '41898282+github-actions[bot]@users.noreply.github.com' - git add -A - git diff --cached --check - git commit -m 'feat: integrate verified Ask Agent evidence workspace' - mkdir -p generated-integration/frontend/src generated-integration/docs - cp frontend/src/App.tsx generated-integration/frontend/src/App.tsx - cp frontend/package.json generated-integration/frontend/package.json - cp docs/product-technical-gap-baseline.md generated-integration/docs/product-technical-gap-baseline.md - cp docs/storybook-inventory.md generated-integration/docs/storybook-inventory.md - git format-patch -1 --stdout > generated-integration/ask-agent-integration.patch - git rev-parse HEAD > generated-integration/generated-commit.txt - - - name: Upload verified integration bundle - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # actions/upload-artifact@v4 - with: - name: ask-agent-integration-${{ github.sha }} - path: generated-integration - if-no-files-found: error - retention-days: 7 - - - name: Publish verified integration through a child pull request - env: - GH_TOKEN: ${{ github.token }} - GENERATED_BRANCH: automation/ask-agent-workspace-integration-353 - TARGET_BRANCH: feat/ask-agent-evidence-workspace-v2180-r2 - run: | - git push origin HEAD:"${GENERATED_BRANCH}" - existing_pr="$(gh pr list --state open --head "${GENERATED_BRANCH}" --base "${TARGET_BRANCH}" --json number --jq '.[0].number // empty')" - if [ -z "${existing_pr}" ]; then - gh pr create \ - --base "${TARGET_BRANCH}" \ - --head "${GENERATED_BRANCH}" \ - --title 'chore: apply verified Ask Agent integration' \ - --body 'Generated only after the Ask Agent focused tests, complete 185-test frontend suite, zero-warning lint, production build, and Storybook build passed on the exact source head. This child PR exists because repository rules correctly require the generated source commit to enter the protected feature branch through a pull request.' - fi diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index e94ffb442..8c2d87710 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -1,5 +1,7 @@ # Product & Technical Gap Baseline +**Active Ask Agent design head:** PR #353, stacked directly on #264 exact head `39f21261052a9d2ae82c4b851a54831eaf909805`; this is proposed work until merged. + ## 1. Known Parsing & Frontend Display Gaps - **Footnote Parsing**: `post=00505695-3e61-1fd1-83c5-263f88a9e77a` fails to recognize footnotes (li/oi level errors). - **Table Parsing**: `post=00505695-3e61-1fd1-80c6-86bb61c8ddc5` completely fails at parsing tables. @@ -77,6 +79,7 @@ claims that an unmerged PR or historical runtime observation is live behavior. | FR-11 | Post summaries expose evidence-bearing events and R&R. Requester/processor actions are nullable and may only name actors already bound to the same post summary. | ADR 0052, ADR 0102 | Commit `15e1a378` is on PR #258 and the schema exists locally; the current database has zero populated action rows, so buyer-data acceptance remains unproven | | FR-12 | A hierarchy-enrichment timeout leaves the source-grounded summary readable and the actor unbound; it never creates a guessed catalog identity. | ADR 0101, ADR 0010, ADR 0026 | Commit `1c260f20` contains the boundary, ADR, and focused test; independent review, protected-main merge, and fresh runtime evidence remain pending | | FR-13 | Customer Master projects authorized corporate entities as a Group → Company → Plant tree. Real organization containment uses W3C ORG while Group/Company/Plant remain separate SKOS level concepts. Missing-parent, self-parent, and cyclic edges remain visible as unresolved roots; the UI owns nested `group` elements from their parent `treeitem`, supports Arrow/Home/End and Enter/Space operation, and opens source-backed evidence outside the tree. | ADR 0124, ADR 0004, ADR 0010 | Ontology/SHACL interoperability tests, `customerMasterTree.ts`, `CustomerMasterTree.tsx`, component tests, Storybook, and code commit `21074cf80cbfab3001bf18b6e1a618f75f4bed24` | +| FR-14 | Global Ask presents a dedicated evidence workspace: semantic form submission, IME-safe keyboard behavior, explicit empty/loading/error/answer states, separated timeline and cited evidence, answer focus, responsive phone/tablet/PC layout, and the existing authorized cited-post → Event Lineage handoff. | ADR 0126, ADR 0002, ADR 0032, ADR 0090 | `AskAgentWorkspace.tsx`, focused component/token tests, Storybook state inventory, and existing App navigation regressions on #353 | ## TRD @@ -153,6 +156,7 @@ sequenceDiagram | NFR-05 | Synthetic fixtures only; runtime validation returns aggregate, non-identifying evidence | repository scan and evidence-document review | | NFR-06 | ADR-first architectural change and paper-grounded model policy | ADR link check and review; unsupported policies remain unavailable | | NFR-07 | Buyer hierarchy controls meet WCAG 2.2 keyboard operation and the WAI-ARIA tree ownership contract without inventing ontology facts | Ontology tests, focused hierarchy tests, full frontend test/lint/build, Storybook build, and final-head hosted verification | +| NFR-08 | Ask Agent uses shared UI-standard button/focus/color/radius tokens, clear focus differentiation, a primary content action, and 1024px/768px responsive transitions without horizontal scrolling | Focused component and CSS-contract tests, complete frontend build, Storybook state build, and UI/UX Standard Guide v3.0 review | ## Current aggregate data and runtime evidence @@ -183,6 +187,7 @@ evidence for one authorized post, not a corpus-wide acceptance claim. | Closed gap | Root cause | Closure evidence | Remaining boundary | |---|---|---|---| +| Ask Agent had no dedicated UI component or executable state inventory; its chatbox reused a Keyman link-style action and mixed answer, timeline, citations, and evidence facts in one generic section. | The Global Ask feature accumulated inside `App.tsx` while the stack focused on authorization and cross-surface navigation, leaving presentation without its own ownership boundary. | #353 extracts a token-based evidence workspace, uses a semantic and IME-safe form, focuses completed answers, separates source-backed result regions, and adds five Storybook scenes plus focused regressions. | Streaming and persisted conversation history remain separate future product work; final-head hosted Checks and independent approval are still required. | | Customer entities could disappear from the buyer surface when `parent_entity_id` formed a self-parent or cycle; the first tree refactor also placed child `group` content beside rather than inside its parent `treeitem`. | The old projection assembled only root-reachable nodes, overloaded evidence state with hierarchy semantics, and did not satisfy the APG ownership rule. | Code commit `21074cf80cbfab3001bf18b6e1a618f75f4bed24` promotes malformed edges to visible unresolved roots, keeps ORG containment separate from SKOS classification, makes every parent `treeitem` own its child `group`, separates evidence into an external region, and adds navigation, failure, stale-response, ontology, and Storybook regressions. | The API still exposes one parent context; authoritative acyclicity, level-transition rules, legal/operating/sales/billing contexts, and effective-dated history remain future normalized-model work. | ## Active PR audit @@ -194,6 +199,7 @@ PR head, valid unresolved threads, qualifying independent review, and terminal h | PR | Proposed increment | Base → head | Snapshot state | |---|---|---|---| +| #353 | Ask Agent evidence workspace and semantic chatbox | `#264` → `v2.18.0` | Exact-head verification and independent review required | | #301 | Global Ask knowledge cutoff | `#264 stack` → `v2.23.0` | Ready / UNSTABLE | | #298 | bounded async lineage LLM rebuild | `#276` → `v2.22.0` | Ready / UNSTABLE | | #287 | exact Event Lineage channel evidence | `#276` → feature | Ready / UNSTABLE | diff --git a/docs/storybook-inventory.md b/docs/storybook-inventory.md index 28c59bd48..b4cda9a6d 100644 --- a/docs/storybook-inventory.md +++ b/docs/storybook-inventory.md @@ -5,6 +5,7 @@ buyer-facing control you can click before changing product CSS. | Story | Buyer next action | Token / module | |---|---|---| +| `Ask/AskAgentWorkspace` | Review empty, loading, answered, unavailable, and phone states; open cited evidence after an answer. | UI-standard primary-button/focus tokens, responsive layout, `AskAgentWorkspace` | | `Evidence/CitationChip` | Click a cited title to open that source post. | `--color-chip-border`, `--radius-chip`, `CitationChip` | | `AnalysisRun/CutoffKnownBody` | Read the cutoff-known sentence, then compare it with the live body below. | `--color-accent-border`, `--space-panel-block`, `--radius-panel`, `CutoffKnownBody` | | `Analysis/LineageEntityPicker` | Choose which corp to reconstruct, then click Request a lineage reconstruction. | `--space-control-gap`, `--size-control-min`, `--radius-control`, `LineageEntityPicker` | diff --git a/frontend/package.json b/frontend/package.json index 7a697d0c9..f216081b9 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,7 +1,7 @@ { "name": "frontend", "private": true, - "version": "2.17.0", + "version": "2.18.0", "type": "module", "scripts": { "dev": "vite", diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index d87dd9aa9..cf859d579 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -4,7 +4,6 @@ import { useCallback, useEffect, useRef, useState, type ReactNode } from "react" import { useAuth } from "react-oidc-context"; import { askPostChat, - askAgent, BackendError, createAnalysisRun, startAnalysisRun, @@ -48,7 +47,6 @@ import { updateTicketStatus, verifyPostRelations, type ActivityEvent, - type AskAgentResponse, type AffiliateNode, type AnalysisRun, type CalendarResponse, @@ -91,6 +89,10 @@ import { PostBody } from "./PostBody"; import { decodeHtmlEntities } from "./postBodyDisplay"; import { FiveW1H } from "./components/FiveW1H"; import { CustomerMasterTree, CustomerRelatedPostCard } from "./components/CustomerMasterTree"; +import { + AskAgentWorkspace as AskAgentPanel, + GLOBAL_ASK_SESSION_STORAGE_KEY, +} from "./components/AskAgentWorkspace"; import { subgraphForPost } from "./lineageLayout"; import { isSupportedLocale, @@ -108,7 +110,6 @@ import { } from "./analysisRunNavigation"; import "./App.css"; -const GLOBAL_ASK_SESSION_STORAGE_KEY = "lineageweave.globalAskSessionId"; function orchestratorUnavailableMessage(err: unknown, action: string): string { if (err instanceof BackendError && err.status === 503) { @@ -783,16 +784,6 @@ function projectProvenanceLabel(provenance: string): string { return t(PROJECT_PROVENANCE_LABELS[provenance] ?? "Recorded evidence"); } -const CHAT_EVIDENCE_KIND_LABELS: Record = { - source_field: "Source field hint", - semantic_project: "Semantic project", - semantic_role: "Semantic role", - semantic_keyman: "Semantic Keyman", -}; - -function chatEvidenceKindLabel(kind: string): string { - return t(CHAT_EVIDENCE_KIND_LABELS[kind] ?? "Evidence"); -} const VERIFICATION_BADGE: Record = { verify_pending: "Not yet checked", @@ -4549,131 +4540,6 @@ function CustomerMasterPanel({ ); } -function AskAgentPanel({ - accessToken, - onOpenPost, -}: { - accessToken: string; - onOpenPost: (postId: string) => void; -}) { - const [question, setQuestion] = useState(""); - const [answer, setAnswer] = useState(null); - const [error, setError] = useState(null); - const [asking, setAsking] = useState(false); - const [sessionId, setSessionId] = useState(() => - window.sessionStorage.getItem(GLOBAL_ASK_SESSION_STORAGE_KEY) ?? undefined, - ); - - async function handleAsk() { - const normalized = question.trim(); - if (!normalized) return; - setAsking(true); - setError(null); - setAnswer(null); - try { - let nextAnswer: AskAgentResponse; - try { - nextAnswer = await askAgent(accessToken, normalized, sessionId); - } catch (err) { - if (!(err instanceof BackendError) || err.status !== 404 || !sessionId) { - throw err; - } - setSessionId(undefined); - window.sessionStorage.removeItem(GLOBAL_ASK_SESSION_STORAGE_KEY); - nextAnswer = await askAgent(accessToken, normalized); - } - setAnswer(nextAnswer); - setSessionId(nextAnswer.session_id); - window.sessionStorage.setItem(GLOBAL_ASK_SESSION_STORAGE_KEY, nextAnswer.session_id); - } catch (err) { - setAnswer(null); - setError(orchestratorUnavailableMessage(err, t("Ask Agent"))); - } finally { - setAsking(false); - } - } - - return ( -
-

{t("Evidence-grounded questions")}

-

{t("Ask Agent")}

-

{t("Questions use authorized posts and their evidence.")}

- {error ?

{error}

: null} -