feat(tasks): download large living artifact files through presigned urls - #110967
Conversation
A download of a stored living artifact version (download=true) now redirects to a short-lived presigned URL, so the file no longer passes through a web worker. The link carries an attachment disposition and the file's content type. Text versions still stream. A preview stays on the app origin, because the media-src policy allows video only from there. A stored version over 25 MB returns 413 instead of loading into memory, and the Artifacts tab shows the download state for it. Generated-By: PostHog Desktop Task-Id: e2367959-ab88-40ff-8761-5632645167aa
|
😎 Merged successfully - details. |
|
Risk: No findings The increment replaces the fixed four-kind live-embed set in the Artifacts tab with a general one: any referenced object whose kind has a registered app page now renders that page in the same-origin embedded frame, and the full-page/link fallbacks follow the same rule. I traced the agent-controlled objectKind/objectId into the URL builder and confirmed the percent-encoding and ChoiceField validation on the write path prevent any origin escape, path/param injection, or parser crash, and that embedded pages enforce their own authorization with the viewer's session. No security issues introduced by these changes. Sentinel reviewed |
🤖 CI report
|
| Function | Location | Complexity | Limit |
|---|---|---|---|
ArtifactToolbar |
products/posthog_ai/frontend/scenes/TaskTracker/components/TaskRunArtifacts.tsx:725 |
33 | 10 |
ArtifactPreview |
products/posthog_ai/frontend/scenes/TaskTracker/components/TaskRunArtifacts.tsx:396 |
25 | 10 |
fileKind |
products/posthog_ai/frontend/scenes/TaskTracker/taskRunArtifacts.ts:89 |
17 | 10 |
ArtifactsWorkspace |
products/posthog_ai/frontend/scenes/TaskTracker/components/TaskRunArtifacts.tsx:930 |
14 | 10 |
parseCsv |
products/posthog_ai/frontend/scenes/TaskTracker/taskRunArtifacts.ts:156 |
14 | 10 |
editableArtifactKind |
products/posthog_ai/frontend/scenes/TaskTracker/taskRunArtifacts.ts:386 |
13 | 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 — 6% of added code lines are comments (12 of 201)
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/scenes/TaskTracker/taskRunArtifactsLogic.ts |
5 | 13 |
products/tasks/backend/logic/services/living_artifacts.py |
4 | 44 |
products/posthog_ai/frontend/scenes/TaskTracker/taskRunArtifacts.ts |
2 | 7 |
products/tasks/backend/facade/api.py |
1 | 45 |
This check does not block merging. It updates on every push and clears when the share drops.
⚠️ Bundle size — 🔺 +170 B (+0.0%)
Uncompressed size of every built .js bundle, compared against the base branch.
Total: 69.79 MiB · 🔺 +170 B (+0.0%)
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.63 MiB · 22 files | no change | █████████░ 88.7% 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 · 661 files | no change | █████████░ 92.3% of 4.03 MiB |
authenticated shell (every logged-in page)src/scenes/AuthenticatedShell.tsx |
7.59 MiB · 2,409 files | 🔺 +252 B (+0.0%) | █████████░ 91.0% of 8.34 MiB |
dashboard scenesrc/scenes/dashboard/Dashboard.tsx |
9.67 MiB · 3,392 files | 🔺 +252 B (+0.0%) | ███████░░░ 71.8% of 13.48 MiB |
today home pathsrc/scenes/AuthenticatedShell.tsx + src/scenes/project-homepage/ProjectHomepage.tsx + src/scenes/project-homepage/today/TodayHome.tsx |
7.61 MiB · 2,417 files | 🔺 +252 B (+0.0%) | █████████░ 88.6% of 8.58 MiB |
events scenesrc/scenes/activity/explore/EventsScene.tsx |
9.29 MiB · 3,244 files | 🔺 +252 B (+0.0%) | ███████░░░ 73.5% of 12.64 MiB |
replay detail scenesrc/scenes/session-recordings/detail/SessionRecordingDetail.tsx |
12.12 MiB · 4,130 files | 🔺 +252 B (+0.0%) | ████████░░ 77.1% 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
🟢 [object Object] stays out of src/index.tsx
🟢 [object Object] 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
🟢 [object Object] stays out of src/scenes/AuthenticatedShell.tsx
🟢 src/scenes/session-recordings/player/sessionRecordingPlayerLogic.ts 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
🟢 [object Object] 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
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 |
| 854 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 |
| 100.5 KiB | src/lib/api.ts |
| 92.7 KiB | src/products.tsx |
| 69.4 KiB | src/lib/lemon-ui/icons/icons.tsx |
| 40.1 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 |
| 279.9 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 |
| 110.1 KiB | ../packages/quill/packages/quill/dist/index.js |
| 100.5 KiB | src/lib/api.ts |
| 93.3 KiB | ../node_modules/.pnpm/prosemirror-view@1.40.1/node_modules/prosemirror-view/dist/index.js |
| 92.7 KiB | src/products.tsx |
| 90.6 KiB | ../node_modules/.pnpm/@tiptap+core@3.20.6_@tiptap+pm@3.20.6/node_modules/@tiptap/core/dist/index.js |
Largest files eagerly shipped from src/scenes/dashboard/Dashboard.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 |
| 279.9 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 |
| 110.1 KiB | ../packages/quill/packages/quill/dist/index.js |
| 100.5 KiB | src/lib/api.ts |
| 93.3 KiB | ../node_modules/.pnpm/prosemirror-view@1.40.1/node_modules/prosemirror-view/dist/index.js |
| 92.7 KiB | src/products.tsx |
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 |
| 279.9 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 |
| 110.1 KiB | ../packages/quill/packages/quill/dist/index.js |
| 100.5 KiB | src/lib/api.ts |
| 93.3 KiB | ../node_modules/.pnpm/prosemirror-view@1.40.1/node_modules/prosemirror-view/dist/index.js |
| 92.7 KiB | src/products.tsx |
| 90.6 KiB | ../node_modules/.pnpm/@tiptap+core@3.20.6_@tiptap+pm@3.20.6/node_modules/@tiptap/core/dist/index.js |
Largest files eagerly shipped from src/scenes/activity/explore/EventsScene.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 |
| 279.9 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 |
| 110.1 KiB | ../packages/quill/packages/quill/dist/index.js |
| 100.5 KiB | src/lib/api.ts |
| 93.3 KiB | ../node_modules/.pnpm/prosemirror-view@1.40.1/node_modules/prosemirror-view/dist/index.js |
| 92.7 KiB | src/products.tsx |
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 |
| 279.9 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 |
| 110.1 KiB | ../packages/quill/packages/quill/dist/index.js |
| 100.5 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.20 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.20 MiB · 19 files | no change | ████░░░░░░ 38.4% of 5.72 MiB |
| Deferred (lazy) | 2.11 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 |
|---|---|
| 835.5 KiB | dist/toolbar/toolbar-app-FSDWO46I.css |
| 657.5 KiB | dist/toolbar/chunk-chunk-BALLB66W.js |
| 259.4 KiB | dist/toolbar/chunk-chunk-7JWMBALG.js |
| 138.2 KiB | dist/toolbar/chunk-chunk-RXJG6CZC.js |
| 131.8 KiB | dist/toolbar/chunk-chunk-FDH2IBXT.js |
| 75.2 KiB | dist/toolbar/toolbar-app-YIYWW6XJ.js |
| 69.0 KiB | dist/toolbar/chunk-chunk-TSAL54PB.js |
| 35.6 KiB | dist/toolbar/chunk-chunk-MM7MZI2L.js |
| 21.0 KiB | dist/toolbar/chunk-chunk-EZFR5QGQ.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 — 🔺 +9.2 KiB (+0.0%)
Total size of the built frontend/dist folder (all assets), compared against the base branch.
Total: 960.36 MiB · 🔺 +9.2 KiB (+0.0%)
ℹ️ MCP UI apps size — 33 app(s), 17633.6 KB JS
Built size of each MCP UI app (main.js + styles.css).
| App | JS | CSS |
|---|---|---|
| debug | 597.9 KB | 199.4 KB |
| action | 454.1 KB | 199.4 KB |
| action-list | 564.2 KB | 199.4 KB |
| cohort | 453.1 KB | 199.4 KB |
| cohort-list | 563.2 KB | 199.4 KB |
| email-template | 452.9 KB | 199.4 KB |
| error-details | 469.6 KB | 199.4 KB |
| error-issue | 454.5 KB | 199.4 KB |
| error-issue-list | 564.8 KB | 199.4 KB |
| experiment | 561.3 KB | 199.4 KB |
| experiment-list | 564.9 KB | 199.4 KB |
| experiment-results | 566.3 KB | 199.4 KB |
| feature-flag | 566.8 KB | 199.4 KB |
| feature-flag-list | 570.5 KB | 199.4 KB |
| feature-flag-testing | 457.3 KB | 199.4 KB |
| inline-scan | 453.6 KB | 199.4 KB |
| insight-actors | 562.3 KB | 199.4 KB |
| invite-email-preview | 452.3 KB | 199.4 KB |
| llm-costs | 559.3 KB | 199.4 KB |
| session-recording | 455.3 KB | 199.4 KB |
| survey | 454.7 KB | 199.4 KB |
| survey-global-stats | 561.9 KB | 199.4 KB |
| survey-list | 564.9 KB | 199.4 KB |
| survey-stats | 561.9 KB | 199.4 KB |
| trace-span | 453.5 KB | 199.4 KB |
| trace-span-list | 564.1 KB | 199.4 KB |
| vision-observation-list | 563.3 KB | 199.4 KB |
| workflow | 453.4 KB | 199.4 KB |
| workflow-list | 563.5 KB | 199.4 KB |
| loops-review | 457.8 KB | 199.4 KB |
| query-results | 774.3 KB | 199.4 KB |
| render-ui | 858.4 KB | 199.4 KB |
| visual-review-snapshots | 457.9 KB | 199.4 KB |
⚠️ Playwright — 1 failed
🎭 Playwright report · View test results →
❌ 1 failed test:
- create experiment via wizard, add metrics, and launch (chromium)
These issues are not necessarily caused by your changes.
Annoyed by this section? Help fix flakies and failures and it will go green!
⚠️ Backend coverage — 92.0% of changed backend lines covered — 7 uncovered
🧪 Backend test coverage
Patch coverage — changed backend lines (products + core): ██████████████████░░ 92.0% (82 / 89)
| File | Patch | Uncovered changed lines |
|---|---|---|
products/tasks/backend/facade/api.py |
78.3% | 4429, 4432–4433, 4437, 4450 |
products/tasks/backend/presentation/views/api.py |
84.6% | 4573, 4578 |
🤖 Agents: add a test only if an uncovered line exposes a realistic regression that existing tests miss. Otherwise explain why no new test is needed under "How did you test this code?". Gap list: the patch-coverage artifact on this run (gh run download 486838320433093 -n patch-coverage), or the coverage-data block at the end of this comment.
Per-product line coverage (touched products)
| Product | Coverage | Lines |
|---|---|---|
platform_features |
██░░░░░░░░░░░░░░░░░░ 12.1% |
7 / 58 |
demo |
███████████░░░░░░░░░ 53.4% |
1,445 / 2,707 |
data_tools |
████████████░░░░░░░░ 61.2% |
90 / 147 |
warehouse_sources_queue |
██████████████░░░░░░ 68.2% |
1,868 / 2,740 |
ai_gateway |
███████████████░░░░░ 75.0% |
9 / 12 |
aeo |
███████████████░░░░░ 76.3% |
617 / 809 |
batch_exports |
████████████████░░░░ 81.3% |
21,587 / 26,561 |
apm |
█████████████████░░░ 84.1% |
1,306 / 1,553 |
cdp |
██████████████████░░ 88.3% |
4,559 / 5,164 |
ml_inference |
██████████████████░░ 88.8% |
539 / 607 |
mcp_analytics |
██████████████████░░ 89.2% |
5,038 / 5,651 |
product_tours |
██████████████████░░ 89.3% |
1,340 / 1,500 |
dashboards |
██████████████████░░ 89.6% |
6,924 / 7,727 |
notebooks |
██████████████████░░ 90.2% |
15,514 / 17,207 |
signals |
██████████████████░░ 90.4% |
60,188 / 66,556 |
cohorts |
██████████████████░░ 90.5% |
8,534 / 9,434 |
data_warehouse |
██████████████████░░ 90.6% |
14,375 / 15,860 |
streamlit_apps |
██████████████████░░ 90.8% |
2,679 / 2,951 |
managed_warehouse |
██████████████████░░ 91.0% |
10,252 / 11,263 |
data_modeling |
██████████████████░░ 91.2% |
10,562 / 11,584 |
tasks |
██████████████████░░ 91.3% |
79,818 / 87,386 |
exports |
██████████████████░░ 91.7% |
9,684 / 10,566 |
business_knowledge |
██████████████████░░ 92.0% |
8,472 / 9,208 |
engineering_analytics |
██████████████████░░ 92.2% |
11,497 / 12,475 |
ai_training |
██████████████████░░ 92.2% |
356 / 386 |
today |
██████████████████░░ 92.3% |
999 / 1,082 |
webmcp |
███████████████████░ 92.5% |
248 / 268 |
early_access_features |
███████████████████░ 92.6% |
1,339 / 1,446 |
conversations |
███████████████████░ 92.6% |
29,225 / 31,559 |
visual_review |
███████████████████░ 92.7% |
10,000 / 10,785 |
managed_migrations |
███████████████████░ 92.7% |
1,581 / 1,705 |
stamphog |
███████████████████░ 92.8% |
8,109 / 8,742 |
canvas |
███████████████████░ 92.9% |
7,155 / 7,703 |
approvals |
███████████████████░ 93.0% |
3,974 / 4,271 |
mcp_registry |
███████████████████░ 93.1% |
1,670 / 1,794 |
notifications |
███████████████████░ 93.2% |
1,144 / 1,228 |
error_tracking |
███████████████████░ 93.3% |
16,389 / 17,573 |
surveys |
███████████████████░ 93.4% |
6,644 / 7,113 |
autoresearch |
███████████████████░ 93.6% |
8,955 / 9,572 |
slack_app |
███████████████████░ 93.7% |
14,611 / 15,600 |
context_layer |
███████████████████░ 93.8% |
3,415 / 3,639 |
web_analytics |
███████████████████░ 93.9% |
23,680 / 25,229 |
billing_alerts |
███████████████████░ 94.1% |
2,094 / 2,226 |
mcp_store |
███████████████████░ 94.3% |
8,959 / 9,501 |
wizard |
███████████████████░ 94.7% |
6,150 / 6,496 |
workflows |
███████████████████░ 94.7% |
15,227 / 16,072 |
reminders |
███████████████████░ 94.8% |
760 / 802 |
alerts |
███████████████████░ 94.9% |
10,037 / 10,575 |
ai_observability |
███████████████████░ 94.9% |
26,288 / 27,689 |
review_hog |
███████████████████░ 95.0% |
11,750 / 12,362 |
annotations |
███████████████████░ 95.1% |
817 / 859 |
endpoints |
███████████████████░ 95.1% |
9,234 / 9,706 |
customer_analytics |
███████████████████░ 95.2% |
26,116 / 27,428 |
legal_documents |
███████████████████░ 95.2% |
2,311 / 2,427 |
marketing_analytics |
███████████████████░ 95.3% |
19,450 / 20,413 |
posthog_ai |
███████████████████░ 95.4% |
2,530 / 2,653 |
actions |
███████████████████░ 95.5% |
756 / 792 |
logs |
███████████████████░ 95.5% |
15,456 / 16,188 |
experiments |
███████████████████░ 95.5% |
33,000 / 34,548 |
data_catalog |
███████████████████░ 95.5% |
4,401 / 4,606 |
tracing |
███████████████████░ 95.6% |
3,536 / 3,699 |
replay_vision |
███████████████████░ 95.6% |
29,389 / 30,727 |
growth |
███████████████████░ 95.7% |
11,381 / 11,888 |
skills |
███████████████████░ 95.8% |
6,972 / 7,274 |
messaging |
███████████████████░ 95.9% |
3,834 / 3,999 |
product_analytics |
███████████████████░ 96.0% |
28,521 / 29,696 |
revenue_analytics |
███████████████████░ 96.4% |
1,889 / 1,959 |
user_interviews |
███████████████████░ 96.5% |
2,870 / 2,974 |
feature_flags |
███████████████████░ 96.6% |
27,119 / 28,060 |
access_control |
███████████████████░ 96.7% |
7,739 / 8,007 |
warehouse_sources |
███████████████████░ 97.3% |
475,070 / 488,180 |
data_quality |
████████████████████ 97.5% |
7,701 / 7,895 |
links |
████████████████████ 97.9% |
234 / 239 |
metrics |
████████████████████ 98.0% |
4,265 / 4,351 |
security |
████████████████████ 98.0% |
1,304 / 1,330 |
analytics_platform |
████████████████████ 98.3% |
2,784 / 2,833 |
pulse |
████████████████████ 98.5% |
2,046 / 2,078 |
live_debugger |
████████████████████ 99.2% |
626 / 631 |
field_notes |
████████████████████ 99.4% |
172 / 173 |
Report-only. Patch coverage = changed backend lines covered vs origin/master. Sorted lowest first.
Known gaps: lines covered only by Temporal tests show as uncovered; core line numbers may drift if master changed the same file.
🦔 Hogbox preview · ✅ ready▶ Open the preview
commit |
|
Navigate logical layers of code changes, visualize relationships, and explore their blast radius. 🧰 Additional context used📚 Code guidelines (16)📝 WalkthroughWalkthroughLiving artifact previews now have a 25 MiB limit. Stored versions can be downloaded through presigned attachment URLs, while oversized inline previews return 413. The frontend requests download-mode URLs and suppresses previews for oversized files. Tests cover download redirects, text responses, and oversized preview behavior. Priority: ⬇️ Low Merge Risk: 🟡 Moderate · up to Missing size metadata can make the artifact preview fail with 413 instead of showing the no-preview state. Concurrent edits can also let an oversized artifact bypass the server’s preview limit and risk worker memory pressure. Resolve these delivery edge cases before merging. Security Architecture ReviewSecurity architecture risk: 🔵 Low · up to Downloads retain task access checks and forced attachment behavior while avoiding application-side buffering. No new tenant-access bypass was identified. The preview-size protection remains incomplete under a preexisting concurrent-edit race, and storage-side deployment controls were not fully verified. Retained concerns Security review detailsSecurity Blast Radius
Trust Boundaries and Controls
Resilience and Maintainability Implications
Hardening Proposals
🚥 Pre-merge checks | ✅ 1✅ Passed checks (1 passed)
✨ Finishing Touches 💡 1📝 Generate docstrings
🧪 Generate unit tests (beta)
🛠️ Fix failing CI checks 💡
Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
Note
Quiet mode is enabled, so only the most important comments were posted inline. Other review comments are grouped below.
🟡 Other comments (2)
products/tasks/backend/logic/services/living_artifacts.py-424-424 (1)
424-424: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick winMock
head_objectintest_living_artifact_version_content.The
stored_filecase omitssize, so the endpoint callsobject_storage.head_objectbefore the patchedread_bytes. The unpatched lookup can reach the configured object-storage client. Mock the metadata lookup to keep the test isolated.Suggested fix
+ @patch("posthog.storage.object_storage.head_object") @patch("posthog.storage.object_storage.read_bytes") - def test_living_artifact_version_content(self, _name, version, expected_body, expected_type, mock_read_bytes): + def test_living_artifact_version_content( + self, _name, version, expected_body, expected_type, mock_read_bytes, mock_head_object + ): + mock_head_object.return_value = None mock_read_bytes.return_value = b"png bytes"Source: Coding guidelines
products/posthog_ai/frontend/scenes/TaskTracker/taskRunArtifacts.ts-72-72 (1)
72-72: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winDo not preview stored versions with an unknown size.
When
record.sizeis absent,artifact.sizeisundefined. The nullish fallback treats it as zero, so an oversized stored image or video can be selected for preview. The backend can then reject the request with413, instead of showing the no-preview state. Treat unknown sizes as not previewable.🐛 Suggested fix
- if (!artifact.living.stored || (artifact.size ?? 0) > LIVING_PREVIEW_MAX_BYTES) { + if (!artifact.living.stored || artifact.size === undefined || artifact.size > LIVING_PREVIEW_MAX_BYTES) {
🧹 Nitpick comments (2)
products/tasks/backend/logic/services/living_artifacts.py (1)
389-389: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winUse the repository's frozen dataclass decorator.
Replace
@dataclass(frozen=True)with@frozenand importfrozenat module scope. As per coding guidelines: “Use@frozenfromposthog.dataclasses.”Source: Coding guidelines
products/tasks/backend/facade/api.py (1)
4420-4420: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚖️ Poor tradeoffPreserve the lazy facade import path when removing these local imports.
Both imports violate the backend module-level import rule. Do not move them directly into
products/tasks/backend/facade/api.py:living_artifacts.pyimportsobject_storageat module scope, and the presentation layer imports the facade module at module scope. Move the presigning entry point behind a module boundary that is not loaded during facade initialization, with its dependencies imported at module scope there.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository: PostHog/posthog/.coderabbit.yaml
Review profile: QUIET
Plan: Enterprise
Run ID: c16dc900-346d-4b1f-b781-0330931dbb18
⛔ Files ignored due to path filters (2)
products/tasks/frontend/generated/api.schemas.tsis excluded by!**/generated/**products/tasks/frontend/generated/api.tsis excluded by!**/generated/**
📒 Files selected for processing (9)
products/posthog_ai/frontend/scenes/TaskTracker/components/TaskRunArtifacts.tsxproducts/posthog_ai/frontend/scenes/TaskTracker/taskRunArtifacts.test.tsproducts/posthog_ai/frontend/scenes/TaskTracker/taskRunArtifacts.tsproducts/posthog_ai/frontend/scenes/TaskTracker/taskRunArtifactsLogic.tsproducts/tasks/backend/facade/api.pyproducts/tasks/backend/logic/services/living_artifacts.pyproducts/tasks/backend/presentation/views/api.pyproducts/tasks/backend/tests/test_api.pyservices/mcp/src/api/generated.ts
Included review availability: This review used your included allowance. Your plan provides up to 12 included reviews per hour; 8 remain after this review.
| def read_living_artifact_version(artifact: TaskArtifact, version: int) -> LivingArtifactVersionContent | None: | ||
| """Return the content of one version, or None when the version is unknown or keeps no content. | ||
|
|
||
| A Slack file version keeps its bytes in object storage. A canvas or message version keeps its | ||
| text in the version record. A stored version above the preview limit raises | ||
| LivingArtifactVersionTooLarge. Storage read errors propagate to the caller. | ||
| """ | ||
| resolved = _resolve_living_version(artifact, version) | ||
| if resolved is None: | ||
| return None | ||
|
|
||
| if resolved.storage_path: | ||
| size = _stored_version_size(resolved) | ||
| if size is not None and size > LIVING_VERSION_PREVIEW_MAX_BYTES: | ||
| raise LivingArtifactVersionTooLarge() | ||
| payload = object_storage.read_bytes(resolved.storage_path, missing_ok=True) | ||
| if payload is None: | ||
| return None | ||
| return LivingArtifactVersionContent(name=artifact.name, content_type=content_type, content=payload) | ||
| return LivingArtifactVersionContent(name=artifact.name, content_type=resolved.content_type, content=payload) |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
🔎 Supported by static analysis
🏁 Script executed:
sed -n '388,465p' products/tasks/backend/logic/services/living_artifacts.py
rg -n 'def head_object|def read_bytes' posthog/storage/object_storage.pyRepository: PostHog/posthog
Length of output: 4464
🏁 Script executed:
#!/bin/bash
set -e
printf '%s\n' '--- object storage module slices ---'
sed -n '1,90p' posthog/storage/object_storage.py
sed -n '560,785p' posthog/storage/object_storage.py
printf '%s\n' '--- reader usages and endpoint context ---'
rg -n -C 5 'read_living_artifact_version|LivingArtifactVersionTooLarge|living_artifact_version_storage_path' products/tasks posthog | head -240
printf '%s\n' '--- relevant route/view names ---'
rg -n -C 4 'preview|living_artifact|artifact.*version|version.*artifact' products/tasks/backend products/tasks/frontend 2>/dev/null | head -260Repository: PostHog/posthog
Length of output: 41511
🏁 Script executed:
#!/bin/bash
set -e
printf '%s\n' '--- object-storage read_bytes implementations ---'
sed -n '100,175p' posthog/storage/object_storage.py
sed -n '180,215p' posthog/storage/object_storage.py
sed -n '280,315p' posthog/storage/object_storage.py
printf '%s\n' '--- preview facade functions ---'
sed -n '4345,4465p' products/tasks/backend/facade/api.py
printf '%s\n' '--- callers and route registration ---'
rg -n -C 6 'get_living_artifact_version_content|get_living_artifact_version_url|living_artifact_version_content|living_artifact_version_url' products/tasks --glob '*.py'Repository: PostHog/posthog
Length of output: 13071
🏁 Script executed:
#!/bin/bash
set -e
printf '%s\n' '--- exact facade callers and route bindings ---'
rg -n -C 5 'read_task_run_living_artifact_version' products/tasks --glob '*.py'
printf '%s\n' '--- preview endpoint test ---'
sed -n '8585,8705p' products/tasks/backend/tests/test_api.pyRepository: PostHog/posthog
Length of output: 9071
Enforce the preview limit when storage size is unknown.
When both the version record and head_object provide no usable size, the guard at living_artifacts.py:442-443 is skipped. The preview endpoint then calls read_bytes, whose S3 implementation uses Body.read() and loads the complete object. A stored object larger than 25 MiB can therefore consume unbounded worker memory. Reject unknown-size previews or read through a bounded storage operation before returning the content.
Suggested fix
size = _stored_version_size(resolved)
- if size is not None and size > LIVING_VERSION_PREVIEW_MAX_BYTES:
+ if size is None or size > LIVING_VERSION_PREVIEW_MAX_BYTES:
raise LivingArtifactVersionTooLarge()📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| def read_living_artifact_version(artifact: TaskArtifact, version: int) -> LivingArtifactVersionContent | None: | |
| """Return the content of one version, or None when the version is unknown or keeps no content. | |
| A Slack file version keeps its bytes in object storage. A canvas or message version keeps its | |
| text in the version record. A stored version above the preview limit raises | |
| LivingArtifactVersionTooLarge. Storage read errors propagate to the caller. | |
| """ | |
| resolved = _resolve_living_version(artifact, version) | |
| if resolved is None: | |
| return None | |
| if resolved.storage_path: | |
| size = _stored_version_size(resolved) | |
| if size is not None and size > LIVING_VERSION_PREVIEW_MAX_BYTES: | |
| raise LivingArtifactVersionTooLarge() | |
| payload = object_storage.read_bytes(resolved.storage_path, missing_ok=True) | |
| if payload is None: | |
| return None | |
| return LivingArtifactVersionContent(name=artifact.name, content_type=content_type, content=payload) | |
| return LivingArtifactVersionContent(name=artifact.name, content_type=resolved.content_type, content=payload) | |
| def read_living_artifact_version(artifact: TaskArtifact, version: int) -> LivingArtifactVersionContent | None: | |
| """Return the content of one version, or None when the version is unknown or keeps no content. | |
| A Slack file version keeps its bytes in object storage. A canvas or message version keeps its | |
| text in the version record. A stored version above the preview limit raises | |
| LivingArtifactVersionTooLarge. Storage read errors propagate to the caller. | |
| """ | |
| resolved = _resolve_living_version(artifact, version) | |
| if resolved is None: | |
| return None | |
| if resolved.storage_path: | |
| size = _stored_version_size(resolved) | |
| if size is None or size > LIVING_VERSION_PREVIEW_MAX_BYTES: | |
| raise LivingArtifactVersionTooLarge() | |
| payload = object_storage.read_bytes(resolved.storage_path, missing_ok=True) | |
| if payload is None: | |
| return None | |
| return LivingArtifactVersionContent(name=artifact.name, content_type=resolved.content_type, content=payload) |
|
The presign facade returns a LivingArtifactVersionDownload contract, and the logic layer exposes the resolved version as a frozen LivingVersionLocation, instead of tuples a caller reads by position. The view no longer reuses one variable for the redirect and the streamed response, which mypy rejected. Generated-By: PostHog Desktop Task-Id: e2367959-ab88-40ff-8761-5632645167aa
New commits were pushed — dismissing the stamphog approval from an earlier head. Re-add the trigger label to request a fresh review.
There was a problem hiding this comment.
Actionable comments posted: 2
Note
Quiet mode is enabled, so only the most important comments were posted inline. Other review comments are grouped below.
🟡 Other comments (1)
products/tasks/backend/facade/api.py-4441-4441 (1)
4441-4441: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick winHandle storage-client initialization failures as
"unavailable".Signing failures already return
None, butobject_storage_client()can raiseValueErrorwhile creating the client for an invalid endpoint. That call occurs before the presigning handler, so the endpoint can return a server error instead of"unavailable".🐛 Suggested fix
- url = object_storage.get_presigned_url( - resolved.storage_path, - content_type=resolved.content_type or None, - # Agent-written HTML or SVG must not render as a page, so the browser always saves it. - content_disposition=content_disposition_header( - as_attachment=True, filename=PurePosixPath(artifact.name).name or "artifact" - ) - or "attachment", - ) + try: + url = object_storage.get_presigned_url( + resolved.storage_path, + content_type=resolved.content_type or None, + # Agent-written HTML or SVG must not render as a page, so the browser always saves it. + content_disposition=content_disposition_header( + as_attachment=True, filename=PurePosixPath(artifact.name).name or "artifact" + ) + or "attachment", + ) + except ValueError: + return contracts.LivingArtifactVersionDownload(url=None, error="unavailable")
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository: PostHog/posthog/.coderabbit.yaml
Review profile: QUIET
Plan: Enterprise
Run ID: efdeba18-8b3a-4158-b75d-103b35a148a9
📒 Files selected for processing (4)
products/tasks/backend/facade/api.pyproducts/tasks/backend/facade/contracts.pyproducts/tasks/backend/logic/services/living_artifacts.pyproducts/tasks/backend/presentation/views/api.py
Included review availability: This review used your included allowance. Your plan provides up to 12 included reviews per hour; 9 remain after this review.
|
|
||
| from products.tasks.backend.logic.services.living_artifacts import ( # noqa: PLC0415 — keep storage deps off the api import path | ||
| get_task_artifact_for_run, | ||
| resolve_living_artifact_version, |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win
🔎 Supported by static analysis
🏁 Script executed:
sed -n '1,100p' products/tasks/backend/facade/api.py
sed -n '4370,4455p' products/tasks/backend/facade/api.py
sed -n '1,85p' products/tasks/backend/logic/services/living_artifacts.pyRepository: PostHog/posthog
Length of output: 10234
🏁 Script executed:
#!/bin/bash
set -eu
printf '%s\n' '--- api.py imports and relevant references ---'
rg -n -C 3 'living_artifacts|object_storage|read_task_run_living_artifact_version|presign_task_run_living_artifact_version_download' products/tasks/backend/facade/api.py
printf '%s\n' '--- living_artifacts.py imports and relevant definitions ---'
sed -n '1,120p' products/tasks/backend/logic/services/living_artifacts.py
rg -n -C 3 'def (get_task_artifact_for_run|resolve_living_artifact_version|read_living_artifact_version)|from products.tasks.backend.facade|import products.tasks.backend.facade|from posthog.storage|object_storage' products/tasks/backend/logic/services/living_artifacts.py
printf '%s\n' '--- storage module location and imports ---'
fd -t f 'object_storage*' posthog products
rg -n -C 4 'from posthog.storage import object_storage|import object_storage|class .*Storage|def get_presigned_url|object_storage[[:space:]]*=' posthog/storage products/tasks/backendRepository: PostHog/posthog
Length of output: 41990
🏁 Script executed:
#!/bin/bash
set -eu
printf '%s\n' '--- storage package files ---'
fd -t f . posthog/storage | sort
printf '%s\n' '--- object_storage.py header and client initialization ---'
sed -n '1,180p' posthog/storage/object_storage.py
rg -n -C 3 '^(object_storage|class |def |[A-Z_]+ =)|boto|S3|Storage' posthog/storage/object_storage.py | head -160
printf '%s\n' '--- storage package initializer ---'
if [ -f posthog/storage/__init__.py ]; then sed -n '1,160p' posthog/storage/__init__.py; fi
printf '%s\n' '--- facade contracts imports and header ---'
sed -n '1,100p' products/tasks/backend/facade/contracts.py
rg -n 'products\.tasks\.backend\.facade\.api|from .*facade import api|import .*facade\.api' products/tasks/backend/logic/services/living_artifacts.py products/tasks/backend/facade/contracts.py
printf '%s\n' '--- direct api imports from living_artifacts service ---'
rg -n 'products\.tasks\.backend\.facade\.api|facade import api|from products\.tasks\.backend\.facade' products/tasks/backend/logic/services/living_artifacts.pyRepository: PostHog/posthog
Length of output: 16642
Move the resolver import to module scope.
The local import violates the backend import rule. living_artifacts.py imports object_storage, but this does not eagerly initialize a storage client: object_storage.py starts with UnavailableStorage, and imports boto3 only when object_storage_client() is called. Do not split the module solely to avoid eager storage initialization.
| content: bytes | ||
|
|
||
|
|
||
| @dataclass(frozen=True, kw_only=True) |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win
Use the repository dataclass decorator.
Replace @dataclass(frozen=True, kw_only=True) with @frozen and import it from posthog.dataclasses. As per coding guidelines, “Use @frozen from posthog.dataclasses.”
Proposed decorator change
-@dataclass(frozen=True, kw_only=True)
+@frozenSource: Coding guidelines
…rect Generated-By: PostHog Desktop Task-Id: e0e344ed-ed9b-462a-8e26-9d05263ffd60
New commits were pushed — dismissing the stamphog approval from an earlier head. Re-add the trigger label to request a fresh review.
There was a problem hiding this comment.
Approved.
The presigned download path keeps the run-visibility check, artifact scoping and task-prefix check, and the author has STRONG familiarity with every file changed. The open CodeRabbit comments are minor (test isolation, an edge-case frontend fallback) and none is a showstopper.
- Author wrote 100% of the modified lines and has 47 merged PRs in these paths (familiarity STRONG).
- Minor: test_living_artifact_version_content may call head_object unmocked when a stored file has no size (CodeRabbit nit).
- Minor: the frontend treats an unknown size as previewable, so the backend can return 413 in that edge case. The backend still enforces the limit.
- Minor: object_storage client init errors are not mapped to 'unavailable' in the presign path.
Gate mechanics and policy version
| Gate | Result | |
|---|---|---|
| prerequisites | ✓ | all clear |
| deny-list | ✓ | no deny categories matched |
| size | ✓ | 200L, 7F substantive, 298L/12F incl. docs/generated/snapshots — within ceiling |
| tier | ✓ | T1-agent / T1c-medium (298L, 12F, two-areas, feat) |
| stamphog 2.3.1 | .stamphog/policy.yml @ 8230de9 · reviewed head 8230de9 |
There was a problem hiding this comment.
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/scenes/TaskTracker/taskRunArtifacts.ts-76-76 (1)
76-76: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winTreat an unknown stored artifact size as non-previewable.
If a stored living artifact omits
size,(artifact.size ?? 0)classifies it as previewable. The preview then uses the app download path, although the backend can reject an oversized stored version. Preserve the size invariant for stored versions, or return'none'whensizeis missing.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository: PostHog/posthog/.coderabbit.yaml
Review profile: QUIET
Plan: Enterprise
Run ID: fd2d8267-9027-487c-acba-4bfadfa09284
⛔ Files ignored due to path filters (2)
products/tasks/frontend/generated/api.schemas.tsis excluded by!**/generated/**products/tasks/frontend/generated/api.tsis excluded by!**/generated/**
📒 Files selected for processing (3)
products/posthog_ai/frontend/scenes/TaskTracker/components/TaskRunArtifacts.tsxproducts/posthog_ai/frontend/scenes/TaskTracker/taskRunArtifacts.tsservices/mcp/src/api/generated.ts
Included review availability: This review used your included allowance. Your plan provides up to 12 included reviews per hour; 9 remain after this review.
|
/trunk merge |
1 similar comment
|
/trunk merge |
Problem
Changes
?download=true. A stored version then redirects to a short-lived presigned URL. The file never passes through the app.Content-Disposition: attachmentand the file's content type, so agent-written HTML or SVG still saves instead of rendering.media-srcpolicy allows video only from there. Redirecting the preview would need a CSP change.downloadquery parameter.No new screen. A file over 25 MB shows the existing no-preview state, which already exists for CSV and text files.
How did you test this code?
artifactPreviewKindtable: a stored video over 25 MB gets no inline preview.Content-Disposition: attachmentand its content type.Release status
The Artifacts tab is behind
today-rail-nav. Thedownloadparameter on the API is additive.Automatic notifications
Docs update
None.
🤖 Agent context
Autonomy: Human-driven (agent-assisted)
Agent: PostHog Desktop (Claude Code), Claude Opus 5.5
Created with PostHog Desktop
🤖 Generated with Claude Code