← The appendix · generated 2026-10-21
Sim: every bot comment, every Heal defect
An open-source AI-agent workflow builder.
44 PRs of its real history (2026-10-14 → 2026-10-15) replayed on a private copy, with CodeRabbit, cubic and Greptile on every PR at their default settings, Greptile's TREX on; the repo ships no bot config file. On the Heal side, a full run before the span (t1) and one after it (t3), asked for what changed since t1; the midway run was stopped.
127 defect-claim comments on 44 PRs, 105 distinct claims once the same point from two bots is merged; the 244 walkthroughs, summaries and "no issues" posts the bots also wrote are listed but not counted. 223 Heal defects shown, 20 of them on lines a replayed PR wrote, the rest on code from before the PRs tested. 4 security defects left out.
What ran, and when
The bots ran on their vendors' hosted services, on the settings above. The vendors publish no version number, so the posting dates below are the only identity of what reviewed these PRs.
- coderabbit: 112 comments, posted between 2026-10-20 13:16 and 2026-10-21 00:16 UTC
- cubic: 195 comments, posted between 2026-10-20 13:24 and 2026-10-21 00:22 UTC
- greptile: 64 comments, posted between 2026-10-20 13:25 and 2026-10-21 00:27 UTC
The comments are shown as the bots posted them, with no verdict on whether they hold; the same-issue judge only links a comment to the Heal defect it names. A Heal defect is a failing test on the running product. Download the comments and the defects as CSV.
This product's caveats
- Judge truth: no human graded a sample on this product, so every judge-based number is the model's alone.
- Blame names the last PR that touched a line, not the one that created the defect, so 'several PRs' and 'pre-span' are upper bounds on what a reviewer could have caught.
- The defect ledger is cumulative over the runs: a defect filed by a later run may sit on lines an earlier PR of the span wrote.
- The run after the span saw the code 16 PRs past the last replayed PR (the replay was stopped early by hand); a defect whose lines those later PRs wrote falls outside the window.
- The bots' account settings are the vendors' defaults with Greptile's TREX on; the repo ships no bot config file.
- Cost sums every metrics row of the workspace's runs, stopped attempts included; a run's summary card shows one segment only.
- The midway run (t2) was stopped by hand at about 84 % of its re-read; the run after the span re-read every feature from the t1 state, so nothing of the span is unread.
- During the last 2.5 hours of the run after the span, the checkout was moved by hand from the run's commit to the last replayed PR (16 PRs earlier): the dev server hot-reloaded; 21 of the run's 37 new defects were filed after the move, none on a file those 16 PRs change.
| PR | Bot | Where | Claims | The comment |
|---|---|---|---|---|
| #9041 2026-10-20 13:16 | coderabbit issue-comment | — | summary | No actionable comments were generated in the recent review. 🎉
📝 Walkthrough
The upload routes now log post-write cleanup errors and continue with a successful response. Search dispatch payloads use different scope fields for workspace and project owners. Integration test setup uses a shared helper to clear inherited database URL variables.
**Changes: Upload cleanup handling**
|Layer / File(s)|Summary|
|:---|:---|
|**Post-write cleanup and route tests** `apps/sim/app/api/v2/uploads/[uploadId]/route.ts`, `apps/sim/app/api/v2/uploads/[uploadId]/parts/[partNumber]/route.ts`, `apps/sim/app/api/v2/uploads/[uploadId]/route.test.ts`, `apps/sim/app/api/v2/uploads/[uploadId]/parts/[partNumber]/r … the rest (4905 characters)oute.test.ts`|Both routes log cleanup errors and continue with a `204` response. If cleanup reports that the Project no longer exists, they return `409 CONFLICT`. Tests verify a `204` response after a database transaction failure.| **Search dispatch owner scopes** |Layer / File(s)|Summary| |:---|:---| |**Owner scope construction and dispatch** `apps/sim/lib/workspace-files/search/scope.ts`, `apps/sim/lib/workspace-files/search/dispatcher.ts`, `apps/sim/lib/workspace-files/search/dispatcher.integration.ts`|`fileSearchOwnerScope` returns `{ workspaceId }` for workspace owners and `{ owner }` for project owners. The dispatcher uses these fields, and integration expectations check the corresponding payloads.| **Integration test database setup** |Layer / File(s)|Summary| |:---|:---| |**Shared environment cleanup helper** `packages/db/testing/test-infrastructure.ts`|`clearInheritedDatabaseUrls` deletes variables beginning with `DATABASE_URL` or `DATABASE_REPLICA_URL`, and deletes `MIGRATION_DATABASE_URL`.| |**Integration setup wiring** `apps/realtime/vitest.integration.setup.ts`, `apps/sim/vitest.integration.setup.ts`|Both integration setups call `clearInheritedDatabaseUrls` before configuring test environment variables.| **Priority:** ⬇️ Low **Estimated code review effort:** 3 (Moderate) | ~20 minutes **Change:** Bug fix **Suggested reviewers:** `waleedlatif1` Merge Risk: ⚪ Minimal · up to 5461c The changed upload, search-dispatch, and integration-setup paths have no identified issue requiring a fix before merge. Security architecture risk: 🔵 Low · up to 5461c The changes retain existing upload credentials and session restrictions. No newly permitted unauthorized write or completion was established. Cleanup after an exceptional post-write failure still depends on later expiry processing, whose production scheduling was not verified. **Retained concerns** No architecture-level concerns identified. Security review details **Security Blast Radius** - _inferred_ — The changed upload behavior is bounded to holders of valid local upload-session credentials and already-written session storage. The changed branches introduce no new storage provider, caller-supplied destination key, or cross-owner identifier. **Security Findings and Attack Paths** - _inferred_ — A retirement-check exception is not evidence of a newly authorized write: both base and head perform the write first, and the base error path did not remove the stored bytes. The new success response alone does not establish increased storage authority, longer session expiry, or a completed orphaned file. **Trust Boundaries and Controls** - _observed_ — The PUT routes retain token-to-session validation, local-provider and method restrictions, uploading-state and expiry checks, and expected-size enforcement. The whole-object destination comes from the authenticated session; multipart writes are bound to its upload ID and validated part number. **Resilience and Maintainability Implications** - _observed_ — Whole-object PUT publishes a final object using create-only links; multipart PUT replaces a session-scoped part. Expiry disposal checks final-object identity before versioned deletion, or removes incomplete local multipart state when no final object exists. These shared mechanisms predate the response change. Pre-merge checks: 5 | Check name | Status | Explanation | | :------------------------ | :--------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Description Check | | Check skipped - the reviewer’s high-level summary is enabled. | | Title check | | The title accurately summarizes the three main changes: legacy workspace search payloads, isolated realtime test database configuration, and best-effort post-upload Project checks. It is specific and … | | Docstring Coverage | | Docstring coverage is 83.33% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 6 functions across 10 files. | | Linked Issues check | | Check skipped because no linked issues were found for this pull request. | | Out of Scope Changes check | | Check skipped because no linked issues were found for this pull request. | Full details: Title check **Explanation** The title accurately summarizes the three main changes: legacy workspace search payloads, isolated realtime test database configuration, and best-effort post-upload Project checks. It is specific and related to the changeset, although it is longer than ideal. ✨ Finishing Touches 📝 Generate docstrings 🧪 Generate unit tests (beta) Comment `@the reviewer help` to get the list of available commands. |
| #9041 2026-10-20 13:24 | cubic review-body | — | summary | **No issues found** across 10 files
View guided diff | Turn on auto-fix | Re-trigger the reviewer |
| #9041 2026-10-20 13:25 | greptile issue-comment | — | summary | Confidence Score: 5/5
**[Medium impact]** No actionable findings remain; the checked changes are safe to merge.
Reviews (1) · Last reviewed commit: "fix(file-search): send legacy workspace ..." · Reviewed by the reviewer |
| #9041 2026-10-20 13:25 | greptile issue-comment | — | summary | Comments Outside Diff
These findings could not be posted inline.
- **Known\-retired Project uploads return success when cleanup scheduling throws**
- **Bug**
- Both local upload PUT routes return 204 No Content after a successful write when the Project lookup positively finds no owner but a subsequent outbox insert fails. The focused reproduction executes the real cleanup helper with an empty Project result and injects failure at the first outbox values call. Runtime evidence confirms one Project lookup, one upload-session update attempt, and one outbox insert attempt before each head route returns 204. The parent routes instead return 500 Internal Server Error. Ordinary retirement with s … the rest (1101 characters)uccessful scheduling still correctly returns 409 Conflict. - **Cause** - The new catch treats every rejection from queueRetiredProjectUploadCleanup as an unavailable retirement check, although that helper combines owner detection and cleanup scheduling. At apps/sim/lib/projects/files/prefix-cleanup.ts:185-209, it establishes owner absence before updating the session and enqueueing sweeps, and returns true only after those writes succeed. The changed catches at apps/sim/app/api/v2/uploads/[uploadId]/route.ts:98-109 and apps/sim/app/api/v2/uploads/[uploadId]/parts/[partNumber]/route.ts:108-119 discard failures occurring after retirement was established and fall through to success. - **Fix** - Distinguish an unavailable Project lookup from a confirmed-retired Project whose cleanup scheduling failed. Preserve the retired outcome through a typed result/error or separate detection from best-effort scheduling, returning 409 Conflict for known retirement while retaining 204 for a successful write whose lookup could not be performed. Add the reproduced outbox-failure case to both route suites. |
| #9042 2026-10-20 13:27 | coderabbit issue-comment | — | summary | 📝 Walkthrough
The changes update API base-URL guidance, append `Vary: Accept` to proxy responses, classify `Event` as a select field, and adjust the tabs scrollbar utility.
**Changes: API URL guidance**
|Layer / File(s)|Summary|
|:---|:---|
|**Deployment URL examples** `apps/docs/app/llms.txt/route.ts`|The API guidance identifies `SIM_SITE_URL` as the Sim Cloud base URL and tells self-hosted users to use their deployment origin in examples.|
**Proxy response headers**
|Layer / File(s)|Summary|
|:---|:---|
|**Append `Vary` to responses** `apps/docs/proxy.ts`|Markdown rewrite and default responses append `Vary: Accept`.|
**Workflow preview fields**
|Layer / File(s)|Summary|
|:---|:---| … the rest (3462 characters)|**Classify `Event` as a select field** `apps/docs/components/workflow-preview/workflow-preview.tsx`|`Event` is now included in `SELECT_TITLES`.| **Tabs styling** |Layer / File(s)|Summary| |:---|:---| |**Update scrollbar utility** `apps/docs/components/ui/tabs.tsx`|The tab-list scrollbar utility retains thin scrollbar styling without the important modifier.| **Priority:** ⬇️ Low **Estimated code review effort:** 2 (Simple) | ~10 minutes **Change:** Bug fix **Suggested reviewers:** `waleedlatif1` Merge Risk: 🔵 Low · up to 794c3 Self-hosted readers may send API requests to Sim Cloud instead of their own deployment. Security architecture risk: 🔵 Low · up to 794c3 The change is confined to documentation delivery and display. No expanded execution authority or data access was observed. The cache-header change is consistent with separating HTML and Markdown responses, but deployed cache behavior was not verified. **Retained concerns** No architecture-level concerns identified. Security review details **Security Blast Radius** - _observed_ — The header change applies across paths matched by the docs proxy. Its existing exclusions include API paths, generated Markdown routes, framework assets, and the LLM manifest routes; the PR does not broaden that matcher. **Trust Boundaries and Controls** - _inferred_ — Clients retain control over the request path and content-negotiation preference, but the PR does not change how those inputs select an existing rewrite. Appending Accept variation addresses representation separation without adding an authorization bypass or a new privileged destination in the inspected proxy. Whether downstream caches preserve and honor the header remains unverified. Pre-merge checks: 4 · 1 Failed checks: 1 warning | Check name | Status | Explanation | Resolution | | :---------------- | :----------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------- | | Docstring Coverage | | Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 3 functions across 4 files. | Write docstrings for the functions missing them to satisfy the coverage threshold. | Passed checks: 4 passed | Check name | Status | Explanation | | :------------------------ | :--------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------- | | Description Check | | Check skipped - the reviewer’s high-level summary is enabled. | | Title check | | The title clearly summarizes the main changes to documentation delivery headers and workflow preview details. It is concise and specific. | | Linked Issues check | | Check skipped because no linked issues were found for this pull request. | | Out of Scope Changes check | | Check skipped because no linked issues were found for this pull request. | ✨ Finishing Touches: 💡 1 📝 Generate docstrings: 💡 🧪 Generate unit tests (beta) Comment `@the reviewer help` to get the list of available commands. |
| #9042 2026-10-20 13:28 | cubic review-body | — | summary | **No issues found** across 4 files
View guided diff | Turn on auto-fix | Re-trigger the reviewer |
| #9042 2026-10-20 13:30 | coderabbit inline · P2 | apps/docs/app/llms.txt/route.ts:40 | docs | **Update the example for self-hosted deployments.**
Line [40] requires the deployment origin in the example below, but Line [41] still hard-codes `${SIM_SITE_URL}`. A self-hosted user will send the request to Sim Cloud instead of the self-hosted deployment. Use a deployment-origin placeholder, or label the example as Sim Cloud-only. |
| #9042 2026-10-20 13:30 | coderabbit review-body | — | summary | **Actionable comments posted: 1** |
| #9042 2026-10-20 13:34 | greptile issue-comment | — | summary | Confidence Score: 5/5
**[Medium impact]** No blocking concerns were identified in the changed code; the targeted proxy response checks passed.
Reviews (1) · Last reviewed commit: "fix(docs): correct delivery headers and ..." · Reviewed by the reviewer |
| #9038 2026-10-20 13:34 | coderabbit issue-comment | — | summary | 📝 Walkthrough
The pull request adds a CLI and workflow that report recurring CI flakes through GitHub issues. It also updates flaky-test guidance, adjusts several tests, and increases the HTTP E2E readiness timeout.
**Changes: CI flake reporting and test reliability**
|Layer / File(s)|Summary|
|:---|:---|
|**Detect and group CI flakes** `scripts/report-ci-flakes.ts`|The CLI parses Vitest and E2E logs, groups failures, and selects failed earlier-attempt jobs from successful runs. It accepts a lookback period and a dry-run option.|
|**Track flakes in GitHub issues** `scripts/report-ci-flakes.ts`, `scripts/report-ci-flakes.test.ts`|The CLI plans issue creation, updates, and reopening while … the rest (5985 characters)avoiding duplicate occurrences. It retrieves runs and issues, handles log redirects, and applies or previews issue actions. Tests cover parsing, grouping, lookback dates, and issue planning.| |**Run flake reporting in CI** `.github/workflows/ci-flakes.yml`|A scheduled or manually triggered workflow runs the CLI with optional lookback and dry-run inputs.| |**Update test reliability and readiness** `.claude/rules/sim-testing.md`, `.cursor/rules/sim-testing.mdc`, `.github/scripts/http-e2e.sh`, `apps/sim/app/api/auth/oauth2/token/route.integration.ts`, `apps/sim/lib/auth/oauth-token-family.integration.ts`, `apps/sim/lib/knowledge/__integration__/listing-continuation.integration.ts`, `apps/sim/lib/knowledge/documents/utils.test.ts`, `apps/sim/scripts/test-workflow-stop-after-e2e.ts`|The guidance describes CI flake handling and remediation constraints. Tests use static imports, fixed time, scan diagnostics, or condition-based waiting. The HTTP E2E readiness timeout increases from 300 to 600 seconds.| **Priority:** ⬇️ Low **Estimated code review effort:** 4 (Complex) | ~35 minutes **Change:** Feature ### Sequence Diagram(s) ```mermaid sequenceDiagram participant Workflow as ci-flakes workflow participant CLI as report-ci-flakes.ts participant ActionsAPI as GitHub Actions API participant IssuesAPI as GitHub Issues API Workflow->>CLI: Run with lookback and dry-run options CLI->>ActionsAPI: Search successful runs and retrieve failed-attempt logs ActionsAPI-->>CLI: Return runs, jobs, and logs CLI->>CLI: Parse logs and plan issue actions CLI->>IssuesAPI: Retrieve and create or update flake issues ``` **Suggested reviewers:** `waleedlatif1` Merge Risk: 🔵 Low · up to 06515 A failed log download can prevent the daily flake report from filing issues. The change remains mergeable with this bounded reporting risk understood. Security architecture risk: 🔵 Low · up to 06515 The new automation has limited repository permissions and does not change production authentication behavior. Remaining uncertainty concerns editable issue state and recovery from interrupted reporting, rather than production credentials or tenant data. **Retained concerns** No architecture-level concerns identified. Security review details **Security Blast Radius** - _observed_ — The new workflow grants write authority over repository issues, alongside read access to repository contents and Actions data. The reporter uses GITHUB_REPOSITORY for its API scope; no production deployment, tenant database, or cloud IAM mutation appears in this execution path. **Trust Boundaries and Controls** - _observed_ — The authenticated log request is followed manually to its signed download location without forwarding the API authorization header. Failure names are handled as issue data, with encoded identity markers and fixed write endpoints, rather than executed as commands. - _observed_ — Reporter ownership is inferred from the ci-flake label and editable body markers. The listing does not retain author provenance or exclude pull-request records, and malformed URI encoding in a matching marker can abort planning. Generated bodies use valid encoding; whether externally edited or mislabeled records exist is unknown. **Resilience and Maintainability Implications** - _observed_ — API failures terminate the reporter with a nonzero exit, and a daily run-search count reaching the documented cap fails explicitly instead of silently accepting incomplete results. These failures affect reporting, not production authentication or deployment controls. **Hardening Proposals** - _proposed_ — Consider explicitly defining reporter-owned records, excluding pull requests, validating persisted markers, and isolating malformed records so one edited issue cannot halt the entire report. This is preventive hardening; no unauthorized mutation or active exploitation was established. Pre-merge checks: 4 · 1 Failed checks: 1 warning | Check name | Status | Explanation | Resolution | | :---------------- | :----------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------- | | Docstring Coverage | | Docstring coverage is 53.33% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 15 functions across 8 files. (3 skipped: … | Write docstrings for the functions missing them to satisfy the coverage threshold. | Passed checks: 4 passed | Check name | Status | Explanation | | :------------------------ | :--------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------- | | Description Check | | Check skipped - the reviewer’s high-level summary is enabled. | | Title check | | The title clearly summarizes the main changes: adding daily flaky-check tracking and fixing existing CI flakes. | | Linked Issues check | | Check skipped because no linked issues were found for this pull request. | | Out of Scope Changes check | | Check skipped because no linked issues were found for this pull request. | Full details: Docstring Coverage **Explanation** Docstring coverage is 53.33% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 15 functions across 8 files. (3 skipped: 3 unsupported.) **Resolution** Write docstrings for the functions missing them to satisfy the coverage threshold. ✨ Finishing Touches: 💡 1 📝 Generate docstrings: 💡 🧪 Generate unit tests (beta) Comment `@the reviewer help` to get the list of available commands. |
| #9038 2026-10-20 13:42 | coderabbit inline · P2 | scripts/report-ci-flakes.ts:398 | defect-functional | **Track jobs when their logs are unavailable.**
`GitHubClient.jobLog` throws when the logs response is not a 302 redirect or when the redirected download fails. `collectFlakes` does not catch this error, so `main` exits with status 1 before it plans any issues. Pass an empty log to `failedTestsInLog` so the job is tracked as an unnamed flake.
🛡️ Suggested fix
```diff
--- "a/scripts/report-ci-flakes.ts"
+++ "b/scripts/report-ci-flakes.ts"
@@ -395,7 +395,12 @@
attempt: job.run_attempt,
at: job.started_at,
},
- tests: failedTestsInLog(await client.jobLog(job.id)),
+ tests: failedTestsInLog(
+ await client.jobLog(job.id).catch((error: unk … the rest (718 characters)nown) => { + console.warn(`Job ${job.id} log unavailable; tracking the job itself`, error) + return '' + }) + ), }) } } ``` 📝 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. ```suggestion tests: failedTestsInLog( await client.jobLog(job.id).catch((error: unknown) => { console.warn(`Job ${job.id} log unavailable; tracking the job itself`, error) return '' }) ), ``` |
| #9038 2026-10-20 13:42 | coderabbit review-body | — | summary | **Actionable comments posted: 1** |
| #9038 2026-10-20 13:44 | greptile issue-comment | — | summary | Confidence Score: 4/5
**[Medium impact]** The PR reaches the repository\'s CI workflows and issue tracker\.
Safe to merge with two non-blocking improvements to CI-flake reporting.
Findings
1. **Backfills reopen fixed issues**
2. **One damaged key stops reports**
Reviews (1) · Last reviewed commit: "improvement(ci): track flaky checks dail..." · Reviewed by the reviewer |
| #9038 2026-10-20 13:44 | greptile inline · P2 | scripts/report-ci-flakes.ts:221 | defect-functional | **Backfills reopen fixed issues**
A wider `--days` backfill can reopen a fixed issue for a failure that happened before it was closed. `planIssueActions` treats every uncounted occurrence as a recurrence, regardless of its date. This is a non-blocking concern, but it can send maintainers back to an already-fixed test.
Keep the issue's close time and reopen only for failures after that time. Older failures can still update the count.
Artifacts
**Full executed planner reproduction source — local file**
- Contains the complete script actually executed for both successful scenarios; this is a local artifact reference, not a confirmed upload.
**Successful narrow-window output — local file** … the rest (767 characters)- Records the executed before command and exit 0 with no planned actions; this is a local artifact reference, not a confirmed upload. **Successful wider-backfill output — local file** - Records the executed after command and exit 0 with historical-only reopening; this is a local artifact reference, not a confirmed upload. **Executed command capture script — local file** - Contains the full capture script used to produce the successful logs; this is a local artifact reference, not a confirmed upload. **Captured source anchors and tracked-file status — local file** - Records numbered production source and unchanged tracked files from the previous execution; this is a local artifact reference, not a confirmed upload. Ran code and verified through TREX |
| #9038 2026-10-20 13:44 | greptile inline · P2 | scripts/report-ci-flakes.ts:125 | hardening | **One damaged key stops reports**
If a tracked issue's marker is edited to contain an invalid escape, such as ``, `decodeURIComponent` throws before any report actions are produced. One damaged marker therefore prevents unrelated new reports and updates until it is repaired. This is a non-blocking robustness concern for the daily reporter.
Catch invalid escapes, warn with the issue number, and skip that marker so other flakes still get reported.
Artifacts
**Executed planner and reporter reproduction source**
- The executed Bun harness invokes the production planner and runs the reporter with mocked GitHub responses, asserting both the valid control and malformed-marker failure.
**Plann … the rest (463 characters)er and reporter output with a valid unrelated marker** - Ran the valid-marker control and captured the command, working directory, exit codes, actions, and mocked requests, showing both reports are produced. **Planner and reporter failure with a malformed unrelated marker** - Changed only the unrelated marker to test%ZZ and reran the same flow, showing URIError propagation and reporter exit 1 before any report summaries. Ran code and verified through TREX |
| #9038 2026-10-20 13:45 | cubic inline · P2 | .claude/rules/sim-testing.md:70 | docs | The reporter only searches successful CI runs in its three-day creation-date lookback, so later re-runs are missed; qualify this as coverage within that window.
```suggestion
A daily job (`.github/workflows/ci-flakes.yml`) scans its three-day lookback and files a `ci-flake` issue per test or job it finds
``` |
| #9038 2026-10-20 13:45 | cubic review-body | — | summary | **2 issues found** across 11 files
Reply with feedback, questions, or to request a fix.View guided diff | Turn on auto-fix | Re-trigger the reviewer |
| #9038 2026-10-20 13:45 | cubic inline · P2 | scripts/report-ci-flakes.ts:398 | defect-functional | Handle unavailable job logs instead of aborting collection; pass an empty log to `failedTestsInLog` so the job is still tracked as an unnamed flake.
```suggestion
tests: failedTestsInLog(await client.jobLog(job.id).catch(() => '')),
``` |
| #9044 2026-10-20 13:47 | coderabbit issue-comment | — | summary | ## Walkthrough
> [!WARNING]
> Review details and warnings were omitted to fit the comment limit. |
| #9044 2026-10-20 13:49 | cubic review-body | — | summary | **No issues found** across 1411 files
**Note:** This PR contains a large number of files. the reviewer selects up to 200 of the highest-priority eligible files for this review, so some files may not have been reviewed.View guided diff | Turn on auto-fix | Re-trigger the reviewer |
| #9044 2026-10-20 13:59 | greptile issue-comment | — | summary | Confidence Score: 5/5
**[Medium impact]** No blocking findings were identified; the refactor is safe to merge within the validated scope, subject to normal CI checks.
Reviews (1) · Last reviewed commit: "improvement(naming): rename sandbox-task..." · Reviewed by the reviewer |
| #9043 2026-10-20 14:01 | coderabbit issue-comment | — | summary | No actionable comments were generated in the recent review. 🎉
📝 Walkthrough
The pull request patches Next.js Vary header handling in its CommonJS and ESM builds. It adds end-to-end tests for header merging and documentation content negotiation, plus a GitHub Actions workflow to build the docs, run the tests, and upload their results.
**Changes: Next.js Vary header preservation**
|Layer / File(s)|Summary|
|:---|:---|
|**Patch Next.js Vary handling** `patches/next@16.4.0.patch`, `package.json`, `patches/README.md`|The CommonJS and ESM builds validate and merge Vary values, remove empty and case-insensitive duplicate fields, and reduce wildcard values to `*`. The package applies the patch … the rest (4809 characters), and the README describes its scope and test commands.| |**Test header merging** `apps/docs/scripts/test-header-merge-e2e.ts`, `apps/docs/package.json`|The script tests header behavior against both implementations, records results, and sets a failing exit code when checks fail. A package script runs the test.| |**Test content negotiation in CI** `apps/docs/scripts/test-negotiation-e2e.ts`, `.github/workflows/docs-negotiation.yml`|The script checks HTML and Markdown responses and writes a JSON report. The workflow builds the docs, runs both end-to-end tests, and uploads test results.| **Priority:** ➖ Normal **Estimated code review effort:** 3 (Moderate) | ~25 minutes **Change:** Bug fix **Suggested reviewers:** `theodorespeaks`, `waleedlatif1` Merge Risk: ⚪ Minimal · up to b38a2 No concrete issue remains that would prevent merging after normal checks. Security architecture risk: 🔵 Low · up to b38a2 The change preserves cache-separation headers and validates values before normalization. No introduced security failure was established. Risk remains low because the framework patch also affects Sim, while the added production HTTP checks focus on docs and do not establish behavior across every deployment or cache layer. **Retained concerns** No architecture-level concerns identified. Security review details **Security Blast Radius** - _inferred_ — The affected production scope includes Node responses using the patched Next package in both docs and Sim, not merely the tested documentation URL. The supplied evidence does not establish tenant-specific exposure or deployed cache topology. **Trust Boundaries and Controls** - _observed_ — The native-header harness binds its listener to 127.0.0.1 on an ephemeral port. The negotiation script is an outbound test client with an initial loopback-host check; its inspected requests supply no Authorization or Cookie headers. The routed test interfaces are local declarations rather than production APIs. - _observed_ — The negotiation client does not restrict redirect following, so its initial hostname check does not guarantee that every request remains on loopback. Exploiting this would require influence over the local server response or invocation environment; the inspected code does not establish a remote production attack path or credential forwarding. **Resilience and Maintainability Implications** - _inferred_ — The new merge uses call-local collections derived from the current response, with validation before collection or normalization. This supports request isolation and rejection before mutation by the added branch. The retained headersSent guard limits post-send work, but runtime failure recovery and interrupted-request behavior remain unverified. **Hardening Proposals** - _proposed_ — As defense in depth, reject redirects in the negotiation client so its loopback-only intent applies to the entire request chain. This is a containment improvement, not an established vulnerability. Pre-merge checks: 5 | Check name | Status | Explanation | | :------------------------ | :--------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Description Check | | Check skipped - the reviewer’s high-level summary is enabled. | | Title check | | The title clearly and concisely describes the main change: preserving negotiated response cache headers in the documentation pipeline. | | Docstring Coverage | | No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff. Analyzed 0 functions across 2… | | Linked Issues check | | Check skipped because no linked issues were found for this pull request. | | Out of Scope Changes check | | Check skipped because no linked issues were found for this pull request. | Full details: Docstring Coverage **Explanation** No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff. Analyzed 0 functions across 2 files. (5 skipped: 5 unsupported.) ✨ Finishing Touches 📝 Generate docstrings 🧪 Generate unit tests (beta) ### Usage-based review receipt - Mode: Continue automatically - Reviewed files: 7 - Waived: $1.75 (charged $0.00) - View usage details > [!NOTE] > This review exceeded your plan’s limits and used usage-based reviews—free during trial, billed after paid activation unless disabled. **Manage usage-based reviews**. Comment `@the reviewer help` to get the list of available commands. |
| #9043 2026-10-20 14:09 | cubic review-body | — | summary | **2 issues found** across 8 files
Reply with feedback, questions, or to request a fix.View guided diff | Turn on auto-fix | Re-trigger the reviewer |
| #9043 2026-10-20 14:09 | cubic inline · P2 | apps/docs/scripts/test-negotiation-e2e.ts:56 | tests | This prefix check accepts invalid types such as `text/html-malformed`, so the negotiation regression can pass while clients receive the wrong media type. Compare the parsed media type for equality, ignoring parameters and case. |
| #9043 2026-10-20 14:09 | cubic inline · P2 | apps/docs/package.json:15 | tests | This suite runs its `node:http` server under Bun, so the invalid-header checks exercise Bun's compatibility layer rather than Node's native response pipeline. Run these edge cases under Node as well; otherwise they can miss regressions in the runtime this patch targets. |
| #9043 2026-10-20 14:18 | greptile issue-comment | — | summary | Confidence Score: 5/5
**[Medium impact]** No merge-blocking defect was established. Native-header checks passed; production HTTP behavior remains unverified because neither build attempt completed.
Reviews (1) · Last reviewed commit: "fix(docs): preserve negotiated response ..." · Reviewed by the reviewer |
| #9039 2026-10-20 14:18 | coderabbit issue-comment | — | summary | > [!IMPORTANT]
> ## Review skipped
>
> Too many files!
>
> This PR contains 644 files, which is 344 over the limit of 300.
>
> To get a review, reduce the PR to 300 files or fewer by splitting it into smaller PRs or changing its base branch.
>
> Usage-priced reviews support at most 300 files.
>
>
>
>
> 📥 Commits
>
>
>
> Reviewing files that changed from the base of the PR and between 2a06f2bb0e148a2d69491adfd29e682a0a543f41 and 3e3a535139aee4ab8673df16495c4d7ab802760a.
>
>
>
>
>
>
>
>
>
> You can disable this status message by setting the `reviews.review_status` to `false` in the the reviewer configuration file.
Comment `@the reviewer help` to get the list of available commands. |
| #9039 2026-10-20 14:23 | cubic inline · P2 | apps/docs/content/docs/integrations/quiver.mdx:16 | docs | This promises a separate SVG markup output, but Quiver v2 exposes only `files` (unlike the legacy block, which had `svgContent`). Describe the returned SVG files without implying a raw-string output.
```suggestion
**List Models** reports available models and capabilities. Generated SVG files are returned for downstream processing, storage, or delivery.
``` |
| #9039 2026-10-20 14:23 | cubic review-body | — | summary | **11 issues found** across 647 files
**Note:** This PR contains a large number of files. the reviewer selects up to 200 of the highest-priority eligible files for this review, so some files may not have been reviewed.View guided diff | Turn on auto-fix | Re-trigger the reviewer |
| #9039 2026-10-20 14:23 | cubic inline · P2 | apps/docs/content/docs/integrations/jupyter.mdx:16 | docs | This overview says directories can be copied, but the Copy Content action only supports copying a file or notebook. Remove directories from the copy claim so users are not led to an unsupported operation.
```suggestion
- List, read, create, upload, rename, or delete files, notebooks, and directories; copy files and notebooks.
``` |
| #9039 2026-10-20 14:23 | cubic inline · P2 | apps/docs/content/docs/integrations/luma.mdx:16 | docs | None of the documented Luma actions accepts a calendar ID, so this sends users looking for a nonexistent input. Refer only to the event ID required by event-specific operations.
```suggestion
Provide the event ID required by the operation, then inspect the returned event or guest details before sending invitations or changing attendance.
``` |
| #9039 2026-10-20 14:23 | cubic inline · P2 | apps/docs/content/docs/integrations/luma.mdx:20 | docs | This heading renders literally as “Use the block [#usage-instructions]” instead of a useful section title. Replace it with `## Usage Instructions`.
```suggestion
## Usage Instructions
``` |
| #9039 2026-10-20 14:23 | cubic inline · P2 | apps/docs/content/docs/integrations/dub.mdx:16 | docs | This overstates the Dub List Links action: it exposes no sort input or query parameter. Remove “sorting” or expose sorting in the action.
```suggestion
List actions support filtering and pagination. Analytics report clicks, leads, and sales, with grouping by time, geography, device, browser, referrer, and other supported dimensions.
``` |
| #9039 2026-10-20 14:23 | cubic inline · P2 | apps/docs/content/docs/integrations/azure_devops.mdx:23 | docs | This heading changes the generated anchor from `#usage-instructions` to `#use-the-block-usage-instructions`, breaking existing links to the section. Restore the old heading or assign its original ID explicitly.
```suggestion
## Usage Instructions
``` |
| #9039 2026-10-20 14:23 | cubic inline · P2 | apps/docs/content/docs/integrations/serper.mdx:26 | docs | This claims the block exposes response sections that `transformResponse` discards. Remove the section list or expose those fields in the block output.
```suggestion
Search Google through the Serper.dev API for web, news, places, images, videos, shopping, scholar, or patent results.
``` |
| #9039 2026-10-20 14:23 | cubic inline · P2 | apps/docs/content/docs/integrations/linkup.mdx:16 | docs | This directs hosted users to enter the API key in the block, but Linkup hides that field on hosted Sim and exposes workspace credentials instead. Describe both credential paths so hosted users aren't sent to a field they can't access.
```suggestion
Configure your Linkup API key in the block or workspace credentials, then provide a query. When using it as an agent tool, the agent decides when to call it based on its instructions.
``` |
| #9039 2026-10-20 14:23 | cubic inline · P2 | apps/docs/content/docs/integrations/brex.mdx:22 | docs | This disclaimer is too broad: Create Spend Limit can configure automatic limit-card creation for members. Clarify that the block has no direct card-issuance action while documenting this setting.
```suggestion
Authenticate with a Brex user token from **Developer → Settings** in the Brex dashboard. **Create Transfer** can move money from a Brex cash account to a vendor. Set **Approval Type** to `MANUAL` when the transfer should require cash-admin approval, and inspect its returned status before assuming payment completed. Archiving a budget makes its child spend limits unusable for future expenses. The block has no direct card-issuance action or card-number access, but **Create Spend Limit** … the rest (61 characters)can configure automatic limit-card creation for members. ``` |
| #9039 2026-10-20 14:23 | cubic inline · P2 | apps/docs/content/docs/integrations/pulse.mdx:14 | docs | This promises selectable text and JSON output formats, but the Pulse block exposes no format input and its structured output is always null. Remove those format claims or document only the available outputs.
```suggestion
Use [Pulse](https://www.runpulse.com) to extract text from PDFs, images, and Office files with optical character recognition (OCR). Supply a file or file reference and select pages when needed.
``` |
| #9039 2026-10-20 14:23 | cubic inline · P3 | apps/docs/content/docs/integrations/cloudwatch.mdx:16 | docs | This implies every alarm action reports the current state, but the history and mute/unmute actions do not. Name `Describe Alarms` as the action that checks current state.
```suggestion
Choose **Query Logs (Insights)** for a query across log groups, or **Get Log Events** for one stream. Metric statistics use a time range and period; use **Describe Alarms** to check current state and **Describe Alarm History** to review state changes. Pass results to later steps for incident investigation or threshold-based notifications.
``` |
| #9039 2026-10-20 14:48 | greptile issue-comment | — | summary | Confidence Score: 5/5
**[Medium impact]** No blocking findings remain; the changes are safe to merge within the reviewed scope.
Reviews (1) · Last reviewed commit: "improvement(docs): standardize integrati..." · Reviewed by the reviewer |
| #9016 2026-10-20 14:50 | coderabbit issue-comment | — | summary | 📝 Walkthrough
This change adds project-file APIs, contracts, uploads, version management, authorization, realtime collaboration, CLI commands, delivery handling, and end-to-end validation. It also preserves read-only document membership after write access is lost.
**Changes: Project file platform**
|Layer / File(s)|Summary|
|:---|:---|
|**Project-file contracts and operations** `apps/sim/lib/api/contracts/*`, `apps/sim/lib/projects/files/application/*`|Adds project-file schemas, lifecycle operations, folders, versions, uploads, content handling, authorization, and presenters.|
|**HTTP and V2 API routes** `apps/sim/app/api/projects/...`, `apps/sim/app/api/v2/projects/...`, `apps/sim/app/a … the rest (7360 characters)pi/internal/project-file-*`|Adds authenticated routes for files, folders, content, uploads, versions, restoration, archival, and movement.| |**Realtime collaboration and permissions** `apps/realtime/...`, `packages/realtime-protocol/...`, `apps/sim/.../collaboration/*`|Adds owner-qualified document targets, project rooms, read-based membership, separate write checks, permission events, and recovery after write-access loss.| |**CLI and validation** `packages/sim-cli/...`, `apps/sim/scripts/*project-file*`, `.github/scripts/http-e2e.sh`, `.github/workflows/checks.yml`|Adds project-file commands, E2E suites, orchestration, and CI execution.| |**Shared delivery and request handling** `apps/sim/lib/uploads/server/delivery.ts`, `apps/sim/lib/api/server/routes/*`, `apps/sim/next.config.ts`|Adds shared file delivery headers, filename handling, body-size controls, safe `HEAD` authorization, and file-delivery CSP handling.| **Priority:** ➖ Normal **Estimated code review effort:** 5 (Critical) | ~90 minutes ### Sequence Diagram(s) ```mermaid sequenceDiagram participant Client participant ProjectFileRoute participant ProjectFileUseCase participant Storage participant RealtimeRelay Client->>ProjectFileRoute: authenticated project-file request ProjectFileRoute->>ProjectFileUseCase: validate and execute operation ProjectFileUseCase->>Storage: read or write project-file data ProjectFileUseCase->>RealtimeRelay: notify file-list or document subscribers RealtimeRelay-->>Client: project-file or permission event ``` Merge Risk: 🟡 Moderate · up to 94dbe Project files and realtime collaboration mostly work as designed, but a Project document cached without an identity can make archive, restore, or opening the document fail until the stored state is repaired. A few smaller issues also remain: a cleanup failure can hide the original upload error, the documented upload size limit is wrong, and the realtime relay sends redundant traffic. Fix the document-identity handling before merging. Security architecture risk: 🟡 Moderate · up to 94dbe The new collaboration paths have substantial ownership and permission controls. However, an authorized editor can alter document lifecycle metadata and disrupt persistence or collaboration for a writable shared document. Deployment and storage-isolation assurance also remains incomplete. **Retained concerns** - **Medium · security · inferred:** A current Project writer can submit a valid Yjs update that deletes or replaces configMap.docId while retaining the legitimate outer docId. The relay checks the outer identity before appending, then applies the update without preserving the internal identity. Subsequent generation checks can suppress persistence and prevent document joins. This is an existing handler weakness made reachable for Project-owned documents by the new callbacks, not evidence of anonymous access or cross-project compromise. Write authorization, valid initial seeds, and lifecycle rotation constrain its scope but do not prevent the accepted mutation. Security review details **Security Blast Radius** - _inferred_ — The identified attack requires current write access and room membership. Its independently attackable scope is a document the caller can write, potentially repeated across such documents; the shared stream can propagate the poisoned state to replicas serving that room. The inspected controls do not establish an attack on unrelated Projects, tenants, credentials, or infrastructure authority. **Security Findings and Attack Paths** - _inferred_ — An admitted writer can retain the legitimate envelope docId while deleting or replacing configMap.docId inside the Yjs delta. Parsing the delta in an empty validation document checks syntax, not preservation of the live identity. The update is accepted, but persistence and join checks subsequently compare the mutated identity with the separately stored generation. This is a static, source-supported availability concern, not a demonstrated cross-tenant exploit. **Trust Boundaries and Controls** - _observed_ — Project upload receipts bind the Project, human subject, and initiating credential or delegated invocation, without a legacy uploader-only fallback. Completion rechecks both authorization and that binding before registration. Realtime mutation handling separately verifies the socket's joined target, current write permission, document generation, and authenticated editor attribution. **Resilience and Maintainability Implications** - _observed_ — The access sweep separates synchronous eviction from retryable presence cleanup and propagates write-capability changes without removing legitimate readers. Authorization timeouts or unexpected errors retain membership rather than proving revocation; therefore the sweep does not provide an unconditional revocation deadline during authorization failure. **Hardening Proposals** - _proposed_ — Keep lifecycle identity outside client mutation authority: validate the effect of an update against the current document before durable append and reject changes to reserved identity metadata. Exercise deletion and replacement attempts through persistence, reconnect, replica replay, and archive/restore recovery. Pre-merge checks: 4 · 1 Failed checks: 1 inconclusive | Check name | Status | Explanation | Resolution | | :---------------- | :--------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------- | | Docstring Coverage | | Docstring coverage is 37.25% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 51 functions across 50 files. (171 skippe… | Write docstrings for the functions missing them to satisfy the coverage threshold. | Passed checks: 4 passed | Check name | Status | Explanation | | :------------------------ | :--------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------ | | Description Check | | Check skipped - the reviewer’s high-level summary is enabled. | | Title check | | The title clearly summarizes the main change: adding core Project file storage and realtime operations. | | Linked Issues check | | Check skipped because no linked issues were found for this pull request. | | Out of Scope Changes check | | Check skipped because no linked issues were found for this pull request. | Full details: Docstring Coverage **Explanation** Docstring coverage is 37.25% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 51 functions across 50 files. (171 skipped: 7 unsupported, 164 over the file limit.) **Resolution** Write docstrings for the functions missing them to satisfy the coverage threshold. ✨ Finishing Touches: 💡 1 📝 Generate docstrings: 💡 🧪 Generate unit tests (beta) Comment `@the reviewer help` to get the list of available commands. |
| #9016 2026-10-20 15:03 | cubic review-body | — | summary | **50 issues found** across 228 files
**Note:** This PR contains a large number of files. the reviewer selects up to 200 of the highest-priority eligible files for this review, so some files may not have been reviewed.View guided diff | Turn on auto-fix | Re-trigger the reviewer |
| #9016 2026-10-20 15:03 | cubic inline · P0 | apps/sim/next.config.ts:4 | defect-functional | Next evaluates `next.config.ts` before resolving app `@/` aliases, so this import prevents `next dev` and `next build` from loading the config. Use a relative import for this module.
```suggestion
import { PROXY_CLIENT_MAX_BODY_BYTES } from './lib/core/config/request-limits'
``` |
| #9016 2026-10-20 15:03 | cubic inline · P1 | apps/sim/lib/api/contracts/project-file-lifecycle.ts:94 | defect-functional | The restore-folder response schema requires `owner` and `userId` on `folder`, but `restoreProjectFileFolder` returns the raw folder row from `restoreFileFolder` without mapping it to the project record shape. The route parses responses against this schema, so a successful restore would fail validation. Map the restored folder to `projectFileFolderRecord` in the use case, as the create and update folder paths do, or relax this schema to match what is returned. |
| #9016 2026-10-20 15:03 | cubic inline · P2 | apps/realtime/src/handlers/file-doc.ts:1248 | defect-performance names defect s2-caret-move-redis-read-1 | This generation check now runs on every inbound frame, including high-frequency awareness (cursor) updates. Consider scoping it to frames that mutate the doc, or caching the result for the frame burst. |
| #9016 2026-10-20 15:03 | cubic inline · P2 | apps/sim/app/workspace/[workspaceId]/files/components/file-viewer/rich-markdown-editor/collaboration/file-doc-provider.ts:1108 | defect-functional | `setCanWrite` returns before emitting `permission` when the value is unchanged. A reader's first join therefore emits no `permission` event even though permission is now known. Emit the event whenever permission becomes known, not only when `canWrite` changes. |
| #9016 2026-10-20 15:03 | cubic inline · P2 | apps/sim/lib/uploads/server/delivery.ts:21 | quality | This duplicates the header-security helpers already in `app/api/files/utils.ts` (`SAFE_INLINE_TYPES`, `FORCE_ATTACHMENT_EXTENSIONS`, `getSecureFileHeaders`, `encodeExtValue`, `encodeFilenameForHeader`). The copies already differ: this `getSecureFileHeaders` normalizes media type parameters and case, and the existing one does not. Move one implementation into a shared module and have both call sites import it, so the download policy lives in one place. |
| #9016 2026-10-20 15:03 | cubic inline · P2 | packages/sim-cli/src/runtime/options.ts:31 | defect-functional | Adding this operation here suppresses its `--cursor` option, even when a positive `--limit` stops pagination and returns `nextCursor`. Expose `--cursor` for paginated operations so users can resume a capped listing. |
| #9016 2026-10-20 15:03 | cubic inline · P2 | apps/sim/lib/api/contracts/v2/project-file-folders.ts:41 | defect-security | The v2 project folder list accepts `scope=all`, which the v2 file contracts deliberately exclude because it drops the `deleted_at` predicate. Narrow this to `active | archived` to match `v2FileScopeSchema` and the v2 folder list.
```suggestion
scope: z.enum(['active', 'archived']).default('active').describe('Folder lifecycle scope.'),
``` |
| #9016 2026-10-20 15:03 | cubic inline · P2 | apps/sim/lib/projects/files/application/folders.ts:101 | defect-functional | This records any PATCH containing `parentId` as a move, even when the parent is unchanged (for example, a rename that resubmits its parent). Compare the previous and resulting parent IDs before emitting `FOLDER_MOVED` so the audit action reflects the change. |
| #9016 2026-10-20 15:03 | cubic inline · P2 | apps/sim/lib/collab-doc/state.ts:65 | defect-performance | With the executor now accepting a transaction, this read can happen inside the authorize transaction. That keeps a potentially 12 MiB binary load and Yjs decode open on the read path. Consider loading the state outside the transaction, or caching the docId, so only the lightweight lookup runs under the transaction. |
| #9016 2026-10-20 15:03 | cubic inline · P2 | apps/realtime/src/handlers/workspace-invalidation-room.test.ts:362 | tests | This test never checks that the malformed join was rejected. Add an assertion that `INVALID_PAYLOAD` was emitted, so the test fails if the payload is silently accepted or ignored. |
| #9016 2026-10-20 15:03 | cubic inline · P2 | apps/sim/lib/api/server/validation.ts:30 | docs | The deleted comment was the only note that `MAX_WORKSPACE_FILE_INLINE_BODY_BYTES` (70 MB) is silently clamped to the proxy limit, which is now 17 MiB. Restore that note here. Otherwise the inline project-file create route reads as accepting 50 MiB files, but it returns 413 above roughly 12.7 MiB raw.
```suggestion
/**
* Clamps oversize requests to the proxy limit. Any cap above PROXY_CLIENT_MAX_BODY_BYTES, including
* MAX_WORKSPACE_FILE_INLINE_BODY_BYTES (70 MB), is silently reduced here, so an inline body above that
* limit (about 12.7 MiB of raw file content) returns 413 until the proxy limit is raised deliberately.
*/
``` |
| #9016 2026-10-20 15:03 | cubic inline · P2 | apps/sim/app/api/v2/projects/[projectId]/files/folders/route.ts:23 | defect-functional | This list returns each folder's raw display path (no leading `/`, slashes escaped as `\/`), while the Project file responses and the workspace folder route return canonical percent-encoded paths. A client cannot pass a folder's `path` back as `folderPath`, because the canonical folder path schema requires a leading `/`. Consider projecting `path` through the canonical path view, or confirm the display-path format is intentional. |
| #9016 2026-10-20 15:03 | cubic inline · P2 | apps/sim/lib/workspace-files/application/version-content.ts:26 | defect-functional | The version-download callback can resolve before its stream reports a missing object, so this catch does not map that race to `not_found`. Handle stream errors at the consumption boundary as well. |
| #9016 2026-10-20 15:03 | cubic inline · P2 | apps/sim/lib/api/contracts/realtime-file-lists.ts:9 | defect-security | This regex accepts `.` and `..`, which URL normalization turns into a different path. The realtime relay then sends an internal-secret POST to that unintended path. Reject dot segments here, for example with a negative lookahead.
```suggestion
.regex(/^(?!\.{1,2}$)[^/:\s]+$/),
``` |
| #9016 2026-10-20 15:03 | cubic inline · P2 | apps/sim/lib/projects/files/application/document-lifecycle.ts:38 | defect-performance | `readProjectFileDocIdInTx` decodes the entire cached Yjs state just to read `docId`. `buildProjectFileDocSeed` runs this check twice per seed request, so a large document is fully decoded twice before any seeding work. Store the identity in a column, or read it without a full decode. |
| #9016 2026-10-20 15:03 | cubic inline · P2 | apps/sim/lib/projects/files/application/lifecycle.ts:168 | defect-concurrency | `restoreProjectFile` decides whether to rotate the document from `context.file?.deletedAt`, which the authorizer reads without a row lock for write operations. If two restores of the same archived file overlap, the second call sees it as archived, but `restoreFileInTx` finds it already restored under its lock. That call still rotates the live file's document and retires the editors' session. Decide retirement from the state `restoreFileInTx` observes under its lock, so it runs only when this call actually restores the file. |
| #9016 2026-10-20 15:03 | cubic inline · P2 | apps/sim/lib/projects/__integration__/foundation.integration.ts:1473 | tests | These denial assertions use bare `.rejects.toThrow()`, so any exception passes. Assert the expected code instead, as the rest of this file does (`.rejects.toMatchObject({ code: 'forbidden' })` or `'not_found'`). The rename/archive checks currently fail at the principal-kind gate, so they do not test the admin access gate their title describes. |
| #9016 2026-10-20 15:03 | cubic inline · P2 | apps/sim/lib/api/contracts/v2/project-file-uploads.ts:23 | design | This v2 upload body exposes `folderId`, but the v2 file contracts say folder placement is canonical-path only and folder ids stay internal. Every other v2 Project and workspace body accepts only `folderPath`. Remove `folderId` from this v2 schema and keep it on the internal v1 contract. The Project v2 routes are still unpublished, so this is contained, but the field would become a public commitment at launch. |
| #9016 2026-10-20 15:03 | cubic inline · P2 | apps/sim/lib/api/contracts/v2/project-file-lifecycle.ts:21 | hardening | The Project archive and move contracts accept empty file or folder IDs. Validate each ID as non-empty so malformed requests fail at the API boundary instead of reaching the lifecycle operation as missing-item requests. |
| #9016 2026-10-20 15:03 | cubic inline · P2 | apps/sim/lib/core/config/feature-flags.ts:107 | docs | This implies the `projects` flag controls memories, but the Project rollout gate currently covers Project and Project-file APIs only. Remove “and memories” unless Project-memory access is also gated here.
```suggestion
'Expose Projects and Project-scoped features, including files. Global on/off only; ' +
``` |
| #9016 2026-10-20 15:03 | cubic inline · P2 | apps/sim/lib/projects/application/use-cases.ts:121 | defect-security | Workspace-scoped Copilot discovery ignores `scope.workspaceId`, exposing other accessible Projects in the same organization (or personal scope) to the conversation. Filter by the invocation workspace when `scope.workspaceId` is set.
```suggestion
${scope.organizationId !== undefined ? sql`AND ${project.organizationId} IS NOT DISTINCT FROM ${scope.organizationId}` : sql``}
${scope.workspaceId !== undefined ? sql`AND ${workspace.id} = ${scope.workspaceId}` : sql``}
``` |
| #9016 2026-10-20 15:03 | cubic inline · P2 | apps/realtime/src/handlers/file-doc-project.integration.ts:166 | tests | The HTTP handler is registered after Socket.IO attaches, so Engine.IO does not forward these `/api/file-doc/*` requests to it and the new HTTP test fails. Register a forwarding listener before constructing Socket.IO, then assign the handler after creating the room manager, as `index.ts` does. |
| #9016 2026-10-20 15:03 | cubic inline · P2 | apps/sim/lib/api/list-query.ts:343 | defect-functional | A direction-array length mismatch is a server bug, but `keysetAfter` returns `null` here and callers turn that into a 400 "cursor does not match the requested sortBy/sortOrder". `listOrderBy` throws for the same mismatch, so the two siblings disagree. Throw from `keysetAfter` as well, or only validate cursor values in the null path. |
| #9016 2026-10-20 15:03 | cubic inline · P2 | apps/sim/app/api/v2/projects/[projectId]/files/folders/route.ts:23 | defect-performance | This response materializes every Project folder but always returns `nextCursor: null`; the underlying query has no row limit or folder-count cap. Add pagination or enforce a hard folder cap before exposing this as a full-set list. |
| #9016 2026-10-20 15:03 | cubic inline · P2 | apps/sim/lib/projects/files/application/authorized-use-case.ts:142 | hardening | `afterSuccess` runs after the transaction has committed, but errors from it propagate to the caller. A failure in post-commit cleanup would report the already-committed file write as failed, which invites a duplicate retry. Consider isolating post-commit `afterSuccess` failures with a logged catch, as `notifyFileListChanged` already does.
```suggestion
try {
await definition.afterSuccess?.(resultContext)
} catch (error) {
logger.error('Project file post-commit effects failed after commit', {
operation: definition.operation.id,
projectId: args.input.projectId,
fileId: args.input.fileId,
error: describeError(error),
} … the rest (13 characters)) } ``` |
| #9016 2026-10-20 15:03 | cubic inline · P2 | apps/sim/lib/projects/application/authorization.ts:197 | defect-performance | `loadProjectAccess` takes the exclusive Project lock for every file authorization, including reads, serializing concurrent reads for the same Project until their transactions finish. Use shared Project locking for read policies and reserve exclusive locking for operations that need it. |
| #9016 2026-10-20 15:03 | cubic inline · P2 | apps/sim/lib/projects/files/application/operations.ts:59 | defect-functional | `HISTORY_POLICY` excludes delegated principals but still declares a Copilot audience, so version routes are advertised as callable and then fail principal authorization. Make `delegationAudience` optional and omit it from this policy. |
| #9016 2026-10-20 15:03 | cubic inline · P2 | apps/sim/lib/api/contracts/v2/project-file-uploads.ts:19 | design | This schema accepts both `folderId` and `folderPath`, but `resolveFileFolderTarget` rejects that combination after contract parsing. Add a `superRefine` so the published and runtime contracts agree. |
| #9016 2026-10-20 15:03 | cubic inline · P2 | apps/sim/lib/realtime/notify.ts:279 | design | `retireLiveFileDoc` accepts a workspace-owned `FileDocTarget`, but the body omits the owner for workspace and the relay always rejects that request with 400. Narrow the target to a project owner so the type matches what the relay accepts.
```suggestion
target: {
fileId: string
owner: { entityType: 'project'; entityId: string }
retiredDocId: string
replacementDocId: string
},
``` |
| #9016 2026-10-20 15:03 | cubic inline · P2 | apps/sim/lib/projects/files/application/uploads.ts:283 | defect-functional | A failed extra storage read aborts completion for small `.html` uploads, even though the verified object can be registered unchanged. Catch sniff failures and fall back to `adopted`, as workspace uploads do.
```suggestion
let bytes: Buffer
try {
bytes = await downloadFile({ key: adopted.key, context: 'project' })
} catch (error) {
logger.warn('Page-source sniff skipped for Project upload', { key: adopted.key, error })
return { staged: adopted, restored: false }
}
``` |
| #9016 2026-10-20 15:03 | cubic inline · P2 | apps/sim/lib/api/contracts/project-files.ts:99 | defect-functional | This schema accepts `folderId` and `folderPath` together, but the create path forwards both and rejects the request at runtime. Add a refinement requiring callers to choose one so the contract matches the endpoint. |
| #9016 2026-10-20 15:03 | cubic inline · P2 | apps/sim/lib/api/contracts/project-file-uploads.ts:25 | defect-functional | This schema accepts both `folderId` and `folderPath`, but upload creation rejects that combination, so a contract-valid request fails with a validation error. Add a cross-field refinement to reject conflicting selectors here. |
| #9016 2026-10-20 15:03 | cubic inline · P2 | apps/sim/lib/api/contracts/v2/openapi/project-file-uploads.ts:123 | docs | Completion retries do not always return the file: after it is archived, `loadRegisteredFile` filters it out and `loadCompleted` returns 404. Qualify this guarantee, for example, by saying it applies while the file remains active.
```suggestion
description: `Finalize verified bytes and atomically register one Project file. Retrying completion returns the same file while it remains active, without billing twice. Current edit access is checked again. ${WORKSPACE_API_KEY_DENIED}`,
``` |
| #9016 2026-10-20 15:03 | cubic inline · P2 | apps/sim/lib/api/contracts/v2/openapi/project-file-uploads.ts:90 | docs | Abort waits for provider cleanup rather than scheduling it: the operation deletes the incomplete object or aborts its multipart upload before returning. Describe cleanup as part of the abort request so callers do not expect it to happen later.
```suggestion
description: `Abort a pending Project upload and discard its unregistered bytes. ${WORKSPACE_API_KEY_DENIED}`,
``` |
| #9016 2026-10-20 15:03 | cubic inline · P2 | apps/sim/lib/workspace-files/application/file-delivery-observer.ts:12 | design | `observeWorkspaceFileDelivery` has no production caller in this PR, so the observer and its refusal path only run under the integration test. If the private-delivery transport is deferred, drop this module and the `content.ts` observer branches until that transport lands. Otherwise, install the observer in the production transport in this PR. |
| #9016 2026-10-20 15:03 | cubic inline · P2 | apps/sim/lib/projects/files/__integration__/documents.integration.ts:61 | tests | This environment stub is never restored, so later integration suites can inherit `FREE_STORAGE_LIMIT_GB=''` and become order-dependent. Call `vi.unstubAllEnvs()` in `afterAll`. |
| #9016 2026-10-20 15:03 | cubic inline · P2 | apps/sim/lib/projects/files/__integration__/documents.integration.ts:493 | tests | This cleanup removes outbox rows only for the lifecycle test's file, but the final test's Markdown update enqueues an event for a different file; processing completes the event without deleting its row. Clean outbox events for every fixture project so repeated integration runs do not accumulate stale rows. |
| #9016 2026-10-20 15:03 | cubic inline · P2 | apps/sim/lib/projects/files/__integration__/uploads.integration.ts:632 | hardening | `afterAll` runs fixture deletes with no try/finally, so one failing delete skips the storage-root removal, Redis close, report write, and `db.$client.end()`. Put the loop in a `try` and move the teardown into the `finally`. |
| #9016 2026-10-20 15:03 | cubic inline · P3 | .github/workflows/checks.yml:200 | docs | The comment above the `e2e` matrix still says only SCIM needs 8 vCPU and the other self-hosted suites fit on 4. This group now runs on 8 vCPU, so update the comment to name `project-files` and state why it needs the larger runner. |
| #9016 2026-10-20 15:03 | cubic inline · P3 | apps/sim/lib/api/contracts/file-browser.ts:23 | quality | The `.max(4)` and `.max(3)` limits duplicate the lengths of `FILE_BROWSER_TYPES` and `FILE_BROWSER_SIZES`. Derive them from the constants, e.g. `.max(FILE_BROWSER_TYPES.length)`, so adding an enum value cannot silently make a valid multi-select filter return 400. |
| #9016 2026-10-20 15:03 | cubic inline · P3 | apps/sim/app/api/workspaces/[id]/files/[fileId]/content/route.test.ts:107 | tests | This test hardcodes `17 * 1024 * 1024 + 1` instead of deriving the boundary from `PROXY_CLIENT_MAX_BODY_BYTES`, and the comment explaining the proxy clamp was removed. If the proxy constant changes, this test keeps passing without checking the boundary. Import `PROXY_CLIENT_MAX_BODY_BYTES` from `@/lib/core/config/request-limits` and use `PROXY_CLIENT_MAX_BODY_BYTES + 1`, or restore a short comment that names the constant. |
| #9016 2026-10-20 15:03 | cubic inline · P3 | apps/realtime/src/handlers/workspace-invalidation-room.test.ts:192 | docs | This comment says the tests use real authorization, but `fetchProjectRoomAccess` is stubbed to `mockAuthorizeRoom`. Correct the comment to say authorization is stubbed, or move the Project collection access checks into their own test. |
| #9016 2026-10-20 15:03 | cubic inline · P3 | apps/realtime/src/access-revalidation.ts:40 | docs | The comment names only document rooms as throwing on a cold-cache failure. Project collection rooms (`PROJECT_FILES`) also throw via `isProjectRoom`, so the fallback is unused for them too. Name both.
```suggestion
* Project and document rooms throw instead; the sweep retains their subscriptions for retry.
``` |
| #9016 2026-10-20 15:03 | cubic inline · P3 | scripts/check-openapi-specs.ts:72 | quality | This key is built inline without `toUpperCase()`, unlike the registry key derivation in this file. Normalize the method here so the two key formats cannot diverge. Hoisting `contractKey` above this constant and reusing it would be cleaner.
```suggestion
`${contract.method.toUpperCase()} ${contract.path.replace(/\[([^\]]+)\]/g, '{$1}')}`,
``` |
| #9016 2026-10-20 15:03 | cubic inline · P3 | apps/sim/lib/auth/realtime-file-delegation.ts:15 | quality | The internal-relay auth block (API-key check, subject/connection header parsing, and emptiness guards) is copied verbatim from `realtime-file-list-delegation.ts`. Extract it into one helper, such as `authenticateRealtimeRelay(request)`, so a future change to the relay trust checks is made once. |
| #9016 2026-10-20 15:03 | cubic inline · P3 | apps/sim/lib/api/contracts/project-file-versions.ts:37 | hardening | `revertProjectFileVersionBodySchema` leaves `expectedRevision` without a length cap, unlike the workspace revert body and the Project content update body, which both use `.max(1024)`. Extend the schema with `.max(1024)` to match.
```suggestion
export const revertProjectFileVersionBodySchema = v2RevertFileVersionBodySchema
.omit({ workspaceId: true })
.extend({ expectedRevision: z.string().min(1).max(1024).optional() })
``` |
| #9016 2026-10-20 15:03 | cubic inline · P3 | apps/sim/lib/api/list-query.ts:247 | docs | The doc comment above `listOrderBy` still says every key takes the requested direction. With the new array form each key takes its own direction, so update the comment to describe the per-key array. |
| #9016 2026-10-20 15:03 | cubic inline · P3 | apps/sim/lib/uploads/server/live-doc-outbox.ts:41 | defect-functional | This owner check also fails when `fileId` is missing or malformed, because `parseFileDocTarget` returns null for those cases too. The error then reports an invalid owner and the `fileId` check below is never reached for owner payloads. Validate `fileId` before the owner parse, or make the message cover both cases.
```suggestion
if (candidate.workspaceId !== undefined || !target?.owner)
throw new Error('Invalid live-document owner or fileId')
``` |
| #9016 2026-10-20 15:03 | cubic inline · P3 | apps/sim/lib/workspace-files/application/file-versions.ts:187 | defect-performance | This adds a second author-email lookup on every v2 version-list page. `toV2FileVersions` re-queries emails and ignores the `authors` this use case already projected. Have the v2 presenter read `version.authors`, or drop the projection for the v2 path. |
| #9016 2026-10-20 15:03 | cubic inline · P3 | apps/sim/lib/projects/application/authorization.ts:41 | design | `requireProjectPrincipal` hard-codes `services: ['copilot']` instead of using the operation's declared `delegatedServices`. Add `delegatedServices` to the generic `Pick` and pass `operation.delegatedServices` so the declaration stays the single source of truth. |
| #9016 2026-10-20 15:03 | greptile issue-comment | — | summary | Confidence Score: 4/5
**[High impact]** The changes reach Project and Workspace file workflows across APIs\, storage\, uploads\, and live collaboration\.
The reported documentation mismatch is non-blocking and does not make the change unsafe to merge.
Findings
1. **Upload help overstates the limit**
Reviews (1) · Last reviewed commit: "feat(project-files): add core storage an..." · Reviewed by the reviewer |
| #9016 2026-10-20 15:03 | greptile inline · P2 | apps/sim/lib/api/contracts/v2/project-files.ts:82 | docs | **Upload help overstates the limit**
The new Project API help promises a 70 MiB JSON request limit and a 50 MiB decoded-file limit, but request parsing caps create and update requests at 17 MiB. Schema-valid requests containing 18 MiB of UTF-8 file content returned HTTP 413 for both operations, with and without Content-Length, despite being below both advertised limits. API and CLI users following this help can therefore prepare uploads that are rejected.
This is a non-blocking documentation mismatch. Describe the effective 17 MiB complete-request limit in both schemas and regenerate the CLI help, or raise both the parser and proxy limits.
Artifacts
**Upload parser results before the PR* … the rest (1237 characters)* - Executed the base parser against identical head create/update contracts and real upload bodies; 8 MiB content passed while 12 and 18 MiB content returned HTTP 413. **Upload parser results at PR head** - Executed the head parser against the advertised create/update contracts; 12 MiB content now passed, but valid 18 MiB content still returned HTTP 413 despite the advertised limits. **Full executed upload contract test** - Contains the complete authored test that constructs actual payloads, checks schema validity and advertised help, and asserts observed parser responses. **Before and after execution command source** - Contains the executed runner that extracts the unchanged base parser and captures both Vitest runs with commands, working directories, exit codes, full test source, and numbered code evidence. **Upload validation Vitest configuration** - Contains the configuration used to run the artifact-local test with existing application setup and real production parser imports. **Exact base parser used for comparison** - Contains the unmodified parser extracted by git show from base revision 3fbe7a7b2 and executed in the before run, making the comparison reproducible. Ran code and verified through TREX |
| #9016 2026-10-20 15:05 | coderabbit inline · P2 | apps/realtime/src/handlers/file-doc.ts:1168 | defect-performance | **Emit `PERMISSION` only when the capability changes.**
`resolveFileDocPermission` runs for every inbound frame in `handleMessage` and for every acknowledged update in `handleClientUpdate`. The `accept` callback calls `socket.emit(FILE_DOC_EVENTS.PERMISSION, …)` each time. Awareness frames are sent on every caret move. As a result, each caret move or keystroke frame now also sends one permission event back to the sender. The client handles repeated events without error (`setCanWrite` returns early when the value is unchanged), so this is extra traffic only. It still roughly doubles the downstream messages for active editors.
Record the last `canWrite` value sent to each socket. Emit only w … the rest (1024 characters)hen that value changes, or when `permission === null`, which is the eviction case. ♻️ Proposed change ```diff +const lastEmittedCanWrite = new Map<string, boolean>() ... const accept = (permission: string | null) => { if (socketToRoomName.get(socket.id) !== name || fileDocRooms.get(name) !== document) return null - socket.emit(FILE_DOC_EVENTS.PERMISSION, { - fileId: document.fileId, - ...fileDocOwnerWireFields(document.owner), - canWrite: permission === 'write' || permission === 'admin', - } satisfies FileDocPermission) + const canWrite = permission === 'write' || permission === 'admin' + if (permission === null || lastEmittedCanWrite.get(socket.id) !== canWrite) { + lastEmittedCanWrite.set(socket.id, canWrite) + socket.emit(FILE_DOC_EVENTS.PERMISSION, { + fileId: document.fileId, + ...fileDocOwnerWireFields(document.owner), + canWrite, + } satisfies FileDocPermission) + } ``` Clear the entry in `cleanupFileDocForSocket` and on join. |
| #9016 2026-10-20 15:05 | coderabbit inline · P2 | apps/sim/app/api/v2/projects/[projectId]/files/route.ts:82 | defect-security | **Authorize the project before you parse the large inline body.**
This `POST` raises `maxBodyBytes` to `MAX_WORKSPACE_FILE_INLINE_BODY_BYTES`. It has no `beforeParse` authorization step. V2 admission authenticates the key, but it does not authorize the target project. A caller with any valid API key can therefore make the server read and JSON-parse a full inline body for a project that the caller cannot write. Authorization then rejects the request in `createProjectFile`.
The internal `POST /api/projects/[id]/files` route and the v2 content `PUT` both authorize in `beforeParse` for this reason. Use the same guard here so that both creation surfaces behave the same way.
🛡️ Proposed fix
` … the rest (1878 characters)``diff parseOptions: { maxBodyBytes: MAX_WORKSPACE_FILE_INLINE_BODY_BYTES }, + beforeParse: async ({ principal, params }) => { + if (typeof params.projectId === 'string') + await createProjectFile.authorize({ + principal, + input: { + projectId: params.projectId, + name: 'admission', + contentType: 'application/octet-stream', + content: '', + encoding: 'utf-8', + }, + }) + }, mapInput: ({ params, body }) => ({ ``` 📝 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. ```suggestion export const POST = defineV2JsonRoute({ contract: v2CreateProjectFileContract, auth: v2ApiKeyAuth, operation: projectFileOperations.create, rateLimit: v2RateLimits.publicApi, errorPolicy: v2OrchestrationErrorPolicy, parseOptions: { maxBodyBytes: MAX_WORKSPACE_FILE_INLINE_BODY_BYTES }, beforeParse: async ({ principal, params }) => { if (typeof params.projectId === 'string') await createProjectFile.authorize({ principal, input: { projectId: params.projectId, name: 'admission', contentType: 'application/octet-stream', content: '', encoding: 'utf-8', }, }) }, mapInput: ({ params, body }) => ({ projectId: params.projectId, name: body.name, contentType: body.contentType ?? getMimeTypeFromExtension(getFileExtension(body.name)), content: body.content, encoding: body.encoding, folderPath: body.folderPath ?? '/', exactName: true, }), useCase: createProjectFile, present: ({ file }) => ({ data: toV2ProjectFile(file) }), }) ``` |
| #9016 2026-10-20 15:05 | coderabbit inline · P2 | apps/sim/lib/api/contracts/v2/project-files.ts:82 | docs | **Confirm the documented 70 MiB request cap against the proxy body limit.**
The proxy limit is 17 MiB. `parseJsonBody` clamps each route's `maxBodyBytes` to this limit, so inline requests larger than 17 MiB receive `413` before reaching the documented 50 MiB decoded-file limit. Update both descriptions to document the effective limit, or raise the proxy limit for these routes. |
| #9016 2026-10-20 15:05 | coderabbit inline · P1 | apps/sim/lib/projects/files/application/document-lifecycle.ts:35 | defect-functional | **Handle identity-less Project snapshots before lifecycle operations.**
When the Project persist route receives a valid Yjs snapshot without `configMap.docId`, the uncached `preparePersistedState` path stores it unchanged. Later, realtime admission calls `readProjectFileDocIdInTx`, while archive and restore call `rotateProjectFileDocInTx`. Both call `documentIdentity`, which throws for a missing identity.
Handle this state explicitly. Return `null` for realtime admission, and make rotation support an unnamed cached document without passing a fabricated ID to `retireLiveFileDoc`. Alternatively, normalize the snapshot before the first Project cache write and repair existing legacy rows. |
| #9016 2026-10-20 15:05 | coderabbit inline · P2 | apps/sim/lib/projects/files/application/uploads.ts:383 | defect-functional | **Do not let retired-upload cleanup replace the completion error.**
The cleanup handler does not run for an existing Project, so the quota-retry scenario does not schedule a prefix sweep. However, if `queueRetiredProjectUploadCleanup` fails, its error replaces the original completion error. Log cleanup failures and rethrow the original error.
Suggested fix
```diff
--- "a/apps/sim/lib/projects/files/application/uploads.ts"
+++ "b/apps/sim/lib/projects/files/application/uploads.ts"
@@ -377,9 +377,14 @@
return { value, completedFileId: value.file.id }
},
})
} catch (error) {
- await queueRetiredProjectUploadCleanup(loaded.session)
+ await queueRetire … the rest (868 characters)dProjectUploadCleanup(loaded.session).catch((cleanupError) => + logger.warn('Upload cleanup will be retried by expiry cleanup', { + uploadId: loaded.session.id, + error: cleanupError, + }) + ) throw error } } ) ``` 📝 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. ```suggestion } catch (error) { await queueRetiredProjectUploadCleanup(loaded.session).catch((cleanupError) => logger.warn('Upload cleanup will be retried by expiry cleanup', { uploadId: loaded.session.id, error: cleanupError, }) ) throw error } ``` |
| #9016 2026-10-20 15:05 | coderabbit review-body | — | summary | **Actionable comments posted: 5** |
| #9047 2026-10-20 15:13 | coderabbit issue-comment | — | summary | No actionable comments were generated in the recent review. 🎉
📝 Walkthrough
Synchronous resume execution now preserves partial results when a failure includes an execution result. The v2 route returns failed runs with structured errors, while the legacy route returns HTTP 400 for synchronous failures.
**Changes: Resume Failure Handling**
|Layer / File(s)|Summary|
|:---|:---|
|**Capture synchronous execution failures** `apps/sim/lib/workflows/executor/resume-execution.ts`|Synchronous resume results now include `structuredError`. When execution throws an error with an execution result, the executor preserves that result and returns a failed status. Errors without a result still propagate … the rest (4688 characters).| |**Expose failure responses and validate behavior** `apps/sim/app/api/v2/workflows/[workflowId]/runs/[runId]/resume/route.ts`, `apps/sim/app/api/resume/resume-handler.ts`, `apps/sim/app/api/v2/workflows/[workflowId]/runs/[runId]/resume/route.test.ts`, `apps/sim/app/api/resume/[workflowId]/[executionId]/[contextId]/route.test.ts`|The v2 route returns `result.structuredError`; its failure response includes the failed run and partial output. The legacy handler returns HTTP 400 with the error string or `Resume execution failed`. Tests cover both response behaviors and failures without an execution result.| **Priority:** ➖ Normal **Estimated code review effort:** 3 (Moderate) | ~20 minutes **Change:** Bug fix ### Sequence Diagram(s) ```mermaid sequenceDiagram participant Client participant V2ResumeRoute participant executeResumeWorkflow participant startResumeExecution V2ResumeRoute->>executeResumeWorkflow: starts synchronous resume executeResumeWorkflow->>startResumeExecution: starts execution startResumeExecution-->>executeResumeWorkflow: throws error with execution result executeResumeWorkflow-->>V2ResumeRoute: returns failed run with structuredError V2ResumeRoute-->>Client: returns HTTP 200 with failed run and partial output ``` **Suggested reviewers:** `icecrasher321`, `waleedlatif1` Merge Risk: ⚪ Minimal · up to 33df1 Synchronous resume failures can return a failed run with partial output, and the durable run is also marked failed. No issue identified here needs to block merging. Security architecture risk: 🔵 Low · up to 33df1 The change is narrowly scoped to authenticated resume responses and preserves existing workflow authorization. No introduced security defect was established, but returning failure details and partial output warrants care because it expands the information returned by this endpoint. **Retained concerns** No architecture-level concerns identified. Security review details **Security Blast Radius** - _inferred_ — The changed exposure is failure information and partial output returned to callers already authorized to resume the workflow run. The inspected path does not establish new unauthenticated, cross-workspace, infrastructure, or credential authority. **Trust Boundaries and Controls** - _observed_ — Request-controlled workflow, run, context, and resume input pass through mandatory authentication and request parsing, canonical run-to-workflow resolution, and workflow authorization. Returned inline files continue through per-file admission before delivery. **Resilience and Maintainability Implications** - _inferred_ — Distinguishing an executed failed run from a failed request improves failure containment without treating every exception as an ordinary run response. The guard is structural rather than proof of provenance, but the inspected resume path supplies execution-owned results and leaves observed admission and cleanup exceptions outside conversion. Pre-merge checks: 4 · 1 Failed checks: 1 warning | Check name | Status | Explanation | Resolution | | :---------------- | :----------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------- | | Docstring Coverage | | Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 4 functions across 5 files. | Write docstrings for the functions missing them to satisfy the coverage threshold. | Passed checks: 4 passed | Check name | Status | Explanation | | :------------------------ | :--------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------- | | Description Check | | Check skipped - the reviewer’s high-level summary is enabled. | | Title check | | The title clearly summarizes the main change: synchronous v2 resume requests now return the failed run instead of a 500 response. | | Linked Issues check | | Check skipped because no linked issues were found for this pull request. | | Out of Scope Changes check | | Check skipped because no linked issues were found for this pull request. | ✨ Finishing Touches: 💡 1 📝 Generate docstrings: 💡 🧪 Generate unit tests (beta) Comment `@the reviewer help` to get the list of available commands. |
| #9047 2026-10-20 15:16 | greptile issue-comment | — | summary | Confidence Score: 5/5
**[Medium impact]** The PR appears safe to merge; no actionable issues were found.
Reviews (1) · Last reviewed commit: "fix(resume): answer a sync v2 resume who..." · Reviewed by the reviewer |
| #9047 2026-10-20 15:22 | cubic inline · P2 | apps/sim/app/api/v2/workflows/[workflowId]/runs/[runId]/resume/route.test.ts:186 | docs | This test codifies block attribution for resume failures, but the public contract says resume responses omit block fields and report `EXECUTION_FAILED`. Update the contract descriptions to reflect this new response behavior so generated API documentation matches the endpoint. |
| #9047 2026-10-20 15:22 | cubic review-body | — | summary | **1 issue found** across 5 files
Reply with feedback, questions, or to request a fix.View guided diff | Turn on auto-fix | Re-trigger the reviewer |
| #9045 2026-10-20 15:28 | coderabbit issue-comment | — | summary | No actionable comments were generated in the recent review. 🎉
📝 Walkthrough
The change preserves database types in the active chunk context, serializes optional date fields in the internal route, and adds PostgreSQL integration tests for date fields across chunk projections.
**Changes: Knowledge chunk date tags**
|Layer / File(s)|Summary|
|:---|:---|
|**Preserve embedding row types** `apps/sim/lib/knowledge/application/contexts.ts`|`ActiveKnowledgeChunkContext.chunk` now uses the inferred embedding select-row type. Chunk resolution returns the queried row without a cast.|
|**Serialize date fields and verify projections** `apps/sim/lib/knowledge/api/internal-route.ts`, `apps/sim/lib/kno … the rest (2255 characters)wledge/__integration__/chunk-read-tags.integration.ts`|The internal route serializes present `date1` and `date2` fields as ISO strings or `null`, while absent fields remain absent. Integration tests check the internal response, chunk listing, and v2 projection.| **Priority:** ⬇️ Low **Estimated code review effort:** 2 (Simple) | ~15 minutes **Change:** Bug fix **Suggested reviewers:** `icecrasher321` Merge Risk: ⚪ Minimal · up to 99afc The date-tag response change has no identified merge-blocking issue; it is ready for normal checks. Pre-merge checks: 4 · 1 Failed checks: 1 warning | Check name | Status | Explanation | Resolution | | :---------------- | :----------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------- | | Docstring Coverage | | Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 3 functions across 3 files. | Write docstrings for the functions missing them to satisfy the coverage threshold. | Passed checks: 4 passed | Check name | Status | Explanation | | :------------------------ | :--------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------- | | Description Check | | Check skipped - the reviewer’s high-level summary is enabled. | | Title check | | The title clearly and concisely describes the main change: serializing chunk date tags in the internal knowledge chunk read. | | Linked Issues check | | Check skipped because no linked issues were found for this pull request. | | Out of Scope Changes check | | Check skipped because no linked issues were found for this pull request. | ✨ Finishing Touches: 💡 1 📝 Generate docstrings: 💡 🧪 Generate unit tests (beta) Comment `@the reviewer help` to get the list of available commands. |
| #9045 2026-10-20 15:38 | greptile issue-comment | — | summary | Confidence Score: 5/5
**[Medium impact]** Safe to merge within the reviewed scope: stored date tags serialize successfully, and internal list and v2 response fields remain unchanged.
Reviews (1) · Last reviewed commit: "fix(knowledge): serialize chunk date tag..." · Reviewed by the reviewer |
| #9049 2026-10-20 17:16 | coderabbit issue-comment | — | summary | No actionable comments were generated in the recent review. 🎉
📝 Walkthrough
The request context now includes an optional request URL. Upload origin resolution uses request headers first, then the request URL or configured base URL. Tests cover origin selection and in-process upload signing through CLI and MCP.
**Changes: Upload origin resolution**
|Layer / File(s)|Summary|
|:---|:---|
|**Request origin resolution and upload coverage** `apps/sim/lib/core/orchestration/types.ts`, `apps/sim/lib/uploads/upload-session/application.ts`, `apps/sim/lib/uploads/upload-session/application.test.ts`, `apps/sim/lib/uploads/upload-session/in-process-origin.integration.ts`|`OrchestrationRequestContex … the rest (4685 characters)t` gains an optional `url`. `requestOrigin` checks the Origin header, forwarded or host headers, the request URL, and the configured base URL. Tests cover origin selection and signed uploads through CLI and MCP. | **Priority:** ➖ Normal **Estimated code review effort:** 3 (Moderate) | ~20 minutes **Change:** Bug fix **Suggested reviewers:** `icecrasher321` Merge Risk: ⚪ Minimal · up to 34e34 Upload signing now works for in-process Chat CLI and MCP callers that send no browser or proxy headers. These calls fall back to the request's own URL and then to the configured app URL. Browser and proxied requests resolve their origin exactly as before. Tests cover each resolution step and the in-process upload flows, and no outstanding issue blocks merging. Security architecture risk: 🔵 Low · up to 34e34 The change restores upload URL generation for authenticated in-process callers without an identified authorization bypass or increase in storage privileges. Destination selection remains constrained by the configured endpoint and existing session-token controls. Deployment configuration and end-to-end recovery behavior were not validated. **Retained concerns** No architecture-level concerns identified. Security review details **Security Blast Radius** - _inferred_ — The newly successful path enables upload operations under the caller's existing authorization. A local transfer capability is bound to one persisted session; changing the destination does not itself grant access to another workspace, upload identifier, or storage provider. This assessment does not establish deployment-wide security coverage. **Security Findings and Attack Paths** - _inferred_ — No PR-introduced destination or authorization bypass was established in the inspected CLI and MCP paths. Network Origin and host headers already influenced transfer destinations at the base revision; that condition is not attributed to this PR. The new headerless path uses a configured MCP destination or the CLI transport's origin-checked endpoint. **Trust Boundaries and Controls** - _observed_ — MCP forwards the established credential, restricts caller-settable headers to the operation contract, and invokes the owning v2 route under the established token audience. CLI attaches private in-process invocation metadata. Upload control operations separately load principal-bound sessions and reauthorize access; request origin is not their authorization subject. **Resilience and Maintainability Implications** - _observed_ — Existing lifecycle mechanisms remain independent of request origin: local writes stage and size-check bytes with failure cleanup; completion uses lease-guarded claims, object-identity checks, completed-result loading, and recovery states; abort and expiry cleanup operate on persisted session/provider identity. These mechanisms were source-reviewed, not fault-injection tested, and do not establish freedom from every pre-existing race. Pre-merge checks: 4 · 1 Failed checks: 1 warning | Check name | Status | Explanation | Resolution | | :---------------- | :----------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------- | | Docstring Coverage | | Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 6 functions across 4 files. | Write docstrings for the functions missing them to satisfy the coverage threshold. | Passed checks: 4 passed | Check name | Status | Explanation | | :------------------------ | :--------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------------------------------- | | Description Check | | Check skipped - the reviewer’s high-level summary is enabled. | | Title check | | The title clearly and concisely describes the main change: fixing upload signing for in-process v2 callers without a network origin. | | Linked Issues check | | Check skipped because no linked issues were found for this pull request. | | Out of Scope Changes check | | Check skipped because no linked issues were found for this pull request. | ✨ Finishing Touches: 💡 1 📝 Generate docstrings: 💡 🧪 Generate unit tests (beta) Comment `@the reviewer help` to get the list of available commands. |
| #9049 2026-10-20 17:22 | greptile issue-comment | — | summary | Confidence Score: 5/5
**[Medium impact]** Safe to merge based on the verified origin-resolution behavior; no actionable issues were found.
Reviews (1) · Last reviewed commit: "fix(uploads): sign transfers for in-proc..." · Reviewed by the reviewer |
| #9045 2026-10-20 17:23 | cubic review-body | — | summary | **No issues found** across 3 files
View guided diff | Re-trigger the reviewer |
| #9049 2026-10-20 17:26 | cubic inline · P2 | apps/sim/lib/uploads/upload-session/in-process-origin.integration.ts:255 | tests | This check can accept a wrong host because `origin` is interpolated unescaped (`.` matches any character), and `token=` accepts an empty signature. Escape the origin and require a non-empty token.
```suggestion
new RegExp(
`^${origin.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}/api/v2/uploads/${uploadId}/parts/${partNumber}\\?token=[^&]+`
)
``` |
| #9049 2026-10-20 17:26 | cubic review-body | — | summary | **1 issue found** across 4 files
Reply with feedback, questions, or to request a fix.View guided diff | Turn on auto-fix | Re-trigger the reviewer |
| #9046 2026-10-20 17:27 | coderabbit issue-comment | — | summary | 📝 Walkthrough
The change adds stable codes for database-read and coalesced-read deadlines, classifies them as retryable infrastructure errors, and marks usage-unavailable preprocessing failures retryable. Tests cover these cases and preserve non-retryable payer-limit behavior. Usage-status failures now emit one log with the raw error and normalized cause.
**Changes: Usage Read Retry Handling**
|Layer / File(s)|Summary|
|:---|:---|
|**Read-deadline error codes and classification** `apps/sim/lib/db/read-retry.ts`, `apps/sim/lib/concurrency/singleflight.ts`, `apps/sim/lib/core/errors/retryable-infrastructure.ts`|Database-read and coalesced-settle timeout errors expose stable codes. The retr … the rest (4549 characters)yable infrastructure classifier recognizes both codes.| |**Usage-unavailable admission handling** `apps/sim/lib/execution/preprocessing.ts`, `apps/sim/lib/execution/preprocessing.test.ts`, `apps/sim/lib/billing/calculations/usage-monitor.ts`|Usage-unavailable preprocessing failures are retryable. Tests verify retryable read failures and non-retryable payer-limit failures. Usage-status error logging now includes the raw error and a normalized cause.| **Priority:** ⬇️ Low **Estimated code review effort:** 2 (Simple) | ~10 minutes **Change:** Bug fix **Suggested reviewers:** `waleedlatif1` Merge Risk: 🔵 Low · up to 9af1a The retry change has no established production blocker, but the new timing-dependent test should use a fake timer before merge. Security architecture risk: 🔵 Low · up to 9af1a Unavailable usage data still blocks execution, genuine usage-limit refusals remain non-retryable, and automatic admission retries retain their existing limits. No new authorization bypass was established. Some downstream timeout behavior remains incompletely verified, particularly where timed-out operations can continue running. **Retained concerns** No architecture-level concerns identified. Security review details **Security Blast Radius** - _inferred_ — The behavioral reach extends beyond automatic resumes because schedule and webhook setup handling also consume the shared classifier. Their inspected setup retry branches retain guards against retrying after workflow-core execution has started. **Trust Boundaries and Controls** - _observed_ — The inspected resume path validates persisted workflow, execution, workspace, actor, and billing bindings before admission. The retry-classification changes do not replace those identity checks with caller-selected authority. **Resilience and Maintainability Implications** - _observed_ — Resume-attempt failure handling releases the reservation before settling the failure. Admission failures preserve the pause for retry using the failure's retryable flag, while cancellation subscriptions and timeout resources are cleaned up in finally. - _observed_ — Coalescing timeouts evict the shared promise but leave the producer running. On the intended usage-admission path, cache writes occur after the caller receives a result, so a timed-out producer cannot later write its stale result through that cache path. **Hardening Proposals** - _proposed_ — Consider making effect-free retry eligibility explicit at the operation boundary rather than assuming every coalescing timeout represents a read with no effect. The helper also wraps credential minting, so future retry consumers should require an independent replay-safety guarantee. This is a contract-hardening proposal, not a demonstrated unsafe replay introduced by this PR. Pre-merge checks: 4 · 1 Failed checks: 1 warning | Check name | Status | Explanation | Resolution | | :---------------- | :----------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------- | | Docstring Coverage | | Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 4 functions across 6 files. | Write docstrings for the functions missing them to satisfy the coverage threshold. | Passed checks: 4 passed | Check name | Status | Explanation | | :------------------------ | :--------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------- | | Description Check | | Check skipped - the reviewer’s high-level summary is enabled. | | Title check | | The title clearly and concisely describes the main change: making automatic resumes retryable after read deadlines and unavailable usage data. | | Linked Issues check | | Check skipped because no linked issues were found for this pull request. | | Out of Scope Changes check | | Check skipped because no linked issues were found for this pull request. | ✨ Finishing Touches: 💡 1 📝 Generate docstrings: 💡 🧪 Generate unit tests (beta) Comment `@the reviewer help` to get the list of available commands. |
| #9046 2026-10-20 17:31 | coderabbit inline · P2 | apps/sim/lib/execution/preprocessing.test.ts:1127 | tests | **Use a fake timer for the settle-deadline test.**
`coalesceLocally(..., 1)` makes this unit test depend on a real timer. Start `resumeAdmission()`, advance a fake timer past the deadline, then assert the result. As per coding guidelines, “No real timers: `vi.useFakeTimers()`, `flushMicrotasks()`, or `flushMacrotask()`.”
_Source: Coding guidelines_ |
| #9046 2026-10-20 17:31 | coderabbit review-body | — | summary | **Actionable comments posted: 1** |
| #9046 2026-10-20 17:36 | cubic review-body | — | summary | **No issues found** across 6 files
View guided diff | Turn on auto-fix | Re-trigger the reviewer |
| #9046 2026-10-20 17:38 | greptile issue-comment | — | summary | Confidence Score: 5/5
**[Medium impact]** The tested changes are safe to merge: transient failures become retryable without bypassing usage checks or the tested downstream retry limits.
Reviews (1) · Last reviewed commit: "fix(resume): retry automatic resumes aft..." · Reviewed by the reviewer |
| #9055 2026-10-20 17:39 | coderabbit issue-comment | — | summary | 📝 Walkthrough
Folder lock checks now support a supplied database executor. The folder reorder route uses its active transaction for mutability checks. PostgreSQL integration tests cover successful reordering and rejection of moves involving locked folders.
**Changes: Folder reorder lock validation**
|Layer / File(s)|Summary|
|:---|:---|
|**Executor-aware lock checks** `packages/platform-authz/src/workflow.ts`|`getFolderLockStatus` and `assertFolderMutable` accept an optional database executor. The default remains `db`.|
|**Transactional reorder validation** `apps/sim/app/api/folders/reorder/route.ts`, `apps/sim/app/api/folders/reorder/route.integration.ts`|The route passes its active tra … the rest (3704 characters)nsaction to folder mutability checks. Integration tests verify unlocked folder reordering and `423` responses for ancestor-locked sources and locked destinations.| **Priority:** ⬇️ Low **Estimated code review effort:** 2 (Simple) | ~10 minutes **Change:** Bug fix **Suggested reviewers:** `waleedlatif1` Merge Risk: 🔵 Low · up to 43d68 The folder reorder change is mergeable with a small test-import cleanup; no material behavior risk is established. Security architecture risk: ⚪ Minimal · up to 43d68 The change preserves workspace authorization and folder-lock enforcement while removing a second database-connection dependency during reordering. No material security risk was found to be introduced or worsened. **Retained concerns** No architecture-level concerns identified. Security review details **Security Blast Radius** - _observed_ — Request-controlled workspace, folder, parent, and sort-order values reach database updates only after session authentication and workspace write authorization. Source folders are filtered to that workspace and resource type; destinations must also belong to that workspace and be active. The PR does not expand these authorization gates. **Trust Boundaries and Controls** - _inferred_ — Reorder and the updateFolder lock-toggle writer serialize through the same workspace/resource advisory transaction lock. Moving the ancestry reads onto tx preserves lock enforcement within that ordering boundary through commit or rollback, rather than hoisting policy checks outside it. **Resilience and Maintainability Implications** - _inferred_ — All lock checks precede batch writes. A lock failure therefore leaves no partial reorder, while later database failures abort the transaction. The retry wrapper reruns the complete callback only for designated PostgreSQL abort conditions; domain lock errors propagate immediately. Repeated successful requests assign the requested parent and order values rather than accumulate an operation. Pre-merge checks: 4 · 1 Failed checks: 1 warning | Check name | Status | Explanation | Resolution | | :---------------- | :----------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------- | | Docstring Coverage | | Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 4 functions across 3 files. | Write docstrings for the functions missing them to satisfy the coverage threshold. | Passed checks: 4 passed | Check name | Status | Explanation | | :------------------------ | :--------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------------------------- | | Description Check | | Check skipped - the reviewer’s high-level summary is enabled. | | Title check | | The title clearly and concisely describes the main change: running folder reorder lock checks through the reorder transaction. | | Linked Issues check | | Check skipped because no linked issues were found for this pull request. | | Out of Scope Changes check | | Check skipped because no linked issues were found for this pull request. | ✨ Finishing Touches: 💡 1 📝 Generate docstrings: 💡 🧪 Generate unit tests (beta) Comment `@the reviewer help` to get the list of available commands. |
| #9055 2026-10-20 17:42 | coderabbit review-body | — | summary | 🧹 Nitpick comments: 1
apps/sim/app/api/folders/reorder/route.integration.ts: 1
`9-9`: **🚀 Performance & Scalability** | **🔵 Trivial** | **💤 Low value**
**Import the test utilities from their subpaths.**
The integration-file rule requires direct testing-module imports. Use the available subpaths:
Suggested fix
```diff
-import { authMock, authMockFns, createMockRequest } from '@sim/testing'
+import { authMock, authMockFns } from '@sim/testing/mocks/auth.mock'
+import { createMockRequest } from '@sim/testing/mocks/request.mock'
``` |
| #9055 2026-10-20 17:45 | cubic review-body | — | summary | **No issues found** across 3 files
View guided diff | Turn on auto-fix | Re-trigger the reviewer |
| #9055 2026-10-20 17:48 | greptile issue-comment | — | summary | Confidence Score: 5/5
**[Medium impact]** Safe to merge based on the scoped checks: the connection fix works while preserving folder-lock enforcement.
Reviews (1) · Last reviewed commit: "fix(folders): run reorder lock checks on..." · Reviewed by the reviewer |
| #9051 2026-10-20 17:49 | coderabbit issue-comment | — | summary | 📝 Walkthrough
MCP routes now handle OAuth redirect-required errors. Task status routes distinguish service unavailability from timeouts. Workspace visit handling maps a missing user owner to an unauthorized response.
**Changes: MCP OAuth Reauthorization**
|Layer / File(s)|Summary|
|:---|:---|
|**Classify OAuth redirect errors during discovery** `apps/sim/lib/mcp/service.ts`, `apps/sim/lib/mcp/service.test.ts`|Discovery treats OAuth redirect-required errors as authorization errors. It returns no tools, records a disconnected status without an error, and does not add a failure cache entry.|
|**Return reauthorization responses from MCP routes** `apps/sim/app/api/mcp/tools/discover/route.ts` … the rest (5223 characters), `apps/sim/app/api/mcp/tools/discover/route.test.ts`, `apps/sim/app/api/v2/mcp-servers/utils.ts`, `apps/sim/app/api/v2/mcp-servers/[mcpServerId]/tools/route.test.ts`|The discovery route returns 401, and the server-tools route returns 409 for OAuth redirect-required errors. Tests verify the responses do not expose OAuth state.| **Task Status Service Errors** |Layer / File(s)|Summary| |:---|:---| |**Classify task-status request failures** `apps/sim/lib/mothership/tasks/application/read-status.ts`|Status retrieval preserves 404 handling and status parsing. Other non-OK responses and timeouts produce `TaskServiceUnavailableError` with a timeout flag.| |**Map task-service errors to route responses** `apps/sim/app/api/mothership/tasks/[taskId]/route.ts`, `apps/sim/lib/mothership/tasks/application/tasks.test.ts`|The task route maps service unavailability to 503 and timeouts to 504. Tests also verify successful status responses.| **Workspace Visit Owner Errors** |Layer / File(s)|Summary| |:---|:---| |**Recognize missing visit owners** `apps/sim/lib/workspaces/visits.ts`|Visit recording converts the specified user foreign-key violation into `WorkspaceOwnerMissingError` and rethrows other database errors.| |**Map missing owners to unauthorized responses** `apps/sim/app/api/workspaces/[id]/visit/route.ts`, `apps/sim/app/api/workspaces/[id]/visit/route.test.ts`|The route returns 401 for `WorkspaceOwnerMissingError`. Tests verify that a workspace foreign-key violation remains a 500 response.| **Priority:** ⬇️ Low **Estimated code review effort:** 3 (Moderate) | ~25 minutes **Change:** Bug fix **Suggested reviewers:** `waleedlatif1` Merge Risk: 🔵 Low · up to e736d Connection failures can still return 500 instead of 503. Correct that response mapping and the test imports before merging, or explicitly accept these bounded issues. Security architecture risk: 🔵 Low · up to e736d The changes preserve existing access controls while making reauthorization, deleted-account, and service-outage responses more specific. No introduced security vulnerability was established. Residual uncertainty concerns OAuth cleanup performed by an external dependency and asynchronous discovery-cache updates. **Retained concerns** No architecture-level concerns identified. Security review details **Security Blast Radius** - _observed_ — Discovery remains configured behind the existing read and MCP-use controls internally and API-key authentication with public API throttling on v2. Pending status updates require the matching workspace and server, exclude deleted rows, and guard against overwriting a newer connected result. **Trust Boundaries and Controls** - _observed_ — Successful task reads still validate the returned task ID and resolve owned-chat context before returning status data. Visit error handling delegates unmatched errors to the existing workspace-concealment policy rather than replacing authorization handling. **Resilience and Maintainability Implications** - _observed_ — Discovery metadata is not used as execution authority in the inspected execution method. Tool execution resolves server configuration for the supplied workspace and obtains a client using the server, workspace, and user identity before invoking the tool. Client leases are released, or non-pooled clients disconnected, on both success and failure. Pre-merge checks: 4 · 1 Failed checks: 1 warning | Check name | Status | Explanation | Resolution | | :---------------- | :----------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | :--------------------------------------------------------------------------------- | | Docstring Coverage | | Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 4 functions across 12 files. | Write docstrings for the functions missing them to satisfy the coverage threshold. | Passed checks: 4 passed | Check name | Status | Explanation | | :------------------------ | :--------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Description Check | | Check skipped - the reviewer’s high-level summary is enabled. | | Title check | | The title clearly summarizes the main API changes: MCP reauthorization mapping, deleted-account visit handling, and task-service outage status mapping. It is specific and related to the changeset. | | Linked Issues check | | Check skipped because no linked issues were found for this pull request. | | Out of Scope Changes check | | Check skipped because no linked issues were found for this pull request. | ✨ Finishing Touches: 💡 1 📝 Generate docstrings: 💡 🧪 Generate unit tests (beta) Comment `@the reviewer help` to get the list of available commands. |
| #9051 2026-10-20 17:55 | coderabbit inline · P2 | apps/sim/lib/mothership/tasks/application/read-status.ts:38 | defect-functional | **Map rejected task-service requests to 503.**
`fetchGo` rethrows connection failures. `fetchTaskStatus` converts only timeout errors, so a rejected request reaches the route's unhandled-error fallback and returns 500. Catch request failures separately and map them to `TaskServiceUnavailableError(false)`. Keep response parsing and 404 handling outside that catch. Add a route test for a rejected fetch that expects 503. |
| #9051 2026-10-20 17:55 | coderabbit review-body | — | summary | **Actionable comments posted: 1**
🧹 Nitpick comments: 1
apps/sim/app/api/workspaces/[id]/visit/route.test.ts: 1
`1-1`: **🚀 Performance & Scalability** | **🔵 Trivial** | **⚡ Quick win**
**Import the database mocks from their module.**
Line 1 adds `dbChainMockFns` and `resetDbChainMock` through the `@sim/testing` barrel. Import them from `@sim/testing/mocks/database.mock`, and move any remaining barrel imports in this file to their direct modules so the barrel no longer loads for this test. As per coding guidelines: “Import the one file you need”; “the `@sim/testing` barrel costs module-fetch time per test file.”
_Source: Coding guidelines_ |
| #9051 2026-10-20 17:57 | cubic review-body | — | summary | **1 issue found** across 12 files
Reply with feedback, questions, or to request a fix.View guided diff | Turn on auto-fix | Re-trigger the reviewer |
| #9051 2026-10-20 17:57 | cubic inline · P2 | apps/sim/lib/mothership/tasks/application/read-status.ts:38 | defect-functional | Map non-timeout `fetchGo` request failures to `TaskServiceUnavailableError(false)` so connection failures return 503 instead of falling through to the route’s 500 handler. Keep response parsing and 404 handling outside the request-failure catch. |
| #9051 2026-10-20 17:59 | greptile issue-comment | — | summary | Confidence Score: 5/5
**[Medium impact]** The reviewed changes are safe to merge based on the exercised error mappings, success responses, and authorization behavior.
Reviews (1) · Last reviewed commit: "fix(api): map MCP reauth redirect, delet..." · Reviewed by the reviewer |
| #9053 2026-10-20 18:00 | coderabbit issue-comment | — | summary | 📝 Walkthrough
AppConfig profile caching now supports Redis snapshots that Trigger.dev runs can adopt. Selected access-control, block-visibility, and feature-flag profiles enable sharing. Unit and integration tests cover snapshot publication, adoption, and fallback behavior.
**Changes: Shared AppConfig snapshots**
|Layer / File(s)|Summary|
|:---|:---|
|**Shared snapshot cache behavior** `apps/sim/lib/core/config/appconfig.ts`|The profile-fetch API accepts a sharing option. Cache entries retain raw configuration documents. Shared snapshots are published to Redis and adopted by Trigger.dev runs when they pass freshness checks; otherwise, the fetch falls back to AppConfig. Strict snapshot fe … the rest (6207 characters)tching remains non-shared.| |**Enable sharing for selected profiles** `apps/sim/lib/auth/access-control.ts`, `apps/sim/lib/auth/access-control.test.ts`, `apps/sim/lib/core/config/block-visibility.ts`, `apps/sim/lib/core/config/feature-flags.ts`, `apps/sim/lib/core/config/feature-flags.test.ts`, `apps/sim/lib/mothership/feature-flags.test.ts`|Access control, block visibility, and feature-flag profile fetches enable sharing with Trigger.dev runs. Related tests expect the sharing option.| |**Validate shared snapshot behavior** `apps/sim/lib/core/config/appconfig.test.ts`, `apps/sim/lib/core/config/appconfig.integration.ts`|Unit and Redis integration tests cover snapshot freshness, adoption, publication, fallback behavior, and protection against older snapshots replacing newer ones.| **Priority:** ⬇️ Low **Estimated code review effort:** 3 (Moderate) | ~20 minutes **Change:** Bug fix ### Sequence Diagram(s) ```mermaid sequenceDiagram participant AppProcess as App process participant AppConfig participant Redis participant TriggerRun as Trigger.dev run AppProcess->>AppConfig: Poll for profile AppConfig-->>AppProcess: Return profile document AppProcess->>Redis: Publish validated snapshot TriggerRun->>Redis: Read shared snapshot Redis-->>TriggerRun: Return snapshot TriggerRun->>TriggerRun: Adopt snapshot if fresh ``` **Suggested reviewers:** `waleedlatif1` Merge Risk: 🔵 Low · up to becd4 Trigger.dev runs can now reuse AppConfig snapshots that app processes publish to Redis. Feature flags, block visibility, and access-control lists in runs can lag a configuration change by up to about 150 seconds, rather than the stated 120. Separately, a test leaves a stubbed Redis client in place for later tests in the same file. Both are small fixes, and the change is mergeable once the staleness bound is either tightened or documented. Security architecture risk: 🟡 Moderate · up to becd4 Shared configuration becomes an additional source for security-relevant decisions. Validation, freshness checks, fallback, and isolation of strict reads reduce risk, but production writer permissions and deployment isolation remain unconfirmed. **Retained concerns** No architecture-level concerns identified. Security review details **Security Blast Radius** - _inferred_ — The sharing unit is an application/environment/profile tuple, not an individual user. A corrupted shared access-control record could therefore affect eligible run-side decisions for multiple users using that tuple. This does not establish cross-tenant reachability, and ordinary application reads do not adopt Redis snapshots. **Security Findings and Attack Paths** - _inferred_ — A principal able to replace the matching Redis key could supply a fresh, parseable policy that a cold Trigger.dev reader accepts without contacting AppConfig. The prerequisite write capability was not established for an attacker or another tenant; this is an authority dependency, not a verified attack path. **Trust Boundaries and Controls** - _observed_ — Age checks and reparsing constrain accepted content but do not authenticate its publisher. Strong counterevidence against broader exposure is the explicit profile opt-in, run-only adoption, non-run publication, and strict API isolation. Tests directly cover these guards and fallback on Redis or parser failure. **Resilience and Maintainability Implications** - _observed_ — The 120-second check bounds adoption age, not every subsequently served value. Adopted entries receive a 30-second local TTL and use existing stale-while-revalidate behavior. Last-known-value recovery and stale serving predate this PR; the new effect is allowing fresh run processes to initialize from shared state. **Hardening Proposals** - _proposed_ — Confirm and document deployment-specific keyspace isolation and restrict snapshot writes to trusted publishers, with run principals read-only for these keys where supported. If access-control requires monotonic revocation or a hard serving-age limit, define that requirement explicitly and use revision-aware ordering or a strict freshness-enforcing consumer rather than relying on validation timestamps alone. Pre-merge checks: 4 · 1 Failed checks: 1 warning | Check name | Status | Explanation | Resolution | | :---------------- | :----------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | :--------------------------------------------------------------------------------- | | Docstring Coverage | | Docstring coverage is 75.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 12 functions across 9 files. | Write docstrings for the functions missing them to satisfy the coverage threshold. | Passed checks: 4 passed | Check name | Status | Explanation | | :------------------------ | :--------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------- | | Description Check | | Check skipped - the reviewer’s high-level summary is enabled. | | Title check | | The title clearly and concisely describes the main change: sharing polled AppConfig snapshots with Trigger.dev runs. | | Linked Issues check | | Check skipped because no linked issues were found for this pull request. | | Out of Scope Changes check | | Check skipped because no linked issues were found for this pull request. | ✨ Finishing Touches: 💡 1 📝 Generate docstrings: 💡 🧪 Generate unit tests (beta) ### Usage-based review receipt - Mode: Continue automatically - Reviewed files: 9 - Waived: $2.25 (charged $0.00) - View usage details > [!NOTE] > This review exceeded your plan’s limits and used usage-based reviews—free during trial, billed after paid activation unless disabled. **Manage usage-based reviews**. Comment `@the reviewer help` to get the list of available commands. |
| #9053 2026-10-20 18:04 | coderabbit inline · P2 | apps/sim/lib/core/config/appconfig.test.ts:266 | tests | **Reset `mockGetRedisClient` in `beforeEach`.**
`redisReturning` calls `mockReturnValue` on the central `redisConfigMockFns.mockGetRedisClient`. The shared config resets do not undo this. The stub Redis client therefore stays in place for every later test in the file. A `*Once` variant does not work here, because adoption and publication each call `getRedisClient`. Add `redisConfigMockFns.mockGetRedisClient.mockReset()` to this `beforeEach`.
Proposed fix
```diff
beforeEach(() => {
+ redisConfigMockFns.mockGetRedisClient.mockReset()
mockSend.mockImplementation(sessionResponses)
markInsideTriggerRun()
})
```
As per coding guidelines: "a test that installs a permanent one … the rest (104 characters)calls `mockFoo.mockReset()` (which restores the default) in `beforeEach`." _Source: Coding guidelines_ |
| #9053 2026-10-20 18:04 | coderabbit inline · P2 | apps/sim/lib/core/config/appconfig.ts:106 | defect-functional | **Limit the adopted entry's TTL to the remaining freshness window.**
The adoption path always sets `options.ttl = DEFAULT_TTL_MS`. A snapshot that is 119 seconds old is accepted and then cached for 30 more seconds. After that, `allowStale: true` serves the old value while the refresh runs. A run can therefore use a value about 150 seconds old.
The TSDoc on `AppConfigProfileOptions` promises a bound of `SHARED_SNAPSHOT_MAX_AGE_MS`. The PR states a worst case of about 120 seconds. This matters for `access-control`, where blocked and allowed login lists stay stale for longer than documented.
To fix this, return the remaining window from `adoptSharedSnapshot` and use it as the TTL. Otherwise, … the rest (984 characters)update the documented bound to `SHARED_SNAPSHOT_MAX_AGE_MS + DEFAULT_TTL_MS`. Proposed fix ```diff --- "a/apps/sim/lib/core/config/appconfig.ts" +++ "b/apps/sim/lib/core/config/appconfig.ts" @@ -100,10 +100,13 @@ remoteMatchesValue: false, strict: context.strict, } - if (!entry.nextToken && context.shared && (await adoptSharedSnapshot(context, entry))) { - options.ttl = DEFAULT_TTL_MS - return entry - } + if (!entry.nextToken && context.shared) { + const remainingMs = await adoptSharedSnapshot(context, entry) + if (remainingMs !== null) { + options.ttl = Math.max(1, Math.min(DEFAULT_TTL_MS, remainingMs)) + return entry + } + } options.ttl = await poll(context.ids, context.parse, entry) if (context.shared) publishSharedSnapshot(context.ids, entry) return entry ``` In `adoptSharedSnapshot`, return `SHARED_SNAPSHOT_MAX_AGE_MS - Math.max(0, age)` on success and `null` on every fallback. |
| #9053 2026-10-20 18:04 | coderabbit review-body | — | summary | **Actionable comments posted: 2** |
| #9053 2026-10-20 18:10 | greptile issue-comment | — | summary | Confidence Score: 5/5
**[Medium impact]** No blocking issues were found in the scoped checks of snapshot adoption, fallback behavior, publication ordering, and strict-read isolation.
Reviews (1) · Last reviewed commit: "fix(appconfig): share the polled snapsho..." · Reviewed by the reviewer |
| #9053 2026-10-20 18:11 | cubic inline · P2 | apps/sim/lib/core/config/appconfig.ts:104 | defect-functional | Cap the adopted entry's TTL to its remaining freshness window; a snapshot accepted at nearly 120 seconds old can otherwise be returned as stale again after the fixed 30-second TTL. |
| #9053 2026-10-20 18:11 | cubic review-body | — | summary | **1 issue found** across 9 files
Reply with feedback, questions, or to request a fix.View guided diff | Turn on auto-fix | Re-trigger the reviewer |
| #9054 2026-10-20 18:12 | coderabbit issue-comment | — | summary | No actionable comments were generated in the recent review. 🎉
📝 Walkthrough
BYOK lookup now retries transient database failures, observes abort signals, and throws on lookup or decryption failures. Enterprise subscription-read errors can propagate through entitlement checks. Provider and hosted-tool callers pass cancellation signals into BYOK resolution.
**Changes: BYOK Resolution and Enterprise Entitlements**
|Layer / File(s)|Summary|
|:---|:---|
|**Enterprise subscription error propagation** `apps/sim/lib/billing/core/subscription.ts`, `apps/sim/lib/billing/core/subscription.integration.ts`, `apps/sim/lib/billing/core/subscription.test.ts`, `apps/sim/lib/billing/core/inbox-entitlemen … the rest (6144 characters)t.test.ts`|Enterprise plan checks request thrown subscription-read errors. Organization and personal subscription reads now receive the selected error policy. Tests cover subscription error propagation and updated lookup arguments.| |**Retryable BYOK resolution and explicit failures** `apps/sim/lib/api-key/byok.ts`, `apps/sim/lib/api-key/byok.test.ts`, `apps/sim/lib/api-key/byok.integration.ts`, `apps/sim/lib/mothership/request/enterprise-byok.ts`|BYOK lookup retries transient database errors within a deadline and accepts an abort signal. Lookup and decryption failures throw; `null` is returned only when eligible credentials are absent. Tests cover entitlement outcomes, retries, timeout, and credential selection.| |**Cancellation forwarding to provider and tool callers** `apps/sim/providers/index.ts`, `apps/sim/providers/index.test.ts`, `apps/sim/tools/index.ts`, `apps/sim/tools/index.test.ts`, `packages/testing/src/mocks/api-key-byok.mock.ts`|Provider and hosted-tool lookup paths forward abort signals. Hosted-tool BYOK failures now propagate before provider dispatch, rate limiting, or cost metering. The mock option now accepts an abort signal.| **Priority:** ➖ Normal **Estimated code review effort:** 4 (Complex) | ~45 minutes **Change:** Bug fix ### Sequence Diagram(s) ```mermaid sequenceDiagram participant ProviderRequest participant getApiKeyWithBYOK participant getBYOKKey participant Database ProviderRequest->>getApiKeyWithBYOK: provider, model, workspace, abort signal getApiKeyWithBYOK->>getBYOKKey: BYOK lookup with abort signal getBYOKKey->>Database: credential query ``` **Suggested reviewers:** `waleedlatif1`, `sg312` Merge Risk: ⚪ Minimal · up to 42a05 When a customer-key lookup or decryption fails, the request now stops instead of silently running on platform credentials. Brief database errors are retried a few times within a short deadline, and caller cancellation is respected. Enterprise eligibility failures surface as errors instead of being treated as "not eligible." No concrete defect was found in the changed paths, and the change appears ready to merge. Security architecture risk: 🔵 Low · up to 42a05 The change strengthens customer credential ownership by stopping requests when credentials or eligibility cannot be resolved. No newly introduced ownership bypass was identified in the reviewed paths, but stricter failure handling affects several shared execution flows. **Retained concerns** No architecture-level concerns identified. Security review details **Security Blast Radius** - _inferred_ — The affected security boundary is customer-versus-platform credential use and associated billing attribution across shared provider, hosted-tool, and enterprise Copilot execution. Organization inheritance extends the effect to eligible workspaces using an organization's provider-key pool; this is broader than a single endpoint but does not introduce a new credential owner. **Trust Boundaries and Controls** - _observed_ — The examined consumers do not convert credential-resolution errors into hosted-key continuation. Providers rethrow before dispatch; hosted-tool acquisition awaits BYOK resolution first; title generation returns without issuing its model request on error. Checkpoint resolution occurs before dispatch, while a failed subagent resolution cancels sibling legs and rethrows after they settle. **Resilience and Maintainability Implications** - _observed_ — The deadline bounds the caller's wait, not the underlying database command: database queries do not receive the abort signal. Late completion is checked before further credential selection and before returning a result, containing the ownership outcome while leaving outstanding database work as a resource limitation. **Hardening Proposals** - _proposed_ — Align hosted-key acquisition with the effective cancellation signal already passed to BYOK resolution and tool transport. Acquisition still uses only executionContext.abortSignal, including at the comparison base; this would improve an existing cancellation inconsistency rather than fix an introduced ownership bypass. Pre-merge checks: 4 · 1 Failed checks: 1 warning | Check name | Status | Explanation | Resolution | | :---------------- | :----------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------- | | Docstring Coverage | | Docstring coverage is 72.73% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 11 functions across 12 files. | Write docstrings for the functions missing them to satisfy the coverage threshold. | Passed checks: 4 passed | Check name | Status | Explanation | | :------------------------ | :--------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------- | | Description Check | | Check skipped - the reviewer’s high-level summary is enabled. | | Title check | | The title clearly identifies the main change: preserving credential ownership when BYOK lookup failures occur. | | Linked Issues check | | Check skipped because no linked issues were found for this pull request. | | Out of Scope Changes check | | Check skipped because no linked issues were found for this pull request. | ✨ Finishing Touches: 💡 1 📝 Generate docstrings: 💡 🧪 Generate unit tests (beta) ### Usage-based review receipt - Mode: Continue automatically - Reviewed files: 12 - Waived: $3.00 (charged $0.00) - View usage details > [!NOTE] > This review exceeded your plan’s limits and used usage-based reviews—free during trial, billed after paid activation unless disabled. **Manage usage-based reviews**. Comment `@the reviewer help` to get the list of available commands. |
| #9054 2026-10-20 18:21 | greptile issue-comment | — | summary | Confidence Score: 5/5
**[High impact]** No merge-blocking issues were identified in the reviewed scope; focused execution supports the fail-closed credential and entitlement behavior.
Reviews (1) · Last reviewed commit: "fix(byok): preserve credential ownership..." · Reviewed by the reviewer |
| #9054 2026-10-20 18:22 | cubic inline · P2 | apps/sim/tools/index.ts:1851 | defect-functional | Pass this signal to `acquireKey` as well; a canceled standalone `executeTool({ signal })` can otherwise remain queued until the limiter's default wait expires. |
| #9054 2026-10-20 18:22 | cubic inline · P2 | apps/sim/tools/index.test.ts:6319 | tests | `resetEnvFlagsMock()` clears the file-wide `isDev: true` baseline, so later tests run with different environment flags. Restore only this test’s `isHosted` override instead. |
| #9054 2026-10-20 18:22 | cubic inline · P2 | apps/sim/lib/mothership/request/enterprise-byok.ts:9 | defect-functional | Enterprise BYOK resolution drops the lifecycle cancellation signal while the new lookup can retry for up to five seconds. Thread the active `AbortSignal` through `resolveEnterpriseByokKey` and its lifecycle callers so cancellation interrupts the lookup and backoff. |
| #9054 2026-10-20 18:22 | cubic inline · P2 | apps/sim/lib/api-key/byok.ts:243 | defect-functional | Several BYOK callers still omit the new `AbortSignal`, so canceled Pi, embedding, and knowledge operations can remain blocked in the five-second lookup/retry window and continue database work. Thread each operation's existing signal through `getBYOKKey`/`getApiKeyWithBYOK` at these call sites. |
| #9054 2026-10-20 18:22 | cubic review-body | — | summary | **4 issues found** across 13 files
View guided diff | Turn on auto-fix | Re-trigger the reviewer |
| #9056 2026-10-20 18:23 | coderabbit issue-comment | — | summary | 📝 Walkthrough
The changes update workflow confirmation and cancellation handling, ingest proxy responses to client aborts, and Stripe plan classification and unresolved-price logging.
**Changes: Workflow handling**
|Layer / File(s)|Summary|
|:---|:---|
|**Workflow confirmation reconciliation** `apps/sim/app/api/copilot/confirm/route.ts`, `apps/sim/app/api/copilot/confirm/route.test.ts`|Workflow acknowledgements validate execution IDs and return stored terminal outcomes. Tests cover matching and conflicting settlements.|
|**Cancellation logging** `apps/sim/lib/execution/cancel-workflow-execution.ts`, `apps/sim/lib/execution/cancel-workflow-execution.test.ts`|Non-internal orchestration err … the rest (4673 characters)ors are logged at info level; other errors remain error-level. The terminal-race test checks that no error is logged.| **Ingest proxy** |Layer / File(s)|Summary| |:---|:---| |**Client abort handling** `apps/sim/app/ingest/[[...path]]/route.ts`, `apps/sim/app/ingest/[[...path]]/route.test.ts`|Aborted client requests receive HTTP 499 and an informational log. Tests also cover upstream failures returning 502 and logging the failure.| **Billing plan resolution** |Layer / File(s)|Summary| |:---|:---| |**Plan classification and price detection** `apps/sim/lib/billing/plan-helpers.ts`, `apps/sim/lib/billing/plans.ts`, `apps/sim/lib/billing/plans.test.ts`, `packages/testing/src/mocks/billing-plan-helpers.mock.ts`|The billing helpers identify legacy plans and detect subscription price changes. Tests and mock wiring cover the added helpers.| |**Stripe plan logging** `apps/sim/lib/auth/auth.ts`|Subscription hooks use centralized unresolved-plan logging. Subscription updates pass whether the Stripe price changed.| **Priority:** ⬇️ Low **Estimated code review effort:** 3 (Moderate) | ~25 minutes **Change:** Bug fix **Suggested reviewers:** `waleedlatif1` Merge Risk: 🟡 Moderate · up to a2ab0 A workflow confirmation without an execution ID can acknowledge another execution’s result. The ingest proxy can also continue work after a disconnect or hide an upstream failure. Fix these paths before merging. Security architecture risk: 🔵 Low · up to a2ab0 The changes are bounded to existing request flows and billing diagnostics. Authentication, ownership checks, and guarded settlement remain intact, and the new race acknowledgement does not repeat writes or notifications. Execution-identity compatibility and live disconnect behavior remain areas of limited assurance. **Retained concerns** No architecture-level concerns identified. Security review details **Security Blast Radius** - _inferred_ — The changed workflow acknowledgement remains scoped to a tool call whose persisted run belongs to the authenticated user. Returning its canonical terminal status after a race does not demonstrate additional tenant access, workflow execution authority, or repeated settlement effects. **Trust Boundaries and Controls** - _observed_ — Session authentication, tool-call lookup, run lookup, and run.userId authorization precede terminal acknowledgement and settlement. Normal workflow settlement also retains foreign-claim checks and trusted execution lookup bound to workflowId and toolCallId. **Resilience and Maintainability Implications** - _observed_ — The new ingest branch classifies failure using the incoming signal alone; the outbound fetch still receives no cancellation signal. This omission predates the PR. Consequently, the 499 response is not evidence that upstream work is cancelled, and an upstream failure coinciding with client abort also receives informational classification. Pre-merge checks: 4 · 1 Failed checks: 1 warning | Check name | Status | Explanation | Resolution | | :---------------- | :----------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------- | | Docstring Coverage | | Docstring coverage is 42.11% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 19 functions across 11 files. | Write docstrings for the functions missing them to satisfy the coverage threshold. | Passed checks: 4 passed | Check name | Status | Explanation | | :------------------------ | :--------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------------------------------------------- | | Description Check | | Check skipped - the reviewer’s high-level summary is enabled. | | Title check | | The title accurately summarizes the two main changes: lowering log severity for expected outcomes and acknowledging a lost workflow-result race. | | Linked Issues check | | Check skipped because no linked issues were found for this pull request. | | Out of Scope Changes check | | Check skipped because no linked issues were found for this pull request. | ✨ Finishing Touches: 💡 1 📝 Generate docstrings: 💡 🧪 Generate unit tests (beta) Comment `@the reviewer help` to get the list of available commands. |
| #9056 2026-10-20 18:29 | coderabbit inline · P2 | apps/sim/app/api/copilot/confirm/route.ts:121 | defect-security | **Reject a missing execution ID for settled workflow calls.**
The confirmation contract permits an omitted `executionId`. A terminal workflow call then reaches `acknowledgeSettledWorkflowToolCall`, whose guard skips comparison when the submitted ID is absent. A stale confirmation can therefore receive `200` with another execution's stored terminal result. The same path is used after a settlement conflict.
Suggested fix
```diff
- if (executionId && submittedExecutionId !== undefined && submittedExecutionId !== executionId) {
+ if (executionId && submittedExecutionId !== executionId) {
``` |
| #9056 2026-10-20 18:29 | coderabbit inline · P2 | apps/sim/app/ingest/[[...path]]/route.ts:60 | defect-performance | **Connect client cancellation to the outbound fetch.**
If the client disconnects while PostHog is still responding, `request.signal.aborted` does not cancel this `fetch`: the call has no `signal` option. The catch branch may never run, and the upstream request can continue after the client leaves. Pass `request.signal` to `fetch` and test an abort after the request starts; the current test supplies an unrelated mock rejection. A fetch uses an abort signal only when its request is associated with that signal. (developer.mozilla.org) |
| #9056 2026-10-20 18:29 | coderabbit inline · P2 | apps/sim/app/ingest/[[...path]]/route.ts:63 | defect-functional | **Classify the caught error before reporting a client abort.**
If an upstream failure rejects after the client has disconnected, this condition reports `499` and suppresses the upstream error log. Check that the caught error represents cancellation before logging it as a closed request. Keep unrelated failures on the `502` error path.
_Source: Learnings_ |
| #9056 2026-10-20 18:29 | coderabbit review-body | — | summary | **Actionable comments posted: 3**
🧹 Nitpick comments: 1
apps/sim/lib/billing/plans.test.ts: 1
`17-17`: **📐 Maintainability & Code Quality** | **🔵 Trivial** | **💤 Low value**
**Name the test group for its behavior.**
`didSubscriptionPriceChange` names the implementation. Name the group for subscription price-change detection instead. As per coding guidelines, “Name the `describe`/`it` for the behavior and the condition … never the implementation.”
_Source: Coding guidelines_ |
| #9056 2026-10-20 18:32 | greptile issue-comment | — | summary | Confidence Score: 5/5
**[Medium impact]** No blocking issues were found in the reviewed changes, and the executed workflow confirmation and analytics proxy checks passed.
Reviews (1) · Last reviewed commit: "fix(logging): log expected outcomes belo..." · Reviewed by the reviewer |
| #9056 2026-10-20 18:35 | cubic inline · P2 | apps/sim/app/ingest/[[...path]]/route.test.ts:29 | tests | The controller is already aborted before `POST`, and this unconditional rejection never depends on the fetch options, so the test passes without verifying mid-request cancellation. Abort after fetch starts and make the mock reject in response to the signal passed to `fetch`. |
| #9056 2026-10-20 18:35 | cubic review-body | — | summary | **4 issues found** across 11 files
Reply with feedback, questions, or to request a fix.View guided diff | Turn on auto-fix | Re-trigger the reviewer |
| #9056 2026-10-20 18:35 | cubic inline · P2 | apps/sim/app/api/copilot/confirm/route.ts:105 | defect-security | Reject settled workflow results when the submitted execution ID is missing; otherwise the missing value bypasses the check and returns another execution’s stored outcome.
```suggestion
if (executionId && submittedExecutionId !== executionId) {
``` |
| #9056 2026-10-20 18:35 | cubic inline · P2 | apps/sim/app/ingest/[[...path]]/route.ts:60 | defect-functional | Check that the caught error is an abort before returning 499; `request.signal.aborted` alone can misclassify a PostHog failure and suppress its error log.
```suggestion
if (request.signal.aborted && error instanceof Error && error.name === 'AbortError') {
``` |
| #9056 2026-10-20 18:35 | cubic inline · P2 | apps/sim/app/ingest/[[...path]]/route.ts:60 | defect-performance | Pass `request.signal` to the outbound `fetch`; otherwise a disconnected client leaves the PostHog request running and this catch cannot return 499 until upstream settles. |
| #9048 2026-10-20 18:37 | coderabbit issue-comment | — | summary | No actionable comments were generated in the recent review. 🎉
📝 Walkthrough
Snapshot copy failures now produce classified orchestration errors, and invalid workspace file references now produce validation errors. Tests cover both error paths and confirm that snapshot read failures propagate through chat reads.
**Changes: Sandbox snapshot failures**
|Layer / File(s)|Summary|
|:---|:---|
|**Classify and map snapshot failures** `apps/sim/lib/execution/remote-sandbox/session-file-snapshot.ts`, `apps/sim/lib/execution/remote-sandbox/session-file-snapshot.test.ts`, `apps/sim/lib/mothership/chat/application/read-sandbox-file.test.ts`|Snapshot copy failures use structured markers that map to o … the rest (4032 characters)rchestration error codes and messages. A missing workbench produces a `not_found` error. Tests cover classified and unclassified failures, stderr handling, and propagation through chat reads.| **Workspace reference validation** |Layer / File(s)|Summary| |:---|:---| |**Convert invalid references to validation errors** `apps/sim/lib/workspace-files/application/resolve-workspace-file-reference.ts`, `apps/sim/lib/workspace-files/application/resolve-workspace-file-reference.test.ts`, `scripts/check-unused-exports.baseline.json`|Workspace reference resolution converts `VfsPathError` failures to validation errors and rethrows other errors unchanged. Tests cover invalid URL references and skipped context loading. The unused-export baseline no longer lists `VfsPathError`.| **Priority:** ⬇️ Low **Estimated code review effort:** 3 (Moderate) | ~25 minutes **Change:** Bug fix Merge Risk: ⚪ Minimal · up to 0b1a6 File-read failures now provide actionable messages for classified cases. No change-introduced issue remains identified before merge. Architecture risk: 🔵 Low · up to 0b1a6 The change affects 2 systems. **Changed systems:** `apps/sim`, `scripts` **Architecture concerns** No architecture-level concerns identified. Review details **Systems and components** - _observed_ — apps/sim (service) was modified; 5 changed files map to changed impact. - _observed_ — scripts (service) was modified; 1 changed file maps to changed impact. **Before / after behavior** - _observed_ — Modified behavior in apps/sim/lib/execution/remote-sandbox/session-file-snapshot.test.ts: Updated test imports to use `spawnSync`, filesystem helpers, networking utilities, and `describe`; removed promisification and the previous error-message helper. - _observed_ — Modified behavior in apps/sim/lib/execution/remote-sandbox/session-file-snapshot.test.ts: Added the `fileReadFailure` import used to inspect normalized model-facing read errors; removed the obsolete promisified command executor. - _observed_ — Modified behavior in apps/sim/lib/execution/remote-sandbox/session-file-snapshot.test.ts: Replaced asynchronous `execFile` handling with synchronous `/bin/sh -c` execution, returning the actual exit status and captured output instead of forcing success or synthesizing a generic stderr on failure. - _observed_ — Modified behavior in apps/sim/lib/execution/remote-sandbox/session-file-snapshot.test.ts: Strengthened the symlink-escape assertion to require the complete permitted-workbench-directories error message. Pre-merge checks: 5 | Check name | Status | Explanation | | :------------------------ | :--------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Description Check | | Check skipped - the reviewer’s high-level summary is enabled. | | Title check | | The title clearly and concisely describes the primary change: exposing actionable workbench file-read failures through the mothership flow. | | Docstring Coverage | | Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 3 functions across 5 files. | | Linked Issues check | | Check skipped because no linked issues were found for this pull request. | | Out of Scope Changes check | | Check skipped because no linked issues were found for this pull request. | ✨ Finishing Touches 📝 Generate docstrings 🧪 Generate unit tests (beta) ### Usage-based review receipt - Mode: Continue automatically - Reviewed files: 5 - Waived: $1.25 (charged $0.00) - View usage details > [!NOTE] > This review exceeded your plan’s limits and used usage-based reviews—free during trial, billed after paid activation unless disabled. **Manage usage-based reviews**. Comment `@the reviewer help` to get the list of available commands. |
| #9048 2026-10-20 18:44 | cubic review-body | — | summary | **No issues found** across 6 files
View guided diff | Turn on auto-fix | Re-trigger the reviewer |
| #9048 2026-10-20 18:46 | greptile issue-comment | — | summary | Confidence Score: 5/5
**[Medium impact]** The reviewed changes are safe to merge; no issues requiring changes were found.
Reviews (1) · Last reviewed commit: "fix(mothership): surface actionable work..." · Reviewed by the reviewer |
| #9052 2026-10-20 18:52 | coderabbit issue-comment | — | summary | 📝 Walkthrough
The organization and workspace layouts now expose the Projects rollout flag. Project-list requests and project restriction UI are gated by that flag.
**Changes: Projects rollout**
|Layer / File(s)|Summary|
|:---|:---|
|**Resolve and expose the Projects flag** `apps/sim/lib/projects/rollout.server.ts`, `apps/sim/app/o/[organizationId]/layout.tsx`, `apps/sim/app/workspace/[workspaceId]/layout.tsx`, `apps/sim/app/workspace/[workspaceId]/providers/feature-flags-provider.tsx`|The server helper resolves the Projects flag. Both layouts provide its value, and `WorkspaceFeatureFlags` includes the optional `projects` flag.|
|**Gate project-list queries** `apps/sim/hooks/queries/proje … the rest (4730 characters)cts.ts`|`useProjects` enables requests only when the Projects flag is on and the organization ID is non-empty.| |**Gate project restriction UI** `apps/sim/ee/access-control/components/project-issue-restrictions.tsx`, `apps/sim/ee/access-control/components/project-issue-restrictions.test.tsx`|The component suppresses its UI when Projects is disabled. Tests cover disabled, enabled, and toggled-off states.| **Priority:** ⬇️ Low **Estimated code review effort:** 2 (Simple) | ~10 minutes **Change:** Bug fix ### Sequence Diagram(s) ```mermaid sequenceDiagram participant WorkspaceLayout participant isProjectsEnabled participant FeatureFlagsProvider participant useProjects participant ProjectsAPI participant ProjectIssueRestrictions WorkspaceLayout->>isProjectsEnabled: Resolve Projects flag WorkspaceLayout->>FeatureFlagsProvider: Provide Projects flag FeatureFlagsProvider->>useProjects: Expose flag to query hook useProjects->>ProjectsAPI: Request projects when enabled and organization ID is present useProjects->>ProjectIssueRestrictions: Return project query state ProjectIssueRestrictions->>ProjectIssueRestrictions: Suppress UI when disabled ``` **Suggested reviewers:** `waleedlatif1`, `mzxchandra` Merge Risk: 🔵 Low · up to a06d9 The rollout change is mergeable with a small test-import cleanup; no material Projects gating failure is established. Security architecture risk: 🔵 Low · up to a06d9 The change limits client requests without replacing server authorization or clearing existing restrictions. No introduced security weakness was demonstrated, but the query-to-UI activation contract still needs confirmation. **Retained concerns** No architecture-level concerns identified. Security review details **Security Blast Radius** - _inferred_ — The availability decision is deployment-wide, but the inspected list endpoint remains bounded by the authenticated principal's grants. An organization ID supplied in the request filters inventory rather than independently granting access. **Trust Boundaries and Controls** - _observed_ — The client flag is an availability and presentation gate, not a replacement authorization control. The unchanged list route requires session authentication and rate limiting; its application operation checks the principal, enforces the server rollout flag, derives candidates from caller access, and invokes authorization before returning projects. **Resilience and Maintainability Implications** - _inferred_ — Hiding the picker does not introduce a restriction-clearing transition. The editor retains its buffer on save failure, and server updates merge configuration transactionally. Cached or late project-list responses only affect choices and do not themselves write policy, so interruption or off/on recovery does not create a new policy-widening path in the inspected flow. Pre-merge checks: 4 · 1 Failed checks: 1 warning | Check name | Status | Explanation | Resolution | | :---------------- | :----------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------- | | Docstring Coverage | | Docstring coverage is 57.14% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 7 functions across 7 files. | Write docstrings for the functions missing them to satisfy the coverage threshold. | Passed checks: 4 passed | Check name | Status | Explanation | | :------------------------ | :--------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------- | | Description Check | | Check skipped - the reviewer’s high-level summary is enabled. | | Title check | | The title clearly and concisely describes the main change: gating the Project list on the projects rollout flag. | | Linked Issues check | | Check skipped because no linked issues were found for this pull request. | | Out of Scope Changes check | | Check skipped because no linked issues were found for this pull request. | ✨ Finishing Touches: 💡 1 📝 Generate docstrings: 💡 🧪 Generate unit tests (beta) > [!WARNING] > ⚠️ This pull request shows signs of AI-generated slop (phantom_api). It has been flagged by the reviewer slop detection and should be reviewed carefully. Comment `@the reviewer help` to get the list of available commands. |
| #9052 2026-10-20 18:55 | coderabbit review-body | — | summary | 🧹 Nitpick comments: 1
apps/sim/ee/access-control/components/project-issue-restrictions.test.tsx: 1
`4-4`: **🚀 Performance & Scalability** | **🔵 Trivial** | **⚡ Quick win**
**Import `flushMacrotask` from its file.**
Change this import to `@sim/testing/helpers/async`. As per coding guidelines: “Import the one file you need (`@sim/testing/helpers/<file>`, …).”
_Source: Coding guidelines_ |
| #9052 2026-10-20 19:00 | cubic review-body | — | summary | **No issues found** across 7 files
View guided diff | Turn on auto-fix | Re-trigger the reviewer |
| #9052 2026-10-20 19:00 | greptile issue-comment | — | summary | Confidence Score: 5/5
**[Medium impact]** No blocking issues were identified; the reviewed changes are safe to merge within the examined scope.
Reviews (1) · Last reviewed commit: "fix(projects): gate the Project list on ..." · Reviewed by the reviewer |
| #9057 2026-10-20 19:02 | coderabbit issue-comment | — | summary | 📝 Walkthrough
This pull request updates realtime file-document permissions and persistence, proxy-aware request body limits, file download presentation and version serialization, editor collaboration behavior, and CLI and MCP operation visibility.
**Changes: Realtime file-document permissions and persistence**
|Layer / File(s)|Summary|
|:---|:---|
|**Room permission dispatch** `apps/realtime/src/handlers/room-permission.ts`, `apps/realtime/src/access-revalidation.ts`, `apps/realtime/src/access-revalidation.test.ts`|Room types can register permission publishers. Membership revalidation dispatches resolved permissions through the registered publisher.|
|**File-document permission state** ` … the rest (9183 characters)apps/realtime/src/handlers/file-doc.ts`, `apps/realtime/src/handlers/file-doc.test.ts`|File-document rooms publish changes to per-socket write capability and deduplicate repeated permission values.| |**Join admission and socket cleanup** `apps/realtime/src/handlers/file-doc.ts`, `apps/realtime/src/handlers/file-doc.test.ts`|Join success uses the permission validated for admission. Socket cleanup removes cached capability state, and frame authorization failures are logged and dropped.| |**Persistence attribution and retry coverage** `apps/realtime/src/handlers/file-doc.ts`, `apps/realtime/src/handlers/file-doc.redis-store.test.ts`|Persistence retains local attribution for eligible owners and reschedules non-final flushes when no author resolves. A test covers persistence after the final collaborator leaves.| **Proxy-aware request body limits** |Layer / File(s)|Summary| |:---|:---| |**Proxy-aware JSON body parsing** `apps/sim/lib/api/server/validation.ts`, `apps/sim/lib/api/server/routes/internal-json-route.ts`, `apps/sim/lib/api/server/validation.test.ts`, `apps/sim/lib/core/config/request-limits.ts`, `apps/sim/next.config.ts`, `apps/sim/app/api/workspaces/[id]/files/[fileId]/content/route.test.ts`|JSON parsing applies a 10 MiB proxy ceiling unless a route opts out. Tests cover the proxy boundary and larger limits for bypassed routes. The previous shared body-size constant and Next.js override are removed.| |**Document persistence proxy bypass** `apps/sim/app/api/internal/project-file-doc/[projectId]/[fileId]/persist/route.ts`, `apps/sim/proxy.ts`, `apps/sim/proxy.test.ts`|The document persistence route sets a body limit based on encoded state size and opts out of proxy clamping. The proxy matcher excludes persistence routes.| **File delivery and version serialization** |Layer / File(s)|Summary| |:---|:---| |**Attachment presentation and safety headers** `apps/sim/lib/uploads/server/delivery.ts`, `apps/sim/app/api/v2/files/[fileId]/route.ts`, `apps/sim/app/api/v2/files/[fileId]/versions/[version]/content/route.ts`, `apps/sim/app/api/v2/files/[fileId]/route.test.ts`|File downloads use a shared attachment presenter. Responses include `nosniff`, and SVG responses receive a sandbox CSP.| |**Single file-version serialization** `apps/sim/app/api/v2/files/utils.ts`, `apps/sim/app/api/v2/files/utils.test.ts`, `apps/sim/app/api/v2/files/[fileId]/versions/route.ts`|Version conversion projects author data and converts records with `toFileVersion`. The batch conversion helper is removed, and the route maps versions synchronously.| **Editor collaboration behavior** |Layer / File(s)|Summary| |:---|:---| |**Permission transition and pending updates** `apps/sim/app/workspace/[workspaceId]/files/components/file-viewer/rich-markdown-editor/collaboration/file-doc-provider.ts`, `apps/sim/app/workspace/[workspaceId]/files/components/file-viewer/rich-markdown-editor/collaboration/file-doc-provider.test.ts`|A pending update is resent only when permission changes from read-only to writable.| |**Read-only collaboration fallback** `apps/sim/app/workspace/[workspaceId]/files/components/file-viewer/rich-markdown-editor/rich-markdown-editor.tsx`, `apps/sim/app/workspace/[workspaceId]/files/components/file-viewer/rich-markdown-editor/editor-lifecycle.test.tsx`|After a non-retryable `ACCESS_DENIED` join error, a read-only editor disables collaboration and remains visible and non-editable.| **Unpublished CLI and MCP surfaces** |Layer / File(s)|Summary| |:---|:---| |**Project commands and CLI documentation** `packages/sim-cli/src/program.ts`, `scripts/generate-cli-docs.ts`|Project commands remain registered but hidden from command help. CLI documentation includes the top-level `projects` command.| |**Unpublished MCP operation filtering** `scripts/generate-v2-mcp-operations.ts`|MCP generation excludes operations whose method and path appear in unpublished route documentation, in addition to non-JSON transports.| **Priority:** ➖ Normal **Estimated code review effort:** 4 (Complex) | ~45 minutes **Change:** Bug fix ### Sequence Diagram(s) ```mermaid sequenceDiagram participant MembershipRevalidation participant RoomPermission participant FileDocPublisher participant AuthenticatedSocket MembershipRevalidation->>RoomPermission: publishRoomPermission(socket, room, permission) RoomPermission->>FileDocPublisher: dispatch by room type FileDocPublisher->>AuthenticatedSocket: publish updated write capability ``` **Suggested reviewers:** `waleedlatif1`, `mzxchandra` Merge Risk: 🔵 Low · up to 943e3 Oversized uploads sent without a declared length may get a malformed-JSON 400 instead of a 413. The change is otherwise mergeable, and the author should confirm when the Projects CLI docs are meant to be published. Security architecture risk: 🔵 Low · up to 943e3 The inspected permission enforcement, internal authentication, and private-download controls remain in place. No newly exploitable path was established. Risk remains bounded but nonzero because deployment-specific routing guarantees and some authorization internals remain unverified. **Retained concerns** No architecture-level concerns identified. Security review details **Security Blast Radius** - _inferred_ — The request-limit change affects proxy-routed APIs broadly, while the larger exception is confined to authenticated document persistence. Relay requests are scoped to one project/file, but the shared internal credential authorizes the supplied actor headers; individual request scopes are not independent containment boundaries for compromise of that credential. This authority model predates the PR. **Security Findings and Attack Paths** - _observed_ — No Security findings are retained in the supplied assessment. The investigated cache-exposure candidate is countered by the binary wrapper, which explicitly sets private, no-store after constructing headers from the attachment presenter. **Trust Boundaries and Controls** - _observed_ — The proxy exception does not remove internal-key authentication or bounded body parsing. The route rejects the dedicated MCP host before invoking its authenticated handler, retains a 17 MiB encoded-body cap, and validates decoded collaborative state size in the persistence use case. The same encoded-body allowance existed at the supplied base. **Resilience and Maintainability Implications** - _observed_ — The acknowledged-update path authorizes before awaiting durable publication and subsequently checks document generation and room identity rather than permission again. An already-admitted update can therefore finish after concurrent revocation. This path is unchanged by the PR; the intended admission-versus-commit revocation policy remains unspecified. **Hardening Proposals** - _proposed_ — Define whether revocation must cancel updates admitted before it. If immediate commit-boundary revocation is required, introduce an authorization fence aligned with durable publication rather than relying only on admission-time permission. Pre-merge checks: 4 · 1 Failed checks: 1 warning | Check name | Status | Explanation | Resolution | | :---------------- | :----------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------- | | Docstring Coverage | | Docstring coverage is 68.97% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 29 functions across 27 files. | Write docstrings for the functions missing them to satisfy the coverage threshold. | Passed checks: 4 passed | Check name | Status | Explanation | | :------------------------ | :--------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Description Check | | Check skipped - the reviewer’s high-level summary is enabled. | | Title check | | The title clearly and concisely identifies two significant changes in the pull request: stopping the file-document permission resend loop and restoring the 10 MB proxy body limit. | | Linked Issues check | | Check skipped because no linked issues were found for this pull request. | | Out of Scope Changes check | | Check skipped because no linked issues were found for this pull request. | ✨ Finishing Touches: 💡 1 📝 Generate docstrings: 💡 🧪 Generate unit tests (beta) ### Usage-based review receipt - Mode: Continue automatically - Reviewed files: 27 - Waived: $6.75 (charged $0.00) - View usage details > [!NOTE] > This review exceeded your plan’s limits and used usage-based reviews—free during trial, billed after paid activation unless disabled. **Manage usage-based reviews**. Comment `@the reviewer help` to get the list of available commands. |
| #9057 2026-10-20 19:07 | coderabbit inline · P2 | apps/sim/lib/api/server/validation.ts:69 | defect-functional | **Leave room to detect proxy-truncated bodies.**
If a client omits `Content-Length` and sends more than 10 MiB to a matched API route, Next can truncate the body before this parser reads it. The stream then contains no byte beyond `limit`, so incomplete JSON returns 400 instead of the intended 413. Set the proxy buffer at least one byte above the parser limit, or reject the oversized body before truncation. Test this path with an oversized request that has no `Content-Length`; the current boundary tests use declared lengths. (nextjs.org) |
| #9057 2026-10-20 19:07 | coderabbit inline · P2 | scripts/generate-cli-docs.ts:1296 | question | **Confirm the publication timing for Projects documentation.**
`buildProgram` registers `projects` with `{ hidden: true }`, and `subcommands` removes hidden commands. Removing the explicit `projects` filter does not add Projects to the generated documentation. If Projects documentation should remain unpublished until launch, this change is correct. Otherwise, update the documentation-specific filtering. |
| #9057 2026-10-20 19:07 | coderabbit review-body | — | summary | **Actionable comments posted: 2** |
| #9057 2026-10-20 19:14 | cubic inline · P2 | scripts/generate-cli-docs.ts:1296 | defect-functional | This includes the unreleased `projects files` commands in generated CLI docs and the sidebar. Keep the `projects` group excluded until the feature launches.
```suggestion
const top = subcommands(program).filter((command) => command.name() !== 'projects')
``` |
| #9057 2026-10-20 19:14 | cubic review-body | — | summary | **1 issue found** across 30 files
View guided diff | Turn on auto-fix | Re-trigger the reviewer |
| #9057 2026-10-20 19:17 | greptile issue-comment | — | summary | Confidence Score: 5/5
**[Medium impact]** No blocking merge concerns were identified in the reviewed changes.
Reviews (1) · Last reviewed commit: "fix(file-doc): stop the permission resen..." · Reviewed by the reviewer |
| #9050 2026-10-20 19:18 | coderabbit issue-comment | — | summary | 📝 Walkthrough
Resource-removal events now discard eligible queued resource upserts before stream recovery or live updates. File resource lookup failures now use log levels based on the error type.
**Changes: Resource removal**
|Layer / File(s)|Summary|
|:---|:---|
|**Queue cleanup and stream wiring** `apps/sim/app/workspace/[workspaceId]/home/hooks/stream/stream-context.ts`, `apps/sim/lib/mothership/resources/client-persistence-queue.ts`, `apps/sim/app/workspace/[workspaceId]/home/hooks/use-chat.ts`|The stream dependency now discards eligible upserts from active and provisional chat scopes. The queue clears tracked upsert state unless a removal is queued or a write is in flight.|
|**Remo … the rest (3854 characters)val handling and regression coverage** `apps/sim/app/workspace/[workspaceId]/home/hooks/stream/handle-resource-event.ts`, `apps/sim/app/workspace/[workspaceId]/home/hooks/stream/stream-test-helpers.ts`, `apps/sim/app/workspace/[workspaceId]/home/hooks/use-chat.dom.test.tsx`|Effect-backed removals discard pending upserts before recovery or live update processing. Tests cover failed persistence, reconnect replay, and later sends without the removed attachment.| **Resource resolution logging** |Layer / File(s)|Summary| |:---|:---| |**File lookup error classification** `apps/sim/lib/mothership/chat/process-contents.ts`, `apps/sim/lib/mothership/chat/process-contents.test.ts`|Missing file errors log at info, forbidden errors at warn, and other failures at error. Tests verify that these lookup failures return no context.| **Priority:** ⬇️ Low **Estimated code review effort:** 3 (Moderate) | ~20 minutes **Change:** Bug fix **Suggested reviewers:** `sg312`, `waleedlatif1` Merge Risk: 🔵 Low · up to 1711c A resource removed by the server can be restored if another add was queued behind an in-flight write. Clear that queued add before merging, or explicitly accept the bounded residual risk. Security architecture risk: 🔵 Low · up to 1711c The change reduces accidental restoration of deleted resources without adding permissions or external access. A pre-existing timing window for writes already underway remains. Authorization of the originating removal events was not independently verified. **Retained concerns** No architecture-level concerns identified. Security review details **Security Blast Radius** - _inferred_ — The added operation is bounded to matching local persistence state for the current and provisional chat scopes. The inspected path adds neither credential access nor a cross-service write. Its direct outcome is suppression of a later upsert, not deletion of the underlying resource. **Trust Boundaries and Controls** - _observed_ — The exported handler is reached through internal stream dispatch after envelope validation. Existing workspace filtering precedes the new callback, which additionally requires a remove operation with effectId. These are client-side controls; they do not independently establish server authorization or tenant provenance of the event. **Resilience and Maintainability Implications** - _observed_ — The in-flight guard preserves a pre-existing restoration window, including a newer queued update for the same key that drains after the current write completes. Base comparison confirms that this ordering behavior predates the PR; the change neither closes it nor establishes a stronger deletion guarantee. Pre-merge checks: 5 | Check name | Status | Explanation | | :------------------------ | :--------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Description Check | | Check skipped - the reviewer’s high-level summary is enabled. | | Title check | | The title clearly describes the primary change: removing queued tab additions after the server has already removed them. | | Docstring Coverage | | Docstring coverage is 83.33% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 6 functions across 8 files. | | Linked Issues check | | Check skipped because no linked issues were found for this pull request. | | Out of Scope Changes check | | Check skipped because no linked issues were found for this pull request. | ✨ Finishing Touches 📝 Generate docstrings 🧪 Generate unit tests (beta) Comment `@the reviewer help` to get the list of available commands. |
| #9050 2026-10-20 19:21 | coderabbit inline · P2 | apps/sim/lib/mothership/resources/client-persistence-queue.ts:142 | defect-concurrency | **Clear queued upserts when an in-flight write exists.**
`enqueue` can queue a second update while the first write is in flight. The remove-effect path then returns from `discardUpsert` without clearing that queued update. The first write completion posts the second update, which can restore the removed resource.
Suggested fix
```diff
- if (this.pendingRemovals.has(key) || this.inFlight.has(key)) return
+ if (this.pendingRemovals.has(key)) return
this.desiredUpdates.delete(key)
this.failedKeys.delete(key)
this.pendingKeys.delete(key)
+ if (this.inFlight.has(key)) return
this.persistedKeys.delete(key)
```
📝 Committable suggestion
> ‼️ **IMPORTANT**
> Careful … the rest (664 characters)ly 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. ```suggestion discardUpsert( type: MothershipResource['type'], id: string, scopeId: string, workspaceId?: string ): void { const key = this.getKey(scopeId, type, id, workspaceId) if (this.pendingRemovals.has(key)) return this.desiredUpdates.delete(key) this.failedKeys.delete(key) this.pendingKeys.delete(key) if (this.inFlight.has(key)) return this.persistedKeys.delete(key) } ``` |
| #9050 2026-10-20 19:21 | coderabbit review-body | — | summary | **Actionable comments posted: 1** |
| #9050 2026-10-20 19:26 | cubic inline · P2 | apps/sim/lib/mothership/chat/process-contents.ts:930 | defect-functional | `processKnowledgeFromDb` catches missing and forbidden failures before they reach this branch and logs them as errors, so active knowledge-base tabs still produce error logs. Apply this classification in that helper or let those failures propagate. |
| #9050 2026-10-20 19:26 | cubic inline · P2 | apps/sim/app/workspace/[workspaceId]/home/hooks/stream/handle-resource-event.ts:210 | defect-functional | This discard can miss a queued upsert when the remove effect omits `resource.workspaceId` but the queued resource carries the current workspace ID. Pass the already-resolved `workspaceId` so both queue keys identify the same resource.
```suggestion
ctx.deps.discardPendingResourceUpsert({ type, id, workspaceId })
``` |
| #9050 2026-10-20 19:26 | cubic inline · P2 | apps/sim/app/workspace/[workspaceId]/home/hooks/use-chat.dom.test.tsx:858 | tests | This snapshot is taken after replay processes the remove effect, so a `DELETE deleted-file` issued by that effect is included in the baseline and passes the later equality check. Assert the snapshot contains no delete, as the live-effect test does.
```suggestion
const writesBeforeRemoval = [...writes]
expect(writesBeforeRemoval).not.toContain('DELETE deleted-file')
``` |
| #9050 2026-10-20 19:26 | cubic inline · P2 | apps/sim/lib/mothership/resources/client-persistence-queue.ts:137 | defect-concurrency | Clear the queued upsert even when another write is in flight, while leaving the active request itself untouched. Otherwise its completion can flush the follow-up update and restore the removed resource.
```suggestion
if (this.pendingRemovals.has(key)) return
``` |
| #9050 2026-10-20 19:26 | cubic review-body | — | summary | **4 issues found** across 8 files
Reply with feedback, questions, or to request a fix.View guided diff | Turn on auto-fix | Re-trigger the reviewer |
| #9050 2026-10-20 19:27 | greptile issue-comment | — | summary | Confidence Score: 5/5
**[Medium impact]** Safe to merge within the reviewed scope; no blocking issues were found.
Reviews (1) · Last reviewed commit: "fix(mothership): drop queued tab adds th..." · Reviewed by the reviewer |
| #9058 2026-10-20 19:28 | coderabbit issue-comment | — | summary | No actionable comments were generated in the recent review. 🎉
📝 Walkthrough
Project-file contract schemas and inferred types are no longer broadly exported. Project-file authorization now supports shared and exclusive locks. Storage accounting, snapshot reads, revision conflict handling, document retirement, and file restoration also receive changes.
**Changes: Project-file API contracts**
|Layer / File(s)|Summary|
|:---|:---|
|**Internalize project-file contract declarations** `apps/sim/lib/api/contracts/project-file*.ts`, `apps/sim/lib/api/contracts/v2/project-file*.ts`, `knip.jsonc`|The contract modules keep route-used schemas available internally while removing selected schema expo … the rest (6591 characters)rts and inferred type aliases. Knip ignores are narrowed for project contract files.| **Project-file authorization and lifecycle** |Layer / File(s)|Summary| |:---|:---| |**Add shared project and organization locks** `apps/sim/lib/db/advisory-locks.ts`, `apps/sim/lib/permission-groups/locks.ts`, `apps/sim/lib/projects/application/authorization.ts`, `apps/sim/lib/projects/membership.ts`, `apps/sim/lib/projects/files/application/authorization.ts`, `apps/sim/lib/projects/files/__integration__/authorization.integration.ts`, `packages/testing/src/mocks/permission-group-locks.mock.ts`|Project and organization locks support shared access with bounded lock timeouts. Project-file authorization selects a lock mode, and integration tests cover contention behavior.| |**Gate exclusive access on storage changes** `apps/sim/lib/projects/files/application/operations.ts`, `apps/sim/lib/billing/storage/{accounting,tracking}.ts`, `apps/sim/lib/projects/files/application/write-effects.ts`|Policies mark storage-charging operations. Project payer usage is read during delta application and locked only for non-zero deltas. Storage accounting requires an exclusive project lock.| |**Prepare snapshot reads and classify revision conflicts** `apps/sim/lib/projects/errors.ts`, `apps/sim/lib/projects/files/application/{authorized-use-case,content,versions,documents,documents.test}.ts`|Use cases can prepare from snapshots. Content and version reads use the snapshot organization’s outbound context. Document persistence uses typed revision conflicts and enforces a maximum read size.| |**Bound document retirement and report restoration** `apps/sim/lib/projects/files/application/{document-lifecycle,lifecycle}.ts`, `apps/sim/lib/uploads/contexts/workspace/file-manager.ts`|Document retirement uses cached document IDs and a concurrency limit of eight. File restoration reports whether restoration occurred, and document retirement runs only after an actual restore.| **Priority:** ➖ Normal **Estimated code review effort:** 4 (Complex) | ~45 minutes **Change:** Bug fix ### Sequence Diagram(s) ```mermaid sequenceDiagram participant ProjectFileOperation participant ProjectFileAuthorizer participant ProjectLock participant StorageAccounting ProjectFileOperation->>ProjectFileAuthorizer: authorize operation alt Storage-charging operation ProjectFileAuthorizer->>ProjectLock: acquire exclusive project lock ProjectFileOperation->>StorageAccounting: apply storage delta else Other operation ProjectFileAuthorizer->>ProjectLock: acquire shared project lock end ``` **Suggested reviewers:** `mzxchandra` Merge Risk: ⚪ Minimal · up to 4fc76 No actionable merge-blocking risk remains from the reviewed changes; the PR is mergeable after normal checks. Security architecture risk: 🔵 Low · up to 4fc76 The inspected paths retain permission checks, exclusive locking for storage charges, revision validation, and durable cleanup. No introduced security weakness was established, but concurrent authorization and recovery behavior make this more than a local implementation change. **Retained concerns** No architecture-level concerns identified. Security review details **Security Blast Radius** - _inferred_ — The material exposure is authorized Project-file data, collaborative-document state, and the Project's canonical storage payer. The inspected authorization path continues to check current principal, Project access, file ownership, capabilities, and delegated organization scope rather than treating caller-supplied identifiers as authority. **Trust Boundaries and Controls** - _observed_ — Permission-group readers and exclusive mutators share the same organization lock identity. File-operation capability decisions occur while the reader lock is held, preserving serialization with the inspected revocation paths despite allowing concurrent readers. - _observed_ — Charging operations obtain exclusive Project access up front, and downstream accounting rejects contexts without that authorization marker. The inspected registered charging operations therefore do not require a shared-to-exclusive upgrade. **Resilience and Maintainability Implications** - _observed_ — Immediate document retirement is now capped at eight concurrent callbacks. Failed or unattempted immediate work is not the sole recovery mechanism: committed retirement rows remain available to the independent durable outbox worker. Pre-merge checks: 4 · 1 Failed checks: 1 warning | Check name | Status | Explanation | Resolution | | :---------------- | :----------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------- | | Docstring Coverage | | Docstring coverage is 72.73% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 33 functions across 31 files. (1 skipped:… | Write docstrings for the functions missing them to satisfy the coverage threshold. | Passed checks: 4 passed | Check name | Status | Explanation | | :------------------------ | :--------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------- | | Description Check | | Check skipped - the reviewer’s high-level summary is enabled. | | Title check | | The title clearly and concisely describes the main change: shared Project and permission-group locks for non-charging project-file operations. | | Linked Issues check | | Check skipped because no linked issues were found for this pull request. | | Out of Scope Changes check | | Check skipped because no linked issues were found for this pull request. | Full details: Docstring Coverage **Explanation** Docstring coverage is 72.73% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 33 functions across 31 files. (1 skipped: 1 unsupported.) **Resolution** Write docstrings for the functions missing them to satisfy the coverage threshold. ✨ Finishing Touches: 💡 1 📝 Generate docstrings: 💡 🧪 Generate unit tests (beta) Comment `@the reviewer help` to get the list of available commands. |
| #9058 2026-10-20 19:38 | cubic review-body | — | summary | **No issues found** across 32 files
View guided diff | Turn on auto-fix | Re-trigger the reviewer |
| #9058 2026-10-20 19:39 | greptile issue-comment | — | summary | Confidence Score: 4/5
**[Medium impact]** The changes reach Project file requests and shared storage\-accounting and permission\-lock paths\.
No blocking issue was established; the remaining file-list notification race is non-blocking.
Findings
1. **Restore skips its change signal**
Reviews (1) · Last reviewed commit: "fix(project-files): hold the Project and..." · Reviewed by the reviewer |
| #9058 2026-10-20 19:39 | greptile inline · P2 | apps/sim/lib/projects/files/application/lifecycle.ts:171 | defect-concurrency | **Restore skips its change signal**
With the new shared Project lock, an archive can commit after restore authorization reads an active file but before `restoreFileInTx` locks it. Restore then changes the file back to active successfully, but `invalidatesFileList` still checks the earlier `context.file.deletedAt === null` and skips `notifyFileListChanged`. Subscribers that refresh after the archive can therefore keep showing the file as archived until another refresh. This is a non-blocking notification consistency issue.
Use the locked `restored` outcome for list invalidation too, rather than only for document retirement.
Artifacts
**Focused restore notification test**
- The executed t … the rest (2029 characters)est invokes production archive and restore with a scheduling barrier and asserts that a committed restore sends its own notification. **Focused integration runner configuration** - The configuration selects only the authored candidate check and uses the application’s real-infrastructure setup. **Database provisioning and test commands** - The executed driver provisions the disposable schema and captures exact commands, working directories, exit codes, and test output. **Disposable PostgreSQL startup** - A PostgreSQL 17 container was started on a loopback endpoint, enabling real database concurrency validation. **Disposable test database creation** - The sim\_test database and required extensions were created successfully, isolating the check from application data. **Application schema provisioning** - The repository’s database push command completed against disposable PostgreSQL, making production lifecycle queries executable. **Initial runner configuration failure** - An initial configuration merge collected unintended files but failed before executing tests because a setup path was unresolved; the focused configuration was corrected before the proof runs. **Ordinary restore sends its notification** - The production restore ran on an already archived file and delivered one HTTP 200 list-change notification, establishing the passing control. **Interleaved restore omits its notification** - Archive committed after restore authorization, then restore committed successfully with zero restore notifications, confirming the candidate through the failed expected-one assertion. **Executed production source and unchanged tracked files** - The command captured the checkout revision, relevant production source with line numbers, and an empty tracked diff, tying the observed failure to unmodified code. **Disposable PostgreSQL cleanup** - The disposable database container was stopped successfully after the proof runs, completing infrastructure cleanup. Ran code and verified through TREX |
| #9017 2026-10-20 19:41 | coderabbit issue-comment | — | summary | 📝 Walkthrough
This change adds Project file search, preview, and rendered-artifact APIs. It adds owner-aware file references and document compilation, updates workspace file delivery and provenance checks, and adds workbench download tracking and related integration and end-to-end tests.
**Changes: Project File Operations and Rendering**
|Layer / File(s)|Summary|
|:---|:---|
|**Project file contracts and routes** `apps/sim/lib/api/contracts/v2/project-file-search.ts`, `apps/sim/lib/api/contracts/v2/openapi/project-files.ts`, `apps/sim/app/api/projects/*/files/*/route.ts`, `apps/sim/lib/projects/files/application/index.ts`, `packages/sim-cli/src/contract/commands.ts`|Adds Project file sea … the rest (10347 characters)rch, artifact, CSV preview, and inline routes. Adds the search contract, OpenAPI registration, application exports, and CLI command contract.| |**Authorized Project reads, previews, and search** `apps/sim/lib/projects/files/application/previews.ts`, `apps/sim/lib/projects/files/application/search.ts`, `apps/sim/lib/file-parsers/csv-preview-slice.ts`, `apps/sim/lib/file-parsers/csv-preview-slice.test.ts`, `packages/testing/src/mocks/file-read-receipt.mock.ts`|Adds authorized inline and CSV reads and Project file search. CSV streaming enforces per-record and total-byte limits.| |**Project artifact preparation and document compilation** `apps/sim/lib/projects/files/application/artifacts.ts`, `apps/sim/lib/projects/files/api/content-presenter.ts`, `apps/sim/lib/uploads/documents/compile.ts`, `apps/sim/lib/uploads/documents/compile.test.ts`, `apps/sim/lib/execution/sandbox/*`, `apps/sim/lib/workspace-files/search/source.ts`|Adds artifact preparation, dependency and revision checks, bounded reads, document compilation, and Project-scoped cache identities.| |**Owner-scoped file references and rendered assets** `apps/sim/lib/uploads/utils/file-reference.ts`, `apps/sim/lib/uploads/utils/embedded-image-ref.ts`, `apps/sim/lib/uploads/server/embedded-image-refs.ts`, `apps/sim/lib/workspace-files/page-compile.ts`, `apps/sim/lib/workspace-files/page-document*`, `apps/sim/hooks/use-file-content-source.tsx`, `apps/sim/lib/uploads/server/image-derivative.ts`, `apps/sim/lib/uploads/utils/file.server.ts`|Adds owner-aware file-reference parsing and resolution, Project page link handling, and owner-scoped image delivery and derivatives.| |**Project file integration and end-to-end coverage** `apps/sim/lib/projects/files/__integration__/*`, `apps/sim/lib/workspace-files/search/owners.integration.ts`, `apps/sim/scripts/test-project-file-rendered-e2e.ts`, `apps/sim/scripts/test-project-files-e2e.ts`, `apps/sim/scripts/test-file-delivery-e2e.ts`, `.github/workflows/checks.yml`|Adds Project search and rendering integration tests and end-to-end suites. The E2E workflow installs the native `isolated-vm` addon for the `project-files` test group.| **File Delivery and Upload Utilities** |Layer / File(s)|Summary| |:---|:---| |**Shared delivery headers and route handling** `apps/sim/lib/uploads/server/delivery.ts`, `apps/sim/app/api/files/utils.ts`, `apps/sim/app/api/files/serve/[...path]/route.ts`, `apps/sim/app/api/workspaces/[id]/files/inline/route.ts`, `apps/sim/app/api/**/export/route.ts`|Centralizes response headers, ETags, and cache policies. File-serving routes add HEAD handling, cache behavior, and mapped orchestration errors. Export routes import the shared filename encoder.| |**Workspace delivery receipts and revalidation** `apps/sim/lib/workspace-files/read-receipt.ts`, `apps/sim/lib/workspace-files/application/finish-file-delivery.ts`, `apps/sim/lib/workspace-files/application/*file*.ts`, `apps/sim/lib/workspace-files/application/file-versions.ts`|Adds read receipts and rechecks authorization, file revisions, and provenance before completing workspace file delivery. Failed validation cancels the stream.| |**Upload metadata, exports, and image derivatives** `apps/sim/lib/uploads/core/storage-client.ts`, `apps/sim/lib/uploads/server/legacy-metadata.ts`, `apps/sim/lib/uploads/server/markdown-export.ts`, `apps/sim/lib/uploads/server/zip.ts`, `apps/sim/lib/uploads/server/image-derivative.ts`, `apps/sim/lib/uploads/index.ts`|Separates raw provider metadata from the legacy metadata projection. Adds bounded ZIP exports, prepared Markdown assets, and owner-scoped image derivatives.| |**Delivery integration and end-to-end checks** `apps/sim/lib/workspace-files/delivery.integration.ts`, `apps/sim/scripts/test-file-delivery-e2e.ts`, `apps/sim/app/api/files/serve/[...path]/route.test.ts`|Adds tests for stream cancellation, receipt revalidation, response headers, caching, conditional requests, and HEAD behavior.| **Workbench File Provenance** |Layer / File(s)|Summary| |:---|:---| |**Workbench download classification and provenance gate** `apps/sim/lib/mothership/agent-cli/file-read-transport.ts`, `apps/sim/lib/mothership/agent-cli/transport.ts`, `apps/sim/lib/mothership/content-delivery/registry-gate.ts`, `apps/sim/lib/mothership/agent-cli/*test.ts`, `apps/sim/lib/mothership/__integration__/content-delivery.integration.ts`, `apps/sim/lib/workspace-files/__integration__/copilot-file-versions.integration.ts`|Adds workbench download tracking and a destination-specific provenance gate. Updates tests and integration setup for tracked downloads.| **Priority:** ➖ Normal **Estimated code review effort:** 4 (Complex) | ~60 minutes **Change:** Feature ### Sequence Diagram(s) ```mermaid sequenceDiagram participant ProjectArtifactRoute participant readProjectFileArtifact participant ProjectFileStorage participant DocumentCompiler participant ProjectFilePresenter ProjectArtifactRoute->>readProjectFileArtifact: authorize and prepare artifact readProjectFileArtifact->>ProjectFileStorage: read source and owned dependencies readProjectFileArtifact->>DocumentCompiler: compile authorized document inputs readProjectFileArtifact->>ProjectFilePresenter: return prepared artifact ProjectFilePresenter->>ProjectArtifactRoute: present buffered content ``` **Suggested reviewers:** `waleedlatif1` Merge Risk: 🔵 Low · up to 4c174 Project file search, previews, and rendering look broadly sound. Two bounded issues remain: large but valid CSV files with wide rows now fail to preview instead of showing a truncated slice, and in configurations without the document sandbox, Project search can index a document's source rather than its rendered output. Neither causes data loss or access exposure; they are reasonable to fix before or shortly after merge. Security architecture risk: 🟡 Moderate · up to 4c174 The added delivery paths have substantial ownership, revision, and protected-content checks. A pre-existing authorization weakness remains in older download paths, although this review did not establish that the PR expands it. Deployment validation and some end-to-end delivery guarantees remain unverified. **Retained concerns** No architecture-level concerns identified. Security review details **Security Blast Radius** - _observed_ — The inspected artifact path confines contributor resolution to the authorized Project owner. Explicit foreign-Project references, missing contributors, and deleted contributors are rejected; source and contributor identity checks run again after rendering. **Security Findings and Attack Paths** - _observed_ — The retained authorization finding concerns authenticated legacy file serving: when canonical ownership is absent, provider metadata can supply ownership fields consumed before local or cloud bytes are delivered. Exact base comparison shows this condition and serving exposure predate the PR. Authorization is unchanged, and additional Project-path rejection narrows reachability; no PR-induced expansion was established. **Trust Boundaries and Controls** - _observed_ — The changed CLI gate permits protected opaque downloads only when workbench tracking is enabled; excerpts remain refused. Secret entries must be imported into the registry, and admitted provenance is associated with the response stream. Workbench receipts bind content digests to user, session, owner scope, provider, and physical sandbox identity. **Resilience and Maintainability Implications** - _observed_ — Workbench classification requires stream completion before recording the digest receipt. Upload provenance is unavailable until classification completes. The download writer uses staged sandbox publication under a session lock and reports failure instead of confirmed success when observation or streaming throws; the underlying atomic-publication implementation was not fully inspected. Pre-merge checks: 4 · 1 Failed checks: 1 inconclusive | Check name | Status | Explanation | Resolution | | :---------------- | :--------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------- | | Docstring Coverage | | Docstring coverage is 60.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 50 functions across 50 files. (34 skipped… | Write docstrings for the functions missing them to satisfy the coverage threshold. | Passed checks: 4 passed | Check name | Status | Explanation | | :------------------------ | :--------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------- | | Description Check | | Check skipped - the reviewer’s high-level summary is enabled. | | Title check | | The title clearly and concisely identifies the main changes: rendered Project file delivery and indexed search. | | Linked Issues check | | Check skipped because no linked issues were found for this pull request. | | Out of Scope Changes check | | Check skipped because no linked issues were found for this pull request. | Full details: Docstring Coverage **Explanation** Docstring coverage is 60.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 50 functions across 50 files. (34 skipped: 1 unsupported, 33 over the file limit.) **Resolution** Write docstrings for the functions missing them to satisfy the coverage threshold. ✨ Finishing Touches: 💡 1 📝 Generate docstrings: 💡 🧪 Generate unit tests (beta) ### Usage-based review receipt - Mode: Continue automatically - Reviewed files: 84 - Waived: $21.00 (charged $0.00) - View usage details > [!NOTE] > This review exceeded your plan’s limits and used usage-based reviews—free during trial, billed after paid activation unless disabled. **Manage usage-based reviews**. Comment `@the reviewer help` to get the list of available commands. |
| #9017 2026-10-20 19:50 | greptile issue-comment | — | summary | Confidence Score: 4/5
**[High impact]** The PR reaches Project file readers\, shared workspace delivery\, and agent file\-reading workflows\.
Safe to merge with one non-blocking image portability issue.
Findings
1. **Image fragments prevent inlining**
Reviews (1) · Last reviewed commit: "feat(project-files): add rendered delive..." · Reviewed by the reviewer |
| #9017 2026-10-20 19:50 | greptile inline · P2 | apps/sim/lib/workspace-files/page-document.server.ts:20 | defect-functional | **Image fragments prevent inlining**
Project page images with fragments are skipped by `IMAGE_SRC`. For example, `` compiles to a URL ending in `/content#chart`, but the Project branch only matches `/content"`. The image is neither inlined nor recorded as a dependency, so the downloaded page retains an authenticated image URL instead of carrying the image bytes. This is a non-blocking portability issue: viewing the downloaded page without an authenticated session loses the image.
Match the fragment separately, track the underlying file, and preserve the fragment on the inlined image.
Artifacts
**Executed Project image fragment reproduction**
- The author … the rest (984 characters)ed harness imports unchanged production compilation and inlining modules and asserts both input conditions, making the reproduction rerunnable. **Image embedding without a fragment** - Ran the actual renderer and strict inliner without a fragment and captured one dependency, one resolver call, and an embedded PNG, showing the control succeeds. **Image embedding after adding a fragment** - Repeated the same execution with only #chart added and captured no dependencies or resolver calls plus the retained live URL, supporting the candidate. **Initial launch with an unsupported Bun option** - Captured the initial commands failing because --tsconfig was not the correct Bun option, after which both runs succeeded with --tsconfig-override. **Validated commit and relevant source lines** - Captured the exact HEAD, relevant numbered source excerpts, and an empty tracked diff, confirming the tested revision and unchanged production code. Ran code and verified through TREX |
| #9017 2026-10-20 19:50 | coderabbit inline · P2 | apps/sim/lib/file-parsers/csv-preview-slice.ts:76 | defect-functional | **🎯 Functional Correctness** | **🟡 Minor** | **⚡ Quick win**
**Treat the 8 MiB cap as a truncation boundary.**
`nextChunk()` throws before the parser can reach the 1,000-row cap. A valid CSV with wide rows can exceed 8 MiB before row 1,001, so both preview callers reject the request instead of returning the available rows with `truncated: true`.
End the parser input at the byte boundary, set `truncated`, and discard a partial final record. Do not pass the remainder of an over-limit chunk to the parser.
Suggested fix
```diff
-import { assertKnownSizeWithinLimit } from '@/lib/core/utils/stream-limits'
import type { StorageContext } from '@/lib/uploads/config'
@@
const reader = sourc … the rest (1233 characters)e[Symbol.asyncIterator]() let bytesRead = 0 + let byteCapReached = false let piped: Readable | undefined let parser: ReturnType<typeof parseCsvStream> | undefined async function nextChunk() { + if (byteCapReached) return { done: true as const, value: undefined } const next = await reader.next() if (!next.done) { - bytesRead += Buffer.byteLength(next.value) - assertKnownSizeWithinLimit(bytesRead, MAX_PREVIEW_BYTES, 'CSV preview') + const chunk = Buffer.isBuffer(next.value) ? next.value : Buffer.from(next.value) + const remaining = Math.max(0, MAX_PREVIEW_BYTES - bytesRead) + bytesRead += chunk.byteLength + if (chunk.byteLength > remaining) { + byteCapReached = true + return { done: false as const, value: chunk.subarray(0, remaining) } + } + return { done: false as const, value: chunk } } return next } @@ for await (const record of parser as AsyncIterable<string[]>) { @@ rows.push(record.map(cell)) } + if (byteCapReached) { + truncated = true + rows.pop() + } + piped.destroy() ``` Update the blank-record test to expect a bounded, truncated result rather than a `PayloadSizeLimitError`. |
| #9017 2026-10-20 19:50 | coderabbit inline · P1 | apps/sim/lib/uploads/server/legacy-metadata.ts:31 | defect-security | **🔒 Security & Privacy** | **🛡️ Detected with Advanced Tier** | **🟠 Major** | **🏗️ Heavy lift**
**Authorization Bypass**
**Reachability:** External
**Exploitability:** Moderate
**CWE:** CWE-863 — Incorrect Authorization
**Do not let provider fallback restore uploader access for general files.**
Project files are rejected before this fallback, but general files reach `verifyRegularFileAccess`, which grants access when fallback metadata contains a matching `userId`. Remove or ignore `userId` from provider fallback for general files unless canonical metadata establishes private ownership. |
| #9017 2026-10-20 19:50 | coderabbit inline · P2 | apps/sim/lib/workspace-files/search/source.ts:110 | defect-functional | **🗄️ Data Integrity & Integration** | **🟡 Minor** | **⚡ Quick win**
**Use one reference language for Project search and rendering.**
When the document sandbox is disabled, Project rendering discovers dependencies as JavaScript, but `loadFileSearchSource` discovers them with the PDF format's Python language. A dialect-specific reference can therefore produce different input identities. Search can miss the rendered artifact and index the source instead.
Suggested fix
```diff
diff --git a/apps/sim/lib/uploads/documents/compile.ts b/apps/sim/lib/uploads/documents/compile.ts
@@
export function getDocumentSourceLanguage(
source: string,
format: E2BDocFormat,
sourceMime?: string
): … the rest (1541 characters)DocumentSourceLanguage { @@ return format.engine === 'node' ? 'javascript' : 'python' } +export function fileDocumentReferenceLanguage( + source: string, + format: E2BDocFormat, + sourceMime: string +): DocumentSourceLanguage { + return isDocSandboxEnabled && sourceMime !== 'text/x-pdflibjs' + ? getDocumentSourceLanguage(source, format, sourceMime) + : 'javascript' +} + diff --git a/apps/sim/lib/projects/files/application/artifacts.ts b/apps/sim/lib/projects/files/application/artifacts.ts @@ collectReferencedFileIds, compileFileDocument, - getDocumentSourceLanguage, + fileDocumentReferenceLanguage, getE2BDocFormat, @@ ? collectReferencedFileIds( source, - isDocSandboxEnabled - ? getDocumentSourceLanguage(source, format, input.source.file.contentType) - : 'javascript' + fileDocumentReferenceLanguage(source, format, input.source.file.contentType) ) diff --git a/apps/sim/lib/workspace-files/search/source.ts b/apps/sim/lib/workspace-files/search/source.ts @@ collectReferencedFileIds, + fileDocumentReferenceLanguage, getDocumentSourceLanguage, @@ ...collectReferencedFileIds( source, - getDocumentSourceLanguage(source, format, file.contentType) + owner.entityType === 'project' + ? fileDocumentReferenceLanguage(source, format, file.contentType) + : getDocumentSourceLanguage(source, format, file.contentType) ), ``` |
| #9017 2026-10-20 19:50 | coderabbit review-body | — | summary | **Actionable comments posted: 3** |
| #9017 2026-10-20 19:55 | cubic inline · P1 | apps/sim/lib/uploads/server/legacy-metadata.ts:31 | defect-security | Do not return provider `userId` values as legacy authorization metadata when the canonical row is missing; `verifyRegularFileAccess` can then grant a general-file read to its uploader. |
| #9017 2026-10-20 19:55 | cubic inline · P2 | apps/sim/app/api/files/serve/[...path]/route.test.ts:382 | tests | This assertion no longer verifies that revalidated responses use the conditional helper: both mocked helpers produce the same response. Keep the cache-control check and assert `mockCreateConditionalFileResponse` was called so a regression that drops validators is caught.
```suggestion
expect(response.headers.get('Cache-Control')).toBe('private, no-cache, must-revalidate')
expect(mockCreateConditionalFileResponse).toHaveBeenCalled()
``` |
| #9017 2026-10-20 19:55 | cubic inline · P2 | apps/sim/lib/uploads/server/image-derivative.ts:23 | defect-data | Each HEIC preview creates a separate object that file-revision cleanup does not identify, so replacing the source leaves its old JPEG in project storage. Enqueue the derivative key for cleanup when retiring the source revision. |
| #9017 2026-10-20 19:55 | cubic inline · P2 | apps/sim/lib/workspace-files/__integration__/copilot-file-versions.integration.ts:152 | tests | This configures durable file provenance under a different session key than the real Chat workbench, so this transport cannot exercise the production session binding. Pass `chatSandboxSessionKey(invocation.chatId)` instead. |
| #9017 2026-10-20 19:55 | cubic inline · P2 | apps/sim/lib/file-parsers/csv-preview-slice.ts:116 | defect-functional | Without `skip_records_with_error`, a `CSV_QUOTE_NOT_CLOSED` now rejects the entire preview instead of preserving earlier valid rows. Preserve ordinary skips while rethrowing `CSV_MAX_RECORD_SIZE`, as `csvParseOptions` does.
```suggestion
skip_records_with_error: true,
on_skip(error) {
if (error?.code === 'CSV_MAX_RECORD_SIZE') throw error
},
max_record_size: MAX_RECORD_SIZE,
``` |
| #9017 2026-10-20 19:55 | cubic inline · P2 | apps/sim/lib/workspace-files/page-compile.ts:246 | defect-functional | Project-file links resolve to `/projects/<projectId>/files/<fileId>`, but this app has no matching page route, so rendered links return 404. Emit an implemented viewer URL or add that route. |
| #9017 2026-10-20 19:55 | cubic inline · P2 | apps/sim/app/api/files/serve/[...path]/route.ts:545 | defect-functional | The HEAD fast path returns 200 after authorization alone, so missing execution objects appear present: `verifyExecutionFileAccess` checks workspace membership, while GET proceeds to `downloadFile`. Check object existence before returning 200, without buffering or rendering it. |
| #9017 2026-10-20 19:55 | cubic inline · P2 | apps/sim/hooks/use-file-content-source.tsx:60 | defect-functional | Public shares still build this source without `owner`, so `sim:file/<id>` embeds are rejected and render without images. Pass the document owner through the source and inline authorization scan. |
| #9017 2026-10-20 19:55 | cubic inline · P2 | apps/sim/lib/file-parsers/csv-preview-slice.ts:73 | design | Stop parsing at the 8 MiB boundary instead of throwing from `nextChunk`; return the parsed rows with `truncated: true` and discard any partial final record. |
| #9017 2026-10-20 19:55 | cubic review-body | — | summary | **9 issues found** across 89 files
View guided diff | Turn on auto-fix | Re-trigger the reviewer |
| #9062 2026-10-20 20:01 | coderabbit issue-comment | — | summary | No actionable comments were generated in the recent review. 🎉
📝 Walkthrough
The project file search query schema remains structurally unchanged. It is now module-private. The exported query type and unused `z` type import are removed.
**Changes: Project file search contract**
|Layer / File(s)|Summary|
|:---|:---|
|**Query contract visibility** `apps/sim/lib/api/contracts/v2/project-file-search.ts`|The query schema keeps its structure and description but is no longer exported. The exported query type and unused `z` type import are removed.|
**Priority:** ⬇️ Low
**Estimated code review effort:** 1 (Trivial) | ~5 minutes
**Change:** Bug fix
**Suggested reviewers:** `mzxchandra`
Merge … the rest (1591 characters)Risk: ⚪ Minimal · up to c5371 The cleanup narrows module visibility without changing the project file-search behavior. Pre-merge checks: 5 | Check name | Status | Explanation | | :------------------------ | :--------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Description Check | | Check skipped - the reviewer’s high-level summary is enabled. | | Title check | | The title clearly and concisely describes the main change: removing unused project file search query exports from the contracts. | | Docstring Coverage | | No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff. Analyzed 0 functions across 1… | | Linked Issues check | | Check skipped because no linked issues were found for this pull request. | | Out of Scope Changes check | | Check skipped because no linked issues were found for this pull request. | Full details: Docstring Coverage **Explanation** No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff. Analyzed 0 functions across 1 files. ✨ Finishing Touches 📝 Generate docstrings 🧪 Generate unit tests (beta) Comment `@the reviewer help` to get the list of available commands. |
| #9062 2026-10-20 20:01 | cubic review-body | — | summary | **No issues found** across 1 file
View guided diff | Turn on auto-fix | Re-trigger the reviewer |
| #9062 2026-10-20 20:07 | greptile issue-comment | — | summary | Confidence Score: 5/5
**[Low impact]** Safe to merge. Existing consumers retain access to the exported contract, and the tested query validation behavior is unchanged.
Reviews (1) · Last reviewed commit: "fix(contracts): drop unused project file..." · Reviewed by the reviewer |
| #9018 2026-10-20 20:08 | coderabbit issue-comment | — | summary | 📝 Walkthrough
The change adds file-copy APIs and CLI support, project-file archive download, Markdown snapshot export, and ZIP extraction. It also adds shared archive preparation and streaming presentation, and updates workspace download selection and authorization checks.
**Changes: File Copy**
|Layer / File(s)|Summary|
|:---|:---|
|**Copy contract and operation policy** `apps/sim/lib/api/contracts/file-copy*`, `apps/sim/lib/api/contracts/v2/file-copy.ts`, `apps/sim/lib/workspace-files/application/copy-operation.ts`, `apps/sim/lib/workspace-files/application/operations.ts`|Defines source and destination validation, copy request and response schemas, route contracts, and the `files.copy` … the rest (11265 characters)operation policy.| |**Copy authorization and transactional storage** `apps/sim/lib/workspace-files/application/copy-authorization.ts`, `apps/sim/lib/workspace-files/copy.ts`, `apps/sim/lib/uploads/contexts/workspace/file-folder-manager.ts`, `apps/sim/lib/uploads/contexts/workspace/file-manager.ts`, `apps/sim/lib/projects/files/application/authorization.ts`, `apps/sim/lib/core/application/resource-delegation.ts`|Adds authorization for source reads and destination writes, bounded source snapshots, folder recreation, and transactional file commitment.| |**Content rewriting and copy response** `apps/sim/lib/workspace-files/application/copy-file-items.ts`, `apps/sim/lib/workspace-files/copy-references.ts`, `apps/sim/lib/workspace-files/copy-references.test.ts`, `apps/sim/lib/workspace-files/api/copy-presenter.ts`|Stages copied content, rewrites supported references, and formats copied file and folder records for API responses.| |**Copy API, CLI, and authorization validation** `apps/sim/app/api/files/copy/route.ts`, `apps/sim/app/api/v2/files/copy/route.ts`, `packages/sim-cli/src/contract/commands.ts`, `apps/docs/content/docs/cli/*`, `apps/sim/lib/projects/files/__integration__/authorization-bulk.integration.ts`, `apps/sim/lib/projects/files/__integration__/content-bulk.integration.ts`, `apps/sim/scripts/test-file-copy-e2e.ts`, `apps/sim/scripts/test-file-list-realtime-e2e.ts`, `apps/sim/scripts/test-project-files-e2e.ts`|Wires copy requests through session and v2 API routes and CLI commands. Adds authorization, copying, recursive-folder, and realtime integration checks.| **Project File Download, Export, and Extraction** |Layer / File(s)|Summary| |:---|:---| |**Download and export contracts and routes** `apps/sim/lib/api/contracts/project-file-downloads.ts`, `apps/sim/lib/api/contracts/v2/project-file-downloads.ts`, `apps/sim/lib/api/contracts/v2/openapi/project-file-downloads.ts`, `apps/sim/lib/api/contracts/v2/openapi/unpublished-project-files.ts`, `apps/sim/app/api/projects/[id]/files/*/route.ts`, `apps/sim/app/api/v2/projects/[projectId]/files/*/route.ts`, `packages/sim-cli/src/commands/protocol/files-get.ts`, `packages/sim-cli/src/commands/protocol/index.ts`, `packages/sim-cli/src/contract/commands.ts`, `apps/sim/scripts/test-file-delivery-e2e.ts`, `apps/sim/scripts/test-project-file-rendered-e2e.ts`|Defines download and export API contracts and routes, documents the operations, adds CLI commands, and extends end-to-end checks.| |**Project archive download and snapshot export** `apps/sim/lib/projects/files/application/downloads.ts`, `apps/sim/lib/projects/files/api/download-presenter.ts`, `apps/sim/lib/uploads/server/markdown-export.ts`|Adds bounded ZIP downloads and Markdown snapshot exports with embedded-asset handling, receipt checks, provenance tracking, and delivery auditing.| |**Project ZIP extraction and shared archive preparation** `apps/sim/lib/api/contracts/project-file-extraction.ts`, `apps/sim/lib/api/contracts/v2/project-file-extraction.ts`, `apps/sim/lib/api/contracts/v2/openapi/project-files.ts`, `apps/sim/app/api/projects/[id]/files/[fileId]/extract/route.ts`, `apps/sim/app/api/v2/projects/[projectId]/files/[fileId]/unzip/route.ts`, `apps/sim/lib/projects/files/application/extract.ts`, `apps/sim/lib/workspace-files/extraction-lease.ts`, `apps/sim/lib/workspace-files/archive-extraction.ts`, `apps/sim/lib/uploads/archive.ts`, `apps/sim/lib/projects/files/__integration__/content-bulk.integration.ts`|Adds lease-backed project ZIP extraction with archive validation, staging, transactional publication, and extraction result reporting.| **Workspace Archive Delivery** |Layer / File(s)|Summary| |:---|:---| |**Workspace selection and download authorization** `apps/sim/lib/workspace-files/download-selection.ts`, `apps/sim/lib/workspace-files/application/download-workspace-file-items.ts`, `apps/sim/lib/workspace-files/application/download-workspace-file-items.test.ts`, `apps/sim/lib/workspace-files/limits.ts`, `apps/sim/app/api/workspaces/[id]/files/download/route-archive.test.ts`|Adds shared selection normalization and folder expansion. Workspace downloads check capabilities, selection consistency, receipts, provenance, and size limits.| |**Shared streaming archive presentation** `apps/sim/lib/workspace-files/api/archive-presenter.ts`, `apps/sim/lib/workspace-files/api/archive-presenter.test.ts`, `apps/sim/lib/workspace-files/api/index.ts`, `apps/sim/app/api/workspaces/[id]/files/download/route.ts`, `apps/sim/app/api/v2/files/bulk-download/route.ts`|Adds a shared ZIP presenter that streams files sequentially and handles cancellation. Workspace download routes use the shared presenter.| **Priority:** ➖ Normal **Estimated code review effort:** 4 (Complex) | ~75 minutes **Change:** Feature ### Sequence Diagram(s) ```mermaid sequenceDiagram participant CLI participant CopyRoute participant copyFileItems participant CopyAuthorizer participant Storage CLI->>CopyRoute: Submit source and destination CopyRoute->>copyFileItems: Validate and execute copy copyFileItems->>CopyAuthorizer: Check source-read and destination-write access copyFileItems->>Storage: Stage copied content copyFileItems->>CopyRoute: Return copied files and folders CopyRoute->>CLI: Present copy response ``` Merge Risk: 🟡 Moderate · up to e41cf The new cross-owner copy, Project download/export, and ZIP extraction flows are broadly guarded. However, the session-based Project download and export endpoints have no request throttling, and each request can hold hundreds of MiB in memory. Add a per-user rate limit and the missing copy-operation delivery declaration before merging. Security architecture risk: 🟡 Moderate · up to e41cf Independent access checks, bounded processing, and transactional revalidation reduce transfer risk. However, secret-related metadata now crosses file ownership boundaries without the existing scope restriction, and its downstream isolation remains unresolved. **Retained concerns** - **Medium · security · inferred:** The new copy flow persists source-scoped secret identifiers and encrypted provenance under a separately owned destination without applying the existing cross-scope downgrade. File read/write authorization does not by itself establish authority to transfer this metadata. Public byte presenters omit it, but internal reads can return it and downstream scope enforcement remains unresolved. This is an inferred boundary concern, not a verified plaintext-secret disclosure. Security review details **Security Blast Radius** - _inferred_ — The transfer scope is the selected source content and destination storage owned by projects/workspaces the acting human can independently read and write. Destination ownership makes copied content available through destination access rules. This review did not establish arbitrary-owner access, infrastructure privilege expansion, or plaintext-secret disclosure. **Security Findings and Attack Paths** - _inferred_ — A caller with source-read and destination-write access can cause source secret-provenance entries to be stored under the destination owner. The existing helper would downgrade such cross-scope entries, but the new path bypasses that restriction. The integration test confirms intentional propagation; HTTP presenters omit sidecars, so a complete external disclosure or downstream decryption attack path remains unproven. **Trust Boundaries and Controls** - _observed_ — Copy checks current subject identity, project/workspace membership, and owner-specific read/write authority. Project download/export calls content admission before loading contributing bytes and again before returning results. Copilot principals require an installed classification gate; other authenticated callers retain ordinary permission-based behavior. **Resilience and Maintainability Implications** - _observed_ — Extraction uses an atomic database claim with token-checked release, a cooperative work deadline, and transaction-time checks against expired or superseded leases. Reauthorization, source snapshot validation, publication, and storage accounting occur before the final fencing check, containing concurrent or stale work. **Hardening Proposals** - _proposed_ — Define the permitted cross-owner secret-metadata transfer policy explicitly and exercise downstream consumers with different source/destination users and workspaces. Distinguish preserving content taint from granting access to originating secret metadata. - _proposed_ — Document that copy and extraction are not exactly-once operations, including recovery after lost responses or uncertain commits. If automatic mutation retries are supported, consider durable request identities and reconciliation before replaying publication. Pre-merge checks: 4 · 1 Failed checks: 1 inconclusive | Check name | Status | Explanation | Resolution | | :---------------- | :--------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------- | | Docstring Coverage | | Docstring coverage is 35.09% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 57 functions across 50 files. (16 skipped… | Write docstrings for the functions missing them to satisfy the coverage threshold. | Passed checks: 4 passed | Check name | Status | Explanation | | :------------------------ | :--------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------------------------- | | Description Check | | Check skipped - the reviewer’s high-level summary is enabled. | | Title check | | The title clearly identifies the main changes: cross-owner file copying and bulk transfer support. It is concise and specific. | | Linked Issues check | | Check skipped because no linked issues were found for this pull request. | | Out of Scope Changes check | | Check skipped because no linked issues were found for this pull request. | Full details: Docstring Coverage **Explanation** Docstring coverage is 35.09% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 57 functions across 50 files. (16 skipped: 3 unsupported, 13 over the file limit.) **Resolution** Write docstrings for the functions missing them to satisfy the coverage threshold. ✨ Finishing Touches: 💡 1 📝 Generate docstrings: 💡 🧪 Generate unit tests (beta) ### Usage-based review receipt - Mode: Continue automatically - Reviewed files: 66 - Waived: $16.50 (charged $0.00) - View usage details > [!NOTE] > This review exceeded your plan’s limits and used usage-based reviews—free during trial, billed after paid activation unless disabled. **Manage usage-based reviews**. Comment `@the reviewer help` to get the list of available commands. |
| #9018 2026-10-20 20:16 | coderabbit inline · P1 | apps/sim/app/api/projects/[id]/files/download/route.ts:15 | defect-performance | **🩺 Stability & Availability** | **🟠 Major** | **⚡ Quick win**
**Add a per-user rate limit to the buffered archive route.**
`downloadProjectFileItems` keeps every selected file in memory, up to `MAX_ZIP_DOWNLOAD_BYTES` (250 MiB). It then buffers the ZIP output, up to the same limit. A request can therefore hold about 500 MiB until the response is sent.
`internalRateLimits.none` puts no limit on how many of these requests one session can run. A few concurrent requests from one authenticated Project member can exhaust process memory. The internal export route has the same problem (`apps/sim/app/api/projects/[id]/files/[fileId]/export/route.ts`, Line 19), with a 250 MiB limit for each expo … the rest (1130 characters)rt. The matching v2 routes already apply `v2RateLimits.publicApi`. Proposed fix ```diff --- "a/apps/sim/app/api/projects/[id]/files/download/route.ts" +++ "b/apps/sim/app/api/projects/[id]/files/download/route.ts" @@ -12,7 +12,7 @@ contract: downloadProjectFileItemsContract, auth: internalSessionAuth, operation: downloadProjectFileItems.operation, - rateLimit: internalRateLimits.none({ reason: 'Authenticated bounded Project archive download' }), + rateLimit: internalRateLimits.user({ bucketName: 'project-files.download' }), errorPolicy: internalOrchestrationErrorPolicy, headSafe: false, mapInput: ({ params, query }) => ({ projectId: params.id, ...query }), ``` Apply the same change to the internal export route. 📝 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. ```suggestion rateLimit: internalRateLimits.user({ bucketName: 'project-files.download' }), ``` |
| #9018 2026-10-20 20:16 | coderabbit inline · P2 | apps/sim/lib/workspace-files/application/copy-operation.ts:15 | defect-functional | **🗄️ Data Integrity & Integration** | **🟡 Minor** | **⚡ Quick win**
**Declare `contentDelivery: 'none'` for `files.copy`.**
`fileCopyOperation` allows `resource_delegated` Copilot principals. The shared contract requires every operation with `delegatedServices: ['copilot']` to declare `contentDelivery`. The copy response returns copied file and folder records, not file content, so use `'none'`.
Suggested fix
```diff
principalKinds: ['session', 'personal_api_key', 'oauth_access_token', 'resource_delegated'],
delegatedServices: ['copilot'],
delegationAudience: 'sim:files:copy',
+ contentDelivery: 'none',
} as const
```
The route-inventory predicate does not include `resource_ … the rest (121 characters)delegated`, so the claim that this specific test necessarily catches the route is too broad. _Source: Coding guidelines_ |
| #9018 2026-10-20 20:16 | coderabbit review-body | — | summary | **Actionable comments posted: 2**
🧹 Nitpick comments: 2
apps/sim/lib/workspace-files/api/archive-presenter.test.ts: 1
`3-3`: **📐 Maintainability & Code Quality** | **🔵 Trivial** | **⚡ Quick win**
**Import `flushMacrotask` from its own helper file.**
Line 3 imports from the `@sim/testing/helpers` barrel. Line 4 already imports `createDeferred` from its own file.
♻️ Proposed change
```diff
-import { flushMacrotask } from '@sim/testing/helpers'
+import { flushMacrotask } from '@sim/testing/helpers/async'
```
As per coding guidelines: "Import the one file you need (`@sim/testing/mocks/<file>`, `@sim/testing/helpers/<file>`, …); the `@sim/testing` barrel costs module-fetch time per tes … the rest (1333 characters)t file." _Source: Coding guidelines_ apps/sim/lib/workspace-files/application/download-workspace-file-items.ts: 1 `203-215`: **📐 Maintainability & Code Quality** | **🔵 Trivial** | **⚡ Quick win** **Remove the repeated `files.bulk_download` check after `authorize`.** `downloadWorkspaceFileItems.authorize` already runs `authorizeResource: requireDownloadCapability`. The HEAD-probe test confirms this, because `authorize` rejects with `capability: 'files.bulk_download'`. Lines 204-215 then run the same `assertWorkspaceCapability` call again. This adds one more capability lookup to each archive download. It also creates a second copy of the predicate, and the two copies can drift apart. Keep the single re-authorization call. ♻️ Proposed change ```diff await downloadWorkspaceFileItems.authorize({ principal, input }) - if (context.fileId === undefined) { - const actingUserId = capabilityGovernedPrincipalUserId(principal) - if (actingUserId) { - // permission-group-enforced: files.bulk_download — publication must use the current archive capability. - await assertWorkspaceCapability( - actingUserId, - context.workspaceId, - 'files.bulk_download', - context.workspaceOrganizationId - ) - } - } const [currentFiles, currentFolders] = await Promise.all([ ``` |
| #9018 2026-10-20 20:18 | greptile issue-comment | — | summary | Confidence Score: 4/5
**[High impact]** The PR adds file\-transfer paths that reach stored content across workspace and Project owners\.
The remaining performance concern is non-blocking and does not prevent merging.
Findings
1. **Extraction repeatedly reloads folder paths**
Reviews (1) · Last reviewed commit: "feat(project-files): add cross-owner cop..." · Reviewed by the reviewer |
| #9018 2026-10-20 20:18 | greptile inline · P2 | apps/sim/lib/workspace-files/archive-extraction.ts:152 | defect-performance | **Extraction repeatedly reloads folder paths**
Each nested folder created by `commitFileArchiveInTx` calls `createFileFolder`, which reloads every destination-owner folder and rebuilds their paths, although this loop only uses `created.id`. This adds non-blocking performance overhead for folder-heavy archives: an executed 1,000-directory workload performed 1,001 owner-wide reads and 501,501 path encodings inside the extraction transaction.
Use `createFileFolderRow` for nested folders and retain path loading for the root. The same workload with that substitution preserved the resulting tree and files while reducing path hydration to one read.
Note: If this suggestion doesn't match your tea … the rest (1094 characters)m's coding style, reply to this and let me know. I'll remember it for next time! Artifacts **Evidence from the check** - Loads the specified Git revisions and executes real extraction and folder-manager bodies against an instrumented in-memory database boundary, making the validation reproducible. **Command output from the check** - Runs seven workloads through the unchanged head extraction path and records growing owner-wide reads and path encodings, confirming redundant hydration. **Command output from the check** - Repeats the same workloads with only nested calls changed in memory to the real row-only writer, showing that root-only hydration suffices. **Command output from the check** - Executes equivalent folder-creation calls against the base manager and shows matching hydration counts, establishing that the manager cost predates this PR. **Command output from the check** - Compares all seven captured workloads and verifies identical output digests and lock-call counts across runs, isolating the removable path-hydration work. Ran code and verified through TREX |
| #9018 2026-10-20 20:20 | cubic review-body | — | summary | **23 issues found** across 69 files
View guided diff | Turn on auto-fix | Re-trigger the reviewer |
| #9018 2026-10-20 20:20 | cubic inline · P1 | apps/sim/app/api/projects/[id]/files/download/route.ts:15 | defect-performance | Limit this buffered archive route per user; concurrent requests can retain up to 250 MiB of selected files and another 250 MiB of ZIP output, exhausting process memory.
```suggestion
rateLimit: internalRateLimits.user({ bucketName: 'project-files.download' }),
``` |
| #9018 2026-10-20 20:20 | cubic inline · P2 | apps/sim/lib/projects/files/__integration__/authorization-bulk.integration.ts:294 | tests | This test title says cross-organization copy is blocked, but the second assertion expects the same copy to succeed for a session principal. That user is not a member of the destination organization. Either rename the test to describe the session behavior or assert the same `not_found` result for the session principal. |
| #9018 2026-10-20 20:20 | cubic inline · P2 | apps/sim/lib/workspace-files/archive-extraction.ts:144 | defect-performance | Intermediate folders use `createFileFolder`, which reloads every folder for the owner and rebuilds the full path map on each call. Inside the commit transaction, an archive with many nested folders repeats that full scan once per folder. Use `createFileFolderRow` here, as `copy.ts` does for bulk tree writes; only the id is needed. Add it to the file-folder-manager import. |
| #9018 2026-10-20 20:20 | cubic inline · P2 | knip.jsonc:58 | quality | This blanket `["exports", "types"]` ignore removes the unused-export ratchet for the whole file, not just the stacked consumer. Many of these exports (e.g. `copiedFileSchema`, `FileCopySource`, `extractProjectFileResponseSchema`, `V2ProjectFileUnzipResult`) have no importer today. Delete the unused exports or drop the `export` keyword, and keep only the contract constants that routes import. If an export truly needs to stay for a downstream PR, mark it `@public` with the reason, and name the consumer and removal condition the way the existing entries do. |
| #9018 2026-10-20 20:20 | cubic inline · P2 | apps/docs/content/docs/cli/files.mdx:805 | docs | `cli/files.mdx` is generated by `scripts/generate-cli-docs.ts`, and `files` is not in `GUIDE_PAGES`. This hand-added Copy section will be overwritten on the next `generate:cli-docs` run, and `check:cli-docs` will fail. Remove the edit and regenerate the page instead. |
| #9018 2026-10-20 20:20 | cubic inline · P2 | apps/sim/scripts/test-file-copy-e2e.ts:171 | tests | This check never creates an unselected sibling, so the count assertions cannot detect copying it. Add a sibling folder or file beside `root` and assert neither appears in the copy result. |
| #9018 2026-10-20 20:20 | cubic inline · P2 | apps/sim/lib/workspace-files/application/copy-operation.ts:10 | defect-functional | This operation is reachable from Copilot (`delegatedServices: ['copilot']`) but declares no `contentDelivery`. Add `contentDelivery: 'none'` so it meets the reviewed-answer rule that the workspace and organization builders enforce. The copy response contains only metadata and revisions, so `'none'` fits. |
| #9018 2026-10-20 20:20 | cubic inline · P2 | apps/sim/scripts/test-file-copy-e2e.ts:239 | tests | Cleanup ignores the archive response, so a failed archive leaves fixtures behind and the report still shows a pass. Record a failed check when the cleanup status is an error.
```suggestion
const cleanup = await request('POST', path, { fileIds: item.fileIds, folderIds: item.folderIds }, 'session')
if (cleanup.status >= 300) checks.push({ name: `cleanup ${path}`, passed: false, durationMs: 0, error: cleanup.text.slice(0, 300) })
``` |
| #9018 2026-10-20 20:20 | cubic inline · P2 | apps/sim/scripts/test-file-copy-e2e.ts:224 | tests | This assertion is vacuous: copied folders get new IDs, so comparing against the source `nested.id` is always false. It also contradicts the `folderIds.length === 2` check above, since the nested folder should be copied. To verify the nested folder was copied with the right name, assert on the copied folder names instead.
```suggestion
toArray(result.folders).some((folder) => toRecord(folder).name === 'nested'),
true
``` |
| #9018 2026-10-20 20:20 | cubic inline · P2 | apps/sim/lib/api/contracts/file-copy-input.ts:7 | defect-functional | This schema accepts owner IDs with surrounding whitespace, but the copy authorization boundary rejects them after contract parsing. Normalize IDs here to keep the request contract and runtime validation consistent.
```suggestion
entityId: z.string().trim().min(1).max(200).describe('Identifier of the owning workspace or Project.'),
``` |
| #9018 2026-10-20 20:20 | cubic inline · P2 | apps/sim/lib/workspace-files/copy-references.ts:172 | defect-functional | When the language scan throws `DocCompileUserError`, `return content` drops all the regex-based rewrites already collected. Keep the collected `replacements` and skip only the language-based pass, so the copy still repoints the selected identities. |
| #9018 2026-10-20 20:20 | cubic inline · P2 | apps/sim/lib/workspace-files/download-selection.ts:21 | hardening | This checks the limit only after deduplication, so legacy download requests with more than 1,000 repeated IDs or folder paths pass the request cap. Validate the raw array lengths before creating the sets.
```suggestion
if (input.fileIds.length > MAX_WORKSPACE_FILE_BULK_REQUEST_IDS)
throw new OrchestrationError(
'validation',
`Too many file IDs selected. Select ${MAX_WORKSPACE_FILE_BULK_REQUEST_IDS} or fewer files.`
)
if (input.folderIds.length + (input.folderPaths?.length ?? 0) > MAX_WORKSPACE_FILE_BULK_REQUEST_IDS)
throw new OrchestrationError(
'validation',
`Too many folders selected. Select ${MAX_WORKSPACE_FILE_BULK_REQUEST_IDS} or fewer folders.`
… the rest (165 characters)) const fileIds = [...new Set(input.fileIds)] const folderIds = [...new Set(input.folderIds)] const folderPaths = [...new Set(input.folderPaths ?? [])] ``` |
| #9018 2026-10-20 20:20 | cubic inline · P2 | apps/sim/lib/workspace-files/api/archive-presenter.ts:81 | defect-functional | This treats every upstream `AbortError` as client cancellation; an independent storage abort leaves the archive open and the download hanging. Ignore the error only when `closed.signal.aborted` is true.
```suggestion
if (closed.signal.aborted && toError(error).name === 'AbortError') return
``` |
| #9018 2026-10-20 20:20 | cubic inline · P2 | apps/sim/lib/projects/files/application/downloads.ts:428 | defect-functional | This catch skips every `downloadFile` failure, including storage outages. A transient error then produces a successful export with the image missing and no signal to the user. Match the workspace export: skip only missing or unauthorized assets and rethrow other errors. |
| #9018 2026-10-20 20:20 | cubic inline · P2 | apps/sim/lib/workspace-files/application/download-workspace-file-items.ts:165 | defect-performance | This fetch can buffer up to 50 MiB even when the archive has only a few bytes remaining; concurrent near-limit downloads can multiply that avoidable memory use. Cap the fetch at the remaining archive allowance and retain the distinct error for an archive-limit overflow. |
| #9018 2026-10-20 20:20 | cubic inline · P2 | apps/sim/lib/workspace-files/copy-references.ts:157 | defect-functional | Valid JS/Python source comments with a file reference followed by sentence punctuation are left pointing at the source because the syntax iterator skips comments and this fallback is disabled for language sources. Apply the punctuation fallback regardless of `language`. |
| #9018 2026-10-20 20:20 | cubic inline · P2 | apps/sim/lib/projects/files/__integration__/authorization-bulk.integration.ts:179 | tests | This uses the same report path as `authorization.integration.ts`, so the full integration run drops whichever suite writes first. Give this suite a distinct report path or aggregate both results.
```suggestion
resolve('test-results/project-file-authorization-bulk.json')
``` |
| #9018 2026-10-20 20:20 | cubic inline · P2 | apps/sim/lib/projects/files/application/extract.ts:231 | defect-functional | A deadline abort during provider I/O can reject with the provider’s `AbortError`, not `deadline.reason`, so this condition misses the timeout and returns a generic failure. Check that the composed signal’s reason came from the deadline instead of matching the caught error.
```suggestion
if (deadline.aborted && signal.reason === deadline.reason)
``` |
| #9018 2026-10-20 20:20 | cubic inline · P2 | apps/sim/app/api/projects/[id]/files/[fileId]/export/route.ts:19 | defect-performance | Apply a per-user limit to this buffered export route; concurrent exports can hold up to 250 MiB each and exhaust process memory. |
| #9018 2026-10-20 20:20 | cubic inline · P3 | apps/sim/lib/api/contracts/file-copy.ts:28 | docs | The `uploadedBy` description says 'when available', but the schema requires a non-empty string and the presenter always sets it. Drop the qualifier so API docs match the contract.
```suggestion
uploadedBy: projectFileRecordSchema.shape.uploadedBy.describe(
'User who performed the copy.'
),
``` |
| #9018 2026-10-20 20:20 | cubic inline · P3 | apps/sim/lib/workspace-files/copy-references.ts:187 | quality | Move this import to the top of the file with the other imports. ES import hoisting makes it work at runtime, but an import after code breaks the convention and trips import-order lint rules. |
| #9018 2026-10-20 20:20 | cubic inline · P3 | apps/sim/lib/workspace-files/application/download-workspace-file-items.ts:204 | quality | This `files.bulk_download` assertion repeats the one `authorize` just ran through `requireDownloadCapability`, with the same predicate and inputs. Remove the block. If the post-render re-check is intended, rely on the `authorize` call alone and note that it also re-reads the context. |
| #9018 2026-10-20 20:20 | cubic inline · P3 | apps/sim/lib/projects/files/application/downloads.ts:278 | quality | The aggregate admission labels a `workspace-file` source with `input.projectId`. Admission is decided by object identity, so behavior is unaffected, but refusal attribution and logs point at the wrong entity. Use a label that names the Project archive rather than a file kind. |
| #9063 2026-10-20 20:21 | coderabbit issue-comment | — | summary | 📝 Walkthrough
Project file reads now stream content and verify file state before delivery. Artifact rendering separates planning, dependency downloads, and rendering, then rechecks revisions. Search readiness updates run after successful delivery and use bounded owner locks.
**Changes: Project file delivery and artifact rendering**
|Layer / File(s)|Summary|
|:---|:---|
|**Snapshot-based file and search delivery** `apps/sim/lib/workspace-files/search/delivery.ts`, `apps/sim/lib/projects/files/application/search.ts`, `apps/sim/lib/projects/files/application/previews.ts`, `apps/sim/app/api/projects/[id]/files/inline/route.ts`, `apps/sim/lib/projects/files/__integration__/content-rendered.in … the rest (6639 characters)tegration.ts`, `knip.jsonc`|Inline reads stream project objects and check file state before returning delivery metadata. Search performs admission, filtering, redaction, and delivery reporting after snapshot execution.| |**Artifact rendering and search readiness** `apps/sim/lib/projects/files/application/artifacts.ts`, `apps/sim/lib/projects/membership.ts`, `apps/sim/lib/workspace-files/page-compile.ts`, `apps/sim/lib/workspace-files/page-document.server.ts`, `apps/sim/lib/workspace-files/search/artifact-ready.ts`, `apps/sim/lib/workspace-files/search/owner-policy.ts`, `apps/sim/lib/projects/files/__integration__/content-rendered.integration.ts`, `.github/workflows/checks.yml`|Artifact rendering validates and downloads dependencies, checks revisions, and schedules search readiness updates after successful delivery. Lock acquisition supports caller-specific timeouts. Integration tests cover rendering, contention, and foreign embeds; the E2E workflow caps native addon build parallelism at four jobs.| **Priority:** ➖ Normal **Estimated code review effort:** 4 (Complex) | ~45 minutes **Change:** Bug fix ### Sequence Diagram(s) ```mermaid sequenceDiagram participant Route as Inline files API route participant Reader as readProjectInlineFile participant Storage as Project object storage participant Resolver as Project file resolver participant Presenter as presentFileDelivery Route->>Reader: Request inline file Reader->>Storage: Open object under organization context Storage-->>Reader: Return file stream Reader->>Resolver: Re-resolve file by immutable ID Resolver-->>Reader: Return current file record Reader-->>Route: Return metadata and stream Route->>Presenter: Present stream with cache-control settings ``` **Suggested reviewers:** `mzxchandra` Merge Risk: 🔵 Low · up to 9b4cd Project file reads now stream content and recheck file state before delivery, and artifact search readiness is updated after delivery with bounded lock waits. One small inconsistency remains: a requested excerpt view is not carried into the second file check, so the two checks can disagree for callers that request it. The inline route does not request a view, so this is a minor follow-up that is easy to fix and does not block the main read paths. Security architecture risk: 🔵 Low · up to 9b4cd Project ownership, revision checks, and protected-content controls remain in place, while search updates no longer require upgrading locks during reads. No newly introduced security issue was verified. Remote-rendering isolation and cancellation guarantees could not be fully established. **Retained concerns** No architecture-level concerns identified. Security review details **Security Blast Radius** - _inferred_ — The inspected data-access path remains scoped to an authorized Project and its referenced files, although storage and compilation execute with service authority. No cross-Project storage delegation or new renderer authority was established by the base-to-head comparison. **Security Findings and Attack Paths** - _observed_ — The existing E2B compilation branch does not forward the request AbortSignal into remote rendering. Provider network-egress restrictions were not established. The shared compiler is unchanged and was already reachable from Project rendering at the base, so these are existing limitations or proof gaps, not verified PR-introduced attack paths. **Trust Boundaries and Controls** - _observed_ — Search validates owner scope, source revision, ready build identity, and dependency revisions before marking a preview current. Admission runs after snapshot commit; noncurrent or refused previews are replaced with withheld text. Copilot principals still require classification and an active content gate. **Resilience and Maintainability Implications** - _observed_ — Dependency downloads check declared byte budgets, limit concurrency, cap individual transfers, reject actual aggregate overruns, and abort sibling work on failure. Concurrent reads do not reserve aggregate capacity, so inaccurate size metadata can cause transient overfetch. Inline validation failures cancel the opened stream; consumer cancellation destroys its source. **Hardening Proposals** - _proposed_ — Establish the document sandbox's explicit egress policy and extend request cancellation through remote compilation. These would close existing control-proof gaps rather than remediate a verified vulnerability introduced by this PR. Pre-merge checks: 4 · 1 Failed checks: 1 warning | Check name | Status | Explanation | Resolution | | :---------------- | :----------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------- | | Docstring Coverage | | Docstring coverage is 58.82% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 17 functions across 11 files. (2 skipped:… | Write docstrings for the functions missing them to satisfy the coverage threshold. | Passed checks: 4 passed | Check name | Status | Explanation | | :------------------------ | :--------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------- | | Description Check | | Check skipped - the reviewer’s high-level summary is enabled. | | Title check | | The title clearly identifies the two main changes: post-commit rendered-artifact search requeueing and reduced Project read transaction scope. | | Linked Issues check | | Check skipped because no linked issues were found for this pull request. | | Out of Scope Changes check | | Check skipped because no linked issues were found for this pull request. | Full details: Docstring Coverage **Explanation** Docstring coverage is 58.82% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 17 functions across 11 files. (2 skipped: 2 unsupported.) **Resolution** Write docstrings for the functions missing them to satisfy the coverage threshold. ✨ Finishing Touches: 💡 1 📝 Generate docstrings: 💡 🧪 Generate unit tests (beta) Comment `@the reviewer help` to get the list of available commands. |
| #9063 2026-10-20 20:25 | coderabbit inline · P2 | apps/sim/lib/projects/files/application/previews.ts:108 | defect-functional | **🎯 Functional Correctness** | **🟡 Minor** | **⚡ Quick win**
**Forward `view` to the head-fence re-resolve.**
When `args.input.view` is `'excerpt'`, the second `resolveInlineRecord.execute` call defaults to `'opaque'`. The two admissions can therefore evaluate different views. Pass the requested view to both calls.
🐛 Suggested fix
```diff
--- "a/apps/sim/lib/projects/files/application/previews.ts"
+++ "b/apps/sim/lib/projects/files/application/previews.ts"
@@ -102,10 +102,14 @@
)
)
try {
const { file, secretProvenance } = await resolveInlineRecord.execute({
...args,
- input: { projectId: args.input.projectId, referenceFileId: snapshot.file.id }, … the rest (868 characters)+ input: { + projectId: args.input.projectId, + referenceFileId: snapshot.file.id, + view: args.input.view, + }, }) if ( file.key !== snapshot.file.key || file.contentUpdatedAt.getTime() !== snapshot.file.contentUpdatedAt.getTime() ``` 📝 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. ```suggestion const { file, secretProvenance } = await resolveInlineRecord.execute({ ...args, input: { projectId: args.input.projectId, referenceFileId: snapshot.file.id, view: args.input.view, }, }) ``` |
| #9063 2026-10-20 20:25 | coderabbit review-body | — | summary | **Actionable comments posted: 1** |
| #9063 2026-10-20 20:30 | cubic inline · P2 | apps/sim/lib/projects/files/application/artifacts.ts:218 | defect-performance | `unclaimed` is granted in full to every worker, so 20 underreported inputs can each buffer up to the per-file cap before `received` rejects the batch. Cap each read at its declared size or reserve the shared remainder across active reads.
```suggestion
maxBytes: Math.min(limits.perFile, declared[index]),
``` |
| #9063 2026-10-20 20:30 | cubic review-body | — | summary | **1 issue found** across 13 files
View guided diff | Turn on auto-fix | Re-trigger the reviewer |
| #9063 2026-10-20 20:31 | greptile issue-comment | — | summary | Confidence Score: 5/5
**[Medium impact]** No merge-blocking issues were identified within the reviewed changes.
Reviews (1) · Last reviewed commit: "fix(project-files): requeue rendered-art..." · Reviewed by the reviewer |
| #9060 2026-10-20 20:32 | coderabbit issue-comment | — | summary | 📝 Walkthrough
The PII service now initializes Presidio engines and derived NLP state during FastAPI lifespan startup. The Docker image launches Uvicorn through an entrypoint that configures worker count and, when applicable, request recycling.
**Changes: PII Worker Startup**
|Layer / File(s)|Summary|
|:---|:---|
|**Initialize PII state during lifespan** `apps/pii/server.py`|The application now builds the analyzer, batch analyzer, anonymizer, NER entity set, and per-language blank NLP artifacts during lifespan startup instead of at module import.|
|**Configure container worker launch** `docker/pii-entrypoint.sh`, `docker/pii.Dockerfile`|The image copies and executes the entrypoint to laun … the rest (5042 characters)ch Uvicorn. It defaults to one worker, 4000 maximum requests, and 2000 jitter; request recycling limits apply when more than one worker is configured.| **Priority:** ➖ Normal **Estimated code review effort:** 3 (Moderate) | ~20 minutes **Change:** Bug fix ### Sequence Diagram(s) ```mermaid sequenceDiagram participant Docker as Docker image participant Entrypoint as PII entrypoint participant Uvicorn participant FastAPI participant Presidio participant NLPArtifacts Docker->>Entrypoint: Execute entrypoint Entrypoint->>Uvicorn: Exec with configured worker arguments Uvicorn->>FastAPI: Start application worker FastAPI->>FastAPI: Run lifespan initialization FastAPI->>Presidio: Build analyzer, batch analyzer, and anonymizer Presidio-->>FastAPI: Return initialized engines FastAPI->>NLPArtifacts: Create per-language blank artifacts FastAPI-->>Uvicorn: Yield after initialization ``` Merge Risk: 🟡 Moderate · up to ee37a A negative recycling-jitter setting can leave the PII service unavailable. Validate it before merging, unless that configuration risk is explicitly accepted. Security architecture risk: 🔵 Low · up to ee37a The changes preserve the HTTP interface and non-root execution while changing startup and worker recovery behavior. No new privilege expansion or redaction bypass was established, but production recovery capacity and completion of long-running requests remain unverified. **Retained concerns** No architecture-level concerns identified. Security review details **Security Blast Radius** - _inferred_ — The directly affected security property is availability of PII processing across workers in the same container. Traffic reaching existing endpoints can advance request-driven retirement, but the changes do not establish new network reachability or cross-tenant authority. Deployed ingress controls and downstream handling of redaction failures remain unknown. **Trust Boundaries and Controls** - _inferred_ — Lifespan completion is the readiness barrier for worker-local processing state. Initialization has no fallback that serves requests with missing engines. The existing validation-error handler also remains unchanged and omits offending input values from its error response. **Resilience and Maintainability Implications** - _inferred_ — Worker replacement reconstructs process-local engines rather than transferring shared persistent state. Interrupted requests can lose their response, but the inspected handlers provide no path that returns a partially assembled redaction response. This does not establish that downstream callers fail closed. **Hardening Proposals** - _proposed_ — Validate recycling under peak traffic and overlapping cold starts, align termination and upstream timeout budgets, and establish that callers retry safely or fail closed when redaction is interrupted. These are validation proposals, not observed vulnerabilities. Pre-merge checks: 4 · 1 Failed checks: 1 warning | Check name | Status | Explanation | Resolution | | :---------------- | :----------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------- | | Docstring Coverage | | Docstring coverage is 75.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 4 functions across 2 files. (1 skipped: 1… | Write docstrings for the functions missing them to satisfy the coverage threshold. | Passed checks: 4 passed | Check name | Status | Explanation | | :------------------------ | :--------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------- | | Description Check | | Check skipped - the reviewer’s high-level summary is enabled. | | Title check | | The title clearly summarizes both main changes: loading models within workers and recycling workers to control memory growth. | | Linked Issues check | | Check skipped because no linked issues were found for this pull request. | | Out of Scope Changes check | | Check skipped because no linked issues were found for this pull request. | Full details: Docstring Coverage **Explanation** Docstring coverage is 75.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 4 functions across 2 files. (1 skipped: 1 unsupported.) **Resolution** Write docstrings for the functions missing them to satisfy the coverage threshold. ✨ Finishing Touches: 💡 1 📝 Generate docstrings: 💡 🧪 Generate unit tests (beta) Comment `@the reviewer help` to get the list of available commands. |
| #9060 2026-10-20 20:33 | cubic review-body | — | summary | **No issues found** across 3 files
View guided diff | Turn on auto-fix | Re-trigger the reviewer |
| #9060 2026-10-20 20:34 | coderabbit inline · P1 | docker/pii-entrypoint.sh:11 | hardening | **🩺 Stability & Availability** | **🟠 Major** | **⚡ Quick win**
The requested validation is supported. `apps/pii/requirements.txt` pins Uvicorn 0.49.0, and a negative `PII_MAX_REQUESTS_JITTER` can cause worker startup failure when Uvicorn calculates the request limit. Validate that the value is non-negative before launching Uvicorn. |
| #9060 2026-10-20 20:34 | coderabbit review-body | — | summary | **Actionable comments posted: 1** |
| #9060 2026-10-20 20:39 | greptile issue-comment | — | summary | Confidence Score: 5/5
**[Medium impact]** The changes are safe to merge based on the completed startup, endpoint, and worker-lifecycle checks; no actionable issues remain.
Reviews (1) · Last reviewed commit: "fix(pii): load models only in workers an..." · Reviewed by the reviewer |
| #9061 2026-10-20 20:40 | coderabbit issue-comment | — | summary | 📝 Walkthrough
The CI workflow and promotion scripts now use a shared image promotion helper. Main-branch promotions assign a `release-${SOURCE_TAG}` tag alongside the `latest` deploy tag. Other branches continue without a release tag.
**Changes: Image Promotion**
|Layer / File(s)|Summary|
|:---|:---|
|**Shared image promotion helper** `.github/scripts/promote-image.sh`|The new helper validates promotion arguments and applies the deploy tag and optional release tag to the source image in one `docker buildx imagetools create` call.|
|**Release tags and promotion wiring** `.github/scripts/promote-app-image.sh`, `.github/workflows/ci.yml`|The app script delegates promotion to the shared help … the rest (4012 characters)er. The workflow sets `release-${SOURCE_TAG}` for main-branch promotions and passes the optional release tag to the app and non-app promotion scripts.| **Priority:** ⬇️ Low **Estimated code review effort:** 2 (Simple) | ~10 minutes **Change:** Feature **Suggested reviewers:** `theodorespeaks` Merge Risk: 🟡 Moderate · up to a5912 A failed release-tag push can leave latest updated without completing the promotion. Publish the release tag first before merging. Security architecture risk: 🔵 Low · up to a5912 The change preserves the existing production authorization and branch gates. The main risk is incomplete publication: production could advance before its rollback alias is secured. Actual retention and deployment-trigger rules remain unverified. **Retained concerns** - **Medium · reliability · inferred:** The new two-target publication does not establish a failure-safe commit boundary. The deploy tag is supplied before the release alias, with no repair path. Under sequential publication, failure or interruption after the deploy-tag write could initiate production deployment without its release alias, fail the promotion job, and skip downstream task-version promotion. A single command and app-last ordering do not resolve this intra-command failure window; exact runtime publication semantics remain unverified. Security review details **Security Blast Radius** - _inferred_ — The newly added registry writes span the four configured production image repositories. This can affect rollback availability across those components, but the evidence does not establish tenant counts, data-store access, or expanded runtime privileges. **Trust Boundaries and Controls** - _inferred_ — The changed path uses workflow identity and configured repository destinations rather than introducing a new untrusted input source. An ECR release alias is a retention handle, not an authorization or integrity boundary. Its ability to avoid unintended deployment depends on external tag-event filtering that remains unverified. **Resilience and Maintainability Implications** - _inferred_ — The security-relevant resilience issue is recovery containment rather than demonstrated attacker reachability: a partially published production promotion could lack the intended retained rollback handle and leave application and task-version rollout stages inconsistent. Source preflight and app-last ordering reduce other failure paths but cannot establish atomicity within the two-target publication. Pre-merge checks: 5 | Check name | Status | Explanation | | :------------------------ | :--------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Description Check | | Check skipped - the reviewer’s high-level summary is enabled. | | Title check | | The title clearly and concisely describes the main change: adding release- tags to production promotions to support rollback retention. | | Docstring Coverage | | No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff. Analyzed 0 functions across 2… | | Linked Issues check | | Check skipped because no linked issues were found for this pull request. | | Out of Scope Changes check | | Check skipped because no linked issues were found for this pull request. | Full details: Docstring Coverage **Explanation** No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff. Analyzed 0 functions across 2 files. (1 skipped: 1 unsupported.) ✨ Finishing Touches 📝 Generate docstrings 🧪 Generate unit tests (beta) Comment `@the reviewer help` to get the list of available commands. |
| #9061 2026-10-20 20:41 | cubic review-body | — | summary | **No issues found** across 3 files
View guided diff | Turn on auto-fix | Re-trigger the reviewer |
| #9061 2026-10-20 20:46 | coderabbit inline · P1 | .github/scripts/promote-image.sh:11 | defect-functional | **🩺 Stability & Availability** | **🟠 Major** | **⚡ Quick win**
**Publish the release tag before the deploy tag.**
Buildx pushes these tags separately, in order. If publication of `release-<sha>` fails after `latest` moves, the promotion step fails even though the app deploy tag has moved. The workflow then lacks the promotion outputs needed for its downstream cutover. Put the optional release tag first and the deploy tag last; one `imagetools create` call does not make the tag moves atomic. (github.com)
Proposed change
```diff
--- "a/.github/scripts/promote-image.sh"
+++ "b/.github/scripts/promote-image.sh"
@@ -7,6 +7,7 @@
SOURCE_TAG="${3:?source tag required}"
DEPLOY_TAG="${4:?deplo … the rest (877 characters)y tag required}" RELEASE_TAG="${5:-}" -TAG_ARGS=(-t "$REGISTRY/$REPOSITORY:$DEPLOY_TAG") -if [ -n "$RELEASE_TAG" ]; then TAG_ARGS+=(-t "$REGISTRY/$REPOSITORY:$RELEASE_TAG"); fi +TAG_ARGS=() +if [ -n "$RELEASE_TAG" ]; then TAG_ARGS+=(-t "$REGISTRY/$REPOSITORY:$RELEASE_TAG"); fi +TAG_ARGS+=(-t "$REGISTRY/$REPOSITORY:$DEPLOY_TAG") docker buildx imagetools create "${TAG_ARGS[@]}" "$REGISTRY/$REPOSITORY:$SOURCE_TAG" ``` 📝 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. ```suggestion TAG_ARGS=() if [ -n "$RELEASE_TAG" ]; then TAG_ARGS+=(-t "$REGISTRY/$REPOSITORY:$RELEASE_TAG"); fi TAG_ARGS+=(-t "$REGISTRY/$REPOSITORY:$DEPLOY_TAG") ``` |
| #9061 2026-10-20 20:46 | coderabbit review-body | — | summary | **Actionable comments posted: 1** |
| #9061 2026-10-20 20:46 | greptile issue-comment | — | summary | Confidence Score: 5/5
**[Medium impact]** The reviewed change is safe to merge; no blocking issues were found.
Reviews (1) · Last reviewed commit: "chore(ci): tag production promotions wit..." · Reviewed by the reviewer |
| #9064 2026-10-20 20:50 | coderabbit issue-comment | — | summary | 📝 Walkthrough
The changes update document cache validation, workspace file responses and delivery receipts, CSV preview parsing, and file-content guidance and contracts. Tests cover cache invalidation, MIME types, receipt validation, and preview truncation.
**Changes: Workspace file delivery**
|Layer / File(s)|Summary|
|:---|:---|
|**Referenced-file dependency tracking** `apps/sim/lib/uploads/utils/file.server.ts`, `apps/sim/lib/uploads/utils/file.server.test.ts`|Sim page renders now mark dependency on referenced files, including when a render reports no contributing files.|
|**Document cache validation** `apps/sim/lib/uploads/documents/compile.ts`, `apps/sim/lib/uploads/documents/compil … the rest (7408 characters)e.test.ts`|Cached builds are revalidated against referenced-file identity and version for supplied principals. Missing or changed files invalidate the cache. The cache now uses an LRU limit of 10 entries.| |**Workspace response resolution** `apps/sim/app/api/files/serve/[...path]/route.ts`, `apps/sim/app/api/files/serve/[...path]/route.test.ts`, `apps/sim/app/api/workspaces/[id]/files/inline/route.ts`|Workspace responses derive rendered MIME types from filenames and handle HEAD and raw requests separately. Cache and error responses receive updated headers. Inline route documentation describes caching behavior for immutable and mutable URLs.| |**Principal-aware delivery receipts** `apps/sim/lib/workspace-files/application/*`, `apps/sim/lib/workspace-files/read-receipt.ts`, `packages/testing/src/mocks/file-read-receipt.mock.ts`|Delivery finalization receives the principal. Receipt validation checks file identity, key, and content revision; callers, tests, and mocks use the updated validation contract.| **CSV preview handling** |Layer / File(s)|Summary| |:---|:---| |**Bounded CSV parsing** `apps/sim/lib/file-parsers/csv-preview-slice.ts`, `apps/sim/lib/file-parsers/csv-preview-slice.test.ts`|The parser returns collected rows as truncated when byte or record limits stop parsing. It skips malformed records, and tests cover truncation and blank-record behavior.| **File content guidance and contracts** |Layer / File(s)|Summary| |:---|:---| |**Exact-content download guidance** `.claude/rules/sim-content-delivery.md`, `.cursor/rules/sim-content-delivery.mdc`|The CLI policy documents describe opaque-content admission, imported entries, redacted output, and refusal conditions.| |**Embedded file reference contract** `apps/sim/hooks/use-file-content-source.tsx`, `apps/sim/executor/utils/resolved-secret-trace-registry.ts`, `apps/sim/app/workspace/[workspaceId]/files/components/file-viewer/rich-markdown-editor/image.test.ts`|The file content source no longer exposes or forwards an owner. The secret-trace incompleteness union no longer includes the project-file provenance reason, and the related public-source test was removed.| **Priority:** ➖ Normal **Estimated code review effort:** 4 (Complex) | ~45 minutes **Change:** Bug fix **Suggested reviewers:** `mzxchandra` Merge Risk: 🔵 Low · up to 00b4a Some workspace files may download instead of displaying inline. Restoring the stored-type fallback is advisable before merging; the remaining risk is bounded. Security architecture risk: 🔵 Low · up to 00b4a The inspected delivery paths preserve workspace authorization and browser safeguards while improving cached-document freshness. No newly introduced security regression was established. Confidence remains limited for legacy document consumers that omit caller identity. **Retained concerns** No architecture-level concerns identified. Security review details **Security Blast Radius** - _observed_ — The affected delivery boundary includes a requested workspace file and every contributor embedded in its rendered output. Receipts bind those files to an owner, ID, storage key, and content revision, and reject missing, deleted, moved, or superseded records at the checked snapshot. **Security Findings and Attack Paths** - _observed_ — Omitting filePrincipal still permits legacy cached bytes to be returned without contributor revalidation. This behavior predates the PR. Attachment-upload and execution-materialization callers omit the principal, but the inspected evidence does not establish a newly introduced attack path or complete end-to-end protections for those consumers. **Trust Boundaries and Controls** - _observed_ — Workspace key reads compare asserted workspace identity with canonical metadata and check owned-file access. Request-selected raw or HEAD handling continues through authorized workspace use cases. The rendered helper preserves the Principal and now namespaces user ownership as user:id. - _observed_ — Extension-derived MIME remains subject to centralized browser-safety headers: HTML/JS/CSS/XML filenames force attachment/octet-stream, responses use nosniff, and SVG responses receive a sandboxing CSP. The still-compiling response additionally gains no-store and nosniff. **Resilience and Maintainability Implications** - _observed_ — Current downloads and inline reads perform final admission after receipt validation and cancel their stream if that admission fails. Historical downloads separately reauthorize and recheck the selected version’s key, while contributor receipts remain subject to the shared finalizer. **Hardening Proposals** - _proposed_ — As separate hardening, make the authority contract explicit for legacy contributor-bearing cache reads: require a principal or a narrowly defined trusted capability, and verify terminal admission and freshness across attachment and materialization consumers. This addresses a pre-existing boundary, not a demonstrated regression in this PR. Pre-merge checks: 4 · 1 Failed checks: 1 warning | Check name | Status | Explanation | Resolution | | :---------------- | :----------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------- | | Docstring Coverage | | Docstring coverage is 56.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 25 functions across 18 files. (2 skipped:… | Write docstrings for the functions missing them to satisfy the coverage threshold. | Passed checks: 4 passed | Check name | Status | Explanation | | :------------------------ | :--------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------- | | Description Check | | Check skipped - the reviewer’s high-level summary is enabled. | | Title check | | The title clearly and concisely summarizes the main change: restoring workspace read-path behavior after rendered delivery. | | Linked Issues check | | Check skipped because no linked issues were found for this pull request. | | Out of Scope Changes check | | Check skipped because no linked issues were found for this pull request. | Full details: Docstring Coverage **Explanation** Docstring coverage is 56.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 25 functions across 18 files. (2 skipped: 2 unsupported.) **Resolution** Write docstrings for the functions missing them to satisfy the coverage threshold. ✨ Finishing Touches: 💡 1 📝 Generate docstrings: 💡 🧪 Generate unit tests (beta) ### Usage-based review receipt - Mode: Continue automatically - Reviewed files: 20 - Waived: $5.00 (charged $0.00) - View usage details > [!NOTE] > This review exceeded your plan’s limits and used usage-based reviews—free during trial, billed after paid activation unless disabled. **Manage usage-based reviews**. Comment `@the reviewer help` to get the list of available commands. |
| #9064 2026-10-20 20:59 | cubic inline · P2 | apps/sim/lib/uploads/documents/compile.test.ts:445 | tests | This rejects only the cache-validation lookup; the broker read during the rebuild then falls back to the earlier successful mock, so the supposedly deleted file is available again. Keep the metadata lookup failing during the rebuild and assert that compilation rejects after invoking the sandbox a second time. |
| #9064 2026-10-20 20:59 | cubic inline · P2 | apps/sim/app/api/files/serve/[...path]/route.ts:244 | defect-functional | Extensionless non-page workspace files lose their recorded MIME type here, so text or media files can be served as `application/octet-stream` instead of rendering inline. Preserve `renderedType` when the filename has no recognized extension.
```suggestion
: resolveEffectiveMimeType(undefined, file.name) === 'application/octet-stream'
? renderedType
: resolveEffectiveMimeType(undefined, file.name)
``` |
| #9064 2026-10-20 20:59 | cubic review-body | — | summary | **2 issues found** across 23 files
View guided diff | Turn on auto-fix | Re-trigger the reviewer |
| #9064 2026-10-20 21:00 | coderabbit inline · P2 | apps/sim/app/api/files/serve/[...path]/route.ts:244 | defect-functional | **🎯 Functional Correctness** | **🟡 Minor** | **⚡ Quick win**
**Fall back to the stored type when the extension gives no specific MIME type.**
`resolveEffectiveMimeType(undefined, file.name)` returns `application/octet-stream` for extensionless and unknown filenames. The `renderedType` value is not a safe fallback here: `fetchAuthorizedServableWorkspaceFileBuffer` does not pass `file.type` to `resolveServableDocBytes`, and its non-document branch also derives the type from the filename.
Use the stored `file.type` when the filename lookup returns the generic MIME type. Keep the `.csv` extension result unchanged.
🐛 Suggested fix
```diff
--- "a/apps/sim/app/api/files/serve/[...path]/rout … the rest (1551 characters)e.ts" +++ "b/apps/sim/app/api/files/serve/[...path]/route.ts" @@ -238,11 +238,16 @@ * local and cloud files, rather than by the stored record's type, so a `.csv` recorded as * `application/vnd.ms-excel` still opens inline. */ function renderedWorkspaceContentType(file: WorkspaceFileRecord, renderedType: string): string { return file.type === SIM_PAGE_CONTENT_TYPE && renderedType === 'text/html' ? renderedType - : resolveEffectiveMimeType(undefined, file.name) + : (() => { + const byName = resolveEffectiveMimeType(undefined, file.name) + return byName === 'application/octet-stream' + ? resolveEffectiveMimeType(file.type, file.name) + : byName + })() } /** * Sends a resolved file, attaching a validator only where the client may actually revalidate. ``` 📝 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. ```suggestion function renderedWorkspaceContentType(file: WorkspaceFileRecord, renderedType: string): string { return file.type === SIM_PAGE_CONTENT_TYPE && renderedType === 'text/html' ? renderedType : (() => { const byName = resolveEffectiveMimeType(undefined, file.name) return byName === 'application/octet-stream' ? resolveEffectiveMimeType(file.type, file.name) : byName })() ``` |
| #9064 2026-10-20 21:00 | coderabbit review-body | — | summary | **Actionable comments posted: 1** |
| #9064 2026-10-20 21:01 | greptile issue-comment | — | summary | Confidence Score: 4/5
**[Medium impact]** The changes reach bounded file\-preview and workspace file\-delivery workflows\.
The two reported CSV preview accuracy issues are non-blocking and do not establish an authorization failure or modification of stored data.
Findings
1. **Keep complete boundary rows**
2. **Recover after malformed records**
Reviews (1) · Last reviewed commit: "fix(files): restore workspace read-path ..." · Reviewed by the reviewer |
| #9064 2026-10-20 21:01 | greptile inline · P2 | apps/sim/lib/file-parsers/csv-preview-slice.ts:183 | defect-data | **Keep complete boundary rows**
When the next storage chunk exceeds the byte budget, destroying the parser bypasses its finalization. The new recovery then returns only rows already delivered through `on_record`, losing a complete record still awaiting parser lookahead. With exactly 8 MiB of accepted input ending in `last\n`, followed by another chunk, the preview omitted `last`; an ordinary wide-row fixture similarly returned 817 of 818 complete accepted rows. This is non-blocking preview incompleteness. Finalize the accepted prefix while excluding any incomplete trailing record before returning `truncated: true`.
Ran code and verified through TREX |
| #9064 2026-10-20 21:01 | greptile inline · P2 | apps/sim/lib/file-parsers/csv-preview-slice.ts:137 | defect-functional | **Recover after malformed records**
Enabling `skip_records_with_error` does not reliably resume at the next record for the installed parser. For `header\nfirst\n"x"y\nsecond\nthird\n`, the changed function returns only `first` with `truncated: false`: both valid trailing rows disappear. This reproduces with the input in one chunk and split into line chunks. This is a non-blocking preview accuracy issue, but the response incorrectly appears complete. Use recovery that preserves subsequent valid records, or explicitly mark the preview truncated when recovery cannot continue safely.
Ran code and verified through TREX |
| #9019 2026-10-20 21:05 | coderabbit issue-comment | — | summary | 📝 Walkthrough
Project-file sharing now supports owner-aware management APIs. Public-file authorization, credential handling, and content delivery use shared application services. Public routes and page rendering use these services, with integration and end-to-end tests covering the flows.
**Changes: Project and public file sharing**
|Layer / File(s)|Summary|
|:---|:---|
|**Project share management and API contracts** `apps/sim/lib/public-shares/manager.ts`, `apps/sim/lib/projects/files/application/*`, `apps/sim/lib/api/contracts/project-file-shares.ts`, `apps/sim/lib/api/contracts/v2/project-file-shares.ts`, `apps/sim/lib/api/contracts/v2/openapi/*`, `apps/sim/app/api/projects/.../share/ … the rest (8526 characters)route.ts`, `apps/sim/app/api/v2/projects/.../share/route.ts`, `packages/sim-cli/src/contract/commands.ts`|Added owner-aware share persistence and policy-based use cases. Added internal and V2 routes, API contracts, OpenAPI definitions, and CLI commands for project file sharing.| |**Credential validation and public-share grants** `apps/sim/lib/core/security/deployment-*`, `apps/sim/lib/core/security/otp.ts`, `apps/sim/lib/public-shares/application/authorization.ts`, `apps/sim/lib/public-shares/application/credentials.ts`, `apps/sim/lib/public-shares/api/credentials.ts`|Added shared deployment credential validation and public-file password, email OTP, and SSO workflows. Authorization issues short-lived grants and revalidates them before registered operations.| |**Owner-scoped public content reads** `apps/sim/lib/public-shares/application/owner-adapters.ts`, `apps/sim/lib/public-shares/application/read.ts`, `apps/sim/lib/public-shares/application/operations.ts`, `apps/sim/lib/public-shares/api/*`|Added workspace and project owner adapters and public-share metadata, content, and inline-read services. The services validate ownership, provenance, revisions, dependencies, and transfer limits.| |**Public-share route and page integration** `apps/sim/app/api/files/public/[token]/*/route.ts`, `apps/sim/app/f/[token]/*`, `apps/sim/app/api/files/serve-inline-image.ts`|Updated public-file routes and page rendering to use shared authorization and read services. Added conditional responses, shared error handling, and canonical-owner data for embedded images. Removed the prior inline-image module and route test suites.| |**Integration and end-to-end validation** `apps/sim/lib/projects/files/__integration__/content-sharing.integration.ts`, `apps/sim/scripts/test-project-file-*-e2e.ts`, `apps/sim/scripts/test-project-files-e2e.ts`|Added integration and end-to-end coverage for sharing policies, credentials, grant invalidation, artifact delivery, public content, and inline-source ownership.| **Priority:** ➖ Normal **Estimated code review effort:** 4 (Complex) | ~60 minutes **Change:** Feature ### Sequence Diagram(s) ```mermaid sequenceDiagram participant ContentRoute as Public content route participant Authorize as authorizePublicFileShare participant Read as readPublicFileShareContent participant Owner as loadPublicFileOwner ContentRoute->>Authorize: Token and request credential Authorize-->>ContentRoute: Verified grant ContentRoute->>Read: Content request and grant Read->>Owner: Load workspace or project owner Owner-->>Read: Owner context and document adapter Read-->>ContentRoute: Authorized file response data ``` **Suggested reviewers:** `waleedlatif1` Merge Risk: 🟡 Moderate · up to c5f35 The new sharing and protected-delivery paths are broadly well structured, but SSO-protected shares do not confirm that the viewer's specific session is still valid. A user who signed out, or whose session was revoked, may keep access to SSO-protected files for a few minutes. Some existing workspace share links may also stop working if their ownership fields were not fully backfilled. Fix the session check and confirm the legacy share migration before merging. Security architecture risk: 🟡 Moderate · up to c5f35 The design adds substantial ownership and content checks, but extends an existing session-revocation delay to newly shareable Project files. Someone retaining a previously authorized session cookie and a matching active share link may continue reading during the configured five-minute session-cache window. Active-share, ownership, file-revision, and referenced-asset checks limit the exposure. **Retained concerns** - **Medium · security · inferred:** New Project SSO sharing inherits a delayed session-revocation boundary. The credential adapter supplies a session ID, but grant issuance and consumption retain only user identity and query the user row. A previously authorized cached session can therefore obtain fresh grants after its session row is revoked or removed, during the configured cache window. This condition predates the PR for workspace shares; its extension to Project-owned files is the material architecture change. Security review details **Security Blast Radius** - _inferred_ — The session-revocation exposure requires a retained cookie for a previously accepted identity and knowledge of an active SSO share link admitting that identity. Each link reaches its shared file and eligible same-owner dependencies, not arbitrary files by identifier. Multiple known qualifying links could expose files across their respective owners; the grant itself does not confer Project membership or write authority. **Security Findings and Attack Paths** - _inferred_ — The two retained findings concern a related attack path: replay a still-accepted cached session after session-row revocation, pass the user-only identity check, obtain a fresh request-local grant, and read a qualifying active share. The configured cookie-cache window governs repeated initiation; the grant's separate expiry bounds an individual grant. Workspace exposure existed in the base, while Project exposure is newly reachable through this PR. **Trust Boundaries and Controls** - _observed_ — Public delivery does not substitute the file creator for the caller. It checks canonical share/file ownership, active share state, and current user blocking state. Referenced files must be live and same-owner; inline delivery additionally requires a current document reference and a recognized raster-image type. Unknown or secret-bearing provenance is rejected by the public admission helper. **Resilience and Maintainability Implications** - _observed_ — Content fetching occurs between validation transactions. Before returning bytes, the final transaction rechecks grant policy, source and dependency revisions, and provenance. This rejects intervening changes detected at that boundary, but does not cancel an already validated response if revocation commits afterward; that is an in-flight response boundary, not persistent grant reuse. **Hardening Proposals** - _proposed_ — Preserve the exact session ID through SSO grant state and validate its current user binding, expiry, and revocation at issuance and consumption. Add focused revocation checks that replay a cached cookie against Project shares, distinguishing new requests from responses already past final validation. Pre-merge checks: 4 · 1 Failed checks: 1 warning | Check name | Status | Explanation | Resolution | | :---------------- | :----------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------- | | Docstring Coverage | | Docstring coverage is 40.85% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 71 functions across 42 files. (1 skipped:… | Write docstrings for the functions missing them to satisfy the coverage threshold. | Passed checks: 4 passed | Check name | Status | Explanation | | :------------------------ | :--------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------- | | Description Check | | Check skipped - the reviewer’s high-level summary is enabled. | | Title check | | The title clearly and concisely summarizes the main changes: project-file public sharing and protected delivery. | | Linked Issues check | | Check skipped because no linked issues were found for this pull request. | | Out of Scope Changes check | | Check skipped because no linked issues were found for this pull request. | Full details: Docstring Coverage **Explanation** Docstring coverage is 40.85% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 71 functions across 42 files. (1 skipped: 1 unsupported.) **Resolution** Write docstrings for the functions missing them to satisfy the coverage threshold. ✨ Finishing Touches: 💡 1 📝 Generate docstrings: 💡 🧪 Generate unit tests (beta) Comment `@the reviewer help` to get the list of available commands. |
| #9019 2026-10-20 21:15 | cubic inline · P2 | apps/sim/app/api/files/public/[token]/content/route.ts:39 | defect-functional | The HEAD response omits the representation headers that GET provides, including `Content-Type`, `Content-Disposition`, `Content-Length`, and `ETag`. Preserve those headers so HEAD clients can inspect and revalidate the shared file. |
| #9019 2026-10-20 21:15 | cubic inline · P2 | apps/sim/lib/public-shares/manager.ts:228 | defect-functional | This rejects legacy workspace shares whose newly added `entity_type`/`entity_id` columns remain NULL, so members cannot update or disable them after upgrading. Treat a NULL pair with a matching `workspaceId` as the same workspace owner.
```suggestion
!((existing.entityType === owner.entityType && existing.entityId === owner.entityId) || (owner.entityType === 'workspace' && existing.entityType === null && existing.entityId === null && existing.workspaceId === owner.entityId))
``` |
| #9019 2026-10-20 21:15 | cubic inline · P2 | apps/sim/lib/api/contracts/v2/openapi/project-file-shares.ts:23 | docs | This PATCH can return 413 when its JSON body exceeds the request-size limit, but `RESOURCE_ERRORS` omits `PayloadTooLarge`. Add that error so clients see the response this operation can emit. |
| #9019 2026-10-20 21:15 | cubic inline · P2 | apps/sim/lib/public-shares/application/read.ts:202 | defect-functional | HEAD reports the share as available even when GET rejects a SimPage with missing or foreign embedded assets, because this check skips SimPage rendering and reference validation. Validate SimPage dependencies here so HEAD reflects content availability. |
| #9019 2026-10-20 21:15 | cubic inline · P2 | apps/sim/lib/projects/files/application/shares.ts:106 | defect-concurrency | This fallback is read before `upsertOwnedFileShare` acquires the file-row lock, so a concurrent update can reactivate a newly password-protected share with stale `public` mode and clear its password. Lock the file before reading the current mode, and hold that lock through policy validation and the upsert. |
| #9019 2026-10-20 21:15 | cubic inline · P2 | apps/sim/lib/public-shares/application/owner-adapters.ts:58 | defect-functional | Workspace shares can return a stale rendering after a referenced file changes: this call ignores the validated `dependencies`, while `resolveServableDoc` accepts cached artifacts without matching their input revisions. Reject artifacts whose captured input revisions differ from these dependencies, as the Project adapter does with its identity-bound lookup. |
| #9019 2026-10-20 21:15 | cubic review-body | — | summary | **6 issues found** across 52 files
View guided diff | Turn on auto-fix | Re-trigger the reviewer |
| #9019 2026-10-20 21:20 | coderabbit inline · P2 | apps/sim/lib/public-shares/application/authorization.ts:64 | defect-data | **🗄️ Data Integrity & Integration** | **🟡 Minor** | **⚡ Quick win**
**Verify migration of existing workspace shares.**
`0034_backfill_public_share_entities` is registered as a repository migration and backfills legacy workspace shares with `entityType = 'workspace'` and `entityId = workspace_id`. However, the migration only updates rows where both fields are `NULL`. Confirm that partial or unresolved rows are handled before this guard is released. |
| #9019 2026-10-20 21:20 | coderabbit inline · P1 | apps/sim/lib/public-shares/application/authorization.ts:163 | defect-security | **🔒 Security & Privacy** | **🛡️ Detected with Advanced Tier** | **🟠 Major** | **⚡ Quick win**
**Broken Authentication**
**Reachability:** External
**Exploitability:** Difficult
**CWE:** CWE-613 — Insufficient Session Expiration
**Revalidate the exact SSO session before serving the grant.**
`SessionPrincipal` includes `sessionId`, but `loadSession` uses only `userId` and reads the user row. A deleted or expired session can therefore authorize a new grant. The grant is request-scoped, but the configured Better Auth cookie cache can return revoked, expired, or signed-out sessions without a database read for up to five minutes. A former session holder can therefore obtain file bytes on la … the rest (1826 characters)ter requests during that cache window. Store `sessionId` in `SessionIdentity` and require the matching, unexpired session row during initial authorization and every `validateState` call. Revalidate the session row ```diff -import { publicShare, user, workspaceFiles } from '@sim/db/schema' +import { publicShare, session, user, workspaceFiles } from '@sim/db/schema' -import { and, eq, isNull } from 'drizzle-orm' +import { and, eq, gt, isNull } from 'drizzle-orm' ... interface SessionIdentity { + sessionId: string userId: string email: string } ... async function loadSession( tx: DbTransaction, - userId: string + userId: string, + sessionId: string ): Promise<SessionIdentity | undefined> { const [row] = await tx .select({ - id: user.id, + sessionId: session.id, + userId: user.id, email: user.email, banned: user.banned, banExpires: user.banExpires, suspendedAt: user.suspendedAt, }) - .from(user) - .where(eq(user.id, userId)) + .from(session) + .innerJoin(user, eq(session.userId, user.id)) + .where( + and( + eq(session.id, sessionId), + eq(session.userId, userId), + gt(session.expiresAt, new Date()) + ) + ) .for('share') - return row && !isAccountBlocked(row) ? { userId: row.id, email: row.email } : undefined + return row && !isAccountBlocked(row) + ? { sessionId: row.sessionId, userId: row.userId, email: row.email } + : undefined } ... - ? await db.transaction((tx) => loadSession(tx, principal.userId)) + ? await db.transaction((tx) => loadSession(tx, principal.userId, principal.sessionId)) ... - const session = await loadSession(tx, state.session.userId) + const session = await loadSession(tx, state.session.userId, state.session.sessionId) ``` |
| #9019 2026-10-20 21:20 | coderabbit inline · P2 | apps/sim/lib/public-shares/application/read.ts:202 | defect-functional | **🎯 Functional Correctness** | **🟡 Minor** | **⚡ Quick win**
**Make HEAD check Sim Page dependencies before reporting success.**
When a shared Sim Page has no compiled-document format, `checkPublicFileShareContent` checks the stored source but skips the embedded-image references. It can return 200 while `readPublicFileShareContent` rejects the same document because a referenced image is missing or has a different owner. Reuse the GET path’s reference and dependency checks for HEAD so the availability responses agree. |
| #9019 2026-10-20 21:20 | coderabbit review-body | — | summary | **Actionable comments posted: 3** |
| #9019 2026-10-20 21:23 | greptile issue-comment | — | summary | Confidence Score: 2/5
**[High impact]** The PR adds public access paths for files owned by Projects and workspaces\.
Not safe to merge until the password-protection race and retained Python document regression are fixed; the foreign-embed response inconsistency is non-blocking.
Findings
1. **Password protection can disappear**
2. **Stored Python documents stop opening**
3. **Missing embeds become server errors**
Reviews (1) · Last reviewed commit: "feat(project-files): add public sharing ..." · Reviewed by the reviewer |
| #9019 2026-10-20 21:23 | greptile inline · P1 | apps/sim/lib/projects/files/application/shares.ts:106 | defect-concurrency | **Password protection can disappear**
Two overlapping updates can both read an existing public share before either acquires the file lock. If one enables password protection and the other omits `authType`, the second explicitly writes its stale `public` value over the newly protected share and clears the password. The share remains active with the same token, so anyone holding the link can read it without the password.
This must be fixed before merging. Acquire the file lock before resolving the access mode, then validate sharing policy and persist the update under that same lock.
**How this was verified:** Concurrent PostgreSQL transactions restored public access and cleared the password … the rest (1773 characters), after which the credential gate accepted an anonymous GET. Artifacts **Complete concurrent share-update execution harness** - Full executed source imports the actual application update body and manager, coordinates real PostgreSQL transactions, and asserts persisted authentication and anonymous credential-gate results. **Reproduction commands and output-capture runner** - The executed runner contains exact setup, before, after, source-inspection, and cleanup commands with working-directory and exit-code capture. **Local PostgreSQL installation output** - Captured package-manager commands installed PostgreSQL locally, enabling real persistence testing without Docker. **Disposable database setup and isolation check** - Started the local cluster and created a dedicated test database whose runtime output confirmed PostgreSQL 15.19 and READ COMMITTED isolation. **Concurrent updates with omitted authentication preserved** - Executed the labeled omission-forwarding counterfactual under real lock contention and observed retained password protection with anonymous GET rejected. **Concurrent updates on unchanged PR head remove password protection** - Executed unchanged application code under the same lock schedule and observed an active public share with its password cleared and anonymous GET authorized. **Head identity and numbered source evidence** - Captured the requested commit, relevant application and database source lines, parent-manager context, and an empty product-source diff supporting the reproduced cause. **Disposable database cleanup and unchanged product-source check** - Removed the test database and role, stopped the local cluster, and verified that product source remained unchanged. Ran code and verified through TREX |
| #9019 2026-10-20 21:23 | greptile inline · P1 | apps/sim/lib/public-shares/application/read.ts:310 | defect-functional | **Stored Python documents stop opening**
If the document sandbox is disabled after Python documents have been compiled, public reads parse their stored source as JavaScript. A retained workspace PDF or spreadsheet containing Python imports and `input_path('wf_…')` then throws before its existing compiled file can be read. Both content requests and HEAD checks return 500 instead of serving or checking the retained artifact.
This must be fixed before merging. Use `getDocumentSourceLanguage` regardless of whether compilation is currently enabled, matching `resolveServableDoc`. Apply the same change to `checkPublicFileShareContent`.
Artifacts
**Public document responses before the change**
… the rest (1316 characters)- Executed the parent content handler for Python PDF and XLSX fixtures with retained artifacts and the sandbox disabled; GET and HEAD both returned 200 OK. **Public document failures after the change** - Executed the head handler and both read services against the same fixtures, capturing parser stacks and storage traces; GET and HEAD failed with 500 before artifact loading. **Executable public document validation harness** - Contains the executed fixtures, controlled infrastructure adapters, loopback HTTP server, direct service calls, and assertions; the product parser and artifact resolver execute unchanged. **Before and after validation command source** - Extracts the parent handler and runs both comparison modes while recording command, working directory, and exit code; the validation is reproducible. **Executed public content handler before the change** - Contains the exact parent-revision content handler extracted by git show and executed by the harness; it establishes the pre-change endpoint behavior. **Revision and source reference verification** - Captures revision IDs, relevant numbered source, matching parent-handler hashes, unchanged compiler files, and a clean tracked diff; the comparison targets the requested code without product edits. Ran code and verified through TREX |
| #9019 2026-10-20 21:23 | greptile inline · P2 | apps/sim/lib/public-shares/application/read.ts:290 | defect-functional | **Missing embeds become server errors**
A stored Project page with an explicit foreign-Project embed causes `renderSimPageDocument` to throw `ProjectPageForeignEmbedError`. Both public content and inline readers leave this error unclassified, so visitors receive a generic 500 rather than the missing-input 404 used by the private reader.
This is a non-blocking error-response inconsistency: unavailable page inputs look like server faults, making failures harder to diagnose. Convert this exception to `OrchestrationError('not_found', ...)` in both public readers.
Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
Ar … the rest (1816 characters)tifacts **Parent endpoint responses for controlled Project shares** - Executed both parent public handlers with three controlled Project-page fixtures and captured all six HTTP responses; all return 404 because the parent rejects Project shares before reading. **Head endpoint responses and foreign-embed exception stacks** - Executed both head public handlers with the same fixtures and captured status lines, JSON bodies, headers, and stacks; foreign-owner embeds return 500 while missing same-Project inputs return 404. **Complete executable endpoint validation harness** - Contains the fixtures, explicit mocks, parent-source extraction, real route imports, loopback HTTP server, requests, and assertions used to reproduce the defect. **Before and after execution commands** - Runs the harness against parent and head and records the exact command, working directory, exit code, and observed output in the paired logs. **Executed parent public content handler source** - Preserves the unmodified content route extracted from parent commit 6be22aab4ea7f64aa70e4a228bf77f8a6274bcda and imported during the before run. **Executed parent public inline handler source** - Preserves the unmodified inline route extracted from parent commit 6be22aab4ea7f64aa70e4a228bf77f8a6274bcda and imported during the before run. **Source evidence capture commands** - Captures numbered runtime sources, the private-reader mapping, parent resolver, harness commands, and product diff status for reproducible source citations. **Numbered executed source and error-mapping references** - Records command output containing the full harness and relevant runtime sources with line numbers; it ties the observed 500 responses to the missing classification and confirms no product diff. Ran code and verified through TREX |
| #9059 2026-10-20 21:25 | coderabbit issue-comment | — | summary | 📝 Walkthrough
The change adds a periodic worker that discovers and recovers eligible abandoned runs. It adds Sim tool execution attempt tracking and retry limits, delegated stream recovery, access-revoked settlement, and chat-stream lease ownership checks.
**Changes: Abandoned Sim-run takeover**
|Layer / File(s)|Summary|
|:---|:---|
|**Execution attempt tracking and claim eligibility** `packages/db/schema.ts`, `packages/db/migrations/*`, `apps/sim/lib/mothership/async-runs/execution-lease.ts`, `apps/sim/lib/mothership/async-runs/repository.ts`, `apps/sim/lib/mothership/async-runs/repository.test.ts`, `apps/sim/lib/mothership/async-runs/browser-download-claim.integration.ts`|Tool calls no … the rest (7685 characters)w store execution-attempt counts. Sim claims can include eligible interrupted executions, subject to the attempt limit.| |**Retry handling and preserved recovery state** `apps/sim/lib/mothership/async-runs/repository.ts`, `apps/sim/lib/mothership/persistence/tool-confirm/*`, `apps/sim/lib/desktop/executor/bound-turn.integration.ts`, `packages/testing/src/mocks/mothership-async-runs.mock.ts`|Repository operations support exhausted-execution revocation, targeted expiry revocation, and recovery of eligible sandbox and workflow state.| |**Abandoned-run discovery and settlement** `apps/sim/lib/mothership/async-runs/orphaned-runs.ts`|A bounded cursor-based scan finds recoverable runs. Settlement supports access-revoked errors and a separate scan cursor.| |**Delegated stream recovery and lease ownership** `apps/sim/lib/mothership/request/application/recover-stream.ts`, `apps/sim/lib/mothership/request/session/*`|Stream recovery validates run context and supports delegated takeover. Chat-stream leases record acquisition time and stop controllers when ownership is lost.| |**Periodic takeover worker and integration coverage** `apps/sim/instrumentation-node.ts`, `apps/sim/lib/core/config/feature-flags.ts`, `apps/sim/lib/mothership/request/application/abandoned-runs.ts`, `apps/sim/lib/mothership/request/application/abandoned-runs.integration.ts`|Startup launches the periodic worker. A feature flag can disable scans. Integration tests cover takeover, access changes, retries, and scan bounds.| **Priority:** ➖ Normal **Estimated code review effort:** 4 (Complex) | ~60 minutes **Change:** Bug fix ### Sequence Diagram(s) ```mermaid sequenceDiagram participant Startup as instrumentation-node register participant Takeover as takeOverAbandonedRuns participant Scanner as findAbandonedRecoverableRuns participant DelegatedRecovery as takeOverStreamRun participant Recovery as recoverStreamRun Startup->>Takeover: start periodic takeover scans Takeover->>Scanner: find recoverable runs Scanner-->>Takeover: return run batch Takeover->>DelegatedRecovery: request delegated recovery DelegatedRecovery->>Recovery: validate and recover stream ``` **Suggested reviewers:** `waleedlatif1`, `sg312` Merge Risk: 🟡 Moderate · up to 5dde2 Abandoned chat runs now resume automatically, and interrupted tools run again. Tools that write data, such as file exports, table overwrites or workflow runs, can apply their effects twice after a process dies. Calls interrupted during this deploy can also run one more time than the three-attempt limit. Gate automatic re-runs to idempotent tools, or add a stable deduplication key. Also backfill the attempt count for calls that started before the migration. Resolve both before merging, unless duplicate effects are an accepted tradeoff. Security architecture risk: 🟡 Moderate · up to 5dde2 Recovery preserves important access checks and ownership controls, but automatically rerunning tools with unknown outcomes can repeat privileged mutations. Retry limits constrain repetition without guaranteeing that an action happens only once. **Retained concerns** - **Medium · security · inferred:** Expired, unfinished Sim executions become automatically replayable without a tool-level replay-safety condition. The dispatch family includes authenticated code execution, so a mutation completed before its result was durably recorded can be performed again after takeover or reconnect. The base rejected claims for already-started calls. New owner tokens fence stale database writes, and the attempt limit bounds repetition, but neither deduplicates completed external effects. Security review details **Security Blast Radius** - _inferred_ — Discovery can select eligible runs across tenants, but each takeover is delegated to the recorded user and chat owner. The principal sensitive exposure is repeated execution within that user's reachable workspace, organization and integration authority, rather than a demonstrated cross-tenant privilege gain. **Security Findings and Attack Paths** - _inferred_ — A tool can complete a privileged mutation and then lose its controller before recording completion. After lease expiry, recovery can dispatch the same arguments again under a new owner. Ordinary crashes or deployments suffice for this failure sequence; attacker-controlled interruption and a concrete downstream exploit were not demonstrated. **Trust Boundaries and Controls** - _observed_ — The inspected boundary binds delegated identity to the original subject, tenant and chat, checks delegation validity and current access, validates saved recovery identity, and requires execution-token and lease predicates for owned result writes. These controls counter identity substitution and stale-owner writes, but do not establish exactly-once external mutations. **Resilience and Maintainability Implications** - _observed_ — Revoked-access settlement durably closes the run through guarded settlement before requesting worker abort. Abort delivery is best-effort and logged on failure; it is not atomic with the database transition. Sandbox recovery similarly retains unresolved process receipts when stopping or settlement fails. **Hardening Proposals** - _proposed_ — Make automatic replay conditional on an explicit replay-safe contract. For mutations, reconcile a durable operation identity with the downstream result before rerunning, or preserve an outcome-unknown terminal state requiring inspection. Keep attempt limits and ownership fences as complementary controls. Pre-merge checks: 4 · 1 Failed checks: 1 warning | Check name | Status | Explanation | Resolution | | :---------------- | :----------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------- | | Docstring Coverage | | Docstring coverage is 55.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 40 functions across 18 files. (2 skipped:… | Write docstrings for the functions missing them to satisfy the coverage threshold. | Passed checks: 4 passed | Check name | Status | Explanation | | :------------------------ | :--------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------------ | | Description Check | | Check skipped - the reviewer’s high-level summary is enabled. | | Title check | | The title clearly summarizes the main changes: abandoned-run takeover after controller failure and re-execution of interrupted tools. | | Linked Issues check | | Check skipped because no linked issues were found for this pull request. | | Out of Scope Changes check | | Check skipped because no linked issues were found for this pull request. | Full details: Docstring Coverage **Explanation** Docstring coverage is 55.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 40 functions across 18 files. (2 skipped: 2 unsupported.) **Resolution** Write docstrings for the functions missing them to satisfy the coverage threshold. ✨ Finishing Touches: 💡 1 📝 Generate docstrings: 💡 🧪 Generate unit tests (beta) Comment `@the reviewer help` to get the list of available commands. |
| #9059 2026-10-20 21:31 | coderabbit inline · P1 | apps/sim/lib/mothership/async-runs/repository.ts:820 | defect-data | **🗄️ Data Integrity & Integration** | **🟠 Major** | **🏗️ Heavy lift**
**Gate interrupted retries on idempotency.**
`claimToolExecution` allows every interrupted Sim tool to run again. This includes `run_function`, which can export files and overwrite tables, as well as workflow and server tools. A lease fence protects ownership writes, not an effect that the previous owner started before its lease expired.
`claimWorkflowToolExecution` also reclaims interrupted workflows. Each server fallback receives a new `boundExecutionId`, so that identifier does not by itself deduplicate the previous workflow execution.
Allow automatic retries only for explicitly read-only or idempotent tools. Set … the rest (232 characters)tle other interrupted calls with `INTERRUPTED_SIM_TOOL_MESSAGE`. Alternatively, pass a stable key such as `toolCallId` to every downstream operation and enforce deduplication there, including workflow execution. _Source: Learnings_ |
| #9059 2026-10-20 21:31 | coderabbit inline · P2 | packages/db/migrations/0430_tool_execution_attempts.sql:1 | defect-data | **🗄️ Data Integrity & Integration** | **🟡 Minor** | **⚡ Quick win**
**Backfill `execution_attempts` for executions that started before this migration.**
The column defaults to `0` for every existing row. Before this change, a call that already started had no increment. A takeover is most likely to find such a row during the deploy that ships this change, because that deploy ends the old processes in the middle of their tools.
For such a row, `interruptedSimExecution` accepts attempts `0`, `1` and `2`. The call can then start three more times after its original execution. That is four executions in total, but `SIM_TOOL_EXECUTION_MAX_ATTEMPTS` is `3`. Count the pre-migration start as one … the rest (808 characters)attempt. Proposed backfill ```diff ALTER TABLE "copilot_async_tool_calls" ADD COLUMN "execution_attempts" integer DEFAULT 0 NOT NULL; +--> statement-breakpoint +UPDATE "copilot_async_tool_calls" SET "execution_attempts" = 1 WHERE "execution_started_at" IS NOT NULL; ``` 📝 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. ```suggestion ALTER TABLE "copilot_async_tool_calls" ADD COLUMN "execution_attempts" integer DEFAULT 0 NOT NULL; --> statement-breakpoint UPDATE "copilot_async_tool_calls" SET "execution_attempts" = 1 WHERE "execution_started_at" IS NOT NULL; ``` |
| #9059 2026-10-20 21:31 | coderabbit review-body | — | summary | **Actionable comments posted: 2** |
| #9059 2026-10-20 21:35 | cubic inline · P1 | apps/sim/lib/mothership/async-runs/repository.ts:819 | defect-data | Gate interrupted re-execution on an explicit retry-safe classification, or deduplicate effects with a stable tool-call key; the lease fence cannot prevent a prior attempt from completing an external side effect. |
| #9059 2026-10-20 21:35 | cubic inline · P2 | apps/sim/lib/mothership/async-runs/execution-lease.ts:22 | docs | This attributes exhaustion to the Sim server stopping, but the code only knows the execution lease expired; heartbeat failures can cause the same condition while the process is alive. Say the execution lease expired instead.
```suggestion
export const EXHAUSTED_SIM_TOOL_MESSAGE = `Tool execution was interrupted ${SIM_TOOL_EXECUTION_MAX_ATTEMPTS} times because its execution lease expired before a result was recorded, so it was not run again. Its outcome is unknown; inspect current state before retrying a mutation.`
``` |
| #9059 2026-10-20 21:35 | cubic inline · P2 | packages/db/migrations/0430_tool_execution_attempts.sql:1 | defect-data | Backfill `execution_attempts` to `1` for rows with `execution_started_at` before enabling retries; otherwise a pre-migration in-flight call can run three more times after its original execution. |
| #9059 2026-10-20 21:35 | cubic review-body | — | summary | **3 issues found** across 22 files
View guided diff | Turn on auto-fix | Re-trigger the reviewer |
| #9059 2026-10-20 21:41 | greptile issue-comment | — | summary | Confidence Score: 4/5
**[Medium impact]** The change affects recovery and tool execution for abandoned interactive Chat runs\.
No blocking issue was established; the remaining concern is a bounded extra tool execution for calls spanning deployment.
Findings
1. **Migration undercounts existing executions**
Reviews (1) · Last reviewed commit: "fix(mothership): take over runs whose co..." · Reviewed by the reviewer |
| #9059 2026-10-20 21:41 | greptile inline · P2 | packages/db/migrations/0430_tool_execution_attempts.sql:1 | defect-data | **Migration undercounts existing executions**
If a Sim tool has already started when this migration runs, its new `execution_attempts` counter is initialized to zero rather than one. After an interruption, recovery permits three additional starts, giving that call four total starts instead of the intended maximum of three. This is a bounded, non-blocking rollout concern, but it allows an extra potentially side-effecting execution. Count already-started Sim executions when introducing the counter, and account for starts made by old-version processes during rollout.
Artifacts
**Persistence harness source and execution script**
- Bundled and uploaded the four existing harness, configuration … the rest (302 characters), execution-script, and base-repository source files; storage confirmed HTTP 200. **Persistence before and after execution outputs** - Bundled and uploaded the existing before and after persistence logs without rerunning their commands; storage confirmed HTTP 200. Ran code and verified through TREX |
| #9066 2026-10-20 21:42 | coderabbit issue-comment | — | summary | 📝 Walkthrough
The change updates Markdown table serialization for documentation output and adds an RFC 9727 API catalog endpoint. It also adjusts discovery endpoint filtering and adds end-to-end checks for catalog responses.
**Changes: Documentation Markdown Serialization**
|Layer / File(s)|Summary|
|:---|:---|
|**Table serialization and LLM output** `apps/docs/source.config.ts`, `apps/docs/lib/llms.ts`|MDX processing configures `remarkGfm` with table pipe alignment disabled. `getLLMText` returns processed Markdown without the separate `compactTables` step.|
**API Catalog Discovery**
|Layer / File(s)|Summary|
|:---|:---|
|**API catalog endpoint and discovery filtering** `apps/sim/app/. … the rest (4339 characters)well-known/api-catalog/route.ts`, `apps/sim/proxy.ts`|The new GET route returns an RFC 9727 Linkset with deployment-relative API links. Security filtering exempts the API catalog and OpenAI Apps challenge endpoints from suspicious-user-agent blocking.| |**API catalog end-to-end checks** `apps/sim/scripts/test-mcp-host-e2e.ts`|The script checks API catalog GET and HEAD responses on the application host and verifies that the dedicated MCP host rejects the catalog path.| **Priority:** ⬇️ Low **Estimated code review effort:** 3 (Moderate) | ~20 minutes **Change:** Feature ### Sequence Diagram(s) ```mermaid sequenceDiagram participant Client participant handleSecurityFiltering participant apiCatalogGET as API catalog GET route Client->>handleSecurityFiltering: Request /.well-known/api-catalog handleSecurityFiltering->>apiCatalogGET: Allow discovery endpoint request apiCatalogGET-->>Client: Return RFC 9727 Linkset response ``` **Suggested reviewers:** `waleedlatif1` Merge Risk: ⚪ Minimal · up to 3a096 The catalog is ready to merge after normal checks. Adding an assertion for its reference-documentation link would improve regression coverage. Security architecture risk: 🔵 Low · up to 3a096 The catalog is read-only, publishes configured public URLs, and receives a narrowly scoped filtering exception. It does not grant access to protected operations. The remaining uncertainty concerns production host routing, URL configuration, and runtime behavior. **Retained concerns** No architecture-level concerns identified. Security review details **Security Blast Radius** - _observed_ — Unauthenticated callers on the application host can retrieve deployment-level API and health URLs plus public documentation URLs. The response contains no workspace identifiers, tenant data, secrets, or delegated credentials. **Trust Boundaries and Controls** - _observed_ — The changed control is a suspicious-User-Agent filter, not an authentication grant. Its new exception is restricted to the exact static catalog path. Request Host, query, body, and cookies do not determine the emitted URL authority, and the handler does not invoke the linked protected APIs. **Resilience and Maintainability Implications** - _observed_ — The changed script is a loopback-only validation harness, not another production entrypoint. It asserts dedicated-host rejection, application-host GET behavior for empty and tool User-Agents, configured URL values, health resolution, and HEAD discovery. These assertions support the intended boundary but are not independently executed results. Pre-merge checks: 4 · 1 Failed checks: 1 warning | Check name | Status | Explanation | Resolution | | :---------------- | :----------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------- | | Docstring Coverage | | Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 2 functions across 5 files. | Write docstrings for the functions missing them to satisfy the coverage threshold. | Passed checks: 4 passed | Check name | Status | Explanation | | :------------------------ | :--------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------------------ | | Description Check | | Check skipped - the reviewer’s high-level summary is enabled. | | Title check | | The title clearly summarizes both main changes: publishing the RFC 9727 API catalog and removing table padding from documentation Markdown. | | Linked Issues check | | Check skipped because no linked issues were found for this pull request. | | Out of Scope Changes check | | Check skipped because no linked issues were found for this pull request. | ✨ Finishing Touches: 💡 1 📝 Generate docstrings: 💡 🧪 Generate unit tests (beta) Comment `@the reviewer help` to get the list of available commands. |
| #9066 2026-10-20 21:46 | coderabbit review-body | — | summary | 🧹 Nitpick comments: 1
apps/sim/scripts/test-mcp-host-e2e.ts: 1
`116-140`: **🗄️ Data Integrity & Integration** | **🔵 Trivial** | **⚡ Quick win**
**Assert the catalog `service-doc` URL.**
The GET checks assert `service-desc` and `status`, but not `service-doc`. A missing or incorrect reference-documentation URL could therefore pass every catalog assertion. Add an assertion for the published contract.
Suggested fix
```diff
assert.equal(api['service-desc'][0].href, `${SIM_DOCS_URL}/openapi.json`)
+ assert.equal(api['service-doc'][0].href, `${SIM_DOCS_URL}/api-reference/getting-started`)
assert.equal(api.status[0].href, `${baseUrl.origin}/api/health`)
``` |
| #9066 2026-10-20 21:49 | cubic inline · P3 | apps/sim/scripts/test-mcp-host-e2e.ts:127 | tests | This check never validates the advertised reference-doc URL, so a missing or incorrect `service-doc` link still passes the catalog E2E test. Assert that `api['service-doc'][0].href` is `${SIM_DOCS_URL}/api-reference/getting-started` as well.
```suggestion
assert.equal(api['service-desc'][0].href, `${SIM_DOCS_URL}/openapi.json`)
assert.equal(api['service-doc'][0].href, `${SIM_DOCS_URL}/api-reference/getting-started`)
``` |
| #9066 2026-10-20 21:49 | cubic review-body | — | summary | **1 issue found** across 5 files
Reply with feedback, questions, or to request a fix.View guided diff | Turn on auto-fix | Re-trigger the reviewer |
| #9066 2026-10-20 22:05 | greptile issue-comment | — | summary | Confidence Score: 5/5
**[Medium impact]** The changes appear safe to merge; no actionable defects or blocking repository-requirement violations were established.
Reviews (1) · Last reviewed commit: "improvement(api): publish an RFC 9727 AP..." · Reviewed by the reviewer |
| #9065 2026-10-20 22:06 | coderabbit issue-comment | — | summary | No actionable comments were generated in the recent review. 🎉
📝 Walkthrough
Chat panel resizing now commits on pointer release, lost pointer capture, and window blur, while pointer cancellation retains the saved width. The resize handle disables default touch gestures, and E2E tests cover mouse-button filtering, interruption behavior, touch resizing, and persistence.
**Changes: Chat panel resizing**
|Layer / File(s)|Summary|
|:---|:---|
|**Resize input and completion** `apps/sim/app/workspace/[workspaceId]/home/hooks/use-mothership-resize.ts`, `apps/sim/app/workspace/[workspaceId]/home/components/chat-panel-layout.tsx`|The resize hook ignores non-primary pointer buttons. Pointer releas … the rest (1887 characters)e, lost capture, and window blur commit the current width; pointer cancellation still cancels. The resize handle disables default touch gestures.| |**Resize persistence and interruption tests** `apps/desktop/e2e/chat-panel.spec.ts`|E2E tests cover committed and cancelled interruptions, non-primary mouse buttons, and touch resizing. They verify saved widths across reloads and chat switching.| **Priority:** ⬇️ Low **Estimated code review effort:** 3 (Moderate) | ~20 minutes **Change:** Bug fix **Suggested reviewers:** `waleedlatif1` Merge Risk: ⚪ Minimal · up to 8925b The resize interruption behavior has no identified merge-blocking issue. The change is ready to merge after normal checks. Pre-merge checks: 5 | Check name | Status | Explanation | | :------------------------ | :--------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Description Check | | Check skipped - the reviewer’s high-level summary is enabled. | | Title check | | The title clearly and concisely describes the main change: preserving chat panel resize gestures when focus or pointer capture is lost. | | Docstring Coverage | | Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 2 functions across 3 files. | | Linked Issues check | | Check skipped because no linked issues were found for this pull request. | | Out of Scope Changes check | | Check skipped because no linked issues were found for this pull request. | ✨ Finishing Touches 📝 Generate docstrings 🧪 Generate unit tests (beta) Comment `@the reviewer help` to get the list of available commands. |
| #9065 2026-10-20 22:12 | cubic inline · P2 | apps/desktop/e2e/chat-panel.spec.ts:343 | tests | This test only moves horizontally and never checks page scrolling, so it can pass without detecting the scroll gesture this scenario claims to prevent. Add a vertical or diagonal touch movement and assert that the page remains at the same scroll position. |
| #9065 2026-10-20 22:12 | cubic review-body | — | summary | **1 issue found** across 3 files
Reply with feedback, questions, or to request a fix.View guided diff | Turn on auto-fix | Re-trigger the reviewer |
| #9065 2026-10-20 22:17 | greptile issue-comment | — | summary | Confidence Score: 5/5
**[Low impact]** No blocking issue was established in the reviewed changes; the focused Electron checks passed, although the full desktop suite encountered a later viewport-clamping assertion failure.
Reviews (1) · Last reviewed commit: "fix(chat): preserve panel resize gesture..." · Reviewed by the reviewer |
| #9083 2026-10-20 22:18 | coderabbit issue-comment | — | summary | 📝 Walkthrough
The new article compares six AI agents for querying SQL databases. It also covers SQL-agent safeguards, tool-selection guidance, and a scheduled BigQuery reporting workflow that can send controlled updates to Slack.
**Changes: SQL agent guide**
|Layer / File(s)|Summary|
|:---|:---|
|**Tool comparison and selection** `apps/sim/content/library/best-ai-agents-for-querying-sql-databases/index.mdx`|The article ranks six tools using weighted criteria, describes their licensing and capabilities, and maps each tool to use cases. It also adds FAQs and links to related guides.|
|**SQL safeguards and reporting workflow** `apps/sim/content/library/best-ai-agents-for-querying-sql-databa … the rest (3806 characters)ses/index.mdx`|The article covers read-only credentials, query restrictions, semantic context, evaluation, and controlled reporting. It describes Sim's workflow and a scheduled BigQuery-to-Slack example.| **Priority:** ⬇️ Low **Estimated code review effort:** 3 (Moderate) | ~20 minutes **Change:** Other Merge Risk: 🔵 Low · up to 4f0ad Readers planning a new Snowflake deployment could receive incomplete tool-selection advice. The article is otherwise mergeable with this bounded correction. Architecture risk: 🔵 Low · up to 4f0ad The change affects 1 system. **Changed systems:** `apps/sim` **Architecture concerns** No architecture-level concerns identified. Review details **Systems and components** - _observed_ — apps/sim (service) was modified; 1 changed file maps to changed impact. **Before / after behavior** - _observed_ — Modified behavior in apps/sim/content/library/best-ai-agents-for-querying-sql-databases/index.mdx: Added article metadata and FAQs covering tool recommendations, database connectivity, SQL generation, reporting, Slack delivery, security controls, licensing, local models, BYOK, MCP, and approved query practices. - _observed_ — Modified behavior in apps/sim/content/library/best-ai-agents-for-querying-sql-databases/index.mdx: Added the TL;DR, six-tool comparison, rankings, weighted scoring criteria, score calculations, and qualification that results measure overall product fit rather than raw SQL accuracy. - _observed_ — Modified behavior in apps/sim/content/library/best-ai-agents-for-querying-sql-databases/index.mdx: Added vendor-specific licensing, deployment, billing, and maintenance facts for Sim, n8n, Retool, Vanna, Snowflake Cortex Analyst, and Gemini in BigQuery. - _observed_ — Modified behavior in apps/sim/content/library/best-ai-agents-for-querying-sql-databases/index.mdx: Added Sim’s cross-database positioning, supported integrations, governed workflow sequence, result handling, reporting, Slack delivery, guardrails, and human approval behavior. Pre-merge checks: 5 | Check name | Status | Explanation | | :------------------------ | :--------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Description Check | | Check skipped - the reviewer’s high-level summary is enabled. | | Title check | | The title clearly identifies the new library article and its focus on AI agents for querying SQL databases in plain English. | | Docstring Coverage | | No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff. Analyzed 0 functions across 0… | | Linked Issues check | | Check skipped because no linked issues were found for this pull request. | | Out of Scope Changes check | | Check skipped because no linked issues were found for this pull request. | Full details: Docstring Coverage **Explanation** No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff. Analyzed 0 functions across 0 files. (1 skipped: 1 unsupported.) ✨ Finishing Touches 🧪 Generate unit tests (beta) ### Usage-based review receipt - Mode: Continue automatically - Reviewed files: 1 - Waived: $0.25 (charged $0.00) - View usage details > [!NOTE] > This review exceeded your plan’s limits and used usage-based reviews—free during trial, billed after paid activation unless disabled. **Manage usage-based reviews**. Comment `@the reviewer help` to get the list of available commands. |
| #9083 2026-10-20 22:23 | coderabbit inline · P2 | apps/sim/content/library/best-ai-agents-for-querying-sql-databases/index.mdx:259 | docs | **🎯 Functional Correctness** | **🟡 Minor** | **⚡ Quick win**
**Qualify the Snowflake recommendation in the FAQ and link the current guidance in the selection paragraph.**
The selection paragraph should link Snowflake’s guidance that recommends Cortex Agents for new deployments and identifies Cortex Analyst as its structured-data tool. Replace the FAQ’s standalone “strongest” claim with a content-only qualification that directs readers to Snowflake’s current deployment guidance. Do not add a citation claim that the FAQ cannot expose as a clickable source.
Suggested fix
```diff
--- a/apps/sim/content/library/best-ai-agents-for-querying-sql-databases/index.mdx
+++ b/apps/sim/content/libra … the rest (1206 characters)ry/best-ai-agents-for-querying-sql-databases/index.mdx @@ - a: "Snowflake Cortex Analyst is the strongest Snowflake-native option, while Sim is the better choice when Snowflake questions must trigger cross-platform reports, Slack messages, or approvals." + a: "For Snowflake-native querying, consult Snowflake's current deployment guidance before choosing Cortex Analyst or Cortex Agents. Sim is the better choice when Snowflake questions must trigger cross-platform reports, Slack messages, or approvals." @@ -Choose **Snowflake Cortex Analyst** when Snowflake is the governed system of record and its [semantic model or view](https://docs.snowflake.com/en/user-guide/snowflake-cortex/cortex-analyst) should define business terminology. +Choose **Snowflake Cortex Analyst** when Snowflake is the governed system of record and its [semantic model or view](https://docs.snowflake.com/en/user-guide/snowflake-cortex/cortex-analyst) should define business terminology. For new Snowflake deployments, Snowflake [recommends Cortex Agents](https://docs.snowflake.com/en/release-notes/2026/other/2026-08-28-cortex-analyst-transition-cortex-agents), which uses Cortex Analyst as its structured-data tool. ``` |
| #9083 2026-10-20 22:23 | coderabbit review-body | — | summary | **Actionable comments posted: 1** |
| #9083 2026-10-20 22:24 | greptile issue-comment | — | summary | Confidence Score: 4/5
**[Low impact]** The PR adds one informational article and its cover image\.
The remaining pricing-content correction is non-blocking; no blocking issue was established.
Findings
1. **Pricing claim lacks support**
Reviews (1) · Last reviewed commit: "feat(library): Best AI Agents for Queryi..." · Reviewed by the reviewer |
| #9083 2026-10-20 22:24 | greptile inline · P2 | apps/sim/content/library/best-ai-agents-for-querying-sql-databases/index.mdx:118 | docs | **Pricing claim lacks support**
The linked cost page does not support the claimed 1.1x hosted-model rate. It describes charges at the applicable Sim rate, and its audit record explicitly says the fixed 1.1x figure was removed. This is a non-blocking content correction: remove the number or cite a current source that establishes it so buyers do not budget against an unsupported rate.
Artifacts
**Evidence from the check**
- The executed Python source reads revision-specific article and documentation files, retrieves the exact cited page, and checks visible pricing wording and the BYOK anchor without modifying product files.
**Command output from the check**
- Ran the focused check agains … the rest (407 characters)t the parent revision and live cited page; the article was absent and the documentation specified an applicable Sim rate rather than a fixed multiplier. **Command output from the check** - Ran the identical check against the supplied head and retrieved the cited page with HTTP 200; the new article asserts 1.1x while both local and live documentation omit that figure. Ran code and verified through TREX |
| #9083 2026-10-20 22:25 | cubic inline · P2 | apps/sim/content/library/best-ai-agents-for-querying-sql-databases/index.mdx:118 | docs | The linked costs page does not substantiate the 1.1x figure; it describes hosted models as billed at the applicable Sim rate. Remove the number or link a source that explicitly documents it. |
| #9083 2026-10-20 22:25 | cubic inline · P2 | apps/sim/content/library/best-ai-agents-for-querying-sql-databases/index.mdx:21 | docs | Qualify this recommendation for new deployments: Snowflake recommends Cortex Agents, which includes Cortex Analyst capabilities for structured data. |
| #9083 2026-10-20 22:25 | cubic review-body | — | summary | **2 issues found** across 2 files
Reply with feedback, questions, or to request a fix.View guided diff | Turn on auto-fix | Re-trigger the reviewer |
| #9082 2026-10-20 22:25 | coderabbit issue-comment | — | summary | No actionable comments were generated in the recent review. 🎉
📝 Walkthrough
The pull request adds a 2026 guide that compares six ecommerce AI-agent platforms. It also describes operational workflows, safeguards, and how to assign tasks to deterministic rules, AI, or human approval.
**Changes: Ecommerce AI-Agent Guide**
|Layer / File(s)|Summary|
|:---|:---|
|**Platform comparison content** `apps/sim/content/library/best-ai-agents-ecommerce-operations-2026/index.mdx`|Adds platform rankings, scoring criteria, licensing and deployment details, individual platform evaluations, FAQs, and platform-selection guidance with related links.|
|**Ecommerce workflows and safeguards** `apps/sim/conten … the rest (3611 characters)t/library/best-ai-agents-ecommerce-operations-2026/index.mdx`|Describes order and returns, inventory, pricing, and customer-question workflows. Specifies safeguards and assigns tasks across deterministic rules, AI, and human approval.| **Priority:** ⬇️ Low **Estimated code review effort:** 2 (Simple) | ~10 minutes **Change:** Other Merge Risk: ⚪ Minimal · up to 02202 This change adds a library article and has no runtime impact. No actionable merge-blocking issue remains after review. Architecture risk: 🔵 Low · up to 02202 The change affects 1 system. **Changed systems:** `apps/sim` **Architecture concerns** No architecture-level concerns identified. Review details **Systems and components** - _observed_ — apps/sim (service) was modified; 1 changed file maps to changed impact. **Before / after behavior** - _observed_ — Modified behavior in apps/sim/content/library/best-ai-agents-ecommerce-operations-2026/index.mdx: Added article metadata, publication details, tags, Open Graph configuration, and FAQs covering ecommerce AI-agent capabilities, licensing, deployment, platform comparisons, safeguards, and recommended starting workflows. - _observed_ — Modified behavior in apps/sim/content/library/best-ai-agents-ecommerce-operations-2026/index.mdx: Added the TL;DR and ranked comparison table, identifying Sim as the overall leader, n8n as strongest for self-hosted integrations, Gorgias as strongest for support conversations, and the primary limitation of each option. - _observed_ — Modified behavior in apps/sim/content/library/best-ai-agents-ecommerce-operations-2026/index.mdx: Added the scoring methodology, six weighted evaluation criteria, per-option scores, weighted totals, and a qualification that the rankings measure suitability for the guide’s ecommerce jobs rather than overall product quality. - _observed_ — Modified behavior in apps/sim/content/library/best-ai-agents-ecommerce-operations-2026/index.mdx: Added factual comparisons of licenses, hosting models, usage-based pricing, and deployment options for Sim, n8n, Zapier, Make, Shopify Flow, and Gorgias AI Agent, with vendor links as authoritative pricing references. Pre-merge checks: 5 | Check name | Status | Explanation | | :------------------------ | :--------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Description Check | | Check skipped - the reviewer’s high-level summary is enabled. | | Title check | | The title clearly and concisely describes the added ecommerce AI-agent comparison guide for 2026. | | Docstring Coverage | | No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff. Analyzed 0 functions across 0… | | Linked Issues check | | Check skipped because no linked issues were found for this pull request. | | Out of Scope Changes check | | Check skipped because no linked issues were found for this pull request. | Full details: Docstring Coverage **Explanation** No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff. Analyzed 0 functions across 0 files. (1 skipped: 1 unsupported.) ✨ Finishing Touches 🧪 Generate unit tests (beta) Comment `@the reviewer help` to get the list of available commands. |
| #9082 2026-10-20 22:28 | cubic inline · P2 | apps/sim/content/library/best-ai-agents-ecommerce-operations-2026/index.mdx:50 | docs | This FAQ asks about Gumloop, which the post never compares. The FAQ answer is also emitted as FAQPage JSON-LD, so the unsupported claim reaches search results. Remove this entry, or replace it with a question about one of the six options in the post. |
| #9082 2026-10-20 22:28 | cubic inline · P3 | apps/sim/content/library/best-ai-agents-ecommerce-operations-2026/index.mdx:43 | defect-functional | These FAQ answers display the license URLs as unlinked text because the FAQ renderer outputs `it.a` directly. Remove the URLs from the FAQ copy and rely on the linked license details in the article body. |
| #9082 2026-10-20 22:28 | cubic review-body | — | summary | **2 issues found** across 2 files
Reply with feedback, questions, or to request a fix.View guided diff | Turn on auto-fix | Re-trigger the reviewer |
| #9082 2026-10-20 22:31 | greptile issue-comment | — | summary | Confidence Score: 5/5
**[Low impact]** Safe to merge based on the scoped content check and successful article loading, rendering, internal-link checks, and cover decoding.
Reviews (1) · Last reviewed commit: "feat(library): 6 Best AI Agent Options f..." · Reviewed by the reviewer |
| #9081 2026-10-20 22:32 | coderabbit issue-comment | — | summary | No actionable comments were generated in the recent review. 🎉
📝 Walkthrough
The pull request adds an article comparing five Discord AI bot builders and describing cross-channel agent designs, moderation, documentation retrieval, human approval, and security controls.
**Changes: Discord AI Bot Builders Article**
|Layer / File(s)|Summary|
|:---|:---|
|**Platform comparison and selection** `apps/sim/content/library/best-discord-ai-bot-builders-2026/index.mdx`|Adds publication metadata, platform rankings and evaluations, selection guidance, and related comparison links.|
|**Cross-channel workflows and safeguards** `apps/sim/content/library/best-discord-ai-bot-builders-2026/index.mdx`|Descr … the rest (3603 characters)ibes a shared Discord and Slack agent design, moderation and retrieval workflows, human approval, and security controls.| **Priority:** ⬇️ Low **Estimated code review effort:** 2 (Simple) | ~15 minutes **Change:** Other Merge Risk: ⚪ Minimal · up to 3091b The article’s related guides remain accessible, and its Discord polling guidance describes a supported setup. No identified issue needs to be resolved before merging. Architecture risk: 🔵 Low · up to 3091b The change affects 1 system. **Changed systems:** `apps/sim` **Architecture concerns** No architecture-level concerns identified. Review details **Systems and components** - _observed_ — apps/sim (service) was modified; 1 changed file maps to changed impact. **Before / after behavior** - _observed_ — Modified behavior in apps/sim/content/library/best-discord-ai-bot-builders-2026/index.mdx: Added article frontmatter defining the title, publication metadata, tags, cover image, draft status, and FAQ entries covering Discord AI bot selection, platform integrations, licensing, deployment, security, moderation, retrieval, memory, and cross-channel operation. - _observed_ — Modified behavior in apps/sim/content/library/best-discord-ai-bot-builders-2026/index.mdx: Added the comparison overview, ranking Sim, n8n, Make, Botpress, and Zapier, plus the weighted scoring methodology and platform score tables. - _observed_ — Modified behavior in apps/sim/content/library/best-discord-ai-bot-builders-2026/index.mdx: Added concise platform fact summaries covering each builder’s Discord and Slack support, hosting model, licensing, and usage or billing model. - _observed_ — Modified behavior in apps/sim/content/library/best-discord-ai-bot-builders-2026/index.mdx: Added the Sim evaluation, describing reusable Discord and Slack agent workflows, scheduled Discord polling, separate platform credentials, retrieval, moderation, tool use, human escalation, self-hosting, local models, and BYOK availability. Pre-merge checks: 5 | Check name | Status | Explanation | | :------------------------ | :--------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Description Check | | Check skipped - the reviewer’s high-level summary is enabled. | | Title check | | The title clearly identifies the new library post and its subject: five Discord AI bot builders for community automation in 2026. | | Docstring Coverage | | No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff. Analyzed 0 functions across 0… | | Linked Issues check | | Check skipped because no linked issues were found for this pull request. | | Out of Scope Changes check | | Check skipped because no linked issues were found for this pull request. | Full details: Docstring Coverage **Explanation** No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff. Analyzed 0 functions across 0 files. (1 skipped: 1 unsupported.) ✨ Finishing Touches 🧪 Generate unit tests (beta) > [!WARNING] > ⚠️ This pull request has been flagged as potential spam (seo-spam) by the reviewer slop detection and should be reviewed carefully. Comment `@the reviewer help` to get the list of available commands. |
| #9081 2026-10-20 22:35 | cubic review-body | — | summary | **No issues found** across 2 files
View guided diff | Turn on auto-fix | Re-trigger the reviewer |
| #9081 2026-10-20 22:38 | greptile issue-comment | — | summary | Confidence Score: 5/5
**[Low impact]** Safe to merge within the reviewed content scope; no blocking issues were identified.
Reviews (1) · Last reviewed commit: "feat(library): 5 Best Discord AI Bot Bui..." · Reviewed by the reviewer |
| #9080 2026-10-20 22:39 | coderabbit issue-comment | — | summary | 📝 Walkthrough
The pull request adds a guide to building a WhatsApp AI agent with Sim. It covers webhook verification, message policies and delivery tracking, CRM/helpdesk routing, operations, platform comparisons, and deployment checks. It also adds an embedded TypeScript helper for validating Meta webhook signatures.
**Changes: WhatsApp AI agent guide**
|Layer / File(s)|Summary|
|:---|:---|
|**Webhook architecture and verification** `apps/sim/content/library/how-to-build-whatsapp-ai-agent-with-sim/index.mdx`|Introduces the WhatsApp Cloud API workflow and documents raw-body HMAC-SHA256 validation with the `verifyMetaSignature` helper.|
|**Message policy and delivery tracking** `apps/sim/ … the rest (4497 characters)content/library/how-to-build-whatsapp-ai-agent-with-sim/index.mdx`|Documents customer-service-window rules, consent suppression, duplicate processing, outbound message correlation, delivery states, and failure handling.| |**Routing and operating guidance** `apps/sim/content/library/how-to-build-whatsapp-ai-agent-with-sim/index.mdx`|Covers CRM/helpdesk routing, human handoff, permissions, data handling, hosting, licensing, and platform comparisons.| |**Acceptance checks and final workflow** `apps/sim/content/library/how-to-build-whatsapp-ai-agent-with-sim/index.mdx`|Adds a predeployment acceptance matrix and a final workflow diagram with related-guide links.| **Priority:** ⬇️ Low **Estimated code review effort:** 3 (Moderate) | ~20 minutes **Change:** Other Merge Risk: 🔵 Low · up to 04928 The guide could mislead builders about webhook setup and should cite Meta’s policy directly. These are bounded documentation fixes; the PR remains mergeable with owner follow-up. Architecture risk: 🔵 Low · up to 04928 The change affects 1 system. **Changed systems:** `apps/sim` **Architecture concerns** No architecture-level concerns identified. Review details **Systems and components** - _observed_ — apps/sim (service) was modified; 1 changed file maps to changed impact. **Before / after behavior** - _observed_ — Modified behavior in apps/sim/content/library/how-to-build-whatsapp-ai-agent-with-sim/index.mdx: Added page metadata, publication details, tags, and FAQs covering WhatsApp agent capabilities, security, policy windows, deduplication, delivery tracking, escalation, integrations, licensing, local models, and platform comparisons. - _observed_ — Modified behavior in apps/sim/content/library/how-to-build-whatsapp-ai-agent-with-sim/index.mdx: Added the guide overview and WhatsApp Cloud API architecture, including verified webhooks, durable queuing, message-ID deduplication, Sim processing, authenticated replies, and status updates. - _observed_ — Modified behavior in apps/sim/content/library/how-to-build-whatsapp-ai-agent-with-sim/index.mdx: Added webhook verification guidance and the exported `verifyMetaSignature` helper, which requires a `sha256=` signature, computes HMAC-SHA256 over the raw body, rejects length mismatches, and compares digests in constant time. - _observed_ — Modified behavior in apps/sim/content/library/how-to-build-whatsapp-ai-agent-with-sim/index.mdx: Added deterministic customer-service-window rules: free-form replies are allowed inside the documented 24-hour window; outside it, an approved template is required, a missing template creates a follow-up task, and opted-out or non-consenting contacts are suppressed. Pre-merge checks: 5 | Check name | Status | Explanation | | :------------------------ | :--------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Description Check | | Check skipped - the reviewer’s high-level summary is enabled. | | Title check | | The title clearly identifies the new library guide about building a WhatsApp AI agent with Sim. It is concise and directly related to the main change. | | Docstring Coverage | | No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff. Analyzed 0 functions across 0… | | Linked Issues check | | Check skipped because no linked issues were found for this pull request. | | Out of Scope Changes check | | Check skipped because no linked issues were found for this pull request. | Full details: Docstring Coverage **Explanation** No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff. Analyzed 0 functions across 0 files. (1 skipped: 1 unsupported.) ✨ Finishing Touches 🧪 Generate unit tests (beta) ### Usage-based review receipt - Mode: Continue automatically - Reviewed files: 1 - Waived: $0.25 (charged $0.00) - View usage details > [!NOTE] > This review exceeded your plan’s limits and used usage-based reviews—free during trial, billed after paid activation unless disabled. **Manage usage-based reviews**. Comment `@the reviewer help` to get the list of available commands. |
| #9080 2026-10-20 22:43 | coderabbit inline · P2 | apps/sim/content/library/how-to-build-whatsapp-ai-agent-with-sim/index.mdx:23 | docs | **🎯 Functional Correctness** | **🟡 Minor** | **⚡ Quick win**
**Document Sim’s built-in signature verification.**
The FAQ and final workflow require an upstream verifier, but Sim’s registered WhatsApp provider already validates `X-Hub-Signature-256` with the configured app secret. This can lead readers to add an unnecessary edge verifier or conclude that Sim cannot verify signatures. State that upstream verification is optional when another component owns the public webhook boundary.
Suggested fix
```diff
- q: "Can Sim verify WhatsApp webhook signatures?"
- a: "Sim should receive events only after an edge endpoint has verified Meta’s signature against the raw request body, because … the rest (1832 characters)signature validation belongs at the public webhook security boundary." + a: "Yes. Sim’s built-in WhatsApp trigger validates X-Hub-Signature-256 with the configured Meta app secret. An upstream edge endpoint may also verify the raw request body when it owns the public webhook boundary." ... -A WhatsApp webhook receiver should validate Meta’s verification challenge during setup and verify the signature of every event against the raw request body before sending the event to Sim. +When Meta sends events directly to Sim’s built-in WhatsApp trigger, Sim validates the signature of every event against the raw request body. An upstream receiver must perform that verification before forwarding events when it owns the public webhook boundary. ... -Sim should sit behind a verified, asynchronous messaging boundary and in front of narrowly scoped business tools rather than acting as the webhook security layer or system of record. +Sim can sit behind an optional verified, asynchronous messaging boundary and in front of narrowly scoped business tools. Its built-in WhatsApp trigger verifies signatures when Meta sends events directly to Sim. ... - → HTTPS webhook verification and signature validation + → HTTPS webhook endpoint (Sim validates the signature, or an optional upstream boundary does) ``` 📝 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. ```suggestion a: "Yes. Sim’s built-in WhatsApp trigger validates X-Hub-Signature-256 with the configured Meta app secret. An upstream edge endpoint may also verify the raw request body when it owns the public webhook boundary." ``` |
| #9080 2026-10-20 22:43 | coderabbit inline · P2 | apps/sim/content/library/how-to-build-whatsapp-ai-agent-with-sim/index.mdx:113 | docs | **📐 Maintainability & Code Quality** | **🟡 Minor** | **⚡ Quick win**
**Cite Meta’s primary policy for the customer-service window.**
Line 119 cites Sim for a Meta-controlled policy. Replace it with Meta’s official WhatsApp Business Platform policy. The repository rule requires a primary source, but it does not require a `developers.facebook.com` URL.
The existing Meta-owned links at lines 113 and 128 are first-party sources. Their being blog posts does not make them secondary citations. The generic developer URL in the proposed wording is not shown to substantiate the 24-hour rule or its scope.
📝 Suggested fix
```diff
-As of October 2026, [Sim’s WhatsApp documentation](https://docs.s … the rest (705 characters)im.ai/integrations/whatsapp) records a 24-hour customer-service window following a customer message. The workflow should calculate the window from authoritative conversation timestamps rather than asking the model whether a reply is allowed. +As of October 2026, [Meta’s WhatsApp Business Platform policy](https://whatsappbusiness.com/policy/?iframe=yes) states that the 24-hour customer-service window opens and resets with each customer message. Businesses may send non-template replies within the window and may send only approved templates after it closes. The workflow should calculate the window from authoritative conversation timestamps rather than asking the model whether a reply is allowed. ``` |
| #9080 2026-10-20 22:43 | coderabbit review-body | — | summary | **Actionable comments posted: 2** |
| #9080 2026-10-20 22:45 | cubic inline · P2 | apps/sim/content/library/how-to-build-whatsapp-ai-agent-with-sim/index.mdx:77 | docs | Sim’s WhatsApp trigger already handles Meta’s verification challenge and validates POST signatures, so this warning implies teams need a separate edge verifier. Clarify that the trigger supplies signature verification and reserve an external edge for additional controls or queueing. |
| #9080 2026-10-20 22:45 | cubic review-body | — | summary | **1 issue found** across 2 files
Reply with feedback, questions, or to request a fix.View guided diff | Turn on auto-fix | Re-trigger the reviewer |
| #9080 2026-10-20 22:46 | greptile issue-comment | — | summary | Confidence Score: 4/5
**[Low impact]** The change adds one public article to the Sim library\.
No blocking issue remains; the crash-recovery guidance is a non-blocking documentation concern.
Findings
1. **Retries can drop unanswered messages**
Reviews (1) · Last reviewed commit: "feat(library): How Do You Build a WhatsA..." · Reviewed by the reviewer |
| #9080 2026-10-20 22:46 | greptile inline · P2 | apps/sim/content/library/how-to-build-whatsapp-ai-agent-with-sim/index.mdx:136 | docs | **Retries can drop unanswered messages**
The guide tells workers to skip every existing event, even when earlier work never finished. If a worker inserts the record and crashes before invoking Sim, the queue retries the message, finds the record, and skips it without answering the customer. This is a non-blocking documentation gap: distinguish completed work from unfinished work, and explain how retries can safely reclaim abandoned records without repeating completed sends.
Artifacts
**Executable model of documented deduplication and crash recovery**
- The exact executed Bun source anchors its assumptions to article lines 132–136 and tests both algorithms with healthy duplicates and inje … the rest (624 characters)cted pre-Sim failure, making the model reproducible. **Execution output with the documented existing-event rule** - Ran the documented-rule model with a crash after insertion and before Sim invocation; the retry was acknowledged with zero runs and zero replies, confirming the unanswered-message path. **Execution output with the proposed incomplete-work recovery control** - Ran the recovery-control model with identical failure injection; incomplete work resumed with one run and one reply while healthy duplicates stayed suppressed, isolating the existing-record rule as the cause. Ran code and verified through TREX |
| #9085 2026-10-20 22:47 | coderabbit issue-comment | — | summary | No actionable comments were generated in the recent review. 🎉
📝 Walkthrough
Post-action observation validation now accepts five additional browser tools: coordinate click, text insertion, option selection, checkbox updates, and dragging. Parameterized tests verify successful dispatch, observation, and inclusion of the observed outline.
**Changes: Browser post-action observation**
|Layer / File(s)|Summary|
|:---|:---|
|**Add browser actions to post-action observation** `apps/desktop/src/main/browser-agent/post-action-observation.ts`, `apps/desktop/src/main/browser-agent/post-action-observation.test.ts`|The observable action list now includes five additional browser tools. Parameterized … the rest (3168 characters)tests verify that each action dispatches successfully, performs observation, and returns the observed outline.| **Priority:** ➖ Normal **Estimated code review effort:** 2 (Simple) | ~8 minutes **Change:** Bug fix **Suggested reviewers:** `waleedlatif1` Merge Risk: ⚪ Minimal · up to 2c2f0 No concrete merge-blocking risk is established. Security architecture risk: ⚪ Minimal · up to 2c2f0 Five existing browser actions can now return a follow-up observation using their existing permissions and data-access controls. Completed action results are preserved when observation fails, and no material security risk was identified in the changed flow. **Retained concerns** No architecture-level concerns identified. Security review details **Security Blast Radius** - _inferred_ — The newly accepted requests can mutate and observe pages accessible to the existing browser scope, including page-side effects of those actions. The same mutations and observations were already available through separate calls; this change combines them without adding another authority-bearing entrypoint. **Security Findings and Attack Paths** - _inferred_ — No introduced control bypass was identified along the traced tool-request-to-page path. The widened allowlist accepts additional combinations of existing capabilities; it does not bypass action validation or introduce a separate observation execution channel. **Trust Boundaries and Controls** - _observed_ — Follow-up observations reuse the existing snapshot/find implementations rather than a new data collector. The inspected snapshot collector retains its visibility limits and sensitive-field handling for passwords, one-time codes, and payment values. Pre-merge checks: 5 | Check name | Status | Explanation | | :------------------------ | :--------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Description Check | | Check skipped - the reviewer’s high-level summary is enabled. | | Title check | | The title clearly summarizes the main change: enabling post-action observation for page actions in the browser driver. | | Docstring Coverage | | No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff. Analyzed 0 functions across 2… | | Linked Issues check | | Check skipped because no linked issues were found for this pull request. | | Out of Scope Changes check | | Check skipped because no linked issues were found for this pull request. | Full details: Docstring Coverage **Explanation** No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff. Analyzed 0 functions across 2 files. ✨ Finishing Touches 📝 Generate docstrings 🧪 Generate unit tests (beta) Comment `@the reviewer help` to get the list of available commands. |
| #9085 2026-10-20 22:48 | cubic review-body | — | summary | **No issues found** across 2 files
View guided diff | Turn on auto-fix | Re-trigger the reviewer |
| #9085 2026-10-20 22:53 | greptile issue-comment | — | summary | Confidence Score: 5/5
**[Medium impact]** The reviewed change is safe to merge; no blocking or non-blocking issues were found.
Reviews (1) · Last reviewed commit: "improvement(browser): accept observe on ..." · Reviewed by the reviewer |
| #9079 2026-10-20 22:56 | coderabbit issue-comment | — | summary | 📝 Walkthrough
This change adds URL-aware links to changelog content, publishes a new changelog edition, adjusts content typography, and updates editorial standards and candidate-batching guidance.
**Changes: Changelog publishing and rendering**
|Layer / File(s)|Summary|
|:---|:---|
|**Resolve and render changelog links** `apps/sim/app/(landing)/changelog/components/changelog-link/*`, `apps/sim/app/(landing)/changelog/components/index.ts`, `apps/sim/lib/changelog/mdx.tsx`|Changelog Markdown links now use `ChangelogLink`. It resolves site and documentation URLs, adds matching integration or model icons, and renders internal links with Next.js `Link` and prefetch disabled. Other links use a … the rest (4977 characters)nchors; external links open in a new tab with secure `rel` attributes.| |**Add the October changelog edition** `apps/sim/content/changelog/oracle-checkr-and-shopify/index.mdx`, `apps/sim/content/changelog/edition-2026-10-15/production.md`|The new edition documents Oracle Database, Checkr, Shopify, Ramp, Vanta, and Chat updates, along with availability requirements, release evidence, and pending publication work.| |**Update content typography** `apps/sim/app/(landing)/components/content-post-page/content-post-page.tsx`, `apps/sim/lib/content/mdx.tsx`, `scripts/check-explicit-any.baseline.json`|The content post page uses theme-backed prose variables. The MDX emphasis renderer uses typed props and preserves inherited text color. The explicit-`any` baseline count is reduced by one.| **Changelog editorial workflow** |Layer / File(s)|Summary| |:---|:---| |**Update release and media guidance** `apps/sim/content/changelog/editorial-standard.md`|Editorial standards allow up to five verified notes in manually curated catch-up editions and clarify that model pickers or operation menus can show choices without a connected account.| |**Revise candidate batch selection** `apps/sim/content/changelog/maintenance-workflow.md`|Candidate batches combine up to ten newest and ten oldest eligible rows, deduplicate by row identity, and remain capped at 20.| **Priority:** ⬇️ Low **Estimated code review effort:** 3 (Moderate) | ~20 minutes **Change:** Feature ## Sequence Diagram(s) ```mermaid sequenceDiagram participant MDX participant ChangelogLink participant NextLink MDX->>ChangelogLink: Render changelog link ChangelogLink->>NextLink: Render internal site URL ``` **Suggested reviewers:** `waleedlatif1`, `andresdjasso` Merge Risk: 🟡 Moderate · up to 0527e The changelog edition can become public before its stated checks are complete. Keep it drafted until verification is finished, and correct the smaller link, guidance, and announcement issues before publication. Security architecture risk: ⚪ Minimal · up to 0527e The new navigation behavior operates on repository-authored changelog content and retains protective attributes for external links. The review found no material security risk introduced or worsened by the change, and no expansion of user-controlled input or privileged operations. **Retained concerns** No architecture-level concerns identified. Security review details **Security Blast Radius** - _inferred_ — The changed path affects public changelog readers and their link navigation. Supplying different href values through the inspected path requires changing repository content. The renderer itself performs catalog lookups and presentation, not credential access, integration execution, or a privileged operation. **Trust Boundaries and Controls** - _observed_ — URL classification is not scheme validation: the new component parses href but forwards its original value. That absence of a scheme allowlist predates this PR in the shared anchor renderer. For external-host links, the new component overrides target and rel with _blank and noopener noreferrer; its first-party subdomain treatment also follows the prior hostname policy. Pre-merge checks: 5 | Check name | Status | Explanation | | :------------------------ | :--------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Description Check | | Check skipped - the reviewer’s high-level summary is enabled. | | Title check | | The title accurately summarizes the primary changes: expanded changelog release coverage and refined content styling. | | Docstring Coverage | | Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 2 functions across 6 files. (5 skipped: 5 … | | Linked Issues check | | Check skipped because no linked issues were found for this pull request. | | Out of Scope Changes check | | Check skipped because no linked issues were found for this pull request. | Full details: Docstring Coverage **Explanation** Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 2 functions across 6 files. (5 skipped: 5 unsupported.) ✨ Finishing Touches 📝 Generate docstrings 🧪 Generate unit tests (beta) ### Usage-based review receipt - Mode: Continue automatically - Reviewed files: 11 - Waived: $2.75 (charged $0.00) - View usage details > [!NOTE] > This review exceeded your plan’s limits and used usage-based reviews—free during trial, billed after paid activation unless disabled. **Manage usage-based reviews**. Comment `@the reviewer help` to get the list of available commands. |
| #9079 2026-10-20 23:02 | coderabbit inline · P2 | apps/sim/app/(landing)/changelog/components/changelog-link/changelog-link.tsx:28 | defect-functional | **🎯 Functional Correctness** | **🟡 Minor** | **⚡ Quick win**
**Restrict `isExternal` to web URLs.**
If a changelog entry uses a `mailto:` or `tel:` URL, `new URL()` gives it an empty hostname. The current check marks it as external and adds `target="_blank"`. This can create a blank browsing context before the external protocol handler runs.
Suggested fix
```diff
--- "a/apps/sim/app/(landing)/changelog/components/changelog-link/changelog-link.tsx"
+++ "b/apps/sim/app/(landing)/changelog/components/changelog-link/changelog-link.tsx"
@@ -25,7 +25,12 @@
} catch {}
const isSite = url?.hostname === SITE_HOST || url?.hostname === SITE_APEX
- const isExternal = url && url.hostname != … the rest (920 characters)= SITE_APEX && !url.hostname.endsWith(`.${SITE_APEX}`) + const isWeb = url?.protocol === 'http:' || url?.protocol === 'https:' + const isExternal = + url !== undefined && + isWeb && + url.hostname !== SITE_APEX && + !url.hostname.endsWith(`.${SITE_APEX}`) const pathname = url?.pathname.replace(/\/$/, '') const integration = isSite ? INTEGRATIONS_BY_PATH.get(pathname ?? '') ``` 📝 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. ```suggestion const isWeb = url?.protocol === 'http:' || url?.protocol === 'https:' const isExternal = url !== undefined && isWeb && url.hostname !== SITE_APEX && !url.hostname.endsWith(`.${SITE_APEX}`) ``` |
| #9079 2026-10-20 23:02 | coderabbit inline · P2 | apps/sim/content/changelog/edition-2026-10-15/production.md:57 | docs | **🎯 Functional Correctness** | **🟡 Minor** | **⚡ Quick win**
**Name the release in the announcement drafts.**
If these pending drafts go out now, “latest Chat fixes” misstates their recency. The drafts describe v0.9.23, but v0.9.26 also contains Chat fixes and v0.9.28 was released on October 20, 2026. Replace “latest” with “v0.9.23” so the announcement remains accurate. (github.com)
Also applies to: 59-59 |
| #9079 2026-10-20 23:02 | coderabbit inline · P2 | apps/sim/content/changelog/editorial-standard.md:41 | docs | **📐 Maintainability & Code Quality** | **🟡 Minor** | **⚡ Quick win**
**Scope the credential requirement to execution demonstrations.**
The first sentence applies to every capture, which conflicts with the stated exception for model-picker and operation-menu captures.
Suggested fix
```diff
-Complete sign-in and credential setup before capturing.
+Complete sign-in and credential setup before capturing an execution demonstration.
``` |
| #9079 2026-10-20 23:02 | coderabbit inline · P2 | apps/sim/content/changelog/oracle-checkr-and-shopify/index.mdx:14 | defect-functional | **🎯 Functional Correctness** | **🟡 Minor** | **⚡ Quick win**
**Keep the entry drafted until production verification is complete.**
`draft: false` passes the loader's only publication filter. The public archive and direct slug route can therefore list and render this entry while the production checklist still marks publication and final verification as pending. Set `draft: true` until those checks are complete, then change it to `false`.
Suggested fix
```diff
-draft: false
+draft: true
```
📝 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 … the rest (614 characters)indentation. Thoroughly test & benchmark the code to ensure it meets the requirements. ```suggestion --- slug: oracle-checkr-and-shopify title: 'Oracle Database, Checkr, and Shopify updates' description: 'Connect Sim agents to Oracle Database and Checkr, manage more Shopify operations, and reuse saved Ramp and Vanta connections across workflows.' date: '2026-10-15T17:00:00Z' authors: [waleed] tags: [Integrations, Workflows] ogImage: /changelog/oracle-operations-v1.jpg ogAlt: 'Oracle Database operations in the Sim workflow editor' technical: false draft: true release: versions: [v0.9.17, v0.9.23] --- ``` |
| #9079 2026-10-20 23:02 | coderabbit review-body | — | summary | **Actionable comments posted: 4** |
| #9079 2026-10-20 23:07 | greptile issue-comment | — | summary | Confidence Score: 5/5
**[Medium impact]** No established defect requires blocking merge; browser rendering and visual acceptance remain unverified.
Reviews (1) · Last reviewed commit: "improvement(changelog): expand release c..." · Reviewed by the reviewer |
| #9079 2026-10-20 23:08 | cubic inline · P3 | apps/sim/app/(landing)/changelog/components/changelog-link/changelog-link.tsx:28 | defect-functional | Restrict `isExternal` to HTTP(S) URLs; `mailto:` and `tel:` have empty hostnames, so this check incorrectly adds `target="_blank"` to them.
```suggestion
const isExternal =
url &&
(url.protocol === 'http:' || url.protocol === 'https:') &&
url.hostname !== SITE_APEX &&
!url.hostname.endsWith(`.${SITE_APEX}`)
``` |
| #9079 2026-10-20 23:08 | cubic inline · P3 | apps/sim/content/changelog/edition-2026-10-15/production.md:57 | docs | Identify these as the v0.9.23 Chat fixes in both announcement drafts; newer releases already contain later Chat changes, making “latest” inaccurate. |
| #9079 2026-10-20 23:08 | cubic inline · P3 | apps/sim/content/changelog/editorial-standard.md:41 | docs | Scope the sign-in and credential requirement to execution demonstrations; the current opening sentence contradicts the following allowance for model-picker and operation-menu captures without a connected account.
```suggestion
For execution demonstrations, complete sign-in and credential setup before capturing. Never save a placeholder key and present it as a working connection, or treat a saved key as evidence that the provider accepted it. A model picker or operation menu can show available choices without a connected account; a demonstration of execution must use a working credential and a real result. Keep these production checks out of public copy.
``` |
| #9079 2026-10-20 23:08 | cubic review-body | — | summary | **3 issues found** across 12 files
Reply with feedback, questions, or to request a fix.View guided diff | Turn on auto-fix | Re-trigger the reviewer |
| #9087 2026-10-20 23:09 | coderabbit issue-comment | — | summary | No actionable comments were generated in the recent review. 🎉
📝 Walkthrough
Migration 0431 sets autovacuum cost delay and cost limit for three tables and their TOAST tables. Integration tests verify the migration’s locking behavior, concurrent access, relation preservation, and applied settings.
**Changes: Large-table vacuum throttling**
|Layer / File(s)|Summary|
|:---|:---|
|**Migration settings and registration** `packages/db/migrations/0431_large_table_vacuum_throttle.sql`, `packages/db/migrations/meta/_journal.json`|Migration 0431 sets `autovacuum_vacuum_cost_delay` to `10` and `autovacuum_vacuum_cost_limit` to `200` on three tables and their TOAST tables. The migration journal inc … the rest (3909 characters)ludes its entry.| |**Migration integration checks** `packages/db/large-table-vacuum-throttle-migration.integration.ts`|Integration tests verify the migration’s lock mode, concurrent reads and writes, relation preservation, behavior while waiting on a conflicting lock, and settings on each table and its TOAST relation.| **Priority:** ➖ Normal **Estimated code review effort:** 3 (Moderate) | ~20 minutes **Change:** Bug fix Merge Risk: ⚪ Minimal · up to 7967a No actionable issue was found with the migration or its integration checks. It is ready for normal merge checks. Security architecture risk: 🔵 Low · up to 7967a The change is limited to maintenance settings on three tables and their TOAST relations. It does not add application access or database privileges. Locking checks and repeatable settings reduce rollout risk, but production vacuum capacity, replication effects, and recovery behavior have not been demonstrated. **Retained concerns** No architecture-level concerns identified. Security review details **Security Blast Radius** - _inferred_ — The direct configuration scope is three shared tables and their TOAST relations in each migrated database, not an individual tenant. The intended availability benefit can extend to other primary-database writers through shared WAL and synchronous-replication pressure, but that benefit is described rather than measured. **Trust Boundaries and Controls** - _observed_ — Migration coordination already depends on session advisory locks and a suitable database connection. The runner warns against transaction pooling, while the workflow permits fallback from the optional migration URL. These controls and assumptions are unchanged by this PR; deployed connection topology is unavailable. **Resilience and Maintainability Implications** - _inferred_ — Repeatable catalog settings limit recovery complexity if execution stops after only some statements. However, completed settings persist independently of application rollback, and the slower-vacuum trade-off requires operational validation to preserve database availability. **Hardening Proposals** - _proposed_ — Validate rollout with commit latency, standby flush lag, vacuum duration, dead-tuple growth, and transaction-ID age. Record the prior effective relation options and a restoration procedure so an unsuitable throttle can be reversed without guessing the previous policy. Pre-merge checks: 5 | Check name | Status | Explanation | | :------------------------ | :--------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Description Check | | Check skipped - the reviewer’s high-level summary is enabled. | | Title check | | The title clearly describes the main change: throttling autovacuum on the largest tables to reduce vacuum-related commit stalls. | | Docstring Coverage | | No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff. Analyzed 0 functions across 1… | | Linked Issues check | | Check skipped because no linked issues were found for this pull request. | | Out of Scope Changes check | | Check skipped because no linked issues were found for this pull request. | Full details: Docstring Coverage **Explanation** No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff. Analyzed 0 functions across 1 files. (2 skipped: 2 unsupported.) ✨ Finishing Touches 📝 Generate docstrings 🧪 Generate unit tests (beta) Comment `@the reviewer help` to get the list of available commands. |
| #9087 2026-10-20 23:16 | greptile issue-comment | — | summary | Confidence Score: 5/5
**[Medium impact]** No merge-blocking concerns were identified within the reviewed scope; the executed PostgreSQL checks support the migration's persistence, concurrency, and no-rewrite behavior.
Reviews (1) · Last reviewed commit: "fix(db): throttle autovacuum on the larg..." · Reviewed by the reviewer |
| #9087 2026-10-20 23:17 | cubic review-body | — | summary | **No issues found** across 4 files
View guided diff | Turn on auto-fix | Re-trigger the reviewer |
| #9086 2026-10-20 23:18 | coderabbit issue-comment | — | summary | No actionable comments were generated in the recent review. 🎉
📝 Walkthrough
The receiver now handles each control request in a batch independently, returns status codes for unsupported and malformed requests, advertises supported control kinds during polling, and records the transport failure phase in reconnect warnings.
**Changes: Receiver transport**
|Layer / File(s)|Summary|
|:---|:---|
|**Independent batch control handling** `apps/sim/lib/mothership/transport/receiver.ts`, `apps/sim/lib/mothership/transport/receiver.test.ts`|The receiver validates each request independently. Supported controls execute; unsupported controls receive 501, and malformed controls receive 400. Tests cove … the rest (4914 characters)r batch replies and dropped unreadable requests.| |**Poll capabilities and reconnect logging** `apps/sim/lib/mothership/transport/receiver.ts`, `apps/sim/lib/mothership/transport/receiver.test.ts`|Poll requests include the generated supported control kinds. Reconnect warnings identify the failing phase. Tests cover capability advertisement after a lost poll and reconnect.| **Priority:** ➖ Normal **Estimated code review effort:** 2 (Simple) | ~10 minutes **Change:** Bug fix ### Sequence Diagram(s) ```mermaid sequenceDiagram participant PollEndpoint participant Receiver participant ControlResponseFunction participant ReplyEndpoint Receiver->>PollEndpoint: poll with supported control kinds PollEndpoint-->>Receiver: batch envelope Receiver->>ControlResponseFunction: execute each supported control ControlResponseFunction-->>Receiver: control result Receiver->>ReplyEndpoint: post reply for each request ``` **Suggested reviewers:** `sg312` Merge Risk: ⚪ Minimal · up to 32c4b Malformed and unsupported controls do not prevent other readable controls in the batch from being handled. No merge-blocking issue was identified. Security architecture risk: 🔵 Low · up to 32c4b The change improves isolation between control requests while preserving existing execution checks. End-to-end compatibility, identity binding, and retry guarantees still depend on the remote service and have not been verified. **Retained concerns** No architecture-level concerns identified. Security review details **Security Blast Radius** - _inferred_ — The affected boundary carries workspace- or organization-scoped data access and task-control authority for the Sim deployment, not merely parser outcomes. The PR changes handling of mixed batches but does not add privileged operation kinds. Maximum tenant reach cannot be established without upstream scope validation and downstream authorization evidence. **Trust Boundaries and Controls** - _observed_ — Poll and reply requests retain API-key headers, channel correlation, and redirect rejection. Fully parsed response members supply the scope used for trusted-principal construction; channelId is not passed into that construction. This separation predates the PR, and upstream authentication and channel-to-scope binding remain unverified rather than an established new bypass. **Resilience and Maintainability Implications** - _inferred_ — The receiver executes before replying and has no local request-ID deduplication. Execution followed by interruption or failed acknowledgement therefore still depends on external delivery and idempotency guarantees. The lost-reply test aborts before redelivery and does not prove exactly-once behavior. Independent 400/501 replies also leave mixed valid/malformed duplicate-ID handling dependent on unverified worker semantics. Pre-merge checks: 4 · 1 Failed checks: 1 warning | Check name | Status | Explanation | Resolution | | :---------------- | :----------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------- | | Docstring Coverage | | Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 2 functions across 2 files. | Write docstrings for the functions missing them to satisfy the coverage threshold. | Passed checks: 4 passed | Check name | Status | Explanation | | :------------------------ | :--------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------- | | Description Check | | Check skipped - the reviewer’s high-level summary is enabled. | | Title check | | The title clearly identifies the two primary changes: independent parsing of checkpoint control requests and declaration of accepted control kinds. | | Linked Issues check | | Check skipped because no linked issues were found for this pull request. | | Out of Scope Changes check | | Check skipped because no linked issues were found for this pull request. | ✨ Finishing Touches: 💡 1 📝 Generate docstrings: 💡 🧪 Generate unit tests (beta) ### Usage-based review receipt - Mode: Continue automatically - Reviewed files: 2 - Waived: $0.50 (charged $0.00) - View usage details > [!NOTE] > This review exceeded your plan’s limits and used usage-based reviews—free during trial, billed after paid activation unless disabled. **Manage usage-based reviews**. Comment `@the reviewer help` to get the list of available commands. |
| #9086 2026-10-20 23:26 | cubic review-body | — | summary | **No issues found** across 3 files
View guided diff | Turn on auto-fix | Re-trigger the reviewer |
| #9086 2026-10-20 23:28 | greptile issue-comment | — | summary | Confidence Score: 5/5
**[Medium impact]** The scoped checks found no defects that would prevent merging; request isolation and poll compatibility behaved as intended.
Reviews (1) · Last reviewed commit: "fix(mothership): parse each checkpoint c..." · Reviewed by the reviewer |
| #9084 2026-10-20 23:29 | coderabbit issue-comment | — | summary | No actionable comments were generated in the recent review. 🎉
📝 Walkthrough
The changes update macOS computer-use observation and input validation, track whether actions reach the target app, and preserve snapshot references for failures before dispatch. The computer-tool result projection also changes its size limit and prioritization of visible menu items.
**Changes: Computer-use input and snapshot lifecycle**
|Layer / File(s)|Summary|
|:---|:---|
|**Window observation and menu discovery** `apps/desktop/native/computer-use/ComputerUse.swift`|Snapshots retain matched Accessibility window identities. Observation prioritizes open-menu descendants and adds valid shortcuts to menu-item la … the rest (6644 characters)bels.| |**Validated input and dispatch tracking** `apps/desktop/native/computer-use/ComputerUse.swift`, `apps/desktop/native/computer-use/README.md`|Native actions track dispatch. Keyboard, pointer, text, scroll, and drag input use updated target and focus validation. The documentation describes the input rules, including `type_text` and keyboard-focusable targets.| |**Snapshot ownership and follow-up observation** `apps/desktop/src/main/computer-use/service.ts`, `apps/desktop/src/main/computer-use/service.test.ts`, `apps/desktop/native/computer-use/README.md`|The service restores snapshot ownership when dispatch is reported as `not_started`. Tests cover pre-dispatch and unspecified helper failures. Follow-up observation uses normalized options.| **Computer-tool result projection** |Layer / File(s)|Summary| |:---|:---| |**Result size and menu-item priority** `apps/sim/lib/mothership/tools/client/computer-tool-result.ts`, `apps/sim/lib/mothership/tools/client/computer-tool-result.test.ts`|The maximum serialized state size changes from 44 KiB to 22 KiB. Visible open menu items receive the highest priority alongside focused nodes, and the tests use the reduced size limit.| **Priority:** ⬆️ High **Estimated code review effort:** 4 (Complex) | ~45 minutes **Change:** Bug fix **Suggested reviewers:** `sg312` Merge Risk: ⚪ Minimal · up to 3da14 No actionable merge-blocking issue was established. The change is mergeable after normal checks. Security architecture risk: 🟡 Moderate · up to 3da14 Input remains limited to the requested application, but the new dialog exception can accept a different window from the one observed. This creates a risk of acting on an unintended prompt. Snapshot recovery otherwise remains conservative about actions whose effects are uncertain. **Retained concerns** - **Medium · security · inferred:** The new auxiliary-window exception accepts any same-app dialog or floating-window subrole without requiring its identity, geometry, or relationship to the selected window. Even with an explicit window target, focused-key or coordinate input can therefore reach an unrelated same-app dialog rather than the observed target. The base required the requested focused-window frame for keys and the exact topmost window ID for coordinate input. Supporting legitimate sheets and popovers does not itself establish that every auxiliary window is associated with the intended target; unintended confirmation is an inferred consequence, not a demonstrated exploit. Security review details **Security Blast Radius** - _inferred_ — The identified target-binding risk is within the requested application process and the operations its dialogs expose. The inspected changes do not establish cross-application, tenant, service, or deployment-authority expansion. **Security Findings and Attack Paths** - _inferred_ — If a different same-app auxiliary dialog receives focus or covers a targeted point, its allowed subrole can satisfy validation despite lacking the selected window's identity or observed geometry. A subsequent key or click may operate that dialog. This is a target-confusion path; no successful exploitation or sensitive operation was demonstrated. **Trust Boundaries and Controls** - _observed_ — Mutation requests remain bound to snapshot bundle, PID, launch date, and expiry. Protected applications are rejected, coordinate hit-testing checks the receiving PID, and text/key paths retain secure-input ancestry checks. These controls constrain, but do not resolve, the same-app auxiliary-window exception. **Resilience and Maintainability Implications** - _observed_ — Press timeouts classified as cannotComplete count as dispatched rather than proof of success. Native dispatch tracking and service ownership handling prevent that ambiguity, partial input, or a failed follow-up observation from making the original snapshot reusable. **Hardening Proposals** - _proposed_ — Preserve legitimate sheet and popover support by tying auxiliary targets to the intended observed window, or require fresh observation when that relationship cannot be established. Exercise unrelated same-app dialogs and moved auxiliary windows as boundary cases. Pre-merge checks: 4 · 1 Failed checks: 1 warning | Check name | Status | Explanation | Resolution | | :---------------- | :----------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------- | | Docstring Coverage | | Docstring coverage is 20.69% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 29 functions across 5 files. (1 skipped: … | Write docstrings for the functions missing them to satisfy the coverage threshold. | Passed checks: 4 passed | Check name | Status | Explanation | | :------------------------ | :--------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------- | | Description Check | | Check skipped - the reviewer’s high-level summary is enabled. | | Title check | | The title clearly and concisely describes the main change: directing computer-use actions to the application visible to the user. | | Linked Issues check | | Check skipped because no linked issues were found for this pull request. | | Out of Scope Changes check | | Check skipped because no linked issues were found for this pull request. | Full details: Docstring Coverage **Explanation** Docstring coverage is 20.69% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 29 functions across 5 files. (1 skipped: 1 unsupported.) **Resolution** Write docstrings for the functions missing them to satisfy the coverage threshold. ✨ Finishing Touches: 💡 1 📝 Generate docstrings: 💡 🧪 Generate unit tests (beta) ### Usage-based review receipt - Mode: Continue automatically - Reviewed files: 6 - Waived: $1.50 (charged $0.00) - View usage details > [!NOTE] > This review exceeded your plan’s limits and used usage-based reviews—free during trial, billed after paid activation unless disabled. **Manage usage-based reviews**. Comment `@the reviewer help` to get the list of available commands. |
| #9084 2026-10-20 23:38 | cubic inline · P2 | apps/desktop/native/computer-use/README.md:15 | docs | This overstates menu completion: `completeMenuPress` skips items with a submenu, so a highlighted submenu entry is not completed with Return. Limit the claim to non-submenu items.
```suggestion
AXPress and AXSetValue are direct semantic operations. Keyboard events target the app PID. Cmd+A uses the focused editor's writable accessibility selection range where supported. Coordinate mouse input requires the target app in front; `activate_app` makes that focus change explicit and confirms it. Click/drag/scroll validate the foreground process, unchanged window geometry and the app that receives the point; the topmost window-list entry is not the click target because Notification Center and the … the rest (755 characters)Dock keep full-screen click-through windows. A press that times out while the app opens a sheet or modal (`cannotComplete`) counts as dispatched. A non-submenu menu-item press that leaves its menu open with the item highlighted (Calendar on macOS 26) is completed with Return. Open menus and their submenus are observed first, and menu item labels carry their shortcuts (for example ⇧⌘N). Some apps ignore background keyboard events. `dispatched:true,verified:false` means only dispatch succeeded; the agent must observe again to establish the outcome. No foreground activation fallback is hidden inside the helper. Native key codes currently assume the US layout for shortcuts; literal text uses Unicode events. Unsupported shortcuts fail explicitly. ``` |
| #9084 2026-10-20 23:38 | cubic inline · P2 | apps/desktop/native/computer-use/ComputerUse.swift:619 | defect-functional | `perform_action` accepts any advertised action, but `press: true` makes `dispatchAX` treat every `.cannotComplete` timeout as completed. Limit this flag to `AXPress` and `AXPick`; otherwise report the unknown outcome instead of success.
```suggestion
try dispatchAX(element, press: action == kAXPressAction || action == kAXPickAction) { AXUIElementPerformAction($0, action as CFString) }
``` |
| #9084 2026-10-20 23:38 | cubic review-body | — | summary | **2 issues found** across 8 files
Reply with feedback, questions, or to request a fix.View guided diff | Turn on auto-fix | Re-trigger the reviewer |
| #9084 2026-10-20 23:39 | greptile issue-comment | — | summary | Confidence Score: 4/5
**[Medium impact]** The changes affect the enabled desktop computer\-use workflow across the apps it can operate\.
Do not merge until the open-menu observation gap is resolved: large documents can leave the agent without references needed to select menu items.
Findings
1. **Open menu items stay hidden**
Reviews (1) · Last reviewed commit: "fix(desktop): make computer use act on t..." · Reviewed by the reviewer |
| #9084 2026-10-20 23:39 | greptile inline · P1 | apps/desktop/native/computer-use/ComputerUse.swift:307 | defect-functional | **Open menu items stay hidden**
If an open menu is not in the focused element's ancestry, it still waits behind document content. `openMenu` raises the priority of children only after the menu itself is visited, while `AXTraversalQueue.next()` visits content before deferred menus. A large document can exhaust the 2,000-node or eight-second budget first, leaving the agent without references to the menu items. Detect and queue open menus before walking document content; this observation gap needs to be resolved before merging. |
| #9088 2026-10-20 23:41 | coderabbit issue-comment | — | summary | 📝 Walkthrough
The API catalog now includes a catalog item linked to itself. Unmatched requests that accept Markdown can receive an uncached Markdown 404, while existing pages and unknown API paths retain their respective response formats.
**Changes: API Catalog Entry**
|Layer / File(s)|Summary|
|:---|:---|
|**Catalog item and service anchors** `apps/sim/app/.well-known/api-catalog/route.ts`, `apps/sim/scripts/test-mcp-host-e2e.ts`|The catalog response includes a catalog item that links to the catalog anchor. The v2 API URL serves as the service anchor, and the E2E check verifies the catalog link.|
**Markdown Not Found Responses**
|Layer / File(s)|Summary|
|:---|:---|
|**Markdown 404 ro … the rest (4374 characters)ute and fallback** `apps/sim/app/markdown-not-found/route.ts`, `apps/sim/next.config.ts`|The route returns an uncached Markdown 404 for five HTTP methods. The fallback rewrite routes unmatched requests that accept Markdown, except when the header sets its quality to zero.| |**Content negotiation coverage** `apps/sim/scripts/test-mcp-host-e2e.ts`|The E2E checks cover Markdown and HTML 404s, Markdown POST requests, a real page, and unknown API paths. The request helper accepts configurable methods and `Accept` headers.| **Priority:** ⬇️ Low **Estimated code review effort:** 3 (Moderate) | ~20 minutes **Change:** Feature ### Sequence Diagram(s) ```mermaid sequenceDiagram participant Client participant Next.js rewrites participant MarkdownNotFoundRoute Client->>Next.js rewrites: Send request path and Accept header Next.js rewrites->>MarkdownNotFoundRoute: Route unmatched Markdown request MarkdownNotFoundRoute->>Client: Return uncached Markdown 404 ``` **Suggested reviewers:** `waleedlatif1` Merge Risk: 🔵 Low · up to 3d257 Some clients may receive a Markdown 404 when they reject Markdown, or an HTML 404 when they request it. This is a bounded content-negotiation issue that should be fixed or accepted before merging. Security architecture risk: 🔵 Low · up to 3d257 The new response contains only public navigation links and performs no privileged operation. Existing API handling and host-isolation controls remain in place. The remaining uncertainty concerns deployed routing behavior rather than an identified authorization bypass. **Retained concerns** No architecture-level concerns identified. Security review details **Security Blast Radius** - _inferred_ — The changed routing can affect unmatched public paths across a sim deployment, but its new handler has no tenant, workspace, asset, or datastore selector. Its direct outcome is a static 404 response, not access to another service's authority or private data. **Trust Boundaries and Controls** - _observed_ — The unchanged proxy checks dedicated MCP-host routing before later request handling and terminates disallowed paths with 404. Its broad matcher includes ordinary unmatched paths and the new endpoint. The host-routing helper uses Host rather than X-Forwarded-Host for this boundary. **Resilience and Maintainability Implications** - _inferred_ — The new handler does not initiate a domain-state transition, so repetition, interruption, or concurrent calls do not require compensation or idempotency coordination. The reused permission-group scope creates a fresh request-local map, and this handler does not populate it or derive authority from it. Pre-merge checks: 4 · 1 Failed checks: 1 warning | Check name | Status | Explanation | Resolution | | :---------------- | :----------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------- | | Docstring Coverage | | Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 1 functions across 4 files. | Write docstrings for the functions missing them to satisfy the coverage threshold. | Passed checks: 4 passed | Check name | Status | Explanation | | :------------------------ | :--------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------- | | Description Check | | Check skipped - the reviewer’s high-level summary is enabled. | | Title check | | The title clearly summarizes both primary changes: listing the v2 API as a catalog item and returning Markdown 404 responses. | | Linked Issues check | | Check skipped because no linked issues were found for this pull request. | | Out of Scope Changes check | | Check skipped because no linked issues were found for this pull request. | ✨ Finishing Touches: 💡 1 📝 Generate docstrings: 💡 🧪 Generate unit tests (beta) Comment `@the reviewer help` to get the list of available commands. |
| #9088 2026-10-20 23:47 | coderabbit inline · P2 | apps/sim/next.config.ts:704 | defect-functional | **🎯 Functional Correctness** | **🟡 Minor** | **⚡ Quick win**
**Make both `Accept` patterns case-insensitive.**
The `has` pattern needs to accept uppercase media-type casing. The `missing` pattern also needs to accept uppercase `Q`. Otherwise, `Accept: text/markdown;Q=0` can match `has` but not `missing`, so the fallback can return the Markdown 404 despite the explicit rejection.
🐛 Suggested fix
```diff
- has: [{ type: 'header', key: 'accept', value: '(.*,)?\\s*text/markdown\\s*([;,].*)?' }],
+ has: [
+ {
+ type: 'header',
+ key: 'accept',
+ value: '(.*,)?\\s*[Tt][Ee][Xx][Tt]/[Mm][Aa][Rr][Kk][Dd][Oo][Ww][Nn]\\s*([;,].* … the rest (2027 characters))?', + }, + ], missing: [ { type: 'header', key: 'accept', value: - '(.*,)?\\s*text/markdown(\\s*;[^,]*?)?\\s*;\\s*q\\s*=\\s*0(\\.0{0,3})?\\s*(,.*)?', + '(.*,)?\\s*[Tt][Ee][Xx][Tt]/[Mm][Aa][Rr][Kk][Dd][Oo][Ww][Nn](\\s*;[^,]*?)?\\s*;\\s*[Qq]\\s*=\\s*0(\\.0{0,3})?\\s*(,.*)?', }, ], ``` 📝 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. ```suggestion return { beforeFiles: [], afterFiles: [ { source: '/favicon.ico', destination: '/icon.svg', }, { source: '/r/:shortCode', destination: 'https://go.trybeluga.ai/:shortCode', }, ], /** * Fallback rewrites run only after every page and dynamic route has failed to match, so * this answers a Markdown client's 404 in Markdown without shadowing any real route. * `text/markdown` must be one of the listed media ranges, and `q=0` (RFC 9110 §12.4.2: * not acceptable) keeps the HTML page. Next anchors both patterns to the whole header. */ fallback: [ { source: '/:path*', has: [ { type: 'header', key: 'accept', value: '(.*,)?\\s*[Tt][Ee][Xx][Tt]/[Mm][Aa][Rr][Kk][Dd][Oo][Ww][Nn]\\s*([;,].*)?', }, ], missing: [ { type: 'header', key: 'accept', value: '(.*,)?\\s*[Tt][Ee][Xx][Tt]/[Mm][Aa][Rr][Kk][Dd][Oo][Ww][Nn](\\s*;[^,]*?)?\\s*;\\s*[Qq]\\s*=\\s*0(\\.0{0,3})?\\s*(,.*)?', }, ], destination: '/markdown-not-found', }, ], } ``` |
| #9088 2026-10-20 23:47 | coderabbit review-body | — | summary | **Actionable comments posted: 1** |
| #9088 2026-10-20 23:51 | cubic review-body | — | summary | **2 issues found** across 4 files
Reply with feedback, questions, or to request a fix.View guided diff | Turn on auto-fix | Re-trigger the reviewer |
| #9088 2026-10-20 23:51 | cubic inline · P2 | apps/sim/app/markdown-not-found/route.ts:37 | defect-functional | An `OPTIONS` request is rewritten here but receives Next.js’s generated 204 response instead of the Markdown 404. Export `OPTIONS = notFound` to keep the fallback behavior consistent across methods. |
| #9088 2026-10-20 23:51 | cubic inline · P2 | apps/sim/next.config.ts:698 | defect-functional | These `Accept` tokens are case-insensitive, but the regexes are not: `text/markdown;Q=0` passes `has` and fails `missing`, so a client that rejects Markdown receives it anyway. Match the media type and `q` parameter case-insensitively in both patterns. |
| #9088 2026-10-20 23:55 | greptile issue-comment | — | summary | Confidence Score: 4/5
**[Medium impact]** The changes affect public API discovery and unknown\-page responses across the web app\.
The response-format and OPTIONS inconsistencies are non-blocking; neither makes the change unsafe to merge.
Findings
1. **Header case changes the response**
2. **Missing pages report success**
Reviews (1) · Last reviewed commit: "improvement(seo): list the v2 API as a c..." · Reviewed by the reviewer |
| #9088 2026-10-20 23:55 | greptile inline · P2 | apps/sim/next.config.ts:698 | defect-functional | **Header case changes the response**
The `Accept` checks are case-sensitive, but HTTP media types and parameter names are not. An unknown page requested with `Accept: Text/Markdown` gets HTML, while `Accept: text/markdown;Q=0` gets Markdown despite explicitly refusing it. This is a non-blocking response-format inconsistency for clients using valid case variants. Make both checks case-insensitive and add tests for these headers.
Artifacts
**Executable candidate 0 validation script**
- Runs the bounded actual-app attempt and before/after Next harness requests on port 3111 without editing repository source, making the verification reproducible.
**Actual app attempt with no HTTP response**
… the rest (1140 characters)- Captures the real app startup and request attempt, which ended with the connection closing before an HTTP response, leaving app-level verification blocked. **Before change, all Accept controls return HTML** - Runs the parent revision’s unchanged rewrites in Next and captures five complete HTTP responses, showing that every control returned 404 Not Found with HTML before the change. **After change, Accept casing changes the response format** - Runs the PR revision’s unchanged rewrites in Next and captures five complete HTTP responses, confirming that uppercase media types miss Markdown and uppercase Q=0 fails to refuse it. **Validation command and execution results** - Captures the script command, working directory, and individual run exit codes, showing two successful harness runs and a separately failed actual-app attempt. **Response comparison, source quotes, and cleanup checks** - Extracts the observed response matrices and executed source quotes, then checks source integrity and port cleanup, showing the candidate is reproduced without source changes or a remaining server. Ran code and verified through TREX |
| #9088 2026-10-20 23:55 | greptile inline · P2 | apps/sim/app/markdown-not-found/route.ts:37 | defect-functional | **Missing pages report success**
An `OPTIONS` request to an unknown page with `Accept: text/markdown` reaches this route, but it has no `OPTIONS` export. Next supplies an empty `204` response with an `Allow` header instead of the intended Markdown `404`, bypassing the handler's `Vary: Accept` and `no-store` headers. This is a non-blocking method-contract inconsistency: clients checking a nonexistent address receive a successful response advertising supported methods. Export `OPTIONS = notFound` and cover it in the tests.
```suggestion
export const GET = notFound
export const POST = notFound
export const PUT = notFound
export const PATCH = notFound
export const DELETE = notFound
export cons … the rest (1210 characters)t OPTIONS = notFound ``` Artifacts **Reproducible candidate 1 HTTP validation script** - The executed script starts bounded servers on port 3112, constructs the unchanged-source before/after harnesses, and captures real HTTP responses so the comparison can be reproduced. **Real application request timed out** - Started the unchanged application and attempted the unknown-page Markdown GET, but no HTTP response arrived within 100 seconds, leaving full-app verification blocked. **Initial harness run with unresolved source imports** - The first head harness run recorded an alias-resolution failure before the harness configuration was corrected, so these responses are not evidence for or against the candidate. **Unknown-page HTTP responses before the PR** - Executed the pre-PR rewrite configuration and captured GET and OPTIONS with Markdown and HTML Accept headers, showing 404 Not Found for all four requests. **Unknown-page HTTP responses after the PR** - Executed the PR rewrite and byte-identical Markdown route with original imports, showing Markdown GET returns 404 Not Found while OPTIONS returns 204 No Content without Accept variation or no-store. Ran code and verified through TREX |
| #9089 2026-10-20 23:56 | coderabbit issue-comment | — | summary | 📝 Walkthrough
This change records stops for live runs affected by chat deletion, account or workspace removal, and access changes. It delivers those stops after transactions, updates run-control authorization responses, and adds tests for delivery failures and removal scenarios.
**Changes: Run stop lifecycle**
|Layer / File(s)|Summary|
|:---|:---|
|**Record stops during access changes** `apps/sim/lib/mothership/async-runs/repository.ts`, `apps/sim/lib/workspaces/access/workspace-access.ts`, `apps/sim/lib/billing/organizations/membership.ts`, `apps/sim/lib/organizations/members/lifecycle.ts`, related tests and mocks|Transaction-scoped helpers find and stop live runs. Workspace and organiz … the rest (6247 characters)ation access changes return stopped-run records when effective access ends.| |**Deliver stops and delete chats** `apps/sim/lib/mothership/request/application/stop-delivery.ts`, `apps/sim/lib/mothership/chat/deletion.ts`, `apps/sim/lib/mothership/request/application/controls.ts`, `apps/sim/lib/mothership/request/session/abort.ts`, chat API routes and tests|Stop delivery coordinates worker, stream, workflow, sandbox, and chat cleanup. Chat deletion records stops in its transaction and delivers them after commit. Abort cleanup handles marker-write failures.| |**Wire stops into removal and archival flows** `apps/sim/lib/users/account-deletion.ts`, `apps/sim/lib/workspaces/lifecycle.ts`, `apps/sim/lib/projects/*`, `apps/sim/lib/organizations/member-manager.ts`, `apps/sim/lib/workspaces/permissions/member-removal-store.ts`, API and SCIM removal routes, integration tests|Account, membership, workspace, and project operations collect stopped runs in transactions and deliver notifications after commit. Removal results omit internal stopped-run details where specified.| |**Reflect authorization in run control** `apps/sim/lib/mothership/request/application/read-control.ts`, `apps/sim/lib/mothership/request/lifecycle/controller-ownership.ts`, `apps/sim/lib/core/application/organization-authorization.ts`, run-control tests and mocks|Run-control reads validate delegated callers and report stopped when non-caller authorization or resource checks fail. Controller takeover rejects deleted chats.| **Priority:** ➖ Normal **Estimated code review effort:** 4 (Complex) | ~60 minutes **Change:** Bug fix ### Sequence Diagram(s) ```mermaid sequenceDiagram participant RemovalTransaction participant StopDelivery participant Worker participant ActiveStream participant ClientWorkflow participant SandboxProcesses RemovalTransaction->>StopDelivery: Return committed stopped-run records StopDelivery->>Worker: Send Stop StopDelivery->>ActiveStream: Abort active stream StopDelivery->>ClientWorkflow: Cancel unsettled workflows StopDelivery->>SandboxProcesses: Recover unsettled processes ``` **Suggested reviewers:** `waleedlatif1`, `sg312` Merge Risk: 🔵 Low · up to 75ab5 Live runs are now stopped when their chat, owner, workspace or access is removed. Stop delivery happens after the removal commits, and run control reports stopped once access is lost. No production defect was found. The remaining follow-up is test hygiene: the new integration suite should delete the idempotency key rows it creates. Security architecture risk: 🔵 Low · up to 75ab5 The change strengthens access revocation without an identified new authorization bypass. Concurrent-start and interrupted-cleanup behavior is not fully established, so the remaining risk is low rather than minimal. **Retained concerns** No architecture-level concerns identified. Security review details **Security Blast Radius** - _observed_ — Stop scope follows the removal authority: an account deletion selects that user's runs, workspace archival selects runs in that workspace, and organization departure selects the departing user within the source organization and its workspaces. These operations can affect multiple runs, but the inspected predicates do not provide an unrestricted cross-tenant stop scope. **Trust Boundaries and Controls** - _observed_ — Workspace grant removal stops runs only where effective access has ended. An organization administrator's derived workspace access can therefore prevent cancellation when withdrawing an explicit grant does not actually revoke access. **Resilience and Maintainability Implications** - _inferred_ — Concurrent admission remains a coverage limitation: removal-driven discovery selects existing runs without visibly sharing the per-stream admission lock, so a not-yet-visible run may escape that snapshot. Chat deletion has additional chat-row serialization. Admission is unchanged and workspace removal previously recorded no Stop, so this is a residual pre-existing exposure rather than an established PR regression; the new run-control behavior adds a cancellation backstop while access remains revoked. **Hardening Proposals** - _proposed_ — Consider a shared revocation/admission synchronization protocol and recoverable cleanup records for effects that must survive process interruption. Bounded delivery concurrency could also improve failure containment for large removals. These are hardening proposals, not verified new vulnerabilities. Pre-merge checks: 4 · 1 Failed checks: 1 warning | Check name | Status | Explanation | Resolution | | :---------------- | :----------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------- | | Docstring Coverage | | Docstring coverage is 67.44% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 43 functions across 39 files. | Write docstrings for the functions missing them to satisfy the coverage threshold. | Passed checks: 4 passed | Check name | Status | Explanation | | :------------------------ | :--------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------------------------------------- | | Description Check | | Check skipped - the reviewer’s high-level summary is enabled. | | Title check | | The title clearly summarizes the main change: stopping live runs when their chat, owner, or access is removed. It is concise and specific. | | Linked Issues check | | Check skipped because no linked issues were found for this pull request. | | Out of Scope Changes check | | Check skipped because no linked issues were found for this pull request. | ✨ Finishing Touches: 💡 1 📝 Generate docstrings: 💡 🧪 Generate unit tests (beta) Comment `@the reviewer help` to get the list of available commands. |
| #9089 2026-10-21 00:05 | coderabbit inline · P2 | apps/sim/lib/mothership/request/application/removal-stops-runs.integration.ts:686 | tests | **📐 Maintainability & Code Quality** | **🟡 Minor** | **⚡ Quick win**
**Delete the seeded `idempotencyKey` rows in `afterAll`.**
Each run of the `it.each` case inserts an `idempotencyKey` row with a generated `run-removal:` key. The suite `afterAll` (lines 315-328) never deletes these rows. Integration files share one database, so the rows build up across CI runs. Track the keys and delete them. Also delete `copilotRequestStops` rows by `userId`, unless a foreign key on `user` already cascades them.
Proposed fix
```diff
const userIds: string[] = []
const workspaceIds: string[] = []
const organizationIds: string[] = []
+const idempotencyKeys: string[] = []
```
```diff
const se … the rest (689 characters)ndClaim = { normalizedKey: `run-removal:${generateId()}`, claimToken: generateId() } + idempotencyKeys.push(sendClaim.normalizedKey) await db .insert(idempotencyKey) ``` ```diff afterAll(async () => { + if (idempotencyKeys.length) + await db.delete(idempotencyKey).where(inArray(idempotencyKey.key, idempotencyKeys)) if (userIds.length) { + await db.delete(copilotRequestStops).where(inArray(copilotRequestStops.userId, userIds)) await db.delete(copilotRuns).where(inArray(copilotRuns.userId, userIds)) ``` As per coding guidelines: "Isolate with a unique schema or generated IDs, and clean up in `afterAll`." _Source: Coding guidelines_ |
| #9089 2026-10-21 00:05 | coderabbit review-body | — | summary | **Actionable comments posted: 1**
🧹 Nitpick comments: 1
apps/sim/lib/users/account-deletion-run-stops.test.ts: 1
`1-1`: **📐 Maintainability & Code Quality** | **🔵 Trivial** | **💤 Low value**
**Import the database mock from its own file instead of the `@sim/testing` barrel.**
This new test imports `dbChainMockFns` and `resetDbChainMock` from the `@sim/testing` barrel. The barrel adds module-fetch time to the test file. Every other import in this file already uses a specific mock path.
Proposed fix
```diff
-import { dbChainMockFns, resetDbChainMock } from '@sim/testing'
+import { dbChainMockFns, resetDbChainMock } from '@sim/testing/mocks/database.mock'
```
As per coding guidelines … the rest (160 characters): "Import the one file you need (`@sim/testing/mocks/<file>`, …); the `@sim/testing` barrel costs module-fetch time per test file." _Source: Coding guidelines_ |
| #9089 2026-10-21 00:09 | cubic review-body | — | summary | **5 issues found** across 41 files
View guided diff | Turn on auto-fix | Re-trigger the reviewer |
| #9089 2026-10-21 00:09 | cubic inline · P1 | apps/sim/lib/mothership/async-runs/repository.ts:336 | defect-functional | Ownerless live runs skip `recordRunStopTx`, leaving tool admission open and desktop calls unsettled; the later cleanup queries then return no work. Close admission and settle calls even when no owner is available for a durable Stop row. |
| #9089 2026-10-21 00:09 | cubic inline · P1 | apps/sim/lib/workspaces/lifecycle.ts:105 | defect-functional | Platform bans archive owned workspaces without passing `deliverStops`, so this path skips post-commit worker/controller/client/sandbox cancellation until the next run-control read. Pass `deliverRunStops` from the ban path. |
| #9089 2026-10-21 00:09 | cubic inline · P1 | apps/sim/lib/billing/organizations/membership.ts:1461 | defect-concurrency | This scan can miss a turn admitted concurrently: `admitChatTurn` authorizes before its separate admission transaction, so a request that passed authorization can insert a run after the scan and remain live after removal commits. Serialize turn admission with membership removal or recheck access inside the admission transaction. |
| #9089 2026-10-21 00:09 | cubic inline · P2 | apps/sim/lib/mothership/request/application/removal-stops-runs.integration.ts:398 | tests | This assertion can pass before post-commit delivery reaches the worker, so it does not verify the worker rejected the Stop. Record incoming abort attempts and wait for the expected 503 before checking run control. |
| #9089 2026-10-21 00:09 | cubic inline · P3 | apps/sim/lib/mothership/request/application/removal-stops-runs.integration.ts:685 | tests | Delete the generated `idempotencyKey` rows in `afterAll`; each `it.each` case inserts a unique `run-removal:` key, leaving persistent test data behind. |
| #9089 2026-10-21 00:10 | greptile issue-comment | — | summary | Confidence Score: 4/5
**[Medium impact]** The change reaches Chat runs across several removal and access workflows\.
Do not merge until workspace admission and removal are coordinated so that removal cannot lose the Stop for an in-flight turn.
Findings
1. **New turns can escape Stop**
Reviews (1) · Last reviewed commit: "fix(mothership): stop live runs when the..." · Reviewed by the reviewer |
| #9089 2026-10-21 00:10 | greptile inline · P1 | apps/sim/lib/mothership/async-runs/repository.ts:324 | defect-concurrency | **New turns can escape Stop**
`stopLiveRunsTx` misses a turn whose admission transaction is still uncommitted when workspace access is removed or the workspace is archived. Admission checks access before its transaction, but removal does not share its locking boundary. Removal can therefore commit without saving a Stop or closing tool admission for that turn.
This occurred for both access revocation and workspace archive: after admission committed and access was restored, the run remained active, had no Stop row, and run control returned `stopped: false`. Restoring access before the next heartbeat therefore lets the run continue instead of remaining stopped. Before merging, coordinate admi … the rest (1465 characters)ssion and removal through a shared transaction-level lock and recheck access inside that boundary before inserting the run. Artifacts **Executed admission and workspace removal concurrency test** - The authored test executes real admission, removal, restoration, and run-control reads with a database lock controlling scheduling, reproducing the lost Stop. **Configuration for the targeted concurrency test** - The executed configuration reuses application integration setup and selects only the authored race test, keeping the final validation narrowly scoped. **Disposable database schema provisioning output** - The captured extension creation and repository db:push command completed with exit code 0, provisioning the real schema used by the proof. **Serialized control with admission committed before removal** - Both removal paths executed after admission committed and retained one Stop after restoration, with run control answering stopped:true. **Concurrent removal while admission remained uncommitted** - Both removal paths committed while admission waited after its run INSERT, then restoration left zero Stops and run control answering stopped:false. **Database schema, relevant source lines, and cleanup output** - Captured PostgreSQL version, isolation, table constraints, exact source lines, unchanged tracked code, and container cleanup establish the tested environment and relevant implementation. Ran code and verified through TREX |
| #9090 2026-10-21 00:11 | coderabbit issue-comment | — | summary | 📝 Walkthrough
This change adds deadline handling for Sim tool calls and cancellation support for Fal.ai audio and video generation. Tool deadlines are persisted and applied to execution, waits, watchdogs, and retries. Abort signals now propagate through Fal.ai queue requests and media downloads.
**Changes: Fal.ai cancellation**
|Layer / File(s)|Summary|
|:---|:---|
|**Queue cancellation and timeout handling** `apps/sim/lib/media/falai.ts`, `apps/sim/lib/media/falai.test.ts`|Queue submission and polling now respond to abort signals, enforce queue and submission timeouts, and attempt best-effort cancellation. Tests cover aborts, timeouts, and cancellation failures.|
|**Media generation and … the rest (7621 characters)download signal propagation** `apps/sim/lib/media/falai-audio.ts`, `apps/sim/lib/media/falai-video.ts`, `apps/sim/lib/media/falai.ts`, `apps/sim/lib/mothership/tools/server/media/generate-audio.ts`, `apps/sim/lib/mothership/tools/server/media/generate-video.ts`, `apps/sim/lib/mothership/tools/server/media/model-boundaries.test.ts`, `apps/sim/lib/media/falai.test.ts`|Audio and video generation pass abort signals to queue execution, downloads, and cost metadata retrieval. Downloads pass signals through URL validation and fetching. Server media tools pass their context signal to generation.| **Sim tool deadlines** |Layer / File(s)|Summary| |:---|:---| |**Deadline contract and persistence** `apps/sim/lib/mothership/chat/payload.ts`, `apps/sim/lib/mothership/chat/payload.test.ts`, `apps/sim/lib/mothership/request/session/contract.ts`, `apps/sim/lib/mothership/request/tools/types.ts`, `apps/sim/lib/mothership/request/tools/deadline.ts`, `apps/sim/lib/mothership/request/types.ts`, `packages/db/schema.ts`, `packages/db/migrations/0432_tool_execution_deadline.sql`, `packages/db/migrations/meta/_journal.json`, `apps/sim/lib/mothership/async-runs/browser-download-claim.integration.ts`|Chat payloads advertise the tool deadline capability. Tool state and database records include execution deadlines. Deadline helpers validate frame values and calculate absolute deadlines.| |**Deadline enforcement during tool handling** `apps/sim/lib/mothership/request/handlers/tool.ts`, `apps/sim/lib/mothership/request/handlers/handlers.test.ts`, `apps/sim/lib/mothership/request/tools/executor.ts`, `apps/sim/lib/mothership/request/tools/executor.test.ts`, `apps/sim/lib/mothership/request/tools/permission.ts`, `apps/sim/lib/mothership/request/tools/permission.test.ts`, `apps/sim/lib/mothership/request/tools/workflow-client-fallback.ts`, `apps/sim/lib/mothership/request/tools/workflow-client-fallback.test.ts`|Tool handlers persist and adopt deadlines, cap wait periods, and fail expired calls. Executors and permission gates apply deadline limits. Workflow pickup does not claim server execution after the deadline.| |**Deadline limits for watchdogs and reruns** `apps/sim/lib/mothership/request/lifecycle/run.ts`, `apps/sim/lib/mothership/request/lifecycle/run.test.ts`, `apps/sim/lib/mothership/async-runs/execution-lease.ts`, `apps/sim/lib/mothership/async-runs/repository.ts`, `apps/sim/lib/mothership/request/application/abandoned-runs.integration.ts`|Watchdog extensions stop at the worker deadline. Interrupted executions with too little remaining time are not retried, and lapsed executions receive deadline-specific failure messages.| **Priority:** ➖ Normal **Estimated code review effort:** 4 (Complex) | ~45 minutes **Change:** Bug fix ### Sequence Diagram(s) ```mermaid sequenceDiagram participant ToolFrame participant ToolHandler participant AsyncToolRepository participant ToolExecutor ToolFrame->>ToolHandler: provide deadline ToolHandler->>AsyncToolRepository: persist execution deadline ToolHandler->>ToolExecutor: execute with deadline ToolExecutor-->>ToolHandler: return result or deadline failure ``` **Suggested reviewers:** `waleedlatif1`, `sg312` Merge Risk: 🟡 Moderate · up to 2e79a When a user stops a chat, or the new per-call deadline expires, after Fal.ai has finished an audio or video generation, the platform can skip recording the cost of that generation. Fal.ai has already charged for it, so usage accounting becomes inaccurate, and video generations are the most expensive case. The deadline enforcement for tool calls looks sound. Recording the cost even when the call is aborted should be fixed before merge unless this loss is explicitly accepted. Security architecture risk: 🔵 Low · up to 2e79a The change generally improves execution containment without expanding user permissions. Remaining uncertainty concerns preserving the original deadline during database failures and coordinating the worker rollout. Cancellation remains best effort and does not guarantee rollback of completed actions. **Retained concerns** No architecture-level concerns identified. Security review details **Security Blast Radius** - _observed_ — The reviewed media path delegates provider requests using a service API key, while workspace reads and writes remain bound to trusted user/workspace context. No new cross-workspace authority was identified in the cancellation change. **Trust Boundaries and Controls** - _observed_ — Provider-returned media URLs still pass through contentFetch URL/address policy and pinned fetching with a 250 MiB limit. Redirect destinations are revalidated. Passing cancellation into these operations does not replace their destination controls. **Resilience and Maintainability Implications** - _observed_ — Recovery requires an eligible expired lease, remaining attempts, and at least 60 seconds of recorded execution time. Run admission locking, execution-owner tokens, and terminal-state predicates fence concurrent recovery and late completion. These controls protect execution ownership, not rollback of external side effects. **Hardening Proposals** - _proposed_ — Preserve the original receipt deadline independently of successful initial persistence, or decline deadline-dependent dispatch when that bound cannot be established. Exercise database failure followed by controller recovery to validate the first-handoff guarantee. Pre-merge checks: 4 · 1 Failed checks: 1 warning | Check name | Status | Explanation | Resolution | | :---------------- | :----------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------- | | Docstring Coverage | | Docstring coverage is 68.29% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 41 functions across 27 files. (2 skipped:… | Write docstrings for the functions missing them to satisfy the coverage threshold. | Passed checks: 4 passed | Check name | Status | Explanation | | :------------------------ | :--------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Description Check | | Check skipped - the reviewer’s high-level summary is enabled. | | Title check | | The title clearly summarizes the primary change: enforcing frame-specified deadlines for handed-off tool calls. It is specific, concise, and related to the changeset. | | Linked Issues check | | Check skipped because no linked issues were found for this pull request. | | Out of Scope Changes check | | Check skipped because no linked issues were found for this pull request. | Full details: Docstring Coverage **Explanation** Docstring coverage is 68.29% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 41 functions across 27 files. (2 skipped: 2 unsupported.) **Resolution** Write docstrings for the functions missing them to satisfy the coverage threshold. ✨ Finishing Touches: 💡 1 📝 Generate docstrings: 💡 🧪 Generate unit tests (beta) Comment `@the reviewer help` to get the list of available commands. |
| #9090 2026-10-21 00:16 | coderabbit inline · P1 | apps/sim/lib/media/falai-audio.ts:108 | defect-data | **🗄️ Data Integrity & Integration** | **🟠 Major** | **🏗️ Heavy lift**
**An abort after the generation finishes skips cost recording for a generation Fal.ai already charged for.**
`runFalQueue` returns only after Fal.ai completes the generation, and Fal.ai charges at that point. Both audio paths then pass `params.signal` to `downloadFalMedia` and `getFalAICostMetadata`.
`getFalAICostMetadata` calls `signal?.throwIfAborted()` before the lookup and again after each retry sleep. The lookup retries billing-event fetches with sleeps, so the abort window lasts several seconds. If the caller aborts in that window, `generateFalAudio` throws.
The tool's `catch` block in `generate-audio.ts` then … the rest (1926 characters)returns `success: false`. That return happens before `recordServiceCost('falai_audio', ...)` runs. The tool deliberately records the cost before `assertServerToolNotAborted(context)`, which shows the intended rule: record the cost even when the call was aborted. Passing the signal into the cost lookup breaks that rule. Two things trigger this: a user stopping the chat, and the new per-call deadline expiring. Each trigger loses the cost of one completed generation. Fix: once `runFalQueue` resolves, do not let an abort lose the cost. Do not pass the signal into the cost lookup. If the lookup must stay bounded, fall back to the `fallback_floor` cost when the signal aborts. The download abort has the same gap: compute the cost before the abortable download, or carry it on the thrown error so the tool can still record it. Proposed direction ```diff --- "a/apps/sim/lib/media/falai-audio.ts" +++ "b/apps/sim/lib/media/falai-audio.ts" @@ -99,13 +99,8 @@ const { requestId, data } = await runFalQueue(model, input, apiKey, params.signal) const url = extractFalMediaUrl(data, ['audio', 'audio_url', 'audio_file', 'output']) if (!url) throw new Error('No audio URL in Fal.ai clone response') - const { buffer, contentType } = await downloadFalMedia(url, params.signal) - const cost = await getFalAICostMetadata({ - apiKey, - endpointId: model, - requestId, - signal: params.signal, - }) + const cost = await getFalAICostMetadata({ apiKey, endpointId: model, requestId }) + const { buffer, contentType } = await downloadFalMedia(url, params.signal) return { buffer, contentType: contentType.startsWith('audio/') ? contentType : 'audio/mpeg', ``` For a download abort to keep the cost, `generate-audio.ts` must also record the cost for a request that completed but was aborted. One option is an error type that carries `cost`. Also applies to: 127-133 |
| #9090 2026-10-21 00:16 | coderabbit inline · P1 | apps/sim/lib/media/falai-video.ts:187 | defect-data | **🗄️ Data Integrity & Integration** | **🟠 Major** | **🏗️ Heavy lift**
**The video path has the same gap: an abort after completion skips cost recording.**
This is the same root cause as in `falai-audio.ts` (lines 102-108 and 127-133). `runFalQueue` has already completed the generation, and Fal.ai has charged for it. An abort during `downloadFalMedia` or during the retrying `getFalAICostMetadata` makes `generateFalVideo` throw.
The `catch` block in `generate-video.ts` then returns before `recordServiceCost('falai_video', ...)` runs. Video generations are the most expensive Fal.ai calls, so each lost record costs more here. Apply the same fix as in the audio file: do not pass the abort s … the rest (82 characters)ignal into the cost lookup, and record the cost even when the download is aborted. |
| #9090 2026-10-21 00:16 | coderabbit review-body | — | summary | **Actionable comments posted: 2** |
| #9090 2026-10-21 00:22 | cubic inline · P2 | apps/sim/lib/mothership/request/tools/permission.test.ts:253 | tests | These deadline tests still pass if the gate rejects immediately: neither verifies the permission waiter ran, and this test checks `settled` only after advancing timers. Assert the waiter's capped timeout and that the promise remains pending before advancing, so the tests cover waiting through the deadline rather than merely returning an error. |
| #9090 2026-10-21 00:22 | cubic inline · P2 | apps/sim/lib/mothership/request/handlers/tool.ts:367 | defect-functional | This records the frame deadline after awaited pre-persistence work, so sealing or desktop-device lookup latency extends the call beyond the worker’s hand-off deadline. Capture the frame receipt timestamp before any await and use that timestamp for both persistence and in-memory deadline adoption. |
| #9090 2026-10-21 00:22 | cubic inline · P2 | apps/sim/lib/mothership/request/lifecycle/run.ts:1467 | defect-functional | The resume watchdog adds 30 seconds after the frame-derived deadline, allowing a stuck pending call to keep the checkpoint waiting past the deadline Sim promised to honor. Cap the complete watchdog budget, including resume grace and lease ceiling, at `toolCall.deadlineAt`. |
| #9090 2026-10-21 00:22 | cubic inline · P2 | apps/sim/lib/mothership/request/tools/executor.ts:382 | defect-functional | The deadline timer stops when `executeTool` resolves, but output-file/table writes and result commits run afterward without a deadline bound. Extend the deadline through final settlement so a stalled post-processing step cannot keep the handoff alive past its frame deadline. |
| #9090 2026-10-21 00:22 | cubic inline · P2 | apps/sim/lib/mothership/request/handlers/tool.ts:982 | defect-functional | This minimum keeps the client waiter alive past `deadlineAt`, and the completion path accepts any result without checking when it was recorded. A result arriving during that grace is reported as success instead of the deadline interruption; accept only results persisted by the deadline. |
| #9090 2026-10-21 00:22 | cubic inline · P2 | apps/sim/lib/media/falai-audio.ts:102 | defect-data | A post-generation abort can make `generateFalAudio` throw before the tool records Fal.ai’s already-incurred cost. Preserve and record the generation cost even when the abortable download or billing lookup is interrupted. |
| #9090 2026-10-21 00:22 | cubic review-body | — | summary | **6 issues found** across 32 files
View guided diff | Turn on auto-fix | Re-trigger the reviewer |
| #9090 2026-10-21 00:27 | greptile issue-comment | — | summary | Confidence Score: 4/5
**[Medium impact]** The changes reach Sim tool waits and media generation across several caller paths\.
Changes are required before merging because an approval timeout does not durably prevent later desktop execution.
Findings
1. **Cancelled actions can still start**
Reviews (1) · Last reviewed commit: "fix(mothership): bound every handed tool..." · Reviewed by the reviewer |
| #9090 2026-10-21 00:27 | greptile inline · P1 | apps/sim/lib/mothership/request/tools/permission.ts:258 | defect-concurrency | **Cancelled actions can still start**
When an approval expires at the new deadline, the cancellation updates only the in-memory call and emits a result; the saved call remains pending. If the run remains open and the desktop call has no pickup deadline, a delayed approval is still accepted, and the desktop can claim the call after its execution deadline. An action can therefore start after the conversation reports that it timed out.
Persist a terminal result before returning from this deadline path, and reject expired calls when recording approval or claiming desktop work. This must be fixed before merging.
Artifacts
**Evidence from the check**
- Existing saved evidence bundle containin … the rest (435 characters)g the complete authored harness, configuration, upload script, relevant numbered production source, and captured execution logs. Previously uploaded successfully with HTTP 200. **Command output from the check** - Existing saved successful harness output containing the command, working directory, exit code, observed state transitions, and controls. Previously uploaded successfully with HTTP 200. Ran code and verified through TREX |