Skip to content

H-6364: Temporal wiring + ingest UI redesign#8572

Draft
lunelson wants to merge 26 commits intoln/h-6363-ingest-routefrom
ln/h-6364-temporal-wiring
Draft

H-6364: Temporal wiring + ingest UI redesign#8572
lunelson wants to merge 26 commits intoln/h-6363-ingest-routefrom
ln/h-6364-temporal-wiring

Conversation

@lunelson
Copy link
Copy Markdown
Contributor

@lunelson lunelson commented Mar 24, 2026

🌟 What is the purpose of this PR?

Wire the HASH frontend to the internal repo's Temporal workers and Mastra API for local dev, and redesign the ingest UI with continuous-scroll document viewer, collapsible entity cards with assertion windows, and a two-panel input layout.

🔗 Related links

🚫 Blocked by

🔍 What does this change?

Temporal wiring:

  • Add Next.js rewrite for /artifacts/* to proxy page images from Mastra API
  • Add SSE proxy API route at /api/ingest/[runId]/events — Next.js rewrites buffer responses, breaking SSE streaming; this API route manually proxies with proper streaming headers
  • Internal repo changes (on branch 6357): TEMPORAL_NAMESPACE env var on TS worker, Python worker, and Mastra API Temporal client

UI redesign — document viewer:

  • Replace paginated PageViewer (Prev/Next buttons, single page) with continuous vertical scroll of all page images
  • Add per-page refs with scrollToPage via useImperativeHandle
  • Bbox overlay highlighting preserved, pre-computed per page via highlightedBlocksByPage map

UI redesign — results panel:

  • Replace flat roster + claims lists with collapsible entity cards (one per roster entry)
  • Expanded cards show assertion windows cross-referenced via participants[].rosterEntryId
  • An assertion window appears under every entity card where that entity is a participant
  • Falls back to roster entry summary when no assertion windows exist
  • New Selection types (entity | assertion) and buildEntityAssertionMap() in evidence-resolver

UI redesign — inputs view:

  • Two-panel layout: left = Ark UI drop zone, right = extraction mode radio toggle
  • Open Extraction (active) and Targeted Extraction (disabled, "Coming soon" tooltip)

Type alignment:

  • IngestRunView now includes mentionContexts: MentionContextPlan[]
  • Full MentionContextPlan discriminated union (assertion_windows | mechanical_fallback)
  • AssertionWindow, FallbackWindow, ContextDiagnostics types matching internal repo contracts

Pre-Merge Checklist 🚀

🚢 Has this modified a publishable library?

This PR:

  • does not modify any publishable blocks or libraries, or modifications do not need publishing

📜 Does this require a change to the docs?

The changes in this PR:

  • are in a state where docs changes are not yet required but will be

🕸️ Does this require a change to the Turbo Graph?

The changes in this PR:

  • do not affect the execution graph

⚠️ Known issues

  • Targeted extraction radio button is disabled — requires typeSelection wiring through to Temporal workflow
  • Assertion windows may be empty for runs from older pipeline versions (falls back to roster summary)
  • Local dev only — requires Mastra API + Temporal workers from internal repo with TEMPORAL_NAMESPACE=HASH

🐾 Next steps

  • Enable targeted extraction with ontology type selector
  • Show structured claim summaries (subject/predicate/object) on assertion windows
  • hash-api GraphQL integration (pending team discussion)
  • Remote deployment

🛡 What tests cover this?

  • turbo lint:tsc --filter=@apps/hash-frontend — type checking
  • yarn fix:eslint — zero lint errors
  • yarn fix:format — formatting clean

❓ How to test this?

  1. Start HASH external services: yarn external-services up -d
  2. Start graph + API + frontend: yarn start:graph, yarn dev:backend, yarn dev:frontend
  3. Start internal repo services (from internal/apps/agent-workflows):
    • TEMPORAL_NAMESPACE=HASH yarn temporal:worker:ts
    • TEMPORAL_NAMESPACE=HASH yarn temporal:worker:py
    • TEMPORAL_NAMESPACE=HASH yarn dev:api
  4. Log in as alice@example.com / password
  5. Navigate to /ingest — two-panel layout with extraction mode toggle
  6. Upload a PDF — SSE progress streams via API route proxy
  7. On completion, navigate to results — entity cards expand to show assertion windows
  8. Click an entity or assertion — document viewer scrolls to relevant page with bbox highlights

📹 Demo

@vercel
Copy link
Copy Markdown

vercel bot commented Mar 24, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
hash Ready Ready Preview, Comment Mar 27, 2026 4:44pm
3 Skipped Deployments
Project Deployment Actions Updated (UTC)
hashdotdesign Ignored Ignored Preview Mar 27, 2026 4:44pm
hashdotdesign-tokens Ignored Ignored Preview Mar 27, 2026 4:44pm
petrinaut Skipped Skipped Mar 27, 2026 4:44pm

@github-actions github-actions bot added area/apps > hash* Affects HASH (a `hash-*` app) type/eng > frontend Owned by the @frontend team area/apps labels Mar 24, 2026
@vercel vercel bot temporarily deployed to Preview – petrinaut March 24, 2026 14:50 Inactive
Copy link
Copy Markdown
Contributor Author

lunelson commented Mar 24, 2026

Warning

This pull request is not mergeable via GitHub because a downstack PR is open. Once all requirements are satisfied, merge this PR as a stack on Graphite.
Learn more

This stack of pull requests is managed by Graphite. Learn more about stacking.

@lunelson lunelson changed the title H-6364: Add artifacts proxy rewrite for page images H-6364: Temporal wiring + ingest UI redesign Mar 24, 2026
@cursor
Copy link
Copy Markdown

cursor bot commented Mar 25, 2026

PR Summary

Medium Risk
Moderate risk: adds a custom SSE proxy route and changes ingest API rewrites/endpoints plus a substantial UI refactor for ingest results navigation and selection/highlighting behavior.

Overview
Wires the ingest UI to updated Mastra endpoints by updating Next.js rewrites (e.g. /api/ingest*/ingest-runs*) and adding new artifact proxies (/api/ingest-artifacts/* and /artifacts/*). Adds a dedicated Next.js API route GET /api/ingest/[runId]/events that proxies text/event-stream responses with streaming-safe headers to avoid rewrite buffering.

Redesigns the ingest UI and results experience: the /ingest page becomes a two-panel layout with an extraction-mode selector, the results left panel becomes collapsible entity cards that show assertion windows (or claims as fallback), and evidence selection now supports assertion windows with per-entity precomputed maps.

Updates document viewing and types: replaces the paginated PageViewer with a continuous-scroll viewer exposing scrollToPage, and extends the ingest view contract to include mentionContexts (MentionContextPlan/AssertionWindow types). Also updates Temporal docker healthcheck to use temporal operator cluster health.

Written by Cursor Bugbot for commit 8709ff3. This will update automatically on new commits. Configure here.

@vercel vercel bot temporarily deployed to Preview – petrinaut March 25, 2026 14:25 Inactive
@augmentcode
Copy link
Copy Markdown

augmentcode bot commented Mar 25, 2026

🤖 Augment PR Summary

Summary: Extends local ingest dev wiring to better integrate with Mastra/Temporal and redesigns the ingest UI to use continuous document scrolling and entity-centric results.

Changes:

  • Adds Next.js rewrites to proxy ingest artifacts, including a direct /artifacts/* path used by page image URLs.
  • Introduces a new /api/ingest/[runId]/events API route that proxies SSE streaming (avoiding buffering behavior of Next.js rewrites).
  • Updates the ingest landing page to a two-panel layout with an “Extraction Mode” radio toggle (open vs targeted/disabled).
  • Replaces the paginated page viewer with a continuous vertical scroll viewer that exposes an imperative scrollToPage handle.
  • Refactors evidence resolution to support new selection types (entity / assertion) and adds mapping from entities to assertion windows.
  • Redesigns the results panel into collapsible entity cards showing assertion windows (with roster-summary fallback when absent).
  • Aligns frontend types by adding mentionContexts and corresponding discriminated-union plan types to IngestRunView.

Technical Notes: Highlights are now computed per-page for the scroll viewer, and selection drives both bbox overlays and programmatic scrolling to relevant pages.

🤖 Was this summary useful? React with 👍 or 👎

Copy link
Copy Markdown

@augmentcode augmentcode bot left a comment

Choose a reason for hiding this comment

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

Review completed. 4 suggestions posted.

Fix All in Augment

Comment augment review to trigger a new review at any time.

@vercel vercel bot temporarily deployed to Preview – petrinaut March 25, 2026 15:13 Inactive
@lunelson lunelson force-pushed the ln/h-6363-ingest-route branch from 2a4d202 to 456597a Compare March 25, 2026 17:34
@vercel vercel bot temporarily deployed to Preview – petrinaut March 25, 2026 17:34 Inactive
@vercel vercel bot temporarily deployed to Preview – petrinaut March 25, 2026 17:39 Inactive
Copy link
Copy Markdown

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

<ResultsPanel
rosterEntries={view.roster.entries}
claims={view.claims}
mentionContexts={view.mentionContexts}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Missing mentionContexts from API crashes results panel

Medium Severity

mentionContexts was added as a required field on IngestRunView, but the API response is cast with as IngestRunView without runtime validation. If the upstream API omits this field (e.g. older pipeline versions, as noted in "Known issues"), view.mentionContexts is undefined, and buildEntityAssertionMap crashes with a TypeError on the for...of loop because undefined is not iterable. A fallback like view.mentionContexts ?? [] at the call site would prevent the crash.

Additional Locations (1)
Fix in Cursor Fix in Web

@vercel vercel bot temporarily deployed to Preview – petrinaut March 27, 2026 14:45 Inactive
@github-actions github-actions bot added the area/deps Relates to third-party dependencies (area) label Mar 27, 2026
if (done) {
break;
}
res.write(value);

Check warning

Code scanning / Semgrep PRO

Semgrep Finding: javascript.express.security.audit.xss.direct-response-write.direct-response-write Warning

Detected directly writing to a Response object from user-defined input. This bypasses any HTML escaping and may expose your application to a Cross-Site-scripting (XSS) vulnerability. Instead, use 'resp.render()' to render safely escaped HTML.
@vercel vercel bot temporarily deployed to Preview – petrinaut March 27, 2026 16:03 Inactive
return;
}

void router.push(navigationAction.path);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Semgrep identified a blocking 🔴 issue in your code:
Untrusted input could be used to tamper with a web page rendering, which can lead to a Cross-site scripting (XSS) vulnerability. XSS vulnerabilities occur when untrusted input executes malicious JavaScript code, leading to issues such as account compromise and sensitive information leakage. To prevent this vulnerability, validate URLs and their protocol before using them in your codebase.

Why this might be safe to ignore:

The tainted data flows through normalizeQueryParam which restricts the value to a string and then through getIngestPageNavigationAction which constructs a safe navigation path. The router.push is using an internally constructed path rather than directly using untrusted user input.

Dataflow graph
flowchart LR
    classDef invis fill:white, stroke: none
    classDef default fill:#e7f5ff, color:#1c7fd6, stroke: none

    subgraph File0["<b>apps/hash-frontend/src/pages/ingest.page.tsx</b>"]
        direction LR
        %% Source

        subgraph Source
            direction LR

            v0["<a href=https://github.com/hashintel/hash/blob/d8d3cbf5bd5fe3e168f11ce8608db14b11a347b5/apps/hash-frontend/src/pages/ingest.page.tsx#L28 target=_blank style='text-decoration:none; color:#1c7fd6'>[Line: 28] router.query.runId</a>"]
        end
        %% Intermediate

        subgraph Traces0[Traces]
            direction TB

            v2["<a href=https://github.com/hashintel/hash/blob/d8d3cbf5bd5fe3e168f11ce8608db14b11a347b5/apps/hash-frontend/src/pages/ingest.page.tsx#L28 target=_blank style='text-decoration:none; color:#1c7fd6'>[Line: 28] normalizeQueryParam</a>"]

            v3["<a href=https://github.com/hashintel/hash/blob/d8d3cbf5bd5fe3e168f11ce8608db14b11a347b5/apps/hash-frontend/src/pages/ingest.page.tsx#L22 target=_blank style='text-decoration:none; color:#1c7fd6'>[Line: 22] value</a>"]

            v4["<a href=https://github.com/hashintel/hash/blob/d8d3cbf5bd5fe3e168f11ce8608db14b11a347b5/apps/hash-frontend/src/pages/ingest.page.tsx#L28 target=_blank style='text-decoration:none; color:#1c7fd6'>[Line: 28] runId</a>"]

            v5["<a href=https://github.com/hashintel/hash/blob/d8d3cbf5bd5fe3e168f11ce8608db14b11a347b5/apps/hash-frontend/src/pages/ingest.page.tsx#L69 target=_blank style='text-decoration:none; color:#1c7fd6'>[Line: 69] navigationAction</a>"]
        end
            v2 --> v3
            v3 --> v4
            v4 --> v5
        %% Sink

        subgraph Sink
            direction LR

            v1["<a href=https://github.com/hashintel/hash/blob/d8d3cbf5bd5fe3e168f11ce8608db14b11a347b5/apps/hash-frontend/src/pages/ingest.page.tsx#L84 target=_blank style='text-decoration:none; color:#1c7fd6'>[Line: 84] navigationAction.path</a>"]
        end
    end
    %% Class Assignment
    Source:::invis
    Sink:::invis

    Traces0:::invis
    File0:::invis

    %% Connections

    Source --> Traces0
    Traces0 --> Sink


Loading

To resolve this comment:

🔧 No guidance has been designated for this issue. Fix according to your organization's approved methods.

💬 Ignore this finding

Reply with Semgrep commands to ignore this finding.

  • /fp <comment> for false positive
  • /ar <comment> for acceptable risk
  • /other <comment> for all other reasons

Alternatively, triage in Semgrep AppSec Platform to ignore the finding created by react-nextjs-router-push.

You can view more details about this finding in the Semgrep AppSec Platform.

@vercel vercel bot temporarily deployed to Preview – petrinaut March 27, 2026 16:37 Inactive
return;
}

void router.push(navigationAction.path);

Check warning

Code scanning / Semgrep PRO

Semgrep Finding: typescript.nextjs.react-nextjs-router-push.react-nextjs-router-push Warning

Untrusted input could be used to tamper with a web page rendering, which can lead to a Cross-site scripting (XSS) vulnerability. XSS vulnerabilities occur when untrusted input executes malicious JavaScript code, leading to issues such as account compromise and sensitive information leakage. To prevent this vulnerability, validate URLs and their protocol before using them in your codebase.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/apps > hash* Affects HASH (a `hash-*` app) area/apps area/deps Relates to third-party dependencies (area) type/eng > frontend Owned by the @frontend team

Development

Successfully merging this pull request may close these issues.

1 participant