Skip to content

v0.6.96: pinned table columns, sequence number in copilot messages, tables UI improvements, new slack scopes, model-level denylists, object storage tracespans#4798

Merged
waleedlatif1 merged 14 commits into
mainfrom
staging
May 30, 2026

Conversation

@waleedlatif1
Copy link
Copy Markdown
Collaborator

@waleedlatif1 waleedlatif1 commented May 29, 2026

waleedlatif1 and others added 8 commits May 29, 2026 13:56
* feat(tables): freeze columns

* fix(tables): sticky meta-header row for frozen workflow groups, remove dead handleChangeType

* fix(tables): scope frozenOffsets dep to frozen column widths only

* fix(tables): restore frozenColumns on delete-column undo/redo

* fix(tables): restore useMemo for isAllRowsSelected (O(n) computation)

* fix(tables): use current frozenColumns on delete-column redo, not stale snapshot

* fix(tables): clean up frozenColumns on create-column undo

* fix(tables): merge frozen state on delete-column undo instead of overwriting

* fix(tables): add previousFrozenColumns to test fixture for delete-column action

* fix(tables): skip frozen state update on delete-column redo when column was not frozen

* refactor(tables): rename frozen columns to pinned, fix sticky-zone UX

- rename frozenColumns → pinnedColumns across types, contract, undo
  actions, grid state/refs/props, and dropdown labels
- add Pin / PinOff emcn icons; use them in the column menu in place of
  Lock / Unlock
- pinned body cells render at z-[6], above the cell selection border
  (z-[5]), so the blue selection border can't draw on top of the
  sticky-left zone
- restrict column drag-reorder to within the pinned or unpinned zone in
  both handleColumnDragOver and handleScrollDragOver; cross-zone drop
  indicators are suppressed
- on unpin, slide the column to the first unpinned slot so the sticky
  zone stays contiguous; consolidates pin and unpin into one branch
  that always re-enforces pinned-at-front

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(tables): biome formatting + tighten pinned-zone comments

- collapse two onPinToggle JSX props that biome wanted on a single line
- drop a WHAT comment in handleScrollDragOver; tighten the why-comments
  in handlePinToggle, handleColumnDragOver, and handleColumnDragEnd so
  they describe the invariant being protected instead of narrating the
  recent change

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(tables): re-sort reorder-columns undo to keep pinned-at-front

If the user reordered, then pinned a column, then undid the reorder, the
restored snapshot could leave a currently-pinned column in the middle of
columnOrder. pinnedOffsets walks displayColumns left→right and assigns
sticky `left` from checkboxColWidth — a pinned column in the middle gets
a sticky offset as if it were at the front, causing it to jump over its
left neighbors on horizontal scroll.

Re-sort the restored order with pinned entries pulled to the front before
applying. Mirrors the belt-and-suspenders re-sort in handleColumnDragEnd.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Theodore Li <theo@sim.ai>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(auth): block signup spam by denylisting shared MX backends

Signup-spam bots rotate throwaway domains rapidly but funnel them through a
small number of shared catch-all mail providers. Across the current wave, 85%
of bot domains resolved to just two MX backends (smtp.215.im,
email.gravityengine.cc), while every domain differed — so the resolved MX host
is a far more durable signal than the domain itself.

Add a server-only MX validator (validateSignupEmailMx) that resolves the
domain's MX records during /sign-up/email and rejects:
  - domains with no MX record (no_mx)
  - domains whose MX backend is on the denylist (blocked_mx_backend)

Seeded with the two observed backends; extend at runtime via
BLOCKED_EMAIL_MX_HOSTS. Fail-open on DNS timeout/transient error so legitimate
users are never blocked by a resolver blip; kill switch via
DISABLE_SIGNUP_MX_VALIDATION. Returns a clean 403 (APIError), not a 500.

* refactor(auth): make MX signup validation opt-in (SIGNUP_MX_VALIDATION_ENABLED)

Aligns with the sibling feature SIGNUP_EMAIL_VALIDATION_ENABLED (disposable
blocking via harmony), which is also opt-in. Default-off avoids adding a DNS
dependency to the signup path and prevents surprise signup blocking on
self-hosted deployments with non-standard mail setups (internal domains, or a
too-broad MX entry catching legit shared infra like Cloudflare Email Routing).
Enable on hosted/abuse-targeted deployments via SIGNUP_MX_VALIDATION_ENABLED;
the flag doubles as the kill switch, so the separate DISABLE_ flag is removed.

* fix(auth): clear MX-lookup timeout to avoid dangling timer on success

* refactor(auth): remove hardcoded MX denylist defaults

The MX-backend denylist is now entirely operator-supplied via
BLOCKED_EMAIL_MX_HOSTS. Sim is open source, so no specific mail backends are
named in the repo, the env example, or the tests — deployments configure their
own list out of band (e.g. via secrets). The no-MX hygiene check is unchanged;
with an empty denylist no backend is blocked.
…ng reads (#4791)

copilot_messages had no column preserving message order: created_at (set
from each message's timestamp) ties at millisecond granularity in 58% of
chats, and some chats have out-of-order timestamps within their array. The
only other tiebreaker, id, is a random UUID — so ORDER BY created_at, id
renders same-timestamp user/assistant pairs swapped. This blocks the R+1
read cutover.

Add an integer seq = the message's 0-based index within the chat's JSONB
array (ground-truth order), backfilled inline in migration 0219 (no script
for self-hosters or us). Reads will use ORDER BY seq NULLS LAST, created_at,
id at cutover; reads still come from JSONB after this PR.

Design:
- seq is a tiebreaker, not the sole sort key (concurrent-append/NULL safety).
- Nullable now; defer NOT NULL so rolling-deploy old pods don't fail inserts.
- replace (update-messages snapshot) overwrites seq = array index
  (re-densifies after a mid-conversation delete); append preserves existing
  seq via COALESCE and assigns base+idx from a single MAX(seq) read (never
  MAX+i in SQL — multi-row batches would collide). The non-atomic
  read-then-insert window is documented and bounded by the read tiebreak +
  snapshot re-densify.
- Dedupe message ids before insert (87 prod chats carry dup ids; a repeated
  id in one INSERT...ON CONFLICT would otherwise throw).
- Backfill picks first-occurrence per (chat,id), gap-free via ROW_NUMBER;
  validated on staging data (0-based, contiguous, 0 bad ranges).

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
…xes (#4789)

* fix(tables): resource-cell icons, embedded filters, run-count + queued fixes

- table-grid: render in-workspace resource URLs (workflow/table/KB/file) as
  tagged-resource cells reusing ContextMentionIcon (colored square for
  workflows), matching @-mention chips; only the matching list is fetched.
- table-grid: fix row-number sticky cell overflow — reserve the full run/stop
  button area (30px, not 16px) so wide row indices don't clip.
- table-grid: show an infinite-scroll loading spinner while the next page
  loads instead of looking like the end of the table.
- table: surface sort + filter (and run/stop via the options-bar extras slot)
  in the embedded mothership table resource view.
- table-grid/utils: stop the dispatch overlay from optimistically painting
  autoRun=false cells Queued for auto-fire dispatches — the dispatcher skips
  those groups ('autoRun-off'); manual runs still show Queued (manual-bypass).
- dispatcher: exclude orphan pre-stamps (pending + executionId null) from
  countRunningCells so the "X running" badge doesn't stick above zero.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(tables): single run/stop control, right-aligned row numbers, View-execution guard

- table: de-duplicate the run/stop control in the embedded mothership view —
  drop TableGrid's own embedded run-status bar; it now lives only in the
  options bar (left-aligned next to Filter + Sort). Removes the orphaned
  RunStatusControl import + onStopAll/cancelRunsPending props.
- data-row: right-align the row number within its box (hugs the right edge,
  no hover position jump) with a scaled right inset — 2px for ≤3-digit
  indices, 4px for 4+ so narrow columns don't look over-padded.
- table-grid: require a real executionId in the action bar's canViewExecution
  flag so an error that never produced an execution (enqueue failure →
  status 'error', executionId null) doesn't offer "View execution".

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(tables): address review — drizzle operators for orphan filter, enabled flag for files query

- dispatcher: replace the `not(and(...)) as SQL` cast in countRunningCells with
  `or(ne(status,'pending'), isNotNull(executionId))` — De Morgan equivalent,
  fully type-checked, no cast and no hand-written raw SQL.
- workspace-files: add an `enabled` option to useWorkspaceFiles; sim-resource
  cell now passes the real workspaceId with `enabled` instead of '' so the
  query cache isn't polluted with an empty-key entry.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(tables): "X running" badge counts actual in-flight cells, not dispatch scope

The badge derived from `runningCellCount` (the dispatch-scope estimate =
rows-ahead × groupCount), which over-counts groups that already finished on
rows still inside a dispatch's scope — a cascade where 3 of 4 workflow columns
completed read "4 running" instead of "1". Derive `totalRunning` from the live
`runningByRowId` map instead (the same per-row source the gutter and action-bar
selection already sum), so it reflects cells actually in flight and updates
per-cell via SSE rather than only on dispatch-window events.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
)

* feat(access-control): add per-model denylist to permission groups

* fix(access-control): default deniedModels in response schema, hide blocked badge on disabled rows, trim comments

* chore(access-control): reuse canonical DYNAMIC_MODEL_PROVIDERS from providers/models
* improvement(logs): obj storage backed tracespans

* fix storage write context

* fix tests

* address comments

* address comments

* chore(db): remove migration 0219 to regenerate after staging merge

Drops the 0219_robust_shard SQL, its snapshot, and the journal entry so the
trace-spans/cost schema migration can be regenerated on top of the latest
staging migration chain (avoids a number collision with staging's migrations).

Co-authored-by: Cursor <cursoragent@cursor.com>

* improvement(billing): accurate per-member usage via shared ledger helper

Per-member/per-user usage in the org-member routes now adds the usage_log
ledger to the currentPeriodCost baseline (which is no longer incremented),
via a shared getOrgMemberLedgerByUser helper to avoid repeating the
subscription→period→ledger lookup across the admin and member-facing routes.

Co-authored-by: Cursor <cursoragent@cursor.com>

* regen migrations

* update migration

* address comments

* more code cleanup

* incorrect type cast

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
#4796)

* improvement(providers): harden OpenAI-compatible providers + add tests

* fix(vllm): let tool-loop errors propagate instead of returning silent partial success

* fix(litellm): force tool_choice 'none' on final structured-output call

The deferred final call used tool_choice 'auto', so the model could emit
another tool_calls round instead of the structured answer, leaving content
stale. Use 'none' (matching vLLM/Fireworks) on both the streaming and
non-streaming final calls so the model must return the structured response.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix(providers/ollama): drop tools from post-tool streaming call

Ollama ignores tool_choice (not in its supported fields), so vLLM/Fireworks'
tool_choice:'none' guard is a no-op here. Omit tools from the final streaming
payload instead so the summarization turn can't emit dropped tool calls.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix(litellm): spread payload into deferred final call so reasoning_effort carries over

The non-streaming deferred finalPayload hand-picked fields and dropped
reasoning_effort (and any future payload field), diverging from the streaming
path which spreads ...payload. Spread payload here too for consistency.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* chore(providers/ollama): restore enrichment TSDoc block

Keeps parity with sibling Chat Completions providers (cerebras/mistral/xai).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* docs(fireworks): restore TSDoc on utils helpers

Restore the TSDoc blocks on supportsNativeStructuredOutputs,
createReadableStreamFromOpenAIStream, and checkForForcedToolUsage —
TSDoc is the codebase documentation standard and should not have been
stripped.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* chore(litellm): remove inline rationale comments (codebase uses TSDoc)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* chore(providers/ollama): drop orphaned enrichment TSDoc

The block documented a function that now lives in trace-enrichment.ts, so it
documents nothing in this file.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
@vercel
Copy link
Copy Markdown

vercel Bot commented May 29, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
docs Skipped Skipped May 30, 2026 12:30am

Request Review

* chore(copilot): deprecate mcp

* update error codes

* deprecate copilot api v1 route
@waleedlatif1 waleedlatif1 marked this pull request as ready for review May 29, 2026 21:49
@cursor
Copy link
Copy Markdown

cursor Bot commented May 29, 2026

PR Summary

High Risk
Breaking API removals (Copilot MCP, v1 chat) and a broad logs/cost schema migration affect billing displays, exports, and any clients still using deprecated endpoints or the old cost JSONB shape.

Overview
This release retires external Copilot integrations, moves execution logs onto ledger-backed costs and object-storage traces, and adds tables and access-control polish.

Copilot deprecation: /api/mcp/copilot, its OAuth discovery routes, and POST /api/v1/copilot/chat now return 410 Gone (JSON-RPC envelope on MCP POST). The large MCP server implementation is removed in favor of shared copilot-deprecated helpers, with route tests added. Copilot docs in de/en/es/fr/ja/zh drop the entire Copilot MCP setup section (API keys, Cursor, Claude, VS Code).

Logs & billing data model: List, detail, export, v1, and workflow execution APIs read cost_total (and models_used for filters) instead of the legacy cost JSONB, and materializeExecutionData loads trace payloads from object storage with bounded concurrency on export/v1 full-detail paths. The log details UI builds cost breakdown from costLedger / usage_log with apportioned credits; the trace tab uses a single runCostDollars total. Org member and admin billing endpoints add per-member usage_log ledger sums to currentPeriodCost and trim legacy fields (e.g. lastActive, lifetime execution counters, seat activity lists).

Product & policy: Model-level denylists surface as ModelNotAllowedError on guardrails validate and providers routes. Tables gain pin/unpin column (sticky headers/cells), sim-resource chips for in-workspace URLs, and row-index layout tweaks. BYOK adds Findymail, Prospeo, and Wiza. A knowledge utils test relaxes ordering when billing inserts appear after doc updates.

Reviewed by Cursor Bugbot for commit 704362d. Bugbot is set up for automated code reviews on this repo. Configure here.

…4777)

* feat(integrations): hosted API keys for Findymail, Prospeo, and Wiza

Add hosted-key support across all credit-consuming Findymail, Prospeo, and Wiza operations so Sim provides the key when a workspace has not brought its own. Register the three BYOK providers, consolidate Wiza's two-step reveal into a single polling wiza_individual_reveal op, and hide the API key field on hosted Sim for hosted operations.

* fix(integrations): harden Wiza reveal polling, soften enrichment getCost guards

Address Greptile + Cursor Bugbot review on #4777: return explicit failures from the Wiza individual_reveal poller instead of throwing (thrown errors were swallowed into a false queued success), short-circuit when the initial reveal is already terminal, tolerate transient 5xx/429 during polling, and return 0 (not throw) from Findymail getCost when the contacts/employees array is absent.

* chore(integrations): biome formatting after wiza merge resolution

* fix(wiza): type isTerminalReveal param structurally for next build typecheck

* feat(enrichments): add Findymail, Prospeo, Wiza to work-email waterfall

* feat(enrichments): add Wiza + Prospeo phone reveal to phone-number waterfall

* feat(enrichments): opportunistic identifiers + LinkedIn URL input across work-email & phone cascades
#4799)

* feat(slack): add install + privacy section to integration landing page

Adds a hand-authored, slug-keyed landing-content module (separate from the generated integrations.json so it survives regeneration) and renders an install walkthrough + privacy-policy link on integration pages when present. Also refreshes generated docs (data-enrichment entry, icon mappings, tool mdx).

* fix(landing): render privacy section independently, align CTA analytics label

* docs(landing): clarify the Slack install button is behind sign-in

* refactor(landing): bake integration landing content into generated json via docs-gen

Moves landing content (install walkthrough + privacy) out of a render-time augment and into the generation pipeline: generate-docs reads the pure-data content map and writes landingContent into integrations.json, so the page reads a single source (integration.landingContent). Canonical types live in integrations/data/types.ts.
#4801)

* improvement(enrichments): align enrichments sidebar with design system

* fix(enrichments): consistent close button pattern and fix url link hover
…ssue for workflow block agent usage (#4803)

* fix(misc): upgrade path change for new better-auth version, double-billing for workflow block agent usage

* fail loudly if stripe sub id missing
@waleedlatif1 waleedlatif1 merged commit a8dcdd5 into main May 30, 2026
30 checks passed
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.

3 participants