Skip to content

chore(dev): sync dev with staging - #9332

Open
waleedlatif1 wants to merge 916 commits into
devfrom
chore/sync-dev-with-staging-2026-10-23
Open

waleedlatif1 wants to merge 916 commits into
devfrom
chore/sync-dev-with-staging-2026-10-23

Conversation

@waleedlatif1

Copy link
Copy Markdown
Collaborator

Summary

  • Makes dev match staging exactly (tree-identical); merges origin/dev with the ours strategy so this fast-forwards dev without rewriting history
  • dev's own 24 commits (benchmark console, private knowledge graph settings, desktop computer use, 2026-09-24→29) are preserved on archive/dev-pre-sync-2026-10-23
  • Dev's schema push (db:push --force, non-interactive renames) brings the dev DB to staging's schema and drops tables/columns only the archived dev commits used

Type of Change

  • Chore

Testing

  • git diff origin/staging HEAD is empty; origin/dev is an ancestor of HEAD
  • PR CI

Checklist

  • Code follows project style guidelines
  • Self-reviewed my changes
  • No new warnings introduced

waleedlatif1 and others added 30 commits October 15, 2026 20:38
… download (#9106)

* fix(media): bill a completed fal generation even when a Stop ends its download

* fix(media): use fake-clock gates in fal billing tests

* fix(media): bill a completed fal generation whose result has no media URL

* fix(media): bill the fal floor when the pricing estimate body is unreadable
…ction commits (#9104)

* fix(scim): push Stop for runs a directory sync ends, after its transaction commits

A directory sync that withdrew a workspace grant or demoted an organization
admin recorded Stop for the user's live Chat runs but never pushed it, so the
runs ended only on the worker's next run-control read.

- Projection deltas carry the runs their withdrawals stopped; withdrawGrant and
  setOrganizationRole return them instead of dropping them
- Group writes and user updates deliver them once their transaction commits;
  the batched reconcile delivers each batch after it commits, so a rolled-back
  batch delivers nothing
- Member removal, transfer and external-collaborator removal results carry
  stoppedRuns as a required field, returned from inside the transaction

* fix(scim): judge directory stops against the pass's final access

- A reconciliation pass that demotes an admin or withdraws a grant while granting the same workspace back no longer stops the run there: access is checked once after every withdrawal and grant
- Fix the readonly skipped result that failed type-check
- Cover a committed batch delivering when a later batch rolls back, and observe rollback deliveries deterministically
…ce than members (#9109)

* fix(slack): refuse binding a Search bot to a different app or workspace than members

* fix(slack): check Search app availability on the caller's transaction
…hare, live-doc persist and cleanup edge cases (#9110)

* fix(file-search): keep a skipped build published so rendered reads stop requeueing it

A skipped publication retired its build and cleared the revision's build id,
so a compiled document whose index build skipped never matched its rendered
artifact key: every rendered read requeued it, and the worker downloaded,
compiled and skipped it again. Skipped builds now stay published with their
bound artifact key (and no text), and the artifact-current checks accept a
skipped revision. Failed revisions still requeue.

* fix(public-shares): answer a shared Project page with a foreign embed as not found

renderSimPageDocument throws ProjectPageForeignEmbedError for a Project page
that embeds another owner's file. The authenticated artifact read maps it to
not_found, but the public content and inline reads let it escape as a 500.
Map it the same way at both public render sites.

* fix(file-doc): let the workspace document persist take a full snapshot

The relay's workspace persist ran behind the proxy with the default 10 MB body
cap, so a collaborative state above ~7.5 MiB (12 MiB is allowed) was refused
with 413 while the Project persist route took it. Exclude the workspace
persist from the proxy matcher and give it the same bypassesProxy body cap,
now shared from collab-doc state, and the same off-app-host refusal.

* chore(knip): drop the stale ignore for the v2 Project file search contract

Its only export is now imported by the v2 route and the OpenAPI spec.

* fix(memory): let a rejected key spend memory cleanup attempts

A 401 from the worker waited hourly without consuming an attempt, like a
missing route, so a permanently revoked self-hosted key kept its cleanup rows
pending forever. A 401 still waits an hour but now spends an attempt, so it
dead-letters after the default attempts (about ten hours), past a worker
rollout. 404, 405 and 501 keep waiting for free.

* fix(public-shares): log expected public file share client errors as warnings

The public file share routes logged every caught error at ERROR, including
classified client failures such as a missing share (404) or a password
exchange against a non-password share (400). Log a classified 4xx as a
warning and keep ERROR for unclassified failures.

* fix(public-shares): import the error logger in the OTP route

* test(file-search): skip on a corrupt compiled document the parsers reject
…locked owner stop their run (#9114)

* fix(mothership): settle a stopped run's call as never run only while nothing started it

* fix(mothership): let a blocked owner stop their admitted run
…utes (#9113)

* fix(copilot): load workflow chat history through the windowed chat routes

* fix(copilot): scope workflow chats without a workspace through their workflow

* test(copilot): name each workflow chat fixture's workflow uniquely
…ms of a longer query (#9115)

* improvement(search): fall back to summaries holding half the terms of a longer query

* fix(search): count Jira half-term summaries by stemmed term, from a wider pool, most terms first

* improvement(search): share the half-terms threshold and convert Jira descriptions only when filtered
* docs(library): update byok-multi-model-ai-agent-builder

* Pi Babysit: address PR #9116 feedback

---------

Co-authored-by: Sim Pi Agent <pi@sim.ai>
* docs(library): update n8n-alternatives

* Pi Babysit: address PR #9119 feedback

---------

Co-authored-by: Sim Pi Agent <pi@sim.ai>
* docs(library): update langgraph-alternatives

* Pi Babysit: address PR #9118 feedback

---------

Co-authored-by: Sim Pi Agent <pi@sim.ai>
…-healthcare-legal-procurement (#9117)

Co-authored-by: Sim Pi Agent <pi@sim.ai>
…26 (#9120)

* docs(library): update best-ai-agent-platforms-for-enterprise-teams-2026

* Pi Babysit: address PR #9120 feedback

---------

Co-authored-by: Sim Pi Agent <pi@sim.ai>
… and AX failures (#9112)

* fix(desktop): tighten computer use input guards for text, tabs, menus and AX failures

* fix(desktop): keep hidden tabs out of the window list and pin typed text to its first editor
…ose holding half of them (#9121)

* improvement(search): follow Jira summaries holding every term with those holding half of them

* improvement(search): dedupe the Jira summary tiers and the all-terms page in one pass
…ms match (#9129)

* fix(search): keep the Jira half-terms summary tier within the all-terms match

* test(search): normalize Jira fake rows before filtering
…ible Agent Building (#9133)

Co-authored-by: Sim Pi Agent <pi@sim.ai>
…ernatives for AI Agents in 2026 (#9132)

* feat(library): 6 Best Microsoft Copilot Studio and Power Automate Alternatives for AI Agents in 2026

* Pi Babysit: address PR #9132 feedback

---------

Co-authored-by: Sim Pi Agent <pi@sim.ai>
…ross Multiple Sessions? (#9131)

* feat(library): How Do You Build an AI Agent That Remembers Context Across Multiple Sessions?

* Pi Babysit: address PR #9131 feedback

---------

Co-authored-by: Sim Pi Agent <pi@sim.ai>
…rms they hold (#9134)

* improvement(search): rank live results across sources by the query terms they hold

Fusion scores rank a result only within its own account, so every account's
first result tied and the merged list followed account order. A plain query now
orders the merged results by the terms each title and preview hold, then the
terms the title holds, then how much of the title they make up; fusion breaks
ties. Date-sorted, queryless and native-query searches keep fusion order.

* fix(search): treat a result without content as empty text when ranking

* fix(search): rank a result without a title by its text alone
…#9130)

* feat(library): How Do You Embed an AI Agent Inside Your SaaS Product?

* Pi Babysit: address PR #9130 feedback

---------

Co-authored-by: Sim Pi Agent <pi@sim.ai>
…erve (#9143)

The file serve route catches its own errors, so an abort thrown after the
client went away was logged at error and answered 500, bypassing the 499
classification withRouteHandler already applies. Rethrow when the request
signal has aborted, in the outer catch and in the cloud and local read
helpers that log before rethrowing.
…ecorded instead of failing them (#9139)

* fix(trigger): complete async workflow runs whose failure is already recorded instead of failing them

Every failed workflow-execution run fires the Trigger.dev error alert, and in
practice those runs are user/workflow errors (missing start block, Function
runtime errors, provider 4xx/5xx) that core already recorded as the run's
failed execution log. The worker meant to rethrow only unrecorded faults, but
it checked wasExecutionFinalizedByCore without awaiting the post-execution
promise that sets the mark, so the check almost never saw it. The webhook
worker already awaited it (#4860); workflow-execution was skipped.

- isRecordedWorkflowFailure awaits post-execution, then checks the mark. The
  webhook worker uses it with no behavior change; the schedule worker uses it
  so it no longer races core's completion (its caller swallows either way).
- workflow-execution completes with { success: false, error } for a recorded
  failure, and for non-retryable 402/403/404/429 preprocessing rejections
  (deleted or undeployed workflow, suspended account, exhausted quota) after
  the same log write as before. Timeouts, unrecorded errors, retryable
  rejections, and 5xx still fail the job. Trigger retries are maxAttempts 1
  and the database runner never retries, so no retry semantics change.
- Both queue backends' getJob read a completed workflow-execution job carrying
  that result as failed, with the same error and output (undefined on Trigger,
  null in the database) the thrown run had, so /api/jobs, the SDKs, and the v2
  run-status queue fallback are unchanged.

resume-execution is left throwing: executeResumeJob is also called inline by
the resume poller and enqueue path, which rely on the throw.

* fix(trigger): bound recorded workflow failure errors in UTF-8 bytes

The previous character cap did not bound bytes against Trigger.dev's 128 KiB
output offload threshold. Cap the error at 16 KiB of UTF-8, cut at a code point
boundary, so even sixfold JSON escaping stays inline; normal-size messages are
returned unchanged. Correct the comment: runs.retrieve resolves offloaded
outputs itself, and only a failed presigned fetch leaves the output missing.
Drop an unconsumed waitForPostExecution mock from the timeout test.

* chore(audits): shrink the unused-exports baseline for PreprocessExecutionError

* fix(trigger): keep alerting on deadline-passed and unlogged async workflow failures

Re-check the deadline after awaiting core's finalization, since that wait can
outlast it, so a timed-out run still fails its job. Complete a non-fault
preprocessing rejection only when the logging session confirms the failure
row was written (hasCompleted, the same signal core uses to mark a failure
finalized); otherwise throw as before so an unsaved rejection still alerts.

* refactor(trigger): share the recorded-failure completion and skip the redundant error write on a timed-out recorded failure
…run (#9144)

* fix(execution): end runs quietly when their workspace is deleted mid-run

Deleting an account hard-deletes its solely-owned workspaces, and the cascade
takes each in-flight run's workflow and execution log with it. A run caught in
that window kept executing, then failed every terminal write: completion threw
"Workflow log not found", the cost-only fallback failed the same way, run
counts threw and logged twice, pause persistence logged errors, and the
admission reservation leaked until its TTL. A run whose log insert failed on
the deleted workspace kept executing blocks with no log row, so nothing could
record or stop it. Along the way a file upload failure surfaced raw Drizzle SQL
and bound parameters (user id, workspace id, storage key) in a block error.

- ExecutionScopeDeletedError (no cause) marks the outcome; classifyFailure
  attributes it to the owner, so it logs at info.
- completeWorkflowExecution, when the log row is missing, checks the run's
  workspace by primary key (inside the completion transaction when the row
  vanished mid-completion) and throws the typed error before any redaction,
  storage, or billing work. A missing row under a live workspace still throws
  "Workflow log not found" as before.
- LoggingSession recognizes it in every completion path: info instead of
  error, no cost-only fallback, admission slot released, later completions
  and force-fails become no-ops, and getDeletedScope() reports it.
- A log start that fails on a foreign key checks whether the workspace or
  workflow still exists; if not, safeStart returns false without the
  fallback, releases the slot, and executeWorkflowCore stops before building
  the executor. Any other start failure behaves exactly as before.
- Run counts skip a deleted scope, and a zero-row update is an info no-op.
- Pause persistence returns quietly for a deleted scope.
- User-visible error text never carries a query failure's SQL: the execution
  upload wrapper keeps its cause and redacts its message, the block executor
  redacts any query failure in the cause chain, and the workspace file,
  file-output, video, image, TTS, ElevenLabs, LaTeX, and pause sites use a
  shared getUserFacingErrorMessage.

* fix(execution): close review gaps in deleted-scope run ending

- Rename the integration suite to scope-deleted.integration.ts so its name
  does not repeat its folder (check:file-names).
- Type the new execution-core tests through ExecutionSnapshot and
  LoggingSession instead of `as any` (check:explicit-any).
- Define FOREIGN_KEY_VIOLATION once in database-query-error and import it in
  the logger and the logging session.
- Cover the guards the first commit left untested: a minimal fallback start
  that hits the deleted scope's foreign key, a cost-only fallback that is the
  first to find the workspace deleted, and pause persistence skipping a run
  whose deletion its paused completion found.
- Give the csv-workflow-execution live test's LoggingSession stub the new
  getDeletedScope method.

Correction to the previous commit message: pause persistence is quiet only
when the paused completion itself found the workspace or workflow deleted. A
deletion that lands after the paused log was written still fails
persistPauseResult, which logs at error and force-fails the run, exactly as
before. The TSDoc now says so.

* test(logs): type the logged-message callbacks in the deleted-scope session tests

* fix(execution): keep wrapped causes and quiet usage logging for deleted workspaces

- The file-output wrapper in FileToolProcessor keeps the original failure as
  its cause, so diagnostics and the tool boundary still see a database
  failure underneath the redacted message.
- recordExecutionUsage logs a missing workflow at info, not error, when the
  run's whole workspace is gone. The completion then reports the deleted run.
  The lookup runs only on that missing-workflow branch, both branches record
  nothing as before, and a failed lookup or a live workspace keeps the error.

* refactor(execution): simplify deleted-scope handling after audit

Fold the deleted-scope note and slot release into one session helper, reuse
the admission-slot release on the normal completion path, share an
ExecutionScope type, drop the unread executionId field and a redundant guard.
* revert(search): restore the v0.9.23 Jira text search

Reverts the Jira summary tiers (#9111, #9115, #9121, #9129). A plain Jira search
again returns the all-terms text match in Jira's order, as in v0.9.23. The
stemmedTerms helper stays; cross-source ranking uses it.

* chore(search): stop exporting stemmedTerms now only text-match uses it
#9151)

* fix(trigger): do not alert on runs whose workspace was deleted mid-run

When an account deletion cascades a workspace (or its workflow) away while a
run is in flight, #9144 makes LoggingSession record the deleted scope and core
throw ExecutionScopeDeletedError when the scope is already gone at start. The
background tasks still rethrew both cases: a start-time ExecutionScopeDeletedError
is not "recorded by core", and a block that then fails (e.g. a file-upload FK
error) cannot be finalized because the log row is gone, so hasCompleted() is
false. The Trigger run FAILED and paged Slack for a workspace that no longer
exists.

workflow-execution and webhook-execution now treat a deleted scope as a quiet
outcome: when the error is ExecutionScopeDeletedError, or the session reports a
deleted scope once core's post-execution settles (or once the task's own failure
log discovers it), they log at info and complete with the #9139 failure result.
The deleted-scope check runs before the timeout rethrow: with the workspace gone
there is no owner to alert and no log to fix, and the admission slot is already
released. Live-workspace timeouts, unrecorded failures, and infra faults still
throw.

The /api/jobs projection reads the string `error` as `failed`, matching the
FAILED status these runs reported before.

schedule-execution already swallows execution errors into schedule bookkeeping
(no Trigger failure), and resume-execution has no task-level logging session,
so neither changes here.

* improvement(trigger): fold the deleted-scope log and result into one in-scope closure per task
…ed, removed or banned (#9145)

* fix(execution): stop in-flight workflow runs when an account is deleted, removed or banned

No removal path stopped workflow executions. Account deletion cascades the
doomed workspaces' log rows away, after which no cancel path can find the run,
so it kept spending hosted provider keys for an account that no longer existed
until it crashed on foreign keys at finalization. A ban archived the
workspaces and stopped nothing; an admin removal cascaded them the same way.

- Account deletion reads the running executions (and claimed resumes, which
  run under their own id) of the doomed workspaces in its transaction, while
  the workspace rows are locked, and records one outbox stop per workspace with
  the erasure. After commit the stops are delivered a few at a time; a stop
  that cannot be delivered stays in the outbox for its worker, and the
  committed deletion is never reported as failed.
- A stop sets the cancellation flag each engine watches and sweeps the job
  queue for the workspace: a new JobQueueBackend.cancelByWorkspace cancels
  queued, delayed and running workflow jobs by the workspaceId tag on
  Trigger.dev (pages of 100, ten cancels at a time, 1,000 runs per attempt,
  continued without spending an attempt) and by metadata.workspaceId on the
  database queue, so queued runs no longer fail preprocessing later.
- A missing Redis completes the stop: the flag is process-local by design and
  no retry could reach further. A refused Redis write or a failed sweep retries.
- A ban stops the runs of the workspaces it archived; the admin remove-user
  hooks read the runs before the bare user delete and record them after it
  commits. Both sit in page module graphs that cannot load the delivery, so
  they signal in-flight runs at once and leave the queue sweep to the outbox
  worker.

* fix(execution): keep removal stops off the deletion and ban critical paths

- Account deletion no longer awaits the full stop delivery before purging
  storage. A slow Trigger.dev listing could hold the response for minutes and
  widen the window in which a restart orphans erased objects. It now signals
  in-flight runs fire-and-forget right after commit, ahead of every other
  post-commit step, under a 10-second deadline; the committed outbox stops
  repeat the signal and sweep the job queue in the outbox worker.
- A failure to record a ban's stops is logged instead of thrown. The ban and
  archives have committed, so a 500 helped no one and a retry finds no
  unarchived workspace to stop.
- Claimed resumes are found from the scope's running and paused log rows and
  joined through resume_queue's parent index, not by scanning resume_queue
  for claimed rows inside the deletion transaction.
- Tests pin the database queue's job-type filter, so a workspace sweep never
  cancels a non-workflow job such as log cleanup.

* test(execution): give each removal-stop fixture workflow a unique name

* fix(execution): close the review's gaps in removal stops

- A ban records and signals each workspace's stops as soon as its archive
  commits, through the archive's post-commit stop hook, instead of after every
  archive's socket and webhook cleanup. It also stops runs in the owner's
  workspaces archived before the ban, which an archive leaves running.
- The outbox handler re-reads a workspace's running executions when it runs.
  An archived workspace keeps its rows, so a run admitted before the ban that
  logged after its stop was recorded is still signalled.
- The admin remove-user hook handlers move to lib/auth/admin-removal-stops.ts,
  and signal the removed runs even when recording their stops fails.
- The database queue's workspace sweep works in batches of 100 up to the
  caller's cap and checks its abort signal between them, like the Trigger.dev
  sweep, rather than one unbounded update reported as complete.

* refactor(execution): tighten removal stops after final audit

- disableUserResources reads owned workspaces once and stops earlier-archived ones up front, dropping the post-archive read that could fail the ban
- Trigger.dev cancelByWorkspace reuses scanAndCancelTriggerRuns; workspace tag shares one builder with enqueue
- database queue shares abortInlineJob with cancelJob and returns completeness from control flow
- removal stop handler parses its payload with zod and signals while it sweeps
- drop the unused event-id return and redundant bucketing state

* fix(execution): finish the removal sweep's edge cases

- The removal stop handler loads both job queues independently and sweeps
  whichever loaded, so a primary queue that fails to load no longer skips the
  database queue's sweep. The failure is still rethrown for the outbox to retry.
- A claimed resume is found under a parent log row in the legacy `paused`
  status too, one of the statuses a resume claims from.
- The database queue re-checks for a matching active job after a short batch,
  since a selected job that finished before the update reached it shrinks the
  batch while later jobs still match.
- The ban's completion log no longer reports its runs stopped when recording
  their stops failed.

* fix(execution): abort local runs before the removal signal deadline can skip them

The signal deadline bounds only the Redis flag writes. Aborting a run this
process holds needs no Redis, so every execution is aborted first, even after
the deadline has passed. Corrects the ban's note on why a failed stop record is
logged: banning again records the stops again.

* fix(execution): guard ban stops against transfers and refusing runs

- A ban records stops only for workspaces the user still owns, re-read in the
  recording transaction and held FOR SHARE until it commits, so a concurrent
  ownership transfer waits rather than having its new owner's runs stopped.
  Only workspace rows are locked, so no lock order is inverted.
- Trigger.dev's workspace sweep counts only cancelled runs toward its cap, with
  a separate bound on failures, so runs that keep refusing cancellation no
  longer hold every retry at the front of the listing. cancelByExecution is
  unchanged.

* fix(execution): sweep a removed workspace's Trigger.dev runs of any age

The workspace sweep searched only runs created in the last 14 days, so an older
run still queued or waiting survived the removal. It now passes only an upper
time bound, which Trigger.dev treats as no lower bound, and falls back to the
retention window only if Trigger.dev refuses that search as too expensive
before returning a run. cancelByExecution is unchanged.
waleedlatif1 and others added 29 commits October 24, 2026 09:47
* docs(library): update best-ai-agents-for-lead-enrichment-2026

* Pi Babysit: address PR #9361 feedback

---------

Co-authored-by: Sim Pi Agent <pi@sim.ai>
…9362)

* docs(library): update best-conversational-ai-platforms-crm-helpdesk

* fix(library): restore the agent vs chatbot FAQ and rewrite Ada's tradeoff without a ranking

---------

Co-authored-by: Sim Pi Agent <pi@sim.ai>
…set their mock between tests (#9365)

- The self-hosting scaling guide budgets every app subpool: add the billing (4)
  and auth (3) pools and correct a web process's ceiling to 37 primary
  connections.
- resetDbChainMock now restores the shared isPrimaryPoolClient spy, so an
  override in one test cannot leak into the next; the per-file afterEach that
  did this by hand is gone.
…9364)

A search-mode poll (no stored cursor) sent historyId: undefined, which updateWebhookProviderConfig treats as a key removal. If it overlapped a newer poll that had just stored a cursor, it deleted that cursor. The poll state is now built once and carries historyId only when this poll started with a cursor or found one, so only a poll whose cursor Gmail rejected can clear it.
… is configured (#9363)

Stripe's verifier accepts signatures computed with an empty key, so the Better Auth Stripe plugin now registers only when billing is on and both STRIPE_SECRET_KEY and a non-blank STRIPE_WEBHOOK_SECRET are set, logging an error otherwise. The sim-setup preflight requires the webhook secret alongside the secret key.
…change (#9370)

Production and staging keep building every affected commit, so a shared-package change that breaks the docs build still fails on staging before main. Other preview branches skip the build unless apps/docs changed since the branch's last successful deployment; a first deployment or a previous SHA outside the shallow clone builds.
… of skipping the run (#9366)

* fix(mothership): retry a job dispatch whose usage read failed instead of skipping the run

- a usage outage (`usage_unavailable`) is a failed dispatch attempt, retried and bounded like any other, not a spent limit
- a run skipped for billing records billing's own reason
- the job lane suite closes open connections before stopping its fake worker

* test(mothership): cover a job dispatch retried after a usage outage and ended at its last attempt
…alidation, and match bare-name alternatives titles (#9367)

* fix(mcp): answer an unpublishable workflow input on tool updates as validation, and match bare-name alternatives titles

Updating a workflow MCP tool's parameter descriptions regenerated its schema without the validation translation the create and add paths use, so a reserved workflow input name returned an internal error instead of a validation failure naming the field. Both paths now share one helper.

The comparison library links scored a title naming a competitor's alternatives only through its mention aliases, which leave out a bare common-word name such as Make. The bare name now counts directly before "Alternatives", so a "Make Alternatives" title ranks first without reading "Make" elsewhere in a title as the competitor.

* test(library): type the comparison fixture's tags so the cast to ContentMeta type-checks
…he-top-options-compare (#9368)

* docs(library): update agentic-ai-coding-tools-what-they-are-and-how-the-top-options-compare

* Pi Babysit: address PR #9368 feedback

---------

Co-authored-by: Sim Pi Agent <pi@sim.ai>
* docs(library): update openai-vs-n8n-vs-sim

* Pi Babysit: address PR #9369 feedback

---------

Co-authored-by: Sim Pi Agent <pi@sim.ai>
)

* fix(mothership): hold callerless runs' sim_cli to read API scopes

An unattributed inbox message runs as the workspace owner with its tool
permission capped to read, but sim_cli has no catalog permission and its
commands authorize the delegated subject's live role, so the CLI could
create, run, and delete with the owner's authority.

A run with no caller of its own now executes the CLI inside a delegated
API-scope grant of api:read, enforced in requireOAuthOperationScope the
same way an OAuth token's scopes are, so every authorization path the
CLI reaches refuses api:write operations.

* fix(mothership): refuse callerless service writes and organization-scoped CLI writes

Mixed server tools reached through sim_cli services (settings, dashboards,
tests, search_sources, workspaces) write through internal operations that
declare no API scope, so the read grant never bound them. Each tool now
declares which validated arguments write, and the router holds those to
the current delegated grant.

The grant also applies to callerless organization-scoped runs.

* test(mothership): model attributed CLI runs with their secret actor
…he-top-options-compare (#9373)

* docs(library): update agentic-ai-coding-tools-what-they-are-and-how-the-top-options-compare

* Pi Babysit: address PR #9373 feedback

---------

Co-authored-by: Sim Pi Agent <pi@sim.ai>
…d Engineering Teams Choose? (#9375)

Co-authored-by: Sim Pi Agent <pi@sim.ai>
…he-top-options-compare (#9380)

Co-authored-by: Sim Pi Agent <pi@sim.ai>
…9381)

* docs(library): update ai-agent-examples-by-department-and-industry

* Pi Babysit: address PR #9381 feedback

---------

Co-authored-by: Sim Pi Agent <pi@sim.ai>
* docs(library): update best-ai-workflow-builders

* Pi Babysit: address PR #9382 feedback

---------

Co-authored-by: Sim Pi Agent <pi@sim.ai>
… the run's job list (#9384)

The indexnow job resolved its diff base by listing each earlier main run's jobs at 100 per page, and GitHub's jobs API answers that page with HTTP 502 for every re-run workflow run. The first release scanned back to such a run and failed the step, so no submission ever recorded a success and every later run would fail the same way.

Look up the one `indexnow` check run per commit instead (small, and it counts every attempt), treat a lookup that errors as no success, and when no success is in view diff from the oldest run in view so URLs no submission ever covered are still sent.
* docs(changelog): prepare Sim adds an Amazon EC2 block

* improvement(changelog): lead with knowledge base portability

* fix(changelog): clarify workspace-readable export limits
* feat(tailscale): expand and validate API operations

* fix(tailscale): normalize controls and output schemas

* fix(tailscale): preserve operation switch defaults
…bodies stop validating every element (#9388)

* fix(deps): backport zod's leading collection size check so oversized bodies stop validating every element

* fix(deps): stop later checks from reading an oversized container's unparsed elements
… executions (#9389)

* fix(isolated-vm): drain worker host deploys without failing in-flight executions

- Retire each remote worker connection at a max age (IVM_REMOTE_WORKER_MAX_AGE_MS,
  default 2 min) so a host the load balancer deregistered stops getting new
  executions and drains before its deregistration delay cuts the connections
- Re-dispatch an execution whose connection closed before it was sent; one that
  may have reached the host is never re-run and fails with a clear error
- Cap raw bytes a host connection may send before authenticating (16 KiB)
- Return a cancelled call before reading the worker-target flag

* fix(isolated-vm): address review on host drain

- Keep counting a refused connection's bytes until its socket closes
- Skip a redispatch the caller cancelled in between
- Look up the owner's state after the admission waits
- Parse IVM_REMOTE_WORKER_MAX_AGE_MS strictly, falling back below 1s
- Hold the inspected execution open until the worker check finishes

* test(isolated-vm): report an execution that fails before it is held

This branch was successfully deployed

1 active deployment
Preview — 75d5a509 Deployed Oct 27, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants