Skip to content

ref(seer): Replace PageContext with SeerContextProvider#111554

Draft
Mihir-Mavalankar wants to merge 5 commits intomasterfrom
mihirmavalankar/feat/seer-structured-page-context
Draft

ref(seer): Replace PageContext with SeerContextProvider#111554
Mihir-Mavalankar wants to merge 5 commits intomasterfrom
mihirmavalankar/feat/seer-structured-page-context

Conversation

@Mihir-Mavalankar
Copy link
Contributor

@Mihir-Mavalankar Mihir-Mavalankar commented Mar 25, 2026

Renames and rewrites the structured page context system for Seer Explorer. The original draft had three blocking issues that prevented it from working:

Nesting never workedregisterPageContext called ctx.registerNode(nodeType) without passing parentId, so all nodes landed at root level. Fix: a second React context (SeerNodeContext) carries the current component's nodeId downward so child HOC wrappers can read it as their parentId synchronously during render.

Initial data writes were silently droppeduseSeerContext(data) effects fire before the parent HOC's registerNode effect (children run before parents in React). With the reducer-based approach the UPDATE_NODE_DATA case was a no-op if the node didn't exist yet. Fix: data is now stored in an imperative useRef<Map> and written synchronously without dispatch. getSnapshot() reads structure from the reducer state and data from the ref at call time.

Infinite re-render loop (OOM) in tests — the context value object was recreated on every useReducer dispatch, giving the HOC's useEffect a new ctx dep on every registration, triggering cleanup+setup in a loop. Fix: useMemo on the context value so callbacks are stable.

Other changes:

  • registerSeerContext(nodeType, Component) — two args, no options/extract bag
  • useSeerContext(data) write overload and useSeerContext() read overload returning { getSeerContext(componentOnly?) }
  • Flat node map with parentId pointers; tree assembled lazily at getSnapshot() time
  • 7 integration tests covering nesting, unmount cleanup, data updates, full-tree and subtree reads, and no-provider graceful render

Add the core infrastructure for capturing semantic page state as a
structured context tree, replacing the lossy ASCII DOM snapshot. This
includes the context types, a pure reducer for tree operations, a React
provider with getSnapshot() serialization, a registerPageContext HOC
for automatic node lifecycle, and unit tests.

Stage 1 of the structured page context plan — no app wiring yet.

Co-Authored-By: Claude Sonnet 4 <noreply@anthropic.com>
@Mihir-Mavalankar Mihir-Mavalankar requested a review from azulus March 25, 2026 20:19
@Mihir-Mavalankar Mihir-Mavalankar self-assigned this Mar 25, 2026
@github-actions github-actions bot added the Scope: Frontend Automatically applied to PRs that change frontend components label Mar 25, 2026
@Mihir-Mavalankar Mihir-Mavalankar changed the title feat(seer): Add structured page context provider for Seer Explorer Draft: feat(seer): Add structured page context provider for Seer Explorer Mar 25, 2026
Use Record<string, unknown> constraint and props-as-any spread to match
existing HOC patterns (withOrganization). Simplify test to avoid OOM.
Mount PageContextProvider in the app shell so files are in the
production import chain.

Co-Authored-By: Claude Sonnet 4 <noreply@anthropic.com>
return <div>{props.title}</div>;
}

const ContextAwareWidget = registerPageContext('widget', DummyWidget, {
Copy link
Member

Choose a reason for hiding this comment

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

I don't think we need the third prop here per previous conversations. I'd mostly use the register function just to wrap + name and make the third prop optional (we might want to use it for filtering data later or some such)

});

describe('registerPageContext HOC', () => {
function DummyWidget(props: {title: string}) {
Copy link
Member

Choose a reason for hiding this comment

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

I think this would be better served using the hook escape hatch (usePageContext({ title: 'Error Rate'});) or whatever it should be called to dedupe the "context" overloading

expect(snapshot.nodes[0].nodeType).toBe('widget');
expect(snapshot.nodes[0].data).toEqual({title: 'Error Rate'});
});

Copy link
Member

Choose a reason for hiding this comment

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

there should probably be a test in here which mounts, renders, then confirms that the PageContextProvider is actually providing the page context for sending to the AI. I'd also add a test with a nested case so we can test that DummyChart in DummyWidget in DummyDashboard (or something similar) nests appropriately and all are providing the right data in the right structure

Renames and rewrites the structured page context system for Seer Explorer.
The original implementation had three blocking issues: nodes were never
nested (parentId was never passed), initial data writes were silently
dropped (useSeerContext effect fired before registerNode), and an infinite
re-render loop caused OOM in tests (unstable context value reference on
every dispatch).

Key design decisions:
- Flat node map with parentId pointers; tree assembled lazily at
  getSnapshot() time to avoid ordering dependencies on registration
- Node data stored in an imperative ref (not reducer state) so writes
  from useSeerContext(data) are visible immediately regardless of whether
  registerNode has fired yet
- Context value memoized so HOC useEffect deps stay stable and don't
  retrigger on every registration
- registerSeerContext(nodeType, Component) — two args only, no options bag
- useSeerContext(data) write overload / useSeerContext() read overload
  returning { getSeerContext(componentOnly?) }

Co-Authored-By: Claude <noreply@anthropic.com>
@azulus azulus changed the title Draft: feat(seer): Add structured page context provider for Seer Explorer ref(seer): Replace PageContext with SeerContextProvider Mar 26, 2026
…et data

Silences lint warnings on chained property access in snapshot assertions
while still failing the test if a node is unexpectedly absent.

Adds type/unit fields to DummyWidget's useSeerContext call so the nesting
test verifies that multi-field payloads survive the full
register → write → snapshot round-trip.

Co-Authored-By: Claude <noreply@anthropic.com>
Replaces the per-property assertions in the nesting test with a single
deep equality check against the expected tree, so a failure prints the
full actual vs expected shape in one diff.

Co-Authored-By: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Scope: Frontend Automatically applied to PRs that change frontend components

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants