Skip to content

feat(posthog-ai): fold turn suggestion frames into the run projection - #106434

Merged
trunk-io[bot] merged 10 commits into
rafa/ts-6-turn-suggestions-benchmarkfrom
rafa/ts-7-turn-suggestion-projection
Oct 6, 2026
Merged

trunk-io[bot] merged 10 commits into
rafa/ts-6-turn-suggestions-benchmarkfrom
rafa/ts-7-turn-suggestion-projection

Conversation

@rafaeelaudibert

@rafaeelaudibert rafaeelaudibert commented Sep 25, 2026 •

Copy link
Copy Markdown
Member

Problem

Changes

  • Feedback numbering: the turn_index feedback event property now uses the index of the user message a turn answers. After a crashed turn the numbers skip one. Feedback events also carry $ai_trace_id, which names the turn regardless of numbering.
  • Stored ratings: a rating is stored under the turn's trace id, so renumbering cannot move it onto another answer. A turn without a trace id keeps the <conversation>:turn-<n> key. Ratings stored under the old index keys stop showing on their answers.
  • Hidden opening prompt: an answer to a hidden opening prompt gets no trailer, so no feedback buttons. The server does not number that turn either.
  • Projection: the run projection now carries the newest suggestion offer and the outcomes seen on the wire.
  • Ledger: the logic reads the server's offer ledger once per task, when the first offer arrives, and combines it with the wire to decide which card shows.
  • Replay: a card stays hidden until that ledger loads, because resolutions reach the log only while a tab is open. A failed read retries up to three times, and the card stays hidden if all fail.
  • Local outcome: a dismiss before the ledger loads still mutes the conversation, and a late ledger read does not wipe it.
  • No fallback copy: a frame without a title or description is dropped instead of falling back to client-side text.
  • Shared trailer: the Max thread and the run surface both render per-turn actions through one TurnTrailerActions. Each host keeps its current rules for showing feedback.
  • Re-renders: the parsed offer is cached on its frame, so trailer rows do not re-render on every streamed frame.

No card renders yet, so the thread looks the same apart from the feedback numbering.

How did you test this code?

  • runStreamLogic.test.ts catches a dismiss that is lost before the ledger loads, a ledger read that overwrites a local dismiss, and a card that shows before the ledger loads or never recovers from a failed read.
  • turnTrailers.test.ts catches a trailer that gets turn index -1, or two trailers that share one index.
  • turnSuggestions.test.ts catches a frame without copy that still renders.
  • wireTypes.test.ts covers parsing of the two new frame kinds.

Release status

  • No feature flag controls this change
  • This change is behind a feature flag and is not available to users
  • This change makes a previously flagged feature available to everyone

The suggestion frames only arrive behind the posthog-ai-turn-suggestions flag. The feedback numbering change applies to everyone.

Automatic notifications

  • Publish to changelog?

Docs update

None.

🤖 Agent context

Autonomy: Human-driven (agent-assisted)

Agent: Claude Code, Claude Fable 5.1 wrote the original #101991. Claude Opus 5.5 split it into this stack and fixed the review findings.

  • Skills invoked: /stacking-prs, /writing-kea-logics, /writing-ui-components, /writing-tests, /code-review, /writing-pr-descriptions.
  • CodeRabbit CLI pass skipped by the user's standing choice.
  • The first split kept a second promptIndex next to turnIndex. The user asked for one index instead. Ratings moved to trace id keys after review, because ratings are stored in localStorage.

🤖 Generated with Claude Code

@github-actions

github-actions Bot commented Sep 25, 2026 •

Copy link
Copy Markdown
Contributor

🤖 CI report

⚠️ Trunk lane — backend Python lane

This PR is assigned to the backend Python lane. It runs backend Python tests and may merge in parallel with PRs in other lanes.

⚠️ Complexity (TypeScript) — 40 functions above the limit (max 123)

Cyclomatic complexity above the limit in changed typescript files (10 for production files, 15 for test files). Warn only: worth simplifying when you next touch these functions.

Function Location Complexity Limit
foldLogFromCheckpoint products/posthog_ai/frontend/logics/runStreamLogic.ts:1608 123 10
ingestAcpFrame products/posthog_ai/frontend/logics/runStreamLogic.ts:4836 92 10
handleSseEvent products/posthog_ai/frontend/logics/runStreamLogic.ts:4079 41 10
<anonymous> frontend/src/scenes/max/Thread.tsx:257 34 10
reconcileRunLog products/posthog_ai/frontend/logics/runStreamLogic.ts:1307 32 10
ThreadRow products/posthog_ai/frontend/components/ThreadRow.tsx:113 30 10
reconcileHistory products/posthog_ai/frontend/logics/runStreamLogic.ts:3799 29 10
<anonymous> frontend/src/scenes/max/Thread.tsx:581 26 10
invocationFromToolCallUpdate products/posthog_ai/frontend/logics/runStreamLogic.ts:1425 24 10
Message frontend/src/scenes/max/Thread.tsx:513 23 10
LegacyThread frontend/src/scenes/max/Thread.tsx:223 21 10
dedupeBufferedAgainstHistory products/posthog_ai/frontend/logics/runStreamLogic.ts:1075 21 10
parseTurnSuggestionParams products/posthog_ai/frontend/utils/turnSuggestions.ts:138 21 10
SuccessActions frontend/src/scenes/max/Thread.tsx:1337 20 10
streamRun products/posthog_ai/frontend/logics/runStreamLogic.ts:4201 20 10
parsePermissionRequestFrame products/posthog_ai/frontend/logics/runStreamLogic.ts:822 18 10
deliverPermission products/posthog_ai/frontend/logics/runStreamLogic.ts:4465 17 10
openSseForRun products/posthog_ai/frontend/logics/runStreamLogic.ts:4042 16 10
handleTerminalStatus products/posthog_ai/frontend/logics/runStreamLogic.ts:4585 16 10
coversEntry products/posthog_ai/frontend/logics/runStreamLogic.ts:1157 14 10
add products/posthog_ai/frontend/logics/runStreamLogic.ts:1188 14 10
<anonymous> products/posthog_ai/frontend/logics/runStreamLogic.ts:3590 14 10
sseDropped products/posthog_ai/frontend/logics/runStreamLogic.ts:4324 14 10
RunSurfaceComposer products/posthog_ai/frontend/components/RunSurfaceImpl.tsx:266 13 10
userAttachment products/posthog_ai/frontend/logics/runStreamLogic.ts:429 13 10
sameFoldOptions products/posthog_ai/frontend/logics/runStreamLogic.ts:1566 13 10
bootstrapRun products/posthog_ai/frontend/logics/runStreamLogic.ts:3947 13 10
Visualization frontend/src/scenes/max/Thread.tsx:1109 12 10
RunSurfaceRoot products/posthog_ai/frontend/components/RunSurfaceImpl.tsx:88 12 10
mergeToolCallUpdateEntries products/posthog_ai/frontend/logics/runStreamLogic.ts:952 12 10
renderLiveHuman products/posthog_ai/frontend/logics/runStreamLogic.ts:1852 12 10
routePermissionRequest products/posthog_ai/frontend/logics/runStreamLogic.ts:4391 12 10
Thread frontend/src/scenes/max/Thread.tsx:130 11 10
<anonymous> frontend/src/scenes/max/Thread.tsx:880 11 10
RunSurfaceThread products/posthog_ai/frontend/components/RunSurfaceImpl.tsx:199 11 10
<anonymous> products/posthog_ai/frontend/logics/runStreamLogic.ts:1280 11 10
finalizeMessage products/posthog_ai/frontend/logics/runStreamLogic.ts:1776 11 10
pushError products/posthog_ai/frontend/logics/runStreamLogic.ts:1926 11 10
<anonymous> products/posthog_ai/frontend/logics/runStreamLogic.ts:3452 11 10
<anonymous> products/posthog_ai/frontend/logics/runStreamLogic.ts:3553 11 10
✅ Duplication (Python) — clean

New Python code duplication introduced by this branch. Fails at 70+ tokens in app code, or 150+ tokens when both copies live in test files. Advisory while the gate proves itself: extract a shared helper instead of copying.

✅ Duplication (TypeScript) — clean

New TypeScript code duplication introduced by this branch. Fails at 70+ tokens in app code, or 150+ tokens when both copies live in test files. Advisory while the gate proves itself: extract a shared helper instead of copying.

⚠️ Comment density — 3% of added code lines are comments (29 of 868)

This section warns when comments are more than 3% of the code lines a PR adds, and alerts above 6%. Before agent-assisted PRs, the typical share was about 2%. Only full-line comments count. Docstrings, generated files, snapshots, migrations, and workflow files are left out.

Comments that restate the code, record how the change came about, or narrate the next line add noise for the next reader. Keep the comments that explain a reason the code cannot show, and remove the rest. See .agents/skills/writing-code-comments/SKILL.md for the house rules.

Files with the most added comment lines:

File Comment lines Added lines
products/posthog_ai/frontend/logics/runStreamLogic.ts 17 231
products/posthog_ai/frontend/utils/turnTrailers.ts 6 10
products/posthog_ai/frontend/components/useTurnRating.ts 1 2
products/posthog_ai/frontend/logics/messageRatingsLogic.ts 1 1
products/posthog_ai/frontend/types/streamTypes.ts 1 73
products/posthog_ai/frontend/types/wireTypes.ts 1 35
products/posthog_ai/frontend/utils/toolCallMessage.ts 1 27
products/posthog_ai/frontend/utils/turnSuggestions.ts 1 171

This check does not block merging. It updates on every push and clears when the share drops.

⚠️ Bundle size — 🔺 +5.7 KiB (+0.0%)

Uncompressed size of every built .js bundle, compared against the base branch.

Total: 76.01 MiB · 🔺 +5.7 KiB (+0.0%)

File Size Δ vs base
render-query/src/render-query/render-query.js 25.15 MiB 🔺 +5.6 KiB (+0.0%)

Posted automatically by build-bundle-size-report · uncompressed bytes from dist-report

⚠️ Eager graph — 2 over 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.64 MiB · 23 files no change █████████░ 88.9% of 1.84 MiB
logged-out boot: index + App + bootApp (preloaded by every page, including /login)
src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
3.72 MiB · 663 files no change █████████░ 92.3% of 4.03 MiB
authenticated shell (every logged-in page)
src/scenes/AuthenticatedShell.tsx
7.62 MiB · 2,417 files 🔺 +5.3 KiB (+0.1%) █████████░ 91.4% of 8.34 MiB
🟡 dashboard scene
src/scenes/dashboard/Dashboard.tsx
13.91 MiB · 4,919 files 🔺 +5.3 KiB (+0.0%) ██████████ 103.2% of 13.48 MiB
today home path
src/scenes/AuthenticatedShell.tsx + src/scenes/project-homepage/ProjectHomepage.tsx + src/scenes/project-homepage/today/TodayHome.tsx
7.64 MiB · 2,429 files 🔺 +5.3 KiB (+0.1%) █████████░ 89.1% of 8.58 MiB
🟡 events scene
src/scenes/activity/explore/EventsScene.tsx
13.64 MiB · 4,791 files 🔺 +5.3 KiB (+0.0%) ██████████ 107.9% of 12.64 MiB
replay detail scene
src/scenes/session-recordings/detail/SessionRecordingDetail.tsx
12.13 MiB · 4,144 files 🔺 +5.3 KiB (+0.0%) ████████░░ 77.2% of 15.72 MiB

🟢 node_modules/monaco-editor/ stays out of src/index.tsx
🟢 src/lib/components/ActivityLog/describers stays out of src/index.tsx
🟢 node_modules/@posthog/brand/dist/generated/hoggies/svg/ stays out of src/index.tsx
🟢 node_modules/@posthog/brand/dist/generated/hoggies/components/ stays out of src/index.tsx
🟢 node_modules/monaco-editor/ stays out of src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
🟢 src/layout/navigation-3000/navigationLogic.tsx stays out of src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
🟢 src/scenes/dashboard/dashboardLogic.tsx stays out of src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
🟢 src/lib/lemon-ui/LemonMarkdown/ stays out of src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
🟢 src/lib/components/RichContentEditor/ stays out of src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
🟢 src/lib/components/CodeSnippet/ stays out of src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
🟢 src/taxonomy/core-filter-definitions-by-group.json stays out of src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
🟢 node_modules/monaco-editor/ stays out of src/scenes/AuthenticatedShell.tsx
🟢 src/lib/components/ActivityLog/describers stays out of src/scenes/AuthenticatedShell.tsx
🟢 products/dashboards/frontend/widgets/previews/ stays out of src/scenes/AuthenticatedShell.tsx
🟢 src/scenes/session-recordings/player/sessionRecordingPlayerLogic.ts stays out of src/scenes/AuthenticatedShell.tsx
🟢 zod/v4/locales/de.js stays out of src/scenes/AuthenticatedShell.tsx
🟢 node_modules/@posthog/brand/dist/generated/hoggies/svg/ stays out of src/scenes/AuthenticatedShell.tsx
🟢 node_modules/@posthog/brand/dist/generated/hoggies/components/ stays out of src/scenes/AuthenticatedShell.tsx
🟢 src/scenes/project-homepage/ai-first/AiFirstHomepage.tsx stays out of src/scenes/AuthenticatedShell.tsx + src/scenes/project-homepage/ProjectHomepage.tsx + src/scenes/project-homepage/today/TodayHome.tsx
🟢 src/scenes/project-homepage/today/TodayReportPage.tsx stays out of src/scenes/AuthenticatedShell.tsx + src/scenes/project-homepage/ProjectHomepage.tsx + src/scenes/project-homepage/today/TodayHome.tsx
🟢 src/queries/Query/Query.tsx stays out of src/scenes/AuthenticatedShell.tsx + src/scenes/project-homepage/ProjectHomepage.tsx + src/scenes/project-homepage/today/TodayHome.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/index.tsx
1.3 KiB src/RootErrorBoundary.tsx
912 B ../node_modules/.pnpm/ieee754@1.2.1/node_modules/ieee754/index.js
839 B src/scenes/ChunkLoadErrorBoundary.tsx
Largest files eagerly shipped from src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
Size File
306.2 KiB ../node_modules/.pnpm/posthog-js@1.435.5_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/module.mjs
220.3 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
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
99.7 KiB src/lib/api.ts
90.6 KiB src/products.tsx
68.7 KiB src/lib/lemon-ui/icons/icons.tsx
40.7 KiB src/lib/utils/eventUsageLogic.ts
38.7 KiB ../node_modules/.pnpm/@dnd-kit+core@6.0.8_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/core.esm.js
33.9 KiB ../node_modules/.pnpm/kea@4.0.0-pre.6_patch_hash=139b8d1f1304f9d9da452a9a1244c94ea679dbcb85687d8999563146879fb6f5_react@18.3.1/node_modules/kea/lib/index.cjs.js
29.0 KiB ../node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/core/schemas.js
Largest files eagerly shipped from src/scenes/AuthenticatedShell.tsx
Size File
306.2 KiB ../node_modules/.pnpm/posthog-js@1.435.5_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/module.mjs
280.3 KiB src/taxonomy/core-filter-definitions-by-group.json
220.3 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
153.7 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
112.3 KiB ../packages/quill/packages/quill/dist/index.js
99.7 KiB src/lib/api.ts
93.3 KiB ../node_modules/.pnpm/prosemirror-view@1.40.1/node_modules/prosemirror-view/dist/index.js
90.6 KiB ../node_modules/.pnpm/@tiptap+core@3.20.6_@tiptap+pm@3.20.6/node_modules/@tiptap/core/dist/index.js
90.6 KiB src/products.tsx
Largest files eagerly shipped from src/scenes/dashboard/Dashboard.tsx
Size File
315.5 KiB ../node_modules/.pnpm/posthog-js@1.435.5_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/rrweb.js
306.2 KiB ../node_modules/.pnpm/posthog-js@1.435.5_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/module.mjs
280.3 KiB src/taxonomy/core-filter-definitions-by-group.json
220.3 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
181.8 KiB src/queries/validators.js
153.7 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
112.3 KiB ../packages/quill/packages/quill/dist/index.js
99.7 KiB src/lib/api.ts
93.3 KiB ../node_modules/.pnpm/prosemirror-view@1.40.1/node_modules/prosemirror-view/dist/index.js
Largest files eagerly shipped from src/scenes/AuthenticatedShell.tsx + src/scenes/project-homepage/ProjectHomepage.tsx + src/scenes/project-homepage/today/TodayHome.tsx
Size File
306.2 KiB ../node_modules/.pnpm/posthog-js@1.435.5_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/module.mjs
280.3 KiB src/taxonomy/core-filter-definitions-by-group.json
220.3 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
153.7 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
112.3 KiB ../packages/quill/packages/quill/dist/index.js
99.7 KiB src/lib/api.ts
93.3 KiB ../node_modules/.pnpm/prosemirror-view@1.40.1/node_modules/prosemirror-view/dist/index.js
90.6 KiB ../node_modules/.pnpm/@tiptap+core@3.20.6_@tiptap+pm@3.20.6/node_modules/@tiptap/core/dist/index.js
90.6 KiB src/products.tsx
Largest files eagerly shipped from src/scenes/activity/explore/EventsScene.tsx
Size File
315.5 KiB ../node_modules/.pnpm/posthog-js@1.435.5_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/rrweb.js
306.2 KiB ../node_modules/.pnpm/posthog-js@1.435.5_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/module.mjs
280.3 KiB src/taxonomy/core-filter-definitions-by-group.json
220.3 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
181.8 KiB src/queries/validators.js
153.7 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
112.3 KiB ../packages/quill/packages/quill/dist/index.js
99.7 KiB src/lib/api.ts
93.3 KiB ../node_modules/.pnpm/prosemirror-view@1.40.1/node_modules/prosemirror-view/dist/index.js
Largest files eagerly shipped from src/scenes/session-recordings/detail/SessionRecordingDetail.tsx
Size File
315.5 KiB ../node_modules/.pnpm/posthog-js@1.435.5_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/rrweb.js
306.2 KiB ../node_modules/.pnpm/posthog-js@1.435.5_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/module.mjs
280.3 KiB src/taxonomy/core-filter-definitions-by-group.json
220.3 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
181.8 KiB src/queries/validators.js
153.7 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
112.3 KiB ../packages/quill/packages/quill/dist/index.js
99.7 KiB src/lib/api.ts
93.3 KiB ../node_modules/.pnpm/prosemirror-view@1.40.1/node_modules/prosemirror-view/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

✅ Toolbar bundle — eager 2.21 MiB within budget

What the toolbar ships to customer pages, measured from the esbuild output (minified, post-tree-shake). The eager set is the entry plus everything statically imported from it — fetched before any feature runs; deferred chunks load lazily. The eager guardrail is 5.72 MiB. Each output file must also stay below 10 MB, where CloudFront stops compressing it. The module boundary is enforced separately by check-toolbar-graph.

Metric Size Δ vs base Budget
Eager (shipped)
entry + static imports
2.21 MiB · 19 files no change ████░░░░░░ 38.7% of 5.72 MiB
Deferred (lazy) 2.12 MiB · 44 files no change n/a — loads on demand
Loader dist/toolbar.js 1.2 KiB no change █░░░░░░░░░ 6.0% of 19.5 KiB
Largest eagerly-shipped chunks
Size File
850.6 KiB dist/toolbar/toolbar-app-5BH4NJL4.css
657.4 KiB dist/toolbar/chunk-chunk-R75Z5TYV.js
259.4 KiB dist/toolbar/chunk-chunk-6EL3FW4B.js
138.2 KiB dist/toolbar/chunk-chunk-2GNJAOKU.js
131.8 KiB dist/toolbar/chunk-chunk-FDH2IBXT.js
75.2 KiB dist/toolbar/toolbar-app-2PA223GW.js
69.0 KiB dist/toolbar/chunk-chunk-TSAL54PB.js
35.6 KiB dist/toolbar/chunk-chunk-46UEXYQR.js
21.0 KiB dist/toolbar/chunk-chunk-Q5QJDMUL.js
6.8 KiB dist/toolbar/chunk-chunk-DV7IWQNF.js

Posted automatically by check-toolbar-size · sizes are toolbar output bytes (shipped, post-tree-shake) from the esbuild metafile

✅ Dist folder size — 🔺 +193.8 KiB (+0.0%)

Total size of the built frontend/dist folder (all assets), compared against the base branch.

Total: 998.81 MiB · 🔺 +193.8 KiB (+0.0%)

✅ Playwright — all passed

All tests passed.

View test results →

✅ Hogbox preview — ready, open the preview

▶ Open the preview

🔑 Login test@posthog.com / 12345678 (demo data)
🧩 Running this PR's backend and frontend, on the PostHog :master base
🔗 Link stable across rebuilds: a re-push swaps the box underneath, the URL stays
🔒 Access tailnet only (PostHog VPN)
🛠️ Admin inspect & debug state in hogland
💤 Idle sleeps after ~30 min idle (snapshot to S3, zero node cost) and wakes on your next visit in ~30s, behind a brief "waking up" screen

commit 3d5a959 · box box-b853f3a4e3ae · ready in 704s (push → usable) · build log · rebuilds on every push, torn down on close

@rafaeelaudibert
rafaeelaudibert requested review from a team, MattBro and fercgomes and removed request for a team September 25, 2026 04:32
@greptile-apps

greptile-apps Bot commented Sep 25, 2026 •

Copy link
Copy Markdown
Contributor

Retrigger

[Medium risk] Adds turn suggestion UI and parsing to the AI assistant.

The PR is not ready to merge because ledger loading can leave a valid offer hidden or make a resolved offer reappear.

Reviews (2) · Last reviewed commit: "chore(posthog-ai): regenerate run stream..."

@trunk-io

trunk-io Bot commented Sep 25, 2026 •

Copy link
Copy Markdown

Static Badge   Static Badge   Static Badge

Failed Test Failure Summary Logs
Scenes/Code review Default play-test The test failed because a logic component was not mounted when accessed, and there were unhandled network requests intercepted by the mock service... Logs ↗︎
Scenes-App/Marketing Analytics/Search performance LandingPages play-test The test failed because it could not find an element with the text 'Landing pages' on the page. Logs ↗︎
compareTopLevelSections() reports a modifiers change when the current query overrides the team default A TypeError occurred because the code attempted to access the 'add' property of an undefined object. Logs ↗︎

View Full Report ↗︎ ⋅ Docs

@coderabbitai

coderabbitai Bot commented Sep 25, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The frontend now parses five kinds of turn-suggestion notifications and tracks offers, outcomes, and persisted mute or resolution state. Turn trailer indexes now follow user-message indexes, including cases with crashed turns or separators that do not produce a trailer. Thread renderers now use a shared trailer action component, and ThreadRow imports a shared tool-invocation message mapper.

Priority: ⬇️ Low

Merge Risk: 🔵 Low · up to 97e12

If ledger reads fail repeatedly, a suggestion can remain hidden until the task resets. This is a bounded issue to fix or explicitly accept before merging.

Security Architecture Review

Security architecture risk: 🔵 Low · up to 97e12

No suggestion card is rendered by this PR, and the new ledger request is read-only. The projection does contain an exception that can show an accepted offer despite mute or ledger checks; its effect should be settled before a card consumes it.

Retained concerns

  • Low · architecture · observed: When the accepted-in-this-tab turn matches an offer, the projection returns it before applying mute, resolution, and matching-task ledger checks. This is a conditional state-policy bypass, not an observed card exposure in this PR.
Security review details

Security Blast Radius

  • inferred — The new reachable sink is a project- and task-scoped ledger GET, rather than a permission decision or suggestion-acceptance request. A suggestion frame can initiate that read, but its payload does not supply the requested task ID.

Trust Boundaries and Controls

  • observed — Wire suggestion data is parsed before becoming an offer; replayed ordinary offers fail closed while ledger state is unavailable. The same-tab acceptance exception precedes those ledger and mute checks.

Resilience and Maintainability Implications

  • observed — Late ledger responses are discarded after a task change, while local outcomes remain intact when a ledger read completes. Refresh on tab visibility addresses resolutions missed while the tab was away.

Hardening Proposals

  • proposed — Before connecting a card to this projection, define whether same-tab acceptance may override conversation mute or a changed task, and scope or order the selector checks accordingly.
🚥 Pre-merge checks | ✅ 1
✅ Passed checks (1 passed)
Check name Status Explanation
Description check ✅ Passed The description explains the problem, user-visible changes, test coverage, release status, documentation status, and agent context. It is mostly complete and gives enough context to understand the cha…
✨ Finishing Touches
📝 Generate docstrings
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Note

Quiet mode is enabled, so only the most important comments were posted inline. Other review comments are grouped below.

🟡 Other comments (1)
products/posthog_ai/frontend/utils/turnSuggestions.ts-111-114 (1)

111-114: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Validate changePercent after rounding, not before.

parseAlertDraft checks alert.changePercent > 0 on the raw value, then returns Math.round(alert.changePercent). A frame with changePercent: 0.3 passes the check and becomes 0. The alert draft then carries a 0% threshold, which the "without a positive bound" rule is meant to reject. Round the value first, then validate it.

🐛 Proposed fix
-    if (typeof alert.changePercent !== 'number' || !(alert.changePercent > 0)) {
+    const changePercent = typeof alert.changePercent === 'number' ? Math.round(alert.changePercent) : NaN
+    if (!(changePercent > 0)) {
         return null
     }
-    return { ...insight, direction: alert.direction, changePercent: Math.round(alert.changePercent) }
+    return { ...insight, direction: alert.direction, changePercent }

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository: PostHog/posthog/.coderabbit.yaml

Review profile: QUIET

Plan: Enterprise

Run ID: f7341d8f-7521-4fac-8e2a-a2612cd71715

📥 Commits

Reviewing files that changed from the base of the PR and between 3a49c38 and 642ff6e.

📒 Files selected for processing (16)
  • frontend/src/scenes/max/Thread.tsx
  • products/posthog_ai/frontend/api/primitives.ts
  • products/posthog_ai/frontend/components/RunSurfaceImpl.tsx
  • products/posthog_ai/frontend/components/ThreadRow.tsx
  • products/posthog_ai/frontend/components/TurnTrailerActions.tsx
  • products/posthog_ai/frontend/logics/runStreamLogic.test.ts
  • products/posthog_ai/frontend/logics/runStreamLogic.ts
  • products/posthog_ai/frontend/types/streamTypes.ts
  • products/posthog_ai/frontend/types/wireTypes.test.ts
  • products/posthog_ai/frontend/types/wireTypes.ts
  • products/posthog_ai/frontend/utils/toolCallMessage.ts
  • products/posthog_ai/frontend/utils/turnSuggestionFixtures.ts
  • products/posthog_ai/frontend/utils/turnSuggestions.test.ts
  • products/posthog_ai/frontend/utils/turnSuggestions.ts
  • products/posthog_ai/frontend/utils/turnTrailers.test.ts
  • products/posthog_ai/frontend/utils/turnTrailers.ts

Included review availability: Your plan provides up to 12 included reviews per hour; 4 remain after this review.

@rafaeelaudibert
rafaeelaudibert force-pushed the rafa/ts-7-turn-suggestion-projection branch from 642ff6e to f43e421 Compare September 25, 2026 05:20
@rafaeelaudibert
rafaeelaudibert force-pushed the rafa/ts-7-turn-suggestion-projection branch from f43e421 to 2b98ccb Compare September 25, 2026 12:56
@rafaeelaudibert

Copy link
Copy Markdown
Member Author

@coderabbitai review-body comment:

  • Validate changePercent after rounding: fixed by f277d5d

@coderabbitai

coderabbitai Bot commented Sep 25, 2026

Copy link
Copy Markdown
Contributor

Tip

For best results, initiate chat on the files or code changes.

@rafaeelaudibert The changePercent validation finding is addressed.

You are interacting with an AI system.

@rafaeelaudibert
rafaeelaudibert force-pushed the rafa/ts-7-turn-suggestion-projection branch from 2b98ccb to 7ae4308 Compare September 25, 2026 13:11
@rafaeelaudibert
rafaeelaudibert force-pushed the rafa/ts-7-turn-suggestion-projection branch from 7ae4308 to 8859f95 Compare September 25, 2026 13:16
@rafaeelaudibert
rafaeelaudibert force-pushed the rafa/ts-7-turn-suggestion-projection branch from 8859f95 to bcb54e7 Compare September 25, 2026 13:44
@rafaeelaudibert
rafaeelaudibert removed this pull request from stack #106431 September 25, 2026 13:45
@rafaeelaudibert
rafaeelaudibert force-pushed the rafa/ts-7-turn-suggestion-projection branch from bcb54e7 to a1e7eac Compare September 25, 2026 13:54
@rafaeelaudibert
rafaeelaudibert force-pushed the rafa/ts-7-turn-suggestion-projection branch from a1e7eac to d33c577 Compare September 25, 2026 14:24
@stamphog
stamphog Bot dismissed their stale review October 4, 2026 20:45

A new stamphog review started for this PR — the fresh verdict replaces this approval.

stamphog[bot]

This comment was marked as outdated.

@posthog

posthog Bot commented Oct 4, 2026 •

Copy link
Copy Markdown
Contributor

✅ Visual changes approved by @rafaeelaudibert — baseline updated in b6179a7.

View this run in PostHog

2 changed.

Changed

Snapshot Before After
products-posthog-ai-threadview--message-footers--dark before after
products-posthog-ai-threadview--message-footers--light before after

Install the Visual Review Chrome extension to see visual review results at the top of your pull requests.

@stamphog
stamphog Bot dismissed their stale review October 4, 2026 23:06

A new stamphog review started for this PR — the fresh verdict replaces this approval.

stamphog[bot]

This comment was marked as outdated.

rafaeelaudibert and others added 10 commits October 6, 2026 04:20
The run projection now carries the newest turn suggestion offer and the
outcomes seen on the wire. The logic combines them with the server's offer
ledger, read once per task when the first offer arrives, to decide which
card shows. Turn trailers carry the index of the user message they answer,
which matches the server's turn numbering, and a shared trailer component
renders per-turn actions for both hosts. Frames without card copy are
dropped instead of falling back to client-side text.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Resolutions reach the run log only while a tab is open, so a card the
user resolved elsewhere could show again before the ledger read landed,
or for good when that read failed. The card now waits for the task's
ledger, and a failed read retries up to three times.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…rd returns

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…took

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…d user message

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2 updated
Run: 1a2aa842-b402-4793-b82e-875aaccccbd4
A stored rating no longer depends on how the thread numbers its turns, so
renumbering turns cannot move a rating onto another answer.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@rafaeelaudibert
rafaeelaudibert force-pushed the rafa/ts-7-turn-suggestion-projection branch from b6179a7 to 3d5a959 Compare October 6, 2026 03:24
@stamphog
stamphog Bot dismissed their stale review October 6, 2026 03:24

A new stamphog review started for this PR — the fresh verdict replaces this approval.

@stamphog stamphog Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Approved.

Frontend-only change behind a flag, outside risky territory. The one behavior change that applies to everyone, the feedback numbering and rating keys, is disclosed in the description, and the localStorage rating-key concern was addressed. The remaining reviewer notes are minor.

  • Author wrote 0% of the modified lines and has 43 merged PRs in these paths (familiarity MODERATE).
  • 👍 on the PR from greptile-apps[bot].
  • Minor: if all three ledger reads fail, a later tab-visibility event does not retry, because the refresh only fires while a card is already showing. The description states the card staying hidden is intended.
Gate mechanics and policy version
Gate Result
prerequisites ✓ all clear
deny-list ✓ no deny categories matched
size ✓ 720L, 16F substantive, 1019L/20F incl. docs/generated/snapshots — within ceiling
tier ✓ T1-agent / T1d-complex (1019L, 20F, two-areas, feat)
stamphog 2.3.1 .stamphog/policy.yml @ 3d5a959 · reviewed head 3d5a959

@trunk-io

trunk-io Bot commented Oct 6, 2026

Copy link
Copy Markdown

This pull request is queued for merge as part of 106435, which will merge 106432, 106433, 106434, 106435.

@trunk-io

trunk-io Bot commented Oct 6, 2026

Copy link
Copy Markdown

Stacked PR 106435 failed testing in the merge queue. Please investigate the failure and re-submit the stack.

@trunk-io

trunk-io Bot commented Oct 6, 2026

Copy link
Copy Markdown

This pull request is queued for merge as part of 106435, which will merge 106432, 106433, 106434, 106435.

@trunk-io
trunk-io Bot merged commit bcd15ac into master Oct 6, 2026
@trunk-io
trunk-io Bot deleted the rafa/ts-7-turn-suggestion-projection branch October 6, 2026 09:23
@trunk-io

trunk-io Bot commented Oct 6, 2026

Copy link
Copy Markdown

This pull request was merged into master as part of stacked PR 106435.

@deployment-status-posthog

deployment-status-posthog Bot commented Oct 6, 2026 •

Copy link
Copy Markdown

Deploy status

Environment Status Deployed At Workflow
dev ✅ Deployed 2026-10-06 09:50 UTC Run
prod-us ✅ Deployed 2026-10-06 10:13 UTC Run
prod-eu ✅ Deployed 2026-10-06 10:14 UTC Run

This branch was successfully deployed

1 active deployment
preview-pr-106434 — 3d5a9593 Deployed Oct 6, 2026 by github-actions[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

stamphog Request AI approval (no full review)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants