Skip to content

feat(tasks): accept side_question commands on task runs - #80023

Merged
trunk-io[bot] merged 7 commits into
masterfrom
posthog-code/btw-side-question-backend
Aug 21, 2026
Merged

trunk-io[bot] merged 7 commits into
masterfrom
posthog-code/btw-side-question-backend

Conversation

@haacked

@haacked haacked commented Aug 8, 2026 •

Copy link
Copy Markdown
Contributor

Bottom layer of a stack with #76461. Split out so desktop and backend halves ship separately, as the desktop backend coupling check requires.

Problem

The desktop /btw command (#76461) needs a way to ask a cloud session's sandbox a one-shot side question. The task-run command endpoint rejects side_question as an unknown method.

Changes

  • The task-run command endpoint accepts side_question and forwards it to the sandbox agent server, like other sandbox control commands.
  • The serializer requires a non-empty question string and strips it.
  • side_question requires Code access (has_tasks_access); without it the endpoint returns 403 with code code_access_required. It drives the agent and spends model tokens on the caller's behalf. user_message stays ungated so the Inbox "Discuss" flow keeps working.
  • Generated API types and MCP schemas pick up the new enum value (hogli build:openapi).

Nothing calls this yet. The desktop /btw command that uses it ships in #76461, so a client on the old build is unaffected, and a sandbox predating the command rejects it with an error the caller sees.

How did you test this code?

New tests in test_api.py cover the proxy round-trip, rejection of a blank or missing question, and the 403 without Code access. Each catches a regression no existing test did: the command surface in front of the dispatch was previously untested, which let an unregistered method slip through. Not run locally: the rest of the tasks suite; backend CI covers it.

Automatic notifications

  • Publish to changelog?

Docs update

None

🤖 Agent context

Autonomy: Human-driven (agent-assisted)

Written with PostHog Code. Skills invoked: /stacking-prs, /improving-drf-endpoints, /writing-pr-descriptions, /debugging-ci-failures. Split out of #76461 after the desktop backend coupling check failed on the combined diff. The split surfaced a bug in the original backend half: the access gate called code_access_required_response, a function that exists nowhere, and wrapped user_message in it too — every cloud message would have raised NameError once deployed (backend CI skipped on the desktop PR, so nothing caught it). Replaced with a has_tasks_access check on side_question only. Generated types were regenerated from serializers rather than copied, which avoided reverting newer master changes to the same files.


Created with PostHog Code

@trunk-io

trunk-io Bot commented Aug 8, 2026 •

Copy link
Copy Markdown

😎 Stack merged successfully - details.

@haacked haacked changed the title posthog code/btw side question backend feat(tasks): accept side_question commands on task runs Aug 8, 2026
@github-actions github-actions Bot added the feature/desktop Feature Tag: Desktop label Aug 8, 2026
@github-actions

github-actions Bot commented Aug 8, 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.

✅ Bundle size — no change

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

Total: 68.61 MiB · no change

No file changed by more than 1000 B.

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.35 MiB · 22 files no change ███░░░░░░░ 30.0% of 4.51 MiB
authenticated shell (every logged-in page)
src/scenes/AuthenticatedShell.tsx
8.69 MiB · 3,215 files no change █████████░ 89.5% of 9.71 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
304.7 KiB ../node_modules/.pnpm/posthog-js@1.418.5/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
250.7 KiB ../node_modules/.pnpm/posthog-js@1.418.5/node_modules/posthog-js/dist/module.js
246.9 KiB src/taxonomy/core-filter-definitions-by-group.json
154.2 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
104.4 KiB src/lib/api.ts
95.1 KiB ../packages/quill/packages/quill/dist/index.js
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

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.24 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.24 MiB · 17 files no change ████░░░░░░ 39.1% of 5.72 MiB
Deferred (lazy) 2.09 MiB · 33 files no change n/a — loads on demand
Loader dist/toolbar.js 1.1 KiB no change █░░░░░░░░░ 5.8% of 19.5 KiB
Largest eagerly-shipped chunks
Size File
743.3 KiB dist/toolbar/toolbar-app-EHNBTBYS.css
574.4 KiB dist/toolbar/chunk-chunk-5UGZG3F7.js
484.6 KiB dist/toolbar/chunk-chunk-QYFXPLLF.js
133.6 KiB dist/toolbar/chunk-chunk-Z4DOL7QW.js
131.8 KiB dist/toolbar/chunk-chunk-T5KY5WYR.js
71.2 KiB dist/toolbar/toolbar-app-4MURQMIW.js
69.0 KiB dist/toolbar/chunk-chunk-27JL52RE.js
35.6 KiB dist/toolbar/chunk-chunk-HLGNLH3R.js
20.9 KiB dist/toolbar/chunk-chunk-JOJIHR7R.js
12.2 KiB dist/toolbar/chunk-chunk-PIK3PADE.js

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

✅ Dist folder size — 🔺 +393 B (+0.0%)

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

Total: 1464.30 MiB · 🔺 +393 B (+0.0%)

✅ ClickHouse migration SQL — none

No ClickHouse migrations in the latest push.

@trunk-io

trunk-io Bot commented Aug 8, 2026 •

Copy link
Copy Markdown

Static Badge   Static Badge   Static Badge

View Full Report ↗︎ ⋅ Docs

Adds side_question to the task-run command channel: the serializer
validates a non-empty question, and the view forwards the command to the
sandbox agent server like other sandbox control commands.

side_question requires Code access (has_tasks_access): it drives the
agent and spends model tokens on the caller's behalf. user_message stays
ungated so the Inbox Discuss flow keeps working.

Nothing calls this yet. The desktop /btw command that uses it ships
separately, so a client on the old build is unaffected and a sandbox
predating the command rejects it with an error the caller sees.

Generated-By: PostHog Code
Task-Id: 9086ddae-4430-49ef-b956-66f90f356b00
@haacked
haacked force-pushed the posthog-code/btw-side-question-backend branch from 733477a to 46b76cc Compare August 16, 2026 21:38
@posthog

posthog Bot commented Aug 16, 2026 •

Copy link
Copy Markdown
Contributor

🦔 ReviewHog reviewed this pull request

Nothing worth raising this time, so here's a calming picture instead:

A panda relaxing and waving

Resolved comments: 1 left for you

@posthog posthog Bot removed the reviewhog label Aug 16, 2026
haacked and others added 4 commits August 16, 2026 15:20
The gate built its own 403 instead of calling code_access_required_response,
so the body omitted the type: permission_denied field every other code-access
denial in this viewset carries, and its message said "PostHog Code" where the
endpoint's own 403 description says "PostHog Desktop".

The proxy test now sends a padded question and asserts the forwarded payload,
covering the serializer's strip, and the access test asserts the gate
short-circuits before the agent-server call.

Claude-Session: https://claude.ai/code/session_01WyZWyiJbQUFSgCfWyM3bCR
Generated-By: PostHog Desktop
Task-Id: 78b6d133-c31c-41ba-bf19-64b034eeff4a
The entitlement gate alone let a team over its usage limit, or in a deactivated
org, keep spending model tokens through side_question, while user_message
returned 429 in the same situation. The endpoint already documented a 429, so
the gate now pairs code_access_required_response with usage_limit_response the
way the rest of this viewset does.

Question length is the direct lever on what a side question costs, so it takes
a 10,000 character cap, following MAX_MCP_RESPONSE_PARAMS_BYTES.

The three rejection cases move into test_command_rejects_invalid_payloads,
where every other method's validation cases live, and gain an oversized-question
row alongside them.

Claude-Session: https://claude.ai/code/session_01WyZWyiJbQUFSgCfWyM3bCR
…ackend' into posthog-code/btw-side-question-backend
Generated-By: PostHog Desktop
Task-Id: e3b1e07a-2d80-441f-be85-011f5e8d59d0
@posthog posthog Bot removed the reviewhog label Aug 18, 2026
@trunk-io

trunk-io Bot commented Aug 19, 2026

Copy link
Copy Markdown

Stacked PR 76461 was cancelled: a user cancelled it.

@haacked
haacked marked this pull request as ready for review August 19, 2026 09:51
Copilot AI lite review requested due to automatic review settings August 19, 2026 09:51
@github-actions

github-actions Bot commented Aug 19, 2026 •

Copy link
Copy Markdown
Contributor

🦔 Hogbox preview · ✅ ready

▶ 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 a69fe59 · box box-31e41969ff18 · ready in 668s (push → usable) · build log · rebuilds on every push, torn down on close

Comment thread products/tasks/backend/presentation/views/api.py
@greptile-apps

greptile-apps Bot commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

Reviews (1): Last reviewed commit: "Merge branch 'master' into posthog-code/..." | Re-trigger Greptile

Copilot AI 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.

Pull request overview

Adds support for a new side_question JSON-RPC method on the Tasks “run command” endpoint, enabling one-shot side questions to be forwarded to the sandbox agent server (to support the desktop /btw command stack layer).

Changes:

  • Extend the task-run command surface to accept and proxy side_question, including access + usage-limit gating in the view.
  • Add serializer validation/normalization for params.question (required, trimmed, and length-capped).
  • Regenerate OpenAPI-derived frontend/MCP generated types and add backend API tests covering proxying and gating/validation.

Reviewed changes

Copilot reviewed 4 out of 7 changed files in this pull request and generated no comments.

Show a summary per file
File Description
services/mcp/src/api/generated.ts Regenerated MCP API schema enum to include side_question.
products/tasks/frontend/generated/api.zod.ts Regenerated Zod schema docs + enum values to include side_question.
products/tasks/frontend/generated/api.ts Regenerated frontend API client docs to mention side_question.
products/tasks/frontend/generated/api.schemas.ts Regenerated frontend schema types/enums to include side_question.
products/tasks/backend/tests/test_api.py Adds coverage for side_question proxying, access gating, usage limit gating, and invalid payload rejection.
products/tasks/backend/presentation/views/api.py Allows side_question in the command endpoint and applies access/usage gates for it.
products/tasks/backend/presentation/serializers.py Adds side_question to allowed methods and validates/normalizes params.question.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Generated-By: PostHog Desktop
Task-Id: 3c69dee1-47cc-4672-8874-f087e999d254
@charlesvien charlesvien added the stamphog Request AI approval (no full review) label Aug 20, 2026 — with PostHog
@stamphog

stamphog Bot commented Aug 20, 2026

Copy link
Copy Markdown

The diff adds a new agent-driving, token-spending command gated only by a non-atomic usage check, and an unresolved inline review comment from an automated reviewer flags a concrete, unaddressed concurrency/rate-limiting gap that lets a caller burn model spend and hold workers for up to 10 minutes each in bursts — a substantive resource-exhaustion concern in security-sensitive surface, not fixed by the current diff.

  • Author wrote 0% of the modified lines and has 18 merged PRs in these paths (familiarity MODERATE).
  • 👍 on the PR from greptile-apps[bot].
  • Unresolved inline comment from @parameterai on products/tasks/backend/presentation/views/api.py: side_question has no dedicated throttle or per-run concurrency guard, and the existing usage_limit_response check is a non-atomic snapshot that fails open, allowing a burst of concurrent requests to bypass it and cause significant model spend / worker exhaustion.
  • Change is in security/access-control and public-API-contract territory (new gated command + generated schema enum) with the PR author not on the owning team (@PostHog/team-posthog-code) and only MODERATE familiarity, so there is no independent assurance covering the unresolved concern.
Gate mechanics and policy version
Gate Result
prerequisites ✓ all clear
deny-list ✓ no deny categories matched
size ✓ 23L, 2F substantive, 120L/7F incl. docs/generated/snapshots — within ceiling
tier ✓ T1-agent / T1c-medium (120L, 7F, two-areas, feat)
stamphog 2.0.0b4 .stamphog/policy.yml @ a69fe59 · reviewed head a69fe59

@stamphog stamphog Bot added reviewhog and removed stamphog Request AI approval (no full review) labels Aug 20, 2026
@parameterai

parameterai Bot commented Aug 20, 2026

Copy link
Copy Markdown

I reviewed the current head. The existing concurrency/rate-limiting security finding remains unresolved; I found no additional security issues to report.

@posthog posthog Bot removed the reviewhog label Aug 20, 2026
@charlesvien charlesvien added the stamphog Request AI approval (no full review) label Aug 21, 2026 — with PostHog

@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.

Adds a new sandbox command gated by the same has_tasks_access/usage-limit pattern already used for every other command in this endpoint, with tests covering the proxy path, access denial, usage-limit denial, and invalid payloads; an agent reviewer explicitly reviewed the current head and reported no additional security issues beyond a pre-existing, unrelated finding.

  • Author wrote 0% of the modified lines and has 18 merged PRs in these paths (familiarity MODERATE).
  • 👍 on the PR from greptile-apps[bot].
Gate mechanics and policy version
Gate Result
prerequisites ✓ all clear
deny-list ✓ no deny categories matched
size ✓ 23L, 2F substantive, 120L/7F incl. docs/generated/snapshots — within ceiling
tier ✓ T1-agent / T1c-medium (120L, 7F, two-areas, feat)
stamphog 2.0.0b4 .stamphog/policy.yml @ a69fe59 · reviewed head a69fe59

Copy link
Copy Markdown
Member

This PR is the bottom layer of a stack, and it is now the only thing holding the top layer (#76461) from landing. Everything automated on it is already satisfied, so I wanted to pin what is actually left, since it needs a person.

State on a69fe592:

  • statusCheckRollup: SUCCESS. Every required context on the master ruleset passes on this head.
  • No unresolved review threads.
  • mergeable: MERGEABLE, not a draft, reviewDecision: APPROVED.

It still reports BLOCKED. Working through the master ruleset, the only rule not accounted for is the extra approval for unattributed changes: the branch carries commits from two different authors, so a single approving review is not enough, and the one approval here is stamphog's. The automated path is exhausted — the stamphog label is applied and stamphog has already approved, so re-triggering it adds nothing.

What clears it is a human approving review on this PR. Once that lands, the stack can go through the merge queue bottom-first and #76461 unblocks with it.

🦉 via talyn.dev

@trunk-io
trunk-io Bot merged commit 896dd35 into master Aug 21, 2026
372 of 379 checks passed
@trunk-io
trunk-io Bot deleted the posthog-code/btw-side-question-backend branch August 21, 2026 16:11
@deployment-status-posthog

deployment-status-posthog Bot commented Aug 21, 2026 •

Copy link
Copy Markdown

Deploy status

Environment Status Deployed At Workflow
dev ✅ Deployed 2026-08-21 17:02 UTC Run
prod-us ✅ Deployed 2026-08-21 17:37 UTC Run
prod-eu ✅ Deployed 2026-08-21 17:35 UTC Run

This branch was successfully deployed

1 active deployment
preview-pr-80023 — a69fe592 Deployed Aug 20, 2026 by github-actions[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature/desktop Feature Tag: Desktop stamphog Request AI approval (no full review)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants