Repository navigation
v0.9.20: project membership enforcement, db and perf improvements, realtime and auth hardening, CI and test fixes - #8963
TheodoreSpeaks wants to merge 35 commits into
Conversation
… 2026 (#8931) Co-authored-by: Sim Pi Agent <pi@sim.ai>
…s finalized (#8935) The v2 sync execute path (executeWorkflowService) returned a completed run while executeWorkflowCore was still writing its log and execution state in the background, so a run-from-block naming that run as its source could read no state and 404. The legacy execute route already awaits waitForPostExecution before responding; do the same here.
* chore(db): drop retired storage whose readers have shipped Drops tables and an index whose last readers and writers were removed in already-released versions, makes chat.include_tool_calls NOT NULL, and un-declares six dead columns ahead of a next-release DROP COLUMN. embedding_keyword_tin is dropped by script migration 0031 so it runs after 0030 retires the triggers that still write it on skipped-release upgrades. * fix(db): bound the chat lock in 0409 with a statement timeout
* fix(enrichments): verified-first waterfalls, billing fixes, and an error state for outages - Work email: hold unverified hits (Hunter accept_all, Wiza risky, Dropcontact non-nominative) as a fallback while later providers look for a verified one; the held hit still fills the cell if none verifies. Ask Prospeo for verified emails only, keep personal addresses out of Wiza results, and move People Data Labs (unverified, $0.28 per hit) to the end, skipping it once a fallback is held. Order is otherwise unchanged. - Phone: skip PDL on a bare name (not a valid match), pass the LinkedIn profile to PDL, prefer its mobile, and ask Prospeo for verified mobiles only (no billed person match without one). - Email verification: unverified/error verdicts fall through; bill nothing for ZeroBounce unknown or MillionVerifier catch-all/unknown, which those vendors do not charge for. - Table cells: when every provider errored, mark the cell errored instead of completing it blank, so an outage no longer silently finalizes empty rows. * fix(enrichments): address review — blank outputs on an all-error run, LeadMagic verified check, toArray * fix(enrichments): accept both Dropcontact verified-address labels
…16 service (#8938) - readTestRedisUrl throws when CI is set and TEST_REDIS_URL is missing, so Redis-gated integration suites can no longer pass by skipping - start the postgres:16 service only on integration (push, 1/4), the one job whose step uses it - move the two env-gated smoke files that no workflow enables to *.live.test.ts and shrink the test-patterns baseline accordingly
… of 120k (#8939) The durable-manifest test built 120,000 small rows (~16 MB). Compaction walks every element (a promise, Object.entries and JSON.stringify per row and per field), so the test ran 575-1522 ms on healthy CI runners and 10.6 s on a contended one, timing out. 64 rows whose payloads sum to LARGE_VALUE_THRESHOLD_BYTES cross the same threshold with the same assertions; the 9 MB string tests beside it run in ~50 ms.
…und trips the server budget (#8937) * fix(e2e): connect the mobile suite to realtime and give dev-server round trips the server budget - Start the realtime server for the mobile group. Without it every workspace page raised a persistent "Reconnecting..." toast ~2s after load; on the locked-workflow reload it raced the lock toast and, when it arrived second, sat in front of the Unlock Workflow action, so the tap timed out on "subtree intercepts pointer events" - Wait 120s, the suite's budget for a next dev round trip, for the URL after a sidebar link tap, the Files list after it, and the table cell after a reload. next dev spent 16.4s (application code 70ms) serving the /home RSC payload and left the rows request unanswered past 20s - Install the browsers while the app boots * fix(e2e): stop the background browser install on exit and surface install and realtime logs on failure
…kes (#8940) * fix(desktop-e2e): remove root causes of four retry-masked desktop flakes - packaged-smoke: remove the profile only after every process that can write it (the app's process group, Crashpad's handler) is gone; SIGKILLing main left helpers creating files during rmSync (ENOTEMPTY) - background-executor: answer shell dialogs by waiting for their window to close, since the dialog destroys itself before the click is acknowledged - background-executor A: replace the 1.5 s p95 wall-clock threshold with a gated check that every call is claimed while chat B's first command still holds its queue, within Sim's 15 s pickup window, and that held leases renew - driver: a click whose tab closes itself mid-dispatch (popup Allow -> window.close()) is a dispatched click, not a failed one, whichever of the close and the input acknowledgement lands first - page-dialogs / browser-focus / browser-tools: print the tool error and the shown dialog id when they fail, to root-cause the remaining flakes * fix(desktop-e2e): rescue only a click whose final release hit a tab that then closed - cdp.clickAt raises TabClosedOnReleaseError only when the final mouseReleased was sent to a live tab and the tab is destroyed when it rejects; the driver rescues only that error (no string match, no pre-input/press/hold cases), with a note that does not claim the page closed itself and doNotRetry - background-executor A: assert each call is claimed within Sim's 15 s pickup window measured from issue, and always release the gated commands * fix(desktop): report a click whose tab closed mid-release as unconfirmed The tab being destroyed proves teardown, not that Chromium processed the release, so the rescued result no longer claims effectObserved and its note says the outcome could not be confirmed. Adds clickAt tests for each TabClosedOnReleaseError guard and a driver test for the rescued shape.
…conciliation in 2026 (#8932) * feat(library): 6 Best AI Agents for Invoice Processing and Finance Reconciliation in 2026 * fix(library): clarify finance recommendations and enterprise features --------- Co-authored-by: Sim Pi Agent <pi@sim.ai> Co-authored-by: Waleed Latif <walif6@gmail.com>
* improvement(changelog): expand release stories with practical detail * improvement(changelog): cover release changes without padding
* chore(changelog): document twice-weekly editorial reviews * docs(changelog): distinguish separate manual editions
* ci: scope pull request checks to what the diff can affect A `changes` job classifies the pull request's files against explicit allowlists (.github/scripts/ci-changes.sh, replacing desktop-live-changes.sh): - content posts, author profiles and their public assets: lint, test, build - apps/docs: lint, test - apps/desktop: lint, test, desktop-live - agent guidance (.agents, .claude, .cursor, AGENTS.md, CLAUDE.md, root README): lint Any other file, any .github change, an empty diff, or a diff that cannot be worked out runs everything; pushes and dispatches always run everything. The live desktop suite keeps its own skip list, now including the content asset folders it previously missed. `ci` accepts a skip only when `changes` set that job's flag to exactly `false`, so a failed or skipped `changes`, or a lost output, fails it. * ci: move the ci gate into a tested script and reject non-boolean change flags The ci aggregator's skip rules now live in .github/scripts/ci-gate.sh, read from NEEDS, with table-driven tests covering every guard. The change-classifier test helper fails on any flag value other than exactly true or false.
…tion foreign keys (#8943) Inserts into embedding could stall for seconds merging the shared GIN pending list in the foreground, while holding the document row lock. Turn fastupdate off (the 0364 pattern) and drain the existing list once. User and workspace deletion ran sequential scans for four referential actions inside the deleting transaction, holding row locks other writers queued behind. Add concurrent indexes backing document.uploaded_by, user_table_rows.created_by, user_table_definitions.created_by and execution_large_values.workspace_id.
* improvement(perf): bound trash, file-path and attachment reads * fix(recently-deleted): cast chat ids in the trash union, keep loaded pages on errors
…ts (#8944) * improvement(rate-limit): admit provider requests in one statement on the database bucket Lock, refill, decide and spend every dimension in a single CTE so a hot bucket row stays locked for one statement plus the commit instead of a round trip per dimension. The clock is read before the statement, matching the Redis backend, so a contended admission never sees more tokens. * improvement(connectors): skip the live document count on unfinished sync slices An unfinished content pass keeps the count its last finished pass recorded, the pass lastSyncAt still names. Connectors with no recorded count are still counted so a first pass shows progress. * fix(rate-limit): judge atomic admission at the moment the bucket locks are held Advance the caller's clock by the lock wait measured inside the statement, so a contended admission refills the time it spent waiting as it did before the single-statement change. Cover the spend rollback when the deadline passes or the caller aborts while the statement runs. * fix(rate-limit): count only the lock wait in the atomic admission clock Sample clock_timestamp() before the first row can reach the lock and again after the last is held, so an uncontended admission decides at exactly the caller's clock and planning or execution time never shifts a refill. * fix(connectors): keep counting every slice until a connector's first pass finishes A first pass's own unfinished slices wrote a count, so later slices of that pass saw it and stopped counting. Skip only once lastSyncAt shows a finished pass, which unfinished slices never advance.
…er (#8948) * ci: run the mobile e2e suite on the shared production build, one job per browser The build job now packages .next (zstd, cache excluded) and uploads it for a day. A new e2e-mobile job, one per browser (chromium, webkit), extracts it and serves it with `next start`, so the suite no longer waits on dev compiles or runs both browsers back to back. The mobile group leaves the e2e matrix. On runs that execute e2e, the build bakes NEXT_PUBLIC_APP_URL=http://localhost:3000, which is what production images bake, so the served build is the one that ships. Content-only pull requests keep the hosted value, under which next build prerenders every post. http-e2e.sh gains a `next start` mode used only by mobile: it installs only the selected browser, drops the dev heap override, and rebuilds the HTTP status log from RouteHandler's JSON lines at LOG_LEVEL=INFO. The ci gate treats e2e-mobile like e2e: a skip passes only when `full` is exactly false. * ci: build mobile's artifact in its own job and keep the hosted build untouched The `build` job is back to staging byte for byte: its www.sim.ai build is CI's only render of every post, and it must stay on every run. A new `e2e-build` job, gated on `full` with its own Turbo cache key, builds with NEXT_PUBLIC_APP_URL=http://localhost:3000 (the Dockerfile default, so the same public-env mode production images use; images run the standalone server) and packages and uploads it for e2e-mobile, now kept 3 days and without .next/trace. e2e-mobile fails fast when the downloaded build prerendered posts, which only a hosted build does; the URL is no marker, since next.config's redirects name www.sim.ai in every build. The ci gate treats e2e-build like e2e. * ci: key the non-hosted guard on prerendered post pages, not every /blog/ route * ci: expect the socket-token rate limit in the mobile e2e suite Each document load mints one realtime token from a route capped at 30/min per IP. On the production build the suite loads well over 30 documents a minute from loopback, so the route's designed 429 is recorded apart from httpErrors (only with Retry-After), and each browser must still mint at least once.
…8590) * feat(projects): add project identity and lifecycle foundation * feat(projects): create projects with their initial environment * docs(projects): record project files follow-up * docs(projects): explain project and workspace creation flows * fix(projects): stage activation after compatible writers deploy * feat(projects): enforce membership after the staged backfill * fix(projects): retry writes after concurrent membership changes * fix(projects): align integration fixtures with membership constraints * refactor(projects): prepare compatible writers for the SQL backfill * refactor(projects): backfill through bounded SQL migration batches * fix(projects): clean up automatically created fixture Projects * fix(projects): backfill only families missing membership * fix(projects): bound the trigger installation lock window * fix(workflows): guard restore against concurrent workspace archive * fix(projects): keep workflow lifecycle guards at workspace scope * fix(workflows): guard restore against concurrent workspace archive * fix(projects): close lifecycle races and surface rollout conflicts * fix(workflows): return not found when import loses archive race * fix(projects): tighten rollout checks and deduplicate lifecycle validation * test(projects): detect missing lifecycle validation calls * test(projects): verify concurrent lifecycle lock contention * test(projects): update new workspace fixtures for enforcement * fix(tests): create Project membership in desktop and CLI fixtures * fix(tests): restore Project enforcement fixtures after migration renumbering * fix(tests): scope migration probes and align remaining Project fixtures * feat(projects): prepare workspace project column compatibility * test(projects): clean up compatibility fixtures atomically * feat(projects): move membership to workspace column with rollout bridge * test(projects): align transfer mocks with workspace membership * test(projects): provision required membership in transfer unit fixtures * improvement(workspaces): present API responses explicitly * feat(projects): prepare legacy membership with a resumable operator tool * fix(projects): support PostgreSQL 16 column migration * fix(projects): allow multi-batch copies to finish * fix(projects): support PostgreSQL 16 preparation and current fixtures * fix(projects): reconcile memberships during schema push * fix(projects): enforce safe schema push provisioning * test(projects): provision newly merged workspace fixtures * fix(projects): use the direct connection for push reconciliation * test(billing): wait for parked transactions before racing writers * test(billing): freeze the clock for exact deadline assertions * fix(projects): close operator verification and contention gaps * test(billing): stabilize member ledger timeout checks * fix(projects): await cleanup and bound backfill artifacts * fix(projects): honor operator cancellation and status exits * fix(projects): reject verification of conflicted plans * fix(projects): defer archive repair on database contention * fix(projects): coordinate read-only maintenance commands * ci(projects): use the standard PostgreSQL test coverage * fix(projects): support trigger-free column rollout * fix(projects): run bounded membership backfill before enforcement * test(projects): verify column-only archive repair assignment * fix(projects): retain healthy indexes during schema push * ci(projects): use standard integration coverage for enforcement * fix(projects): correct rollout fixtures and schema-push index * fix(projects): reconcile assigned environments before enforcement * fix(projects): preserve backfill repair and resume guarantees Lock and verify effective legacy memberships before materializing reviewed assignments and applying the shared detach policy. Reject resume reports whose code hash differs before changing their checkpoint. Isolate local pubsub subscriber failures so healthy archive subscribers still receive notifications. Extend existing CLI and real-database integration coverage for mixed memberships, concurrent and stale connector changes, unchanged mismatched reports, replay, and local subscriber delivery. * test(projects): align fixture lifecycle with enforced project ownership * test(projects): skip archive repair suite when Redis is unset * chore(projects): normalize enforcement SQL whitespace * feat(projects): commit membership authority before reconciliation * fix(projects): switch membership authority after compatible rollout * test(projects): guard optional authority fixtures explicitly * test(projects): seed authority in billing lock-order mock * fix(projects): bound authority barriers and verify push replay * fix(projects): pin operator schema and pace detach repairs * docs(projects): record native constraint rollout decisions * refactor(projects): replace integrity triggers with native foreign keys * fix(projects): recognize completed rollout without its marker * fix(projects): retire rollout marker with legacy membership * test(projects): model expansion authority in workspace move fixtures * fix(projects): keep repair reads compatible with expansion schema * fix(projects): retain project name for workspace archival * docs(projects): consolidate permanent storage rules in README * fix(tests): seed Project membership in new staging fixtures * Update packages/db/scripts/reconcile-project-membership.ts Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> --------- Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
Fails on webkit/tablet with a strict-mode violation: '.workspace-content-shell' resolves to two elements (previous Logs page still mounted) after navigating to the workflow. Phone keeps running it. Claude-Session: https://claude.ai/code/session_01UEUUMctneYa5p25wTg5b57 Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…ves (#8951) * Revert "ci(e2e): temporarily skip tablet workflow-controls mobile check (#8950)" This reverts commit 23b0561. * fix(e2e): read the visible workspace shell while a streamed page arrives On the production build, a query made mid-stream can also match the next segment's shell that React parks in a hidden <div id="S:n"> until it swaps it in, so the class-only locator hit a strict-mode violation in WebKit. Scope the shell to the visible element, and restore the tablet workflow-controls check #8950 skipped for the same cause.
…etry-After (#8952) * fix(realtime): end the socket attempt when the token mint fails The Socket.IO auth callback never invoked cb when POST /api/auth/socket-token failed (429, 5xx, network), so the open transport sat until the realtime server's 45 s connectTimeout while the UI showed Reconnecting, and Retry-After was ignored. The client `timeout` cannot help: the Manager clears it when the transport opens, and resets its backoff on every open, so each retry ran at the 1 s floor. On a retryable mint failure, disconnect the socket and reconnect it on the existing auth backoff (1 s to 30 s, matching the reconnection config), never before the response's Retry-After. 401 keeps its cb({ token: null }) path. * fix(realtime): clear connected state and jitter Retry-After on token retry disconnect() on a socket that has not connected yet emits no 'disconnect' event. After a native reconnect is followed by a failed token mint, isConnected stayed true for the whole outage. Clear it, and the socket id, exactly as the 'disconnect' handler does. Spread a Retry-After-driven delay by up to +20% above the floor, so tabs behind one IP do not retry in the same second. * fix(realtime): tighten the token-retry comment * fix(realtime): ignore token failures from a superseded handshake and report persistent token outages
The seven suites excluded from the integration run since 2026-09-25 failed against a freshly provisioned database (fixtures predate connector and credential changes) and never ran in CI. Delete them, the quarantine list in vitest.config.ts, their explicit-any baseline entries, and getCredentialGroupOAuthContext (plus its @sim/testing mock), whose only caller was the GitHub member suite. The testing rule now says to fix or delete a failing suite rather than exclude it.
* refactor(knowledge): share the processing checkpoint store
OCR and embedding checkpoints each carried their own copy of the framed
header + body format, the outbox cleanup reservation and the cleanup
handler factory. Move them into processing-checkpoint-store so a third
checkpoint kind can reuse them.
* feat(knowledge): index Confluence image attachments with a vision model
Confluence images (PNG, JPEG, WebP, GIF) were dropped at listing, so
tables, scans and screenshots attached to pages never reached search.
- Connectors declare an image policy; Confluence reads images with a
dedicated Gemini adapter that returns the image's text, every other
source keeps OCR unchanged.
- A new Image Attachments setting on the Confluence connector, on by
default, so existing knowledge bases pick images up on their next sync.
- Decorative images (logos, icons, images under 64 px) complete with no
chunks; files under 2 KB and SVGs are never listed.
- Each sync admits at most KB_IMAGE_EXTRACTIONS_PER_SYNC new images
(default 500); the rest wait for the next sync, which reports partial.
- A vision checkpoint lets a retried pass reuse the extraction instead
of paying for a second call; usage is billed per image.
- Completing a pass now always replaces old embeddings, so a document
that re-indexes to zero chunks drops its stale ones.
- sharp is added to the Trigger.dev bundle for image preparation.
* feat(knowledge): explain image documents with nothing to index
A completed image with no chunks shows an empty state instead of bare
table headers, and the connector and self-hosting docs cover image
attachments and the two new environment variables.
* fix(knowledge): bound image re-reads and handle image opt-out directly
Review follow-ups for Confluence image indexing.
- The per-sync cap now counts changed images as well as new ones, and a
member sync shares one budget across its members. Held-back images
that already exist are still marked seen, so they are never reconciled
away.
- A full resync no longer re-reads unchanged images; their bytes are
pinned to the attachment version.
- Without any Gemini key, images are left out of the sync instead of
becoming failed documents.
- Turning Image Attachments off removes the indexed images on the next
sync, outside the soft-delete and mass-deletion hold meant for source
deletions.
- Gemini errors: a response cut off at the token limit, a rejected key
or region, and an unknown model fail permanently with an accurate
message instead of retrying or blaming the image; an image whose pixel
data cannot be decoded fails as invalid.
- The admission wait keeps the post-call time reserve, Retry-After uses
the shared parser, and a configured model must be a catalog Gemini
model so its pricing is known.
* fix(knowledge): make image indexing opt-in for existing Confluence connectors
- New connectors are created with Image Attachments on, through a
server-side defaultSourceConfig on the connector meta that every create
surface applies; an unset value now means off, so existing connectors
only read images once their owner turns the setting on.
- The Gemini call retries transient server and network errors within the
extraction's time budget; throttling still defers the pass.
- Gemini error bodies are reduced to their status and reason codes.
- Images under the byte floor complete as decorative even when the source
reported no size, and the extraction model must be a generateContent
Gemini model.
- A member sync that held images back forces a full listing next time,
the image count survives a listing restart and is saved per batch, and
turning images off removes them for member-credential connectors too.
- The disabled-image removal skips rows the delete would refuse.
- An integration suite covers the cap, held-back images staying indexed,
full resync, opt-out removal, opt-in for existing connectors, zero-chunk
re-indexing and the no-key hold-back against real PostgreSQL; the OCR
input-failure suite now uses a source that still sends images to OCR.
* fix(knowledge): retry malformed extractions in-call and clean up images on every member run
- A Gemini reply that is not valid JSON is retried within the extraction's
budget and fails permanently once the attempts are spent, instead of
costing a whole document retry each time.
- A member sync that skips its content pass (content not due yet) still
removes images once Image Attachments is turned off.
- The reconciliation integration suite runs with images on, so it keeps
exercising reconciliation alone.
* fix(knowledge): count image removals in member runs and bill every extraction attempt
- Member runs add the lifecycle's purges to the run's deletion counts
instead of overwriting them, so image removals after Image Attachments
is turned off are reported and logged as purges.
- A retried extraction reports the tokens of every attempt Gemini
answered, since each one was billed.
- The checkpoint header check uses isRecordLike.
- The create-time default is tested through the real creation path in
the integration suite, replacing a mock-only unit test.
* fix(knowledge): resume a member run whose image removal hit its deadline
An unfinished disabled-image removal now keeps the member run marked as
having work remaining, so the next run starts promptly instead of waiting
a full sync interval with images still searchable.
* refactor(knowledge): declare image extraction once and remove images only when queued
- Connectors declare image extraction once on their meta
(`imageExtraction: { settingId }`), read by the shared
`isImageExtractionEnabled`; drops `ConnectorConfig.imageExtractionEnabled`
and the Confluence-only helper.
- Turning the image setting off sets `knowledge_connector.image_removal_pending`
(migration 0412); the next sync removes the indexed images and clears it, so
ordinary syncs no longer scan a connector's documents for images.
- Gemini specifics (key, Gemini 3 model resolution, error classification) live
in the adapter. Requests send `thinkingLevel: LOW`, and any finish reason other
than STOP fails without paid retries.
- Image reads get their own admission budget (`vision`,
KB_CONFIG_VISION_REQUESTS_PER_MINUTE, default 300) instead of sharing OCR's.
- One zod schema validates the reply and generates the request's JSON schema.
- The prompt is source-neutral and treats text in an image as content, never
instructions; sharp loads lazily so it can only fail image documents.
- Full relisting after held-back work is one named rule
(`noticeRequiresFullListing`).
* fix(knowledge): keep op narrowing in processDocOps and clean up Project fixtures
* refactor(knowledge): tighten image extraction after a full review
- Every Gemini attempt takes its own admission, and 429/503 records a provider
cooldown for the key; the retry delay is read from the body's RetryInfo when
no Retry-After header is sent.
- The image is base64-encoded once per extraction, rotated upright even when it
already fits, and flattened onto white before a JPEG fallback.
- Cost goes through calculateBillableModelCost; both indexing charges share one
recordIndexingUsage helper.
- Reconciliation waits until queued image removal finishes, and the removal walks
by id instead of rescanning from the start.
- The per-sync image cap is at least 1, so a sync can always finish.
- canExtractImages lives with the extractor; isSemanticImage treats an undeclared
policy as OCR, so callers drop their fallbacks.
- Tests: unique embedding vectors, restored pool keys, waits for dispatched syncs,
fake timers in finally, native noise fixtures; drops mock-only assertions.
---------
Co-authored-by: Waleed Latif <walif6@gmail.com>
…ved quarantined suite (#8956)
The collapsed toast stack paints newest-first and shows only the front
card whole; back cards are clamped to the front card's height and peek
13px above it. A persistent status toast raised after an actionable one
("Reconnecting..." / "Joining workflow..." after "This workflow is
locked") therefore covered the action, and on touch the first tap only
expanded the stack.
Order the stack so persistent toasts without an action sit behind every
other toast; everything else stays newest-first.
…ope (#8957) Real-Postgres integration suite for the member sync's scope-unavailable branch (member-sync-engine listForMember): a provider answer classified as a lost scope is an authoritative, complete, empty listing that withdraws only that member's observations on that connector, while a 503 or timeout keeps access. Asserts on document ACL rows, observation rows, and search visibility. Each document gets a unique one-hot embedding (index < 512) and is searched with its own vector, so visibility never depends on HNSW ties or ranking.
) * fix(auth): rate-limit socket-token mints per user, keep a generous IP backstop The 30/min budget was keyed on client IP and checked before the session, so an office behind one NAT address (or every tab reconnecting after a deploy) shared a single budget and throttled each other. The same 30 burst / 30 per minute now applies per session user, after a cookie-cached session read; the mint still re-reads the session from the database. A 300/min IP backstop stays in front of everything so unauthenticated traffic is rejected before any session lookup. 401 and 429 + Retry-After responses are unchanged. * docs(realtime): the Retry-After jitter spreads any tabs sharing a 429 window * fix(auth): give the socket-token IP backstop its own bucket and pin both budgets in tests
* chore(tests): ratchet real wall-clock waits in unit tests (check:test-patterns real-wait) New `real-wait` rule in scripts/check-test-patterns.ts flags a unit test that waits on the wall clock with no fake timers in scope: - `sleep`/`interruptibleSleep` resolved through their `@sim/utils/helpers` import binding (aliases included; skipped when the file mocks that module), - `setTimeout` from `node:timers/promises`, - `new Promise((resolve) => setTimeout(resolve, ms))` and variants whose timer callback resolves the promise (reject-only timeout guards are not waits). Zero or omitted delays are macrotask flushes and are not flagged. Fake timers cover a wait when an earlier `vi.useFakeTimers()` in an enclosing function or the module, or a `beforeEach`/`beforeAll` of an enclosing describe or the module, fakes `setTimeout` (`toFake: ['Date']` and `shouldAdvanceTime: true` do not). Integration and *.live.test.ts files are exempt: their waits are on real services. Each occurrence is a numbered entry, capping the count per file. `--update --init-rule <rule>` admits the one-time baseline for a rule the baseline does not track yet; `--update` stays shrink-only. Baseline: 121 real-wait entries across 46 files (72 -> 193 total). * fix(tests): keep a real-wait flagged before the fake-timer install in its own hook A beforeEach/beforeAll that installs fake timers covered its whole suite, including waits earlier in the same hook body, which run on the real clock. Only waits after the install in that hook are exempt now; tests and other hooks in the suite keep the exemption. * fix(tests): make real-wait's fake-timer exemption exact and drop --init-rule - Remove `--update --init-rule`: it admitted entries for any rule with no remaining baseline entries. `--update` is strictly shrink-only again; the real-wait entries enter once, in this PR's baseline diff. - `vi.useRealTimers()` ends the exemption from where it runs, including a nested suite restoring real timers after an outer hook faked them. - A clock installed in `beforeEach` no longer covers `beforeAll`/`afterAll` or earlier sibling `beforeEach` hooks; `beforeAll` no longer covers earlier sibling `beforeAll` hooks. - Only `vi.useFakeTimers()` with no config, or a literal config proven to fake setTimeout without shouldAdvanceTime, exempts a wait. - Namespace imports (`helpers.sleep`, `timers.setTimeout`) are flagged. * chore(tests): make the wait-export table read-only * fix(tests): let a module-scope fake-timer install cover helper functions declared above it Functions run only after the module loads, so a module-scope vi.useFakeTimers() (or vi.useRealTimers()) applies to every function body regardless of source order; module-scope waits still follow source order. * fix(tests): exempt helpers from a module-scope fake-timer install only when nothing ran before it A helper called at module scope before vi.useFakeTimers() waits on the real clock. A module-scope install now reaches function bodies only when every earlier module-scope statement is load-safe (imports, function/class declarations, type-only statements, vi.mock/doMock/hoisted, and variables whose initializers call nothing); otherwise source order applies. A module-scope vi.useRealTimers() still reaches every function body. * fix(tests): skip only helpers called before a module-scope fake-timer install Any unrelated module-scope call (const run = vi.fn()) used to drop the helper exemption. Now a module-scope vi.useFakeTimers() covers every function body except a helper (function declaration or variable bound to a function) that earlier module-scope code calls directly by name; calls through other helpers are not traced. WAIT_EXPORTS and HOOK_KINDS are as const. * fix(tests): recognize module-scope helpers whose initializer is wrapped in a type assertion helperName now unwraps as/satisfies/non-null/parenthesized initializers with the shared unwrap helper, so a wrapped arrow called before a module-scope vi.useFakeTimers() stays flagged.
* ci: ratchet type errors in apps/sim unit tests per file
apps/sim's tsconfig excludes *.test.ts(x), so ~3.4k test files are never
type-checked and any new test can add errors. check:test-types runs the
native tsc on apps/sim/tsconfig.tests.json (the app config with tests left
in), counts errors per file, and compares with a shrink-only baseline,
matching check:explicit-any's semantics: a rise or a new file fails, a drop
fails until --update shrinks it, --update never raises, --update --init only
creates a missing baseline. Output it cannot place (global diagnostics, a
crash) fails outright instead of reading as fewer errors.
It type-checks the whole app, so it runs in its own test-types job gated
like test (wired into ci-gate.sh), not in check:audits. On failure the job
uploads counts.json and the compiler output; --counts <file> lets the
baseline be bootstrapped or shrunk from that artifact without a local
compile.
* ci: commit the test type-error baseline from CI and drop the one-time --init path
Baseline from run 38342772080's test-types counts: 3209 errors in 874 files.
--update stays shrink-only; a missing baseline is restored from git.
* ci: ratchet test type errors per file and TS code, with command-level tests
A per-file count let one new error replace a fixed one with the total flat.
The baseline is now { file: { TSnnnn: count } }: any (file, code) count
that rises fails, including a new code in a baselined file, and --update
stays shrink-only per pair. The key stops at the code: line and column
move with edits, and messages print types that change with unrelated
source or compiler versions.
--diagnostics <file> replaces --counts: it reads a saved compiler output
(the CI artifact's diagnostics.txt) through the same parser and undercount
checks, so a fix can shrink the baseline without a local compile. The
baseline was migrated from run 38342772080's diagnostics.txt with the
script's parser: 3209 errors in 874 files across 52 codes, every per-file
total equal to the previous baseline's.
Command-level tests run the real script on fixture diagnostics: unchanged,
a rising count, a new code replacing a fixed error, a new file, a dropped
count, --update refusing a raise, --update shrinking, and unparseable or
inconsistent output. The checks.yml comment now describes the artifact as
input for shrinking the existing baseline.
* ci: verify saved test-type diagnostics against the compile's exit status
--diagnostics read an empty or truncated diagnostics.txt as fewer errors,
so a failed compile's artifact plus --update could erase the baseline.
--report now writes status.json (exit code and printed error count) once
the compile's output and exit code agree, and --diagnostics requires it:
exit 0 must mean no errors, the parse must match the recorded count, and
a missing or malformed status fails. Command-level tests cover each case
and that --update never writes the baseline from such input.
Also passes a route context to the socket-token route test's POST call,
the one new test type error (TS2554) the ratchet caught after #8958.
* ci: read the saved compiler status through toRecord
…8960) * fix(ui): simplify responsive layouts and compact workflow controls * fix(ui): align mobile breakpoints and preserve compact widths * fix(test): sample responsive resize geometry atomically
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
There was a problem hiding this comment.
All reported issues were addressed across 387 files
Heads up: you’ve reached your flex budget. Increase your flex budget or wait for usage to reset.
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.
Turn on auto-fix | Re-trigger cubic
|
* fix(db): reduce Project backfill round trips and scheduling limits * fix(db): repair archived workspace workflows during Project backfill * fix(db): retry busy Project archive repairs
* fix(lifecycle): retain shared resources when creators leave * fix(lifecycle): preserve replacement workspace grants * fix(lifecycle): preserve upload history during creator handoff * fix(lifecycle): preserve empty upload attribution through handoff * fix(lifecycle): order workspace locks before file mutations * fix(admin): use renamed member not-found response * fix(lifecycle): acquire organization fences before workspace handoff * fix(lifecycle): lock resource workspaces before account erasure barrier * fix(lifecycle): refuse erasure while creator references are in flight * fix(lifecycle): lock Project workspaces before successor grants * fix(lifecycle): make shared file contexts readonly
…ges off while disabled (#8965) - Vision checkpoints include the filename the extraction prompt names, so a rename never reuses text extracted under the old title - Restoring an excluded connector image is rejected while its image attachments are off; the setting check runs after the document update in the same transaction under a connector share lock, matching sync's lock order
Uh oh!
There was an error while loading. Please reload this page.