Skip to content

Run 2: ux-prototype Bridge & Highlights

Implement the full Agentation → Hypothesis bridge in the ux-prototype Storybook site: API proxy, annotation transform, bridge integration with localStorage cleanup, Hypothesis sidebar embed, and DOM highlight layer with badge rendering.

  • Repository: /ux-prototype
  • Base branch: jmpicnic/item-image-upload-components
  • Working branch: jmpicnic/integrate-agentation-hypothesis
  • Worktree: Required — other sessions are active on the repo.
    • Path: integrate-hypothesis-worktrees/ux-prototype
    • Create from base branch before starting work.

Single agent, single worktree. No integration branch needed.

Terminal window
# Create worktree
git -C /Users/jmp/code/arda/ux-prototype worktree add \
/Users/jmp/code/arda/integrate-hypothesis-worktrees/ux-prototype \
-b jmpicnic/integrate-agentation-hypothesis \
jmpicnic/item-image-upload-components

All tool calls (Read, Edit, Write, Glob, Grep, Bash) must use absolute paths rooted at /Users/jmp/code/arda/integrate-hypothesis-worktrees/ux-prototype.

After all work is complete and the user signals approval:

Terminal window
git -C /Users/jmp/code/arda/ux-prototype worktree remove \
/Users/jmp/code/arda/integrate-hypothesis-worktrees/ux-prototype
#CriterionVerification CommandExpected Output
1Base branch exists locallygit -C /Users/jmp/code/arda/ux-prototype branch --list jmpicnic/item-image-upload-componentsBranch name listed
2Worktree created successfullytest -d /Users/jmp/code/arda/integrate-hypothesis-worktrees/ux-prototype/.storybookExit code 0
3Storybook builds on base branchcd /Users/jmp/code/arda/integrate-hypothesis-worktrees/ux-prototype && npx storybook build 2>&1 | tail -5Build succeeded
4Lint passes on base branchcd /Users/jmp/code/arda/integrate-hypothesis-worktrees/ux-prototype && npm run lintNo errors
ArtifactPathFormatDescription
API proxy middleware.storybook/middleware.tsTypeScriptExpress middleware proxying Hypothesis API
Hypothesis config.storybook/preview-body.htmlHTMLembed.js injection into preview iframe
Bridge constants.storybook/addons/hypothesis-bridge/constants.tsTypeScriptGroup ID, tag names, proxy base URL
Annotation transform.storybook/addons/hypothesis-bridge/transform.tsTypeScriptAgentation JSON → Hypothesis payload
Proxy client.storybook/addons/hypothesis-bridge/client.tsTypeScriptFetch wrapper for proxy endpoints
Highlight layer.storybook/addons/hypothesis-bridge/highlight-layer.tsxReact TSXBadge rendering + positioning + observers
Highlight decorator.storybook/addons/hypothesis-bridge/with-highlights.tsxReact TSXStorybook decorator
Transform tests.storybook/addons/hypothesis-bridge/__tests__/transform.test.tsVitestField mapping, URL normalization, tag generation, edge cases
Client tests.storybook/addons/hypothesis-bridge/__tests__/client.test.tsVitestProxy URL construction, fetch mocking, error handling
Middleware tests.storybook/addons/hypothesis-bridge/__tests__/middleware.test.tsVitestRoute matching, token injection, unproxied route rejection
Highlight utils tests.storybook/addons/hypothesis-bridge/__tests__/highlight-utils.test.tsVitestSelector tag parsing, severity color mapping, annotation filtering
#TaskPersonaDepends OnStatusAcceptance Criteria
2.1Create worktree and working branch from basefront-endPendingWorktree at expected path, on correct branch
2.2Create constants.ts with group ID, tag names, proxy URLfront-end2.1PendingConstants exported and importable
2.3Create .storybook/middleware.ts — Hypothesis API proxyfront-end2.2PendingPOST/GET/PATCH routes proxy to hypothes.is with Bearer token from env var
2.4Create transform.ts — Agentation → Hypothesis payload mappingfront-end2.2PendingMaps all fields per spec: uri (normalized), text (Markdown + HTML comment), tags (Forensic, agentation, selector, intent, severity), target (CssSelector + optional TextQuoteSelector)
2.5Create client.ts — thin HTTP client for proxy endpointsfront-end2.2PendingpostAnnotation() and searchAnnotations() functions
2.6Create .storybook/preview-body.html — Hypothesis sidebar embedfront-end2.1Pendingembed.js loaded in preview iframe, sidebar toggle visible, openSidebar: false

Write tests immediately after the modules they cover, before integration.

#TaskPersonaDepends OnStatusAcceptance Criteria
2.7Unit tests for transform.tsfront-end2.4PendingSee Transform Test Coverage
2.8Unit tests for client.tsfront-end2.5PendingSee Client Test Coverage
2.9Unit tests for middleware.tsfront-end2.3PendingSee Middleware Test Coverage
#TaskPersonaDepends OnStatusAcceptance Criteria
2.10Modify with-agentation.tsx — bridge onSubmit + localStorage cleanupfront-end2.3, 2.4, 2.5PendingOn submit: transform, POST via proxy, clear localStorage via saveAnnotations(pathname, []), copy JSON to clipboard, dispatch hypothesis-annotations-updated event
2.11Create highlight-layer.tsx — badge rendering React component. Extract pure utility functions (selector tag parsing, severity color mapping, annotation filtering, URL normalization) into a separate highlight-utils.ts module.front-end2.5PendingFetches agentation-tagged annotations, resolves CSS selectors to DOM elements, renders numbered badges color-coded by severity, ResizeObserver + MutationObserver for repositioning, tooltip on hover
2.12Unit tests for highlight-utils.tsfront-end2.11PendingSee Highlight Utils Test Coverage
2.13Create with-highlights.tsx — Storybook decoratorfront-end2.11PendingDecorator renders HighlightLayer with current story URL
2.14Modify preview.ts — register highlight decoratorfront-end2.13Pendingdecorators: [withAgentation, withHighlights, withFullAppProviders]
#TaskPersonaDepends OnStatusAcceptance Criteria
2.15Run all checks: lint, tsc, Storybook build, testsfront-end2.14PendingAll pass with zero errors
2.16Signal user for further instructionsfront-end2.15PendingUser notified that work is complete and ready for review

File: .storybook/addons/hypothesis-bridge/__tests__/transform.test.ts

Test CaseDescription
Maps all required fieldsFull Agentation annotation → Hypothesis payload with uri, text, tags, group, target
Includes Forensic tagEvery output includes Forensic in tags array
Includes agentation origin tagEvery output includes agentation in tags array
Generates selector: tagelementPath encoded as selector:<cssPath> tag
Includes intent and severity tagsfix/change/question/approve and blocking/important/suggestion
Formats Markdown text bodyHTML comment with elementPath, human-readable metadata block below ---
Normalizes URLStrips volatile query params (viewMode, args), retains id
Handles missing selectedTextNo TextQuoteSelector in target when selectedText absent
Includes TextQuoteSelectorWhen selectedText present, adds TextQuoteSelector to target selectors
Handles missing optional fieldsGracefully handles absent reactComponents, cssClasses, intent, severity
Batch transformMultiple annotations produce an array of payloads

File: .storybook/addons/hypothesis-bridge/__tests__/client.test.ts

Test CaseDescription
postAnnotation sends POST to proxyCalls /hypothesis-proxy/annotations with correct method, headers, body
postAnnotation returns created annotationParses JSON response, returns annotation with id
postAnnotation throws on HTTP errorNon-2xx response throws with status and message
searchAnnotations sends GET with query paramsConstructs URL with uri, tag, group, limit params
searchAnnotations returns parsed resultsReturns { total, rows } from response
searchAnnotations URL-encodes parametersSpecial characters in uri/tag are properly encoded

File: .storybook/addons/hypothesis-bridge/__tests__/middleware.test.ts

Test CaseDescription
Proxies POST to /hypothesis-proxy/annotationsForwards body to https://hypothes.is/api/annotations with Bearer token
Proxies GET to /hypothesis-proxy/searchForwards query params to https://hypothes.is/api/search with Bearer token
Proxies PATCH to /hypothesis-proxy/annotations/:idForwards body to https://hypothes.is/api/annotations/:id
Injects Authorization headerEvery proxied request includes Authorization: Bearer <token>
Returns Hypothesis response verbatimStatus code and body from Hypothesis API passed through
Rejects unrecognized routesRequests to /hypothesis-proxy/other receive 404
Handles missing HYPOTHESIS_API_TOKENReturns 500 with descriptive error when env var not set

File: .storybook/addons/hypothesis-bridge/__tests__/highlight-utils.test.ts

Test CaseDescription
Parses selector: tagExtracts CSS selector from selector:div.container > form > button tag
Handles missing selector tagReturns null when no selector: tag present
Maps severity to colorblocking → red, important → orange, suggestion → blue, default → gray
Filters agentation-origin annotationsKeeps only annotations with agentation tag
Extracts severity from tagsIdentifies severity tag from mixed tag array
Extracts intent from tagsIdentifies intent tag from mixed tag array
Normalizes story URLSame logic as transform: strips volatile params, retains id
Parses HTML comment for elementPathExtracts elementPath from <!-- agentation:elementPath=... -->
Phase A: Infrastructure
2.1 (worktree setup)
├── 2.2 (constants) ──┬── 2.3 (middleware)
│ ├── 2.4 (transform)
│ └── 2.5 (client)
└── 2.6 (sidebar embed)
Phase B: Unit Tests
2.7 (transform tests) ← 2.4
2.8 (client tests) ← 2.5
2.9 (middleware tests) ← 2.3
Phase C: Integration + Highlights
2.10 (bridge onSubmit) ← 2.3 + 2.4 + 2.5
2.11 (highlight layer) ← 2.5
2.12 (highlight utils tests) ← 2.11
2.13 (highlight decorator) ← 2.11
2.14 (register decorator) ← 2.13
Phase D: Verification
2.15 (run checks) ← all above
2.16 (signal user) ← 2.15

Parallelizable within Phase A: Tasks 2.3, 2.4, 2.5, 2.6 can proceed in any order after 2.2. Since this is a single agent, they are done sequentially.

Test-then-integrate: Phase B tests validate infrastructure modules before Phase C wires them together. This catches field mapping and API contract issues early, before integration makes debugging harder.

#CriterionVerification CommandExpected Output
1Lint passescd $WT && npm run lintNo errors
2TypeScript compilescd $WT && npx tsc --noEmitNo errors
3Storybook buildscd $WT && npx storybook build 2>&1 | tail -3Build succeeded
4All unit tests pass (including new)cd $WT && npm run testAll tests pass
5Bridge files existls $WT/.storybook/addons/hypothesis-bridge/transform.ts, client.ts, constants.ts, highlight-layer.tsx, highlight-utils.ts, with-highlights.tsx
6Test files existls $WT/.storybook/addons/hypothesis-bridge/__tests__/transform.test.ts, client.test.ts, middleware.test.ts, highlight-utils.test.ts
7Middleware existstest -f $WT/.storybook/middleware.tsExit code 0
8Sidebar embed existstest -f $WT/.storybook/preview-body.htmlExit code 0
9Highlight decorator registeredgrep -c 'withHighlights' $WT/.storybook/preview.tsAt least 1

Where $WT=/Users/jmp/code/arda/integrate-hypothesis-worktrees/ux-prototype.

Front-End Engineer — fe-hypothesis-bridge

Section titled “Front-End Engineer — fe-hypothesis-bridge”

You are working in a worktree at /Users/jmp/code/arda/integrate-hypothesis-worktrees/ux-prototype. Use absolute paths for ALL tool calls.

Goal: Implement the Agentation → Hypothesis bridge in the ux-prototype Storybook site: API proxy, annotation transform, bridge integration with localStorage cleanup, Hypothesis sidebar embed, and DOM highlight layer.

Base branch: jmpicnic/item-image-upload-components Working branch: jmpicnic/integrate-agentation-hypothesis

Tasks: See Run 2 task list in the project plan.

Specification: Read /Users/jmp/code/arda/documentation/src/content/docs/roadmap/completed/integrate-agentation-hypothesis/specification.md for complete component specifications (Components 1-5).

Key patterns to follow:

  • Existing addon structure: /Users/jmp/code/arda/ux-prototype/.storybook/addons/agentation-toggle/
  • Decorator pattern: with-agentation.tsx
  • Storybook globals pattern: preview.ts initialGlobals

Tag convention: All annotations must include Forensic tag by default.

localStorage cleanup: After posting to Hypothesis, call saveAnnotations(pathname, []) from the agentation package to clear submitted annotations.

Testing strategy: Write unit tests for each pure-logic module immediately after implementing it (Phase B before Phase C). Extract testable pure functions from highlight-layer.tsx into a highlight-utils.ts module. Test files go in __tests__/ alongside the source. See the Test Coverage Specifications section for exact test cases per module. Use Vitest with vi.fn() / vi.mock() for mocking fetch and environment. The project uses @testing-library/jest-dom/vitest (not @testing-library/jest-dom).

After completing all tasks: Run all checks (npm run lint, npx tsc --noEmit, npm run test, npx storybook build). Signal the user for further instructions.

ArtifactSource RunPath
hypothesis-mcp API contract (optional)Run 1/hypothesis-mcp/src/client.ts

Note: Run 2 does not depend on Run 1’s completion. The bridge calls the Hypothesis REST API directly, not the MCP. The target parameter with CssSelector is a progressive enhancement.

None — this is the final run.