Skip to content

fix(posthog-ai): keep a closed context chip closed only in its scene - #119049

Closed
Silthus wants to merge 3 commits into
PostHog:masterfrom
Silthus:fix/posthog-ai-context-dismiss-per-group
Closed

Silthus wants to merge 3 commits into
PostHog:masterfrom
Silthus:fix/posthog-ai-context-dismiss-per-group

Conversation

@Silthus

@Silthus Silthus commented Oct 17, 2026 •

Copy link
Copy Markdown
Contributor

Problem

  • People who close a context chip in the PostHog AI sidebar lose that chip on other pages too.
  • On master, a closed chip's key and dismiss group stay hidden for the rest of the session, everywhere. Another page that attaches the same key or group name shows its chip as closed, though the person never closed it there.
  • feat(workflows): request a change to a code-managed email template through PostHog Code #119032 worked around this for email templates. The store itself still leaks.

Merge Danger

Note

🔵 Merge risk: low · two-way door (merge-risk rubric)

  • Risk: if maxGlobalLogic stops setting the scope, every dismissal falls back to one shared scope, which is today's behavior.
  • Limits: no danger areas, in-memory state only, focused tests on the store and on the scene wiring, and a revert undoes it fully.

Changes

  • Closing a chip now hides it in the current scene only. Another scene that attaches the same key or dismiss group keeps its chip.
  • Inside one scene nothing changes. A closed chip stays closed across tabs, such as a workflow's Metrics tab or an insight's edit mode, and when the person comes back.
  • Two entities in one scene still share dismissals, such as two email templates. A page that needs them separate gives each entity its own dismiss group, as feat(workflows): request a change to a code-managed email template through PostHog Code #119032 does.
  • attachedContextLogic records dismissals against a generic dismissScope, set with setDismissScope. dismissedKeys and dismissedGroups stay as selectors for the current scope.
  • maxGlobalLogic, which the app shell always mounts, sets the scope to the active scene from a sceneId subscription.
  • The store does not import sceneLogic. Connecting it would mount the scene router wherever the store mounts.
  • Mechanical: regenerated kea types for the logics that connect these actions, and doc updates.

Close both chips on a workflow's Workflow tab, then open other views. Captured in Storybook with a scratch story that drives the real maxGlobalLogic bridge; the story is not committed.

Step Before (master) After
Workflow tab, before closing Same as after Workflow tab shows the skill and workflow chips
Close both chips Same as after Workflow tab with both chips closed
Open the Metrics tab of the same workflow Same as after Metrics tab keeps both chips closed
Open an insight that attaches the same skill chip and dismiss group Insight shows no chips on master Insight shows its skill and insight chips
Back to the Workflow tab Same as after Workflow tab keeps both chips closed

How did you test this code?

Test rationale:

  • attachedContextLogic.test.ts: one it.each case, for an ungrouped and a grouped chip. It fails on master, where the other scope stays hidden, and if a dismissal stops sticking when its scope comes back. The grouped case comes back with a new member of the group, so the group dismissal must hold, not only the key. The nearest existing tests cover one scope only.
  • maxGlobalLogic.test.ts: one it.each case that the scope follows the active scene. It fails if the wiring breaks, which would quietly make dismissals shared again.
  • Test seams: the public attachedContextLogic actions and contextItems, and sceneLogic.setScene into maxGlobalLogic.

Checks:

  • Ran the 21 test files that use the context store or maxGlobalLogic, including the workflows, BI, picker, Max and task runner logics. All pass.
  • Ran the frontend typecheck. No errors.
  • Live run in Storybook (above): owed and captured at HEAD. The master frame comes from the run on the previous commit, whose base is unchanged. Prod shape and cross-version: not owed, because dismissals live in memory only.
  • Not run: the full app stack, because the running dev stack on the devbox serves another checkout. The recordings stay in proof storage, because a fork PR cannot attach video.

Release status

  • No feature flag controls this change

Docs update

Updated the dismissal paragraphs in products/posthog_ai/frontend/AGENTS.md, products/posthog_ai/frontend/README.md and the integrating-with-posthog-ai skill reference.

🤖 Agent context

Autonomy: Human-driven (agent-assisted)

Question Answer Who Where
Which scope does a dismissal have? The active scene. It replaced the first draft's URL path scope after review found that tabs change the path. 👍 Accepted default Agent thread question
How does the store learn the scene? A host-fed setDismissScope from maxGlobalLogic. Connecting sceneLogic from the store mounted the scene router in every test that mounts the store. 🤖 Agent Changes above
Add a route-level test of the workflow tab switch? No. The Storybook proof covers it, and a route test needs real scene loading. 🤖 Agent Final-read review notes
Follow the scene with listeners or a subscription? One sceneId subscription. sceneLogic sets sceneId on both scene actions, so two listeners and a mount seed said the same thing three times. 🤖 Agent QA swarm round 2

Involvement: 1 question answered. Review round 1 and a final read by GPT-6.1 Sol. QA swarm round 2 at the maintainer's request: GPT-6.1 Sol on correctness, risk, design, systems and the author's review perspective, Opus 5.5 on fresh eyes; 3 findings fixed, 1 rejected, then a clean final read. Review bots: none on the draft. Storybook proof captured at HEAD.

Agent: Claude Code, Claude Opus 5.5. Review by GPT-6.1 Sol through T3.

🤖 Generated with Claude Code

Closing a context chip in the PostHog AI composer recorded its key and
dismiss group globally, so another page that attached the same key or
reused the group name lost its chip too. Record each dismissal against
the URL path it happened on and filter by the current path.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@trunk-io

trunk-io Bot commented Oct 17, 2026

Copy link
Copy Markdown

Merging to master in this repository is managed by Trunk.

  • To merge this pull request, check the box to the left or comment /trunk merge below.

After your PR is submitted to the merge queue, this comment will be automatically updated with its status. If the PR fails, failure details will also be posted here

Scoping a dismissal by URL path brought a closed chip back when a scene
changed its path between tabs, such as a workflow's Metrics tab or an
insight's edit mode, so removed context rode the next message.

The store now records dismissals against a generic dismiss scope, and
maxGlobalLogic, which the app shell always mounts, sets it to the active
scene. A dismissal holds across a scene's tabs and entities and never
reaches another scene. The store stays free of sceneLogic, so mounting it
does not mount the scene router.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Silthus added a commit to Silthus/posthog that referenced this pull request Oct 17, 2026
Silthus added a commit to Silthus/posthog that referenced this pull request Oct 17, 2026
Silthus added a commit to Silthus/posthog that referenced this pull request Oct 17, 2026
Silthus added a commit to Silthus/posthog that referenced this pull request Oct 17, 2026
@Silthus Silthus changed the title fix(posthog-ai): keep a closed context chip closed only on its page fix(posthog-ai): keep a closed context chip closed only in its scene Oct 17, 2026
maxGlobalLogic now sets the dismiss scope from a sceneId subscription
instead of two scene action listeners and a mount seed. sceneId already
changes on both setScene and setExportedScene, and the subscription also
fires on mount.

The scope test now returns with a re-keyed member of the dismissed group,
so it fails if the group dismissal stops holding in its own scene.
The Max test imports the store through the api/logics facade.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Silthus added a commit to Silthus/posthog that referenced this pull request Oct 19, 2026
Silthus added a commit to Silthus/posthog that referenced this pull request Oct 19, 2026
Silthus added a commit to Silthus/posthog that referenced this pull request Oct 19, 2026
Silthus added a commit to Silthus/posthog that referenced this pull request Oct 19, 2026
Silthus added a commit to Silthus/posthog that referenced this pull request Oct 19, 2026
@Silthus
Silthus marked this pull request as ready for review October 19, 2026 08:57
@parameterai

parameterai Bot commented Oct 19, 2026 •

Copy link
Copy Markdown

Risk: No findings

This change scopes context-chip dismissals in the PostHog AI attached-context store to the active scene, with maxGlobalLogic feeding the scene id into a generic dismissScope. I traced every security-relevant surface the change touches — the store's reducers/selectors, the send-time contextItems consumers (runInteractionLogic, taskTrackerSceneLogic, wrapWithPosthogContext), and the wiring in maxGlobalLogic — and found no vulnerability: the store is in-memory, single-user UI state whose only trust-boundary effect is suppressing context from the user's own outgoing messages, and the cross-scene re-attachment of a dismissed item is the intended product behavior (self-only impact). The '' fallback scope when maxGlobalLogic is not mounted only hides more context, not less.

Sentinel reviewed d1d8acc · Review settings

@pr-assigner-resolver-posthog
pr-assigner-resolver-posthog Bot requested review from a team October 19, 2026 08:57
@pr-assigner-resolver-posthog

Copy link
Copy Markdown

👀 Auto-assigned reviewers

These soft owners were skipped because they only have minor changes here. Nothing blocks merge, so self-assign if you'd like a look:

  • @PostHog/team-workflows (products/workflows/product.yaml)

Soft owners come from each directory's owners.yaml and each product's product.yaml (resolved nearest-file-wins). For a skipped owner, the locator is the file that decided it. Generated files and lockfiles are ignored when deciding ownership.

@Silthus Silthus closed this Oct 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant