Repository navigation
v0.9.37: search split, deps bumps, db improvements, unified integration permissions - #9474
waleedlatif1 wants to merge 39 commits into
Conversation
#9428) * feat(search): move assistant into organization search * feat(search): add personal assistant actions and per-tool permissions * chore(search): finalize migration and validation artifacts * chore(search): align regression fixtures with account permissions * chore(tests): make asynchronous validation deterministic * fix(db): rebase assistant migration and preserve atomic expansion * docs(search): show dedicated organization search navigation * fix(search): preserve drafts and harden reviewed action delivery * fix(search): finalize refusal stream contract and validation * test(search): assert credential rejection independently of wording * fix(search): align review limits and isolate OAuth token refresh * fix(docs): preserve spacing above nested sidebar sections * docs(search): remove stale mode instructions and clarify actions * fix(search): distinguish unavailable account connections * chore(search): validate rebased migration and module graph * fix(tests): wait for durable text before recovery faults * fix(tests): wait for Search URL persistence before reload
* docs(library): update ai-agent-vs-chatbot * Pi Babysit: address PR #9441 feedback --------- Co-authored-by: Sim Pi Agent <pi@sim.ai>
…ions Compared (#9443) Co-authored-by: Sim Pi Agent <pi@sim.ai>
…ts (#9442) Co-authored-by: Sim Pi Agent <pi@sim.ai>
#9445) The backfill walk checked each file for a revision with a correlated EXISTS in its select list. PostgreSQL plans that as an alternative subplan and picks between a per-row probe and a hashed subplan from the scan's own row estimate, before the page limit applies. Sized against every file left in the walk, the hashed form wins, so every page sequentially scanned and hashed the whole revision table to answer a thousand lookups. The page now left-joins the revision on its primary key, the file id, and reads hasRevision as the joined key being non-null. Under the limit the planner nests that join over the ordered keyset scan, one index probe per file returned. The key is unique, so the join cannot repeat a file, and the keyset predicate, order and limit are unchanged. On a production-sized replica the page went from about 500ms with a full scan of the revision table to about 12ms warm with index probes, with the keyset index scan on workspace_files unchanged. The new integration case walks a second page over a settled table and asserts the revision table is only read through its primary key, probed per file; it fails on the previous query with the hashed sequential scan.
…tch ended (#9446) * perf(outbox): resume each retention batch where the previous run's batch ended The completed-event prune deletes one oldest-first batch per type per run. Every batch started its scan of outbox_event_type_created_idx at the oldest row of its type, and the rows earlier batches deleted stay in that index until vacuum removes them, so while a large backlog drains each batch first walks everything deleted since the last vacuum. That walk grows with each run: on a read replica during a large drain it took about 0.6s before the first live row, and a batch can reach the 10s statement timeout. Each batch now resumes after the (created_at, id) of the last row the previous run's batch deleted, the same shape as the idempotency sweep's resume. Batches are ordered by (created_at, id) so ties on created_at split exactly, the cursor keeps PostgreSQL's microsecond text form, and the row comparison becomes a created_at >= bound on the index, with the full comparison as a filter. Resuming from a cursor, the same batch took about 20ms. The prune runs once per processor run, so the cursor has to outlive the run; it is kept in Redis as a hint, one MGET before the batches and one pipeline after. A row the pass went by before it completed, or while an overlapping run held its lock, is covered by the next pass: the cursor is cleared when a batch comes up short of the cutoff, and a pass older than an hour starts over from the oldest row. Without Redis, or with an unreadable cursor, a batch starts from the oldest row as before. Batch size, timeout, cadence and which rows are eligible are unchanged. Autopsy: the retention suite asserted which rows each run deleted, which a scan from the oldest row gets right, so nothing observed where a batch started. The new Redis cases complete a row behind the cursor between runs: resuming leaves it for the next pass and the old scan takes it at once, so the first case fails on the previous code. The others split one creation time across batches with pending rows mixed in, and restart a pass that is over an hour old or whose cursor is unreadable. * fix(outbox): start a pass from the oldest row when its stored cursor names no real time A cursor whose JSON parsed but whose creation time was not a calendar time reached the batch's ::timestamp cast and failed the run, which stopped every later type's prune until the cursor expired. The cursor's creation time is now checked as PostgreSQL's ISO text with a calendar round trip, so such a cursor is dropped like an unreadable one and the pass starts from the oldest row.
…rkspace keyset scans (#9450) * perf(audit-logs): read a listing narrowed only by time through per-workspace keyset scans An organization's audit listing is one OR predicate over the organization's workspaces and its organization-level rows. With no filter, or only a time range (the audit page's default view), PostgreSQL has no index that returns that OR in listing order, so it collects every row of the scope inside the range and sorts it for each page; for a busy organization that is a scan of a large part of the table. Such a listing now reads its page ids as a disjoint union: one keyset scan of audit_log_workspace_created_at_id_idx per organization workspace, the organization-level metadata rows through audit_log_org_level_created_at_id_idx, and the organization resource rows that do not name it in metadata. Each part stops after a page, and the first page of the union is exactly the first page of the scope. The time range is kept verbatim and also stated as implied bounds on the sort key, so each scan starts and stops at the range; the cursor is the same keyset position written as a row comparison so the scan seeks to it. A listing with any other filter (action, resource, actor, workspace, search) keeps the single predicate unchanged, byte for byte: per-workspace scans cannot stop early under such a filter, which is what made #9419 slow, while the single predicate lets the filter's own index drive. queryAuditLogs now takes the scope and the filters rather than prebuilt SQL so it can make that choice. list-scope.integration.ts pages every filter shape, with and without departed members, across page sizes and the byte budget, and requires exactly the single predicate's order, including sub-millisecond ties, bounds inside a millisecond and a workspace the organization no longer holds. list-plans.integration.ts pins the keyset plan for the unfiltered and time-bounded shapes (failing on the previous single-predicate listing) and the single predicate for every other one. * test(audit-logs): plan the keyset listing over a workspace written mostly by a departed member
…9447) * perf(db): serve workspace usage drill-downs index-only on usage_log Every Workspaces drill-down read filters on the billing entity, one workspace and a created_at window, and reads cost with user_id, source or workflow_id. usage_log_workspace_created_at_idx held only (workspace_id, created_at), so the planner matched the window there or on usage_log_billing_entity_created_at_cost_idx and fetched a heap row per match to check the rest: the workspace's rows on one, the whole organization's on the other. 0441 dropped the compact entity/period index that used to narrow the second through a BitmapAnd, so a large organization's workflow ranking went from about 4.6s to 13.7s, reading thousands of rows per row it returned. usage_log_workspace_created_at_cost_idx replaces it: the same leading (workspace_id, created_at), then the entity and every column the drill-down reads. Each drill-down read is now an index-only scan bounded by the workspace's rows in the window, and the readers that name only the workspace (the foreign key's ON DELETE SET NULL, the ledger list filtered to a workspace) keep the order they had. The new index is built concurrently before the old one is dropped, so inserts maintain the same number of indexes. The plan integration test explains the exact SQL of the totals, series and rankings for a workspace holding most and a small share of its organization's usage, and fails on the old schema. * perf(db): scope the workspace covering index's claim to created_at windows
…9448) * perf(admin): read dashboard spend and workflow runs index-only The dashboard's per-entity usage was one statement OR-ing every entity's period, which the planner can only answer with a BitmapOr and a heap fetch per matched ledger row, and its count(distinct execution_id) needed the heap anyway because no index carries execution_id. Each read is now a UNION ALL with one arm per entity, so spend is an index-only scan on the existing covering cost indexes, and workflow runs are a separate statement on a new partial index over workflow rows that carries execution_id. The four copies of the period predicate now come from buildUsageAnalyticsScope. What the dashboard shows is unchanged: a run is still a distinct execution_id among the entity's workflow rows in the period. The reads stay on the primary: the replica serves these scans from disk and cancels statements held past its replay delay. * perf(admin): count dashboard workflow runs on the existing ledger indexes Drops the workflow-runs index and its migration: an extra write on every workflow ledger insert is not worth paying for a staff-only page. Spend stays index-only per entity; the separate run-count statement fetches the matched workflow rows from the heap on the existing period and created_at indexes.
…indows (#9449) The reconciliation count read every window of a connector, then the ACL, soft-delete and hard-delete walks each read the same windows again. The tally now counts every decision input and keeps the rows each removal acts on in the same window statement, so removals page through those rows instead of walking the connector again. A condition matching more than 10,000 documents keeps only its count and falls back to the existing walk, so memory and each statement's result stay bounded.
…them running (#9452) * improvement(sandbox): pause idle chat workbenches instead of keeping them running - Session sandboxes now pause after a 5-minute idle lease (was: kept running for 20 minutes, then killed). Resume keeps files, packages and processes and takes well under a second; paused sandboxes are not billed and do not count toward the provider's concurrency limit. - A new cleanup-session-sandboxes cron kills workbenches paused for more than 15 minutes, so a workbench is still discarded about 20 minutes after its last use. Each kill runs under the session lock and re-checks the sandbox's own info, so a just-resumed workbench is never killed. - Streamed workbench writes and upload snapshots lease their full transfer budget so a machine cannot pause mid-transfer. - E2B Mothership sandboxes are priced at their template's 2 vCPU / 1 GiB instead of the 4 GiB Function profile. * chore(helm): bump chart version for the session sandbox cleanup cron * fix(sandbox): bound the session sandbox sweep by a deadline, not a batch size
- Pi sandboxes are built at 4 vCPU / 8 GiB (Daytona adds a 10 GiB disk) but were priced on the 2 vCPU / 4 GiB Function profile, so Pi runs were billed at about half their provider cost. - Pi sizing moves from the build-script package list into lib/execution/remote-sandbox/pi-resources.ts, which both provider builds and sandbox pricing now read, so the build and the price cannot drift apart.
…its (#9456) * fix(workflows): refuse new placements of sunset blocks in workflow edits * test(workflows): cover sunset refusal when a container edit merges children
* fix(search): inline action review and unify account menus * fix(search): back off durable permission recovery * fix(search): wait for URL updates in browser checks * fix(search): polish inline action review interactions
… @ menus and search, enforced by an audit (#9457) * fix(integrations): hide integrations the permission group disallows * fix(integrations): fall back from emptied categories and fail closed on detail gate * fix(integrations): fail closed on the catalog until the deployment allowlist loads * feat(integrations): offer requestable integrations in the catalog and gate @ mentions by policy * improvement(integrations): one access verdict for every integration listing, enforced by check:integration-access * fix(integrations): require the access hook to be called and read namespace imports in check:integration-access * fix(integrations): treat an untraceable namespace read as reading every export in check:integration-access
…t Builder shutdown migration (#9460) Adds an optional migration section and search-title overrides to comparison profiles, leads /comparisons/openai-agentkit with the Agent Builder shutdown and migration path, re-sources the shutdown claims to OpenAI's docs, and corrects the Evals API claim in the Sim vs n8n vs OpenAI AgentKit library post.
* fix(billing): hold free plans to their allowance mid-run * fix(billing): read free payers fresh in the provider check and judge free by the admitted plan * fix(billing): bound free payers' fresh usage reads and shrink the test-types baseline
* fix(search): unify navigation and preserve action review history * fix(search): preserve current view and uncertain action outcomes
…gnments (#9463) * fix(executor): stop condition loops at an iteration ceiling and reject unnamed variable assignments A While loop, or a Do While loop given a condition, had no iteration bound: a body that never changed what the condition checks repeated until the run timed out, and billing-disabled deployments run untimed, so it repeated until the process stopped. Such loops now fail with an error on the loop after 10,000 iterations if the condition is still true. For, For Each and count-driven Do While loops are unchanged. A Variables assignment with a value but no variable name was skipped without an error. It now fails the block; blank editor rows are still ignored, and a row that selects its variable by id alone now updates that variable. The block's published input description named the wrong field ("name"), which is corrected to variableName. * fix(executor): give untyped variable assignments their target variable's type * chore(executor): shrink the explicit-any baseline for the variables handler
…er a wait timeout (#9464) * feat(workflows): let a synchronous run continue in the background after a wait timeout A synchronous run, including a manual draft run (--manual, --trigger, --from-block, --stop-after), could only be waited on until it settled or hit the sync execution limit. Manual runs refuse async, so a caller had no way to get the run id back from a long or stuck draft run and decide to keep waiting, watch it, or cancel it. The v2 execute body takes waitTimeoutSeconds. Past it the response answers 202 with the run receipt (NDJSON: a `detached` frame) and the run keeps going in this process exactly as it started: same captured draft state, entry point and pause persistence. Such a run is admitted like an async one (async rate bucket, reservation and timeout), takes no request abort signal so a dropped connection never cancels it, and registers an in-process aborter so runs cancel reaches it without Redis. Without the field nothing changes. The CLI exposes it as `workflows run --wait-timeout <seconds>`. A run that outlasts it is read back once and reported the way `workflows runs wait` reports an elapsed bound: the run record on stdout and exit 4 while it is still moving, so `workflows runs wait <runId>` continues it. * fix(workflows): hand out a detached run's receipt only once the run can be read A detach could fire before the run's log row existed, so the runs resource answered 404 for the receipt just handed out. The response now waits for the logging session to start before detaching, and the wait timeout docs say how each transport carries the receipt. * feat(mothership): declare that workflows run outlasts --wait-timeout to the worker Sim now sends the workflow-run-wait-timeout client capability on chat turns, so the worker waits on a synchronous workflows run in slices only on a Sim whose CLI takes --wait-timeout there; an older Sim keeps its held run. The protocol copy is synced from the mothership contract that defines the token.
* feat(mcp): type mcp block replies from declared output schemas
MCP servers may declare an outputSchema on a tool and return
structuredContent, but discovery copied only name, description and
inputSchema, so no surface showed a reply shape and the MCP block declared
only content. Agents building workflows guessed field names, and a
reference such as <mcp.structuredContent.x> failed validation even when the
tool returned it.
- Discovery keeps a declared outputSchema on McpTool; the tool cache carries
it, and managed connections persist it in the existing mcp_tools jsonb
snapshot (type only, no migration).
- Surfaced on GET /api/v2/mcp-servers/{id}/tools (and so the CLI's
mcp-servers tools list), mcp_list_operations, the editor tool list, and the
integration catalog (synced contract, optional field). The v2 tool shape is
strict, so keeping the field without declaring it would have turned
discovery into a 500.
- The MCP block gains a hidden, server-managed toolOutputSchema sub-block: a
structure-only snapshot of the selected operation's schema, bound to the
server and operation it was taken for. The editor writes it when an
operation is picked; applyWorkflowOperations writes it for agent edits,
through the same authorized discovery use cases, best effort and only when
the snapshot is missing or stale.
- With a matching snapshot, the block declares a typed structuredContent
output beside content, so the run's reference check, lint (which now walks
paths below structuredContent and names the declared fields) and the tag
paths all read the declared shape, and workflows deps fills mock leaves
from it. Without one, outputs are exactly as before.
* fix(mcp): address review on mcp output schema snapshots
- Read the MCP target with the block's saved canonical modes in lint,
workflows deps and effective outputs, so a dormant basic/advanced member
never selects or drops the snapshot.
- Expand repeated bracket indices before the nested lint check, as the run
resolves them.
- Stop expanding a schema once its node budget is spent and leave that object
open, instead of saving an untyped node per remaining field.
- Keep every declared field name, constructor and __proto__ included.
- Snapshot only blocks the edit changed, and discover best effort, so an
unreachable server neither slows unrelated edits nor gets marked unhealthy.
* fix(mcp): keep declared fields in deps whole reads and sample __proto__ fields safely
workflows deps now adds an operation's declared fields wherever a consumer reads a structuredContent value whole, beside the paths it reads by name. Trigger mock payloads define sampled fields with Object.fromEntries, so a declared __proto__ field stays a field instead of replacing the sample's prototype.
* fix(mcp): carry a whole structuredContent read through nested deps mocks
A whole read now adds every declared field below it, through nested objects and array items, even where the consumer also reads a nested path by name.
Remove the redundant Assistant tool rollout gate while retaining organization access, account ownership, source restrictions, and action approval policies. Keep Search editing and submission disabled until hydration is ready, then autofocus the field. Cover early edits and draft restoration with a held-script browser regression.
* feat(extension): bring Sim chat and page context to Chrome * refactor(extension): consolidate page capture in the chat composer * fix(extension): align shared chat and harden capture lifecycle * fix(extension): revalidate access and protect page previews * fix(extension): refresh permissions and retain completed answers * fix(extension): keep workspace selection recoverable * chore(extension): tighten production QA evidence * fix(extension): retain drafts through permission-policy outages * fix(extension): enforce policy independently of access requests
…as done, not failed (#9469) A wait whose --wait-timeout elapsed with the work still going (workflows runs wait, a detached synchronous workflows run, a workspace operation wait) exits 4 and prints the record to continue from. The sim_cli handler mapped every non-zero exit to a failed call, so each still-running slice the worker issues for a long draft run was recorded as a failed async tool call, published to the chat as an errored row (titled 'Running workflow' / 'Waiting for workflow run' instead of the past tense, and dropping the activity's completed title), and counted as outcome=error in copilot.tool.calls. The CLI now names that status (STILL_RUNNING_EXIT_CODE, exported from sim/embed) at both producers, and the handler settles it as success while keeping exitCode 4 in the output the worker branches on.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
[High impact] The PR reaches organization chat, connected-account actions, workflow execution, billing, and shared data paths. Fix the Assistant transaction read and MCP open-field handling before merging. FindingsSummaryThis release splits organization Search from Home and adds reviewed Assistant actions, shared integration access checks, and a Chrome extension.
|
| const open = | ||
| (node.additionalProperties !== undefined && node.additionalProperties !== false) || | ||
| node.patternProperties !== undefined | ||
| if (open || !isRecordLike(node.properties)) return { type: 'object' } |
There was a problem hiding this comment.
An object with properties but no additionalProperties allows extra fields in JSON Schema, but this code saves it as closed. For example, {type: 'object', properties: {known: {type: 'string'}}} permits other fields, yet references to them now fail lint. If a reply omits such a field, the runtime throws InvalidFieldError instead of returning an empty value. Arrays without items have the same problem for nested element paths.
Preserve these open shapes: only reject extra object fields when additionalProperties is explicitly false, and represent unspecified array items as any.
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!
There was a problem hiding this comment.
2 issues found across 562 files
Confidence score: 3/5
apps/sim/lib/integrations/access.tscan treat a retired integration ID as unavailable even when its successor is available, because the availability and deployment-gate checks use the unresolved ID. Resolve superseded IDs consistently in those checks.apps/extension/src/extract.tscan discard extracted text: the byte-budget loop removes 1,000 characters per pass, so slightly oversized text loses more than necessary and text of 1,000 characters or less can be dropped entirely. Trim only enough to fit the budget.
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="apps/extension/src/extract.ts">
<violation number="1" location="apps/extension/src/extract.ts:87">
P3: The byte-budget loop trims a fixed 1,000 characters per pass, not just enough to fit. A text that is only slightly over budget loses up to 1,000 extra characters, and a text of 1,000 characters or fewer is dropped entirely. Trim by the actual overflow, or shrink proportionally so the cut stays close to the excess.</violation>
</file>
<file name="apps/sim/lib/integrations/access.ts">
<violation number="1" location="apps/sim/lib/integrations/access.ts:92">
P2: The availability and deployment-gate checks read the raw block type, but the allowlist check resolves superseded IDs to its successor. A retired ID such as `gmail` therefore never finds its `gmail_v2` availability and is reported `available` even when Gmail's OAuth client is not configured. Resolve the type once and use it for both the availability lookup and the deployment-gate check.</violation>
</file>
Note: This PR contains a large number of files. cubic selects up to 200 of the highest-priority eligible files for this review, so some files may not have been reviewed.
This PR changes authentication, authorization, or input validation. Ultrareviews find 2.4x more serious bugs than standard reviews. Comment @cubic-dev-ai ultrareview to run one.
Turn on auto-fix | Re-trigger cubic
| truncated = true | ||
| } | ||
| while (text && bytes + encoder.encode(JSON.stringify(text)).byteLength > maxBytes - 10_000) { | ||
| text = text.slice(0, Math.max(0, text.length - 1_000)) |
There was a problem hiding this comment.
P3: The byte-budget loop trims a fixed 1,000 characters per pass, not just enough to fit. A text that is only slightly over budget loses up to 1,000 extra characters, and a text of 1,000 characters or fewer is dropped entirely. Trim by the actual overflow, or shrink proportionally so the cut stays close to the excess.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At apps/extension/src/extract.ts, line 87:
<comment>The byte-budget loop trims a fixed 1,000 characters per pass, not just enough to fit. A text that is only slightly over budget loses up to 1,000 extra characters, and a text of 1,000 characters or fewer is dropped entirely. Trim by the actual overflow, or shrink proportionally so the cut stays close to the excess.</comment>
<file context>
@@ -0,0 +1,113 @@
+ truncated = true
+ }
+ while (text && bytes + encoder.encode(JSON.stringify(text)).byteLength > maxBytes - 10_000) {
+ text = text.slice(0, Math.max(0, text.length - 1_000))
+ truncated = true
+ }
</file context>
* feat(auth): implement isolated Paper design system * chore(auth): remove design-tool attribution * fix(auth): preserve navigation and desktop layout in redesign * fix(auth): consolidate fields and localize icons * fix(auth): resolve review findings and complete layout isolation * fix(auth): preserve invitation loading and branding boundaries --------- Co-authored-by: Waleed Latif <walif6@gmail.com>
|
| GitGuardian id | GitGuardian status | Secret | Commit | Filename | |
|---|---|---|---|---|---|
| 39283785 | Triggered | Generic High Entropy Secret | 06faa07 | apps/sim/auth-migration/baseline.json | View secret |
| 39283784 | Triggered | Generic Password | 06faa07 | apps/sim/auth-migration/baseline.json | View secret |
| 39283782 | Triggered | Generic High Entropy Secret | 06faa07 | apps/sim/auth-migration/baseline.json | View secret |
| 39283788 | Triggered | Generic High Entropy Secret | 06faa07 | apps/sim/auth-migration/baseline.json | View secret |
| 39283787 | Triggered | Generic High Entropy Secret | 06faa07 | apps/sim/auth-migration/baseline.json | View secret |
| 39283781 | Triggered | Generic High Entropy Secret | 06faa07 | apps/sim/auth-migration/baseline.json | View secret |
| 39283783 | Triggered | Generic High Entropy Secret | 06faa07 | apps/sim/auth-migration/baseline.json | View secret |
| 39283789 | Triggered | Generic High Entropy Secret | 06faa07 | apps/sim/auth-migration/baseline.json | View secret |
| 39283786 | Triggered | Generic High Entropy Secret | 06faa07 | apps/sim/auth-migration/baseline.json | View secret |
🛠 Guidelines to remediate hardcoded secrets
- Understand the implications of revoking this secret by investigating where it is used in your code.
- Replace and store your secrets safely. Learn here the best practices.
- Revoke and rotate these secrets.
- If possible, rewrite git history. Rewriting git history is not a trivial act. You might completely break other contributing developers' workflow and you risk accidentally deleting legitimate data.
To avoid such incidents in the future consider
- following these best practices for managing and storing secrets including API keys and other credentials
- install secret detection on pre-commit to catch secret before it leaves your machine and ease remediation.
🦉 GitGuardian detects secrets in your source code to help developers and security teams secure the modern development process. You are seeing this because you or someone else with access to this repository has authorized GitGuardian to scan your pull request.
…l controller (#9475) * test(mothership): drive a draft run past a wait slice through the real controller A live case for the worker's sliced synchronous `workflows run` (#9464, #9469): a draft with Wait blocks totalling 500 s runs through runCopilotLifecycle, the sim_cli handler, the embedded CLI and the v2 execute and runs routes against the worker's scripted draft-run probe. With workflow-run-wait-timeout declared it checks the detached first slice, the `workflows runs wait` slices, the output read-back, that no call holds the run and no slice row is failed, and that the model receives the run's output. Without the capability it checks one held call as before, and a model's own --wait-timeout 5 reaches the model as exit 4 with the running receipt. The controller fixture now pins direct Sim transport, since self-hosted defaults to checkpoint delivery and its run control went unanswered, and the fixture plan's execution timeout is per case so a run can outlast a slice. * test(mothership): keep the draft-run case inside the repo's audits Uses sleep from @sim/utils/helpers, guards the last wait slice instead of a non-null assertion, gives the probe's startup its own ten-second deadline like the neighbouring controller case, and tells knip the probe path lives in the worker checkout.
* fix(sandbox): correct the E2B build default in the Pi sizing doc * fix(sandbox): clarify the Pi sizing sentence
… windows (#9479) * docs(billing): scope the usage_log workspace index note to created_at windows * docs(billing): limit the workspace index note to the reads it covers
* fix(search): harden assistant review and account discovery * fix(search): clarify reconnect recovery and receipt states * fix(search): tighten review spacing and capture full UI states * test(search): scope filter assertion to the result link * fix(search): align account actions and simplify tool rows * chore(search): refresh permissions docs and verify receipt captures * fix(search): match tool descriptions to permission group info badges * docs(search): refresh tool permissions with description badges
* fix(mcp): honor json schema openness in mcp output shapes Objects without additionalProperties: false now keep their declared fields and record that others are allowed, so references to undeclared fields lint clean and resolve empty when missing. Arrays without items accept element paths. Also documents the v2 execute 202 receipt returned after waitTimeoutSeconds. * fix(mcp): keep openness flag out of field lookup and close empty objects A declared field named open on an open object resolved to the flag instead of the field. Open nodes now look fields up in their properties only. A closed object declaring no properties now rejects every field instead of saving as untyped. Documents the NDJSON detached frame for waitTimeoutSeconds. * fix(workflows): offer no child fields for arrays of typed elements The connection panel listed an items child for an array whose elements are a typed node without properties, such as an MCP array of strings or of untyped elements, offering an invalid reference. * fix(workflows): scope the typed-elements check to arrays and type the field helper * chore(lint): shrink the explicit-any baseline for the output fields hook
* fix(search): trace live provider latency and partial failures * fix(search): use the shared deferred test helper * fix(search): report every supported date filter in diagnostics
Uh oh!
There was an error while loading. Please reload this page.