feat(signals): rich scanner-finding evidence cards in inbox - #71925
Conversation
Replay-vision scanner findings previously fell through to the generic signal card (markdown + raw JSON), with no way to view the recording at the observation's time. Render them with a dedicated card analogous to the session-problem card: a thumbnail preview that plays the recording seeked to the finding, problem-type and confidence tags, and an affected user / window / duration meta line. Also register replay_vision in the source-product icon set, inbox source filter, and header source line. Generated-By: PostHog Code Task-Id: 100cc36a-09c9-4edf-9ac8-21f4c14f8e84
|
Hey @andrewm4894! 👋 It looks like your git author email on this PR isn't your
You can fix it for this repo with: git config user.email "you@posthog.com"Or set it globally with |
🤖 CI report
|
| File | Size | Δ vs base |
|---|---|---|
posthog-app/src/scenes/inbox/InboxScene.js |
672.9 KiB | 🔺 +2.9 KiB (+0.4%) |
Posted automatically by build-bundle-size-report · uncompressed bytes from dist-report
✅ Eager graph — within budget
How much code each root ships on the eager path — downloaded and parsed before the surface is interactive. Measured from the esbuild output chunks (post-tree-shake, static imports only); lazy import() / React.lazy chunks are not counted.
| Root | Eager (shipped) | Δ vs base | Budget |
|---|---|---|---|
entry (logged-out pages, app bootstrap)src/index.tsx |
1.23 MiB · 22 files | no change | ███░░░░░░░ 28.6% of 4.29 MiB |
authenticated shell (every logged-in page)src/scenes/AuthenticatedShell.tsx |
8.15 MiB · 2,988 files | no change | █████████░ 88.1% of 9.25 MiB |
🟢 node_modules/monaco-editor/ stays out of src/index.tsx
🟢 src/lib/components/ActivityLog/describers stays out of src/index.tsx
🟢 [object Object] stays out of src/index.tsx
🟢 [object Object] stays out of src/index.tsx
🟢 node_modules/monaco-editor/ stays out of src/scenes/AuthenticatedShell.tsx
🟢 src/lib/components/ActivityLog/describers stays out of src/scenes/AuthenticatedShell.tsx
🟢 [object Object] stays out of src/scenes/AuthenticatedShell.tsx
🟢 [object Object] stays out of src/scenes/AuthenticatedShell.tsx
Largest files eagerly shipped from src/index.tsx
| Size | File |
|---|---|
| 126.8 KiB | ../node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.production.min.js |
| 24.6 KiB | ../node_modules/.pnpm/buffer@6.0.3/node_modules/buffer/index.js |
| 6.3 KiB | ../node_modules/.pnpm/react@18.3.1/node_modules/react/cjs/react.production.min.js |
| 4.5 KiB | ../node_modules/.pnpm/@jspm+core@2.1.0/node_modules/@jspm/core/nodelibs/browser/process.js |
| 3.9 KiB | ../node_modules/.pnpm/scheduler@0.23.2/node_modules/scheduler/cjs/scheduler.production.min.js |
| 1.4 KiB | ../node_modules/.pnpm/base64-js@1.5.1/node_modules/base64-js/index.js |
| 1.3 KiB | src/RootErrorBoundary.tsx |
| 912 B | ../node_modules/.pnpm/ieee754@1.2.1/node_modules/ieee754/index.js |
| 789 B | src/scenes/ChunkLoadErrorBoundary.tsx |
| 762 B | src/index.tsx |
Largest files eagerly shipped from src/scenes/AuthenticatedShell.tsx
| Size | File |
|---|---|
| 281.3 KiB | ../node_modules/.pnpm/posthog-js@1.404.0/node_modules/posthog-js/dist/rrweb.js |
| 267.7 KiB | ../node_modules/.pnpm/@posthog+icons@0.38.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@posthog/icons/dist/posthog-icons.es.js |
| 235.5 KiB | src/taxonomy/core-filter-definitions-by-group.json |
| 223.2 KiB | ../node_modules/.pnpm/posthog-js@1.404.0/node_modules/posthog-js/dist/module.js |
| 164.0 KiB | src/queries/validators.js |
| 154.3 KiB | ../node_modules/.pnpm/re2js@0.4.1/node_modules/re2js/build/index.esm.js |
| 126.8 KiB | ../node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.production.min.js |
| 105.8 KiB | src/lib/api.ts |
| 93.3 KiB | ../node_modules/.pnpm/prosemirror-view@1.40.1/node_modules/prosemirror-view/dist/index.js |
| 93.3 KiB | ../packages/quill/packages/quill/dist/index.js |
Posted automatically by check-eager-graph · sizes are eager output bytes (shipped, post-tree-shake) from the esbuild metafile · part of #32479
✅ Dist folder size — 🔺 +13.9 KiB (+0.0%)
Total size of the built frontend/dist folder (all assets), compared against the base branch.
Total: 1336.57 MiB · 🔺 +13.9 KiB (+0.0%)
Reuse identifierToHuman for the problem-type label instead of a local helper, drop the dead exported_asset_id undefined-check (the field is required), and render confidence unconditionally. Generated-By: PostHog Code Task-Id: 100cc36a-09c9-4edf-9ac8-21f4c14f8e84
Collapse the totalDuration line to satisfy oxfmt and rename the local `window` variable to avoid shadowing the browser global. Generated-By: PostHog Code Task-Id: 100cc36a-09c9-4edf-9ac8-21f4c14f8e84
Generated-By: PostHog Code Task-Id: 100cc36a-09c9-4edf-9ac8-21f4c14f8e84
There was a problem hiding this comment.
This review was skipped because it would exceed your organization's monthly flex usage limit. Raise the limit in billing settings or wait until the next billing period resets limits.
🦔 Hogbox preview · ✅ ready▶ Open the preview
commit |
|
Going to merge this without testing really, as it's a surface not seen by users - low blast ardius, and I have 98% in the solution here. |
There was a problem hiding this comment.
Self-contained, additive frontend feature (new Inbox signal card + registry/filter/icon wiring) by an author on the owning team; all referenced generated types and helper functions verified to exist. No risky-territory surface touched.
- Author wrote 0% of the modified lines and has 46 merged PRs in these paths (familiarity MODERATE).
- greptile-apps[bot] reviewed the current head.
Gate mechanics and policy version
| Gate | Result | |
|---|---|---|
| prerequisites | ✓ | all clear |
| deny-list | ✓ | no deny categories matched |
| size | ✓ | 176L, 5F substantive — within ceiling |
| tier | ✓ | T1-agent / T1c-medium (176L, 5F, single-area, feat) |
| stamphog 2.0.0b3 | .stamphog/policy.yml @ e0d7721 · reviewed head 62eb7a9 |
@Twixes here - I'm the actual initiator via PostHog in Slack. This is not well-tested, which I think is fine.
Problem
Replay-vision scanner findings in the Inbox rendered with the generic fallback card — a markdown blurb plus a raw-JSON metadata dump — with no way to jump to the recording at the moment the finding was observed. "Session problem" evidence, by contrast, already gets a rich card with a thumbnail that plays the recording seeked to the observation. This closes that gap so both kinds of replay-derived evidence read the same way.
Changes
ScannerFindingSignalCardforreplay_vision/scanner_findingsignals, modeled onSessionReplaySignalCard:recording_start_time + start_time.replay_visionto the source-product icon metadata, the Inbox source filter, and the "Product · Signal type" header line so the source is recognized rather than falling back to a generic dot/label.No backend or serializer changes — the finding payload already carried everything needed (
session_id,exported_asset_id, offsets,recording_start_time).How did you test this code?
Static review against the sibling
SessionReplaySignalCardand the generatedReplayVisionScannerFindingSignalExtraApitype; the field usage and cast pattern mirror the existing card. I was not able to run the frontend typecheck/lint or Storybook in this environment (nonode_modulespresent), so those still need to run in CI. No automated tests were added — the sibling rich card has none, and a component test would require heavy kea setup for marginal value.Automatic notifications
Docs update
🤖 Agent context
Autonomy: Human-driven (agent-assisted)
Authored by the PostHog Slack app from a Slack thread. The task: rework scanner-finding evidence cards in the Inbox to match the rich, seek-to-recording "session problem" cards. Explored the Inbox card registry, found
replay_visionhad no dedicated renderer (fell through toGenericSignalCard) and was missing from the source-icon and filter maps, then added a card built on the sameuseRecordingButton/ thumbnail / existence-check primitives asSessionReplaySignalCard. Key difference handled: scanner findings carrystart_time/end_timeas float second-offsets plus an absoluterecording_start_time, so the seek instant is computed withdayjs(recording_start_time).add(start_time, 'second')rather than the colon-delimited-offset math the session-problem card uses. No skills were invoked (no migration/DRF/API-type/test surface touched).Created with PostHog from a Slack thread