DB migration compat / Back-compat — Current branch migrations with ${{ needs.check-migrations-changed.outputs.base_branch }} branch code (push) Has been cancelled
DB migration compat / Forward-compat — Current branch code with ${{ needs.check-migrations-changed.outputs.base_branch }} branch migrations (push) Has been cancelled
CommitErrors are hard to parse as they stand so we unwrap them.
<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Unwrap `lmdb` commit failures to surface the real underlying error
(e.g., ENOSPC/MDB_MAP_FULL) instead of the opaque "Commit failed"
wrapper. Improves logs and error propagation across
availability/durability paths.
- **Refactors**
- Added `unwrapLmdbCommitError` to await and rethrow the real `lmdb`
commit error; returns `HexclaveAssertionError` if not an `Error`
(`@hexclave/shared`).
- Routed all availability/durability trackers and batched commit paths
through the unwrapping helper to ensure callers see the true cause.
- Tests cover pass-through, unwrap behavior, and non-Error assertions.
- Updated a comment in `instant-availability` to note low-level LMDB
unwrapping.
<sup>Written for commit 0a1d69beae.
Summary will update on new commits.</sup>
<a
href="https://cubic.dev/pr/hexclave/hexclave/pull/1775?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>
<!-- End of auto-generated description by cubic. -->
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Bug Fixes**
* Improved LMDB commit error reporting by exposing the underlying cause
instead of an opaque wrapper.
* Ensured pending availability and durability operations receive the
unwrapped commit error.
* Added handling for commit failures with unexpected error values.
* **Tests**
* Added coverage for wrapped, unwrapped, and non-standard commit error
scenarios.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
## Problem
On a customer's payments view, submitting a manual item quantity change
makes the "New balance: X → Y" preview in the dialog briefly flip to the
post-change values (e.g. `0 → 10` flashes to `10 → 20`) right before the
dialog closes.
## Root cause
The preview was computed from the live `currentQuantity` prop, which
comes from `useItem()` in the parent row. The SDK's
`createItemQuantityChange` awaits its item cache refresh before
resolving, so the prop updates to the new quantity while the dialog is
still open (and stays visible through the close animation), recomputing
the preview with stale input text.
## Fix
Snapshot the quantity when the dialog opens (in the existing
reset-on-open effect) and compute the preview from the snapshot instead
of the live prop. The preview now consistently shows the balance as of
when the dialog was opened.
## Before vs after
Recorded against built servers (before = `dev`, after = this branch).
The transactions refetch is artificially delayed by 5s in both
recordings to stretch the flicker window to a visible length — on
production latency it's a split-second flash.
https://github.com/user-attachments/assets/c005ef3b-45cb-4b75-bd71-5f723eae0c50
## Tradeoffs
If the quantity changes externally while the dialog is open, the preview
shows the value from open time. The mutation is a delta, so correctness
of the applied change is unaffected.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Bug Fixes**
* Stabilized the quantity change preview while the dialog is open.
* The “New balance” display now consistently shows the quantity at
opening and the calculated updated quantity, even if underlying values
change during submission.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
DB migration compat / Back-compat — Current branch migrations with ${{ needs.check-migrations-changed.outputs.base_branch }} branch code (push) Has been cancelled
DB migration compat / Forward-compat — Current branch code with ${{ needs.check-migrations-changed.outputs.base_branch }} branch migrations (push) Has been cancelled
DB migration compat / Back-compat — Current branch migrations with ${{ needs.check-migrations-changed.outputs.base_branch }} branch code (push) Has been cancelled
DB migration compat / Forward-compat — Current branch code with ${{ needs.check-migrations-changed.outputs.base_branch }} branch migrations (push) Has been cancelled
Updates the UI of the walkthrough
<img width="1285" height="731" alt="image"
src="https://github.com/user-attachments/assets/1467e134-a86e-4b80-bfe0-7272cc1f419f"
/>
<img width="946" height="425" alt="image"
src="https://github.com/user-attachments/assets/4e958141-e59a-4694-9abf-f5b47e9fd3b9"
/>
<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Makes the Preview App walkthrough smoother and clearer with a glowing
spotlight, speech-bubble tooltip, improved cursor motion with a dwell
pulse, and a timed progress card. Also removes preview project pooling
and its cron jobs, restoring the standard environment health gate.
- **New Features**
- Spotlight: rounded cutout with a blue border/glow and smoother easing;
tooltip has a speech-bubble pointer, flips above/below, and supports
dark mode.
- Cursor: smoother 500ms moves with a dwell pulse ring and a crisper
shadow.
- Progress: bottom “Tour” card shows step count and a timed % fill that
advances during dwell, with a “navigating…” state; the tour
auto-restarts after a brief pause; the “Click to take control” overlay
now fades/blurs in; Escape-to-stop is guarded by `isTrusted`. Updated
step copy for clarity.
- **Refactors**
- Removed preview pooling and its cron loop; restored the default health
gate and `Loading` import for preview environments.
<sup>Written for commit efdbe6fc6b.
Summary will update on new commits.</sup>
<a
href="https://cubic.dev/pr/hexclave/hexclave/pull/1511?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>
<!-- End of auto-generated description by cubic. -->
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Added a preview dashboard experience with short-lived, auto-expiring
access leases.
* Enhanced walkthrough tour with improved visual animations, phase-based
styling, and optimized pacing for better user guidance.
* **Documentation**
* Updated internal testing guidance for managed email onboarding
workflows.
<!-- review_stack_entry_start -->
[](https://app.coderabbit.ai/change-stack/hexclave/stack-auth/pull/1511?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack)
<!-- review_stack_entry_end -->
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
---------
Co-authored-by: Cursor <[email protected]>
Fixes four recurring production Sentry issues (triaged from the last 24h
of `vercel-production`):
## X OAuth: 403 client-not-enrolled → 400 (STACK-BACKEND-1JE)
When a customer's X developer App isn't attached to an X API Project, X
deterministically rejects `GET /2/users/me` with 403
`client-not-enrolled` even though the token exchange succeeds. This
previously surfaced as a `HexclaveAssertionError` (opaque 500 + Sentry
alert) on every sign-in attempt for the misconfigured project. It's now
a 400 `StatusError` telling the developer to attach their App to a
Project, mirroring the existing `invalid_client` handling in
`providers/base.tsx`. Other non-OK statuses still fail loud.
## Stripe: ignore `refund.updated` (STACK-BACKEND-1D9)
Stripe emits `refund.updated` asynchronously when the card network fills
in `destination_details` on refunds we created — and already ledgered —
synchronously in the internal refund route, so it carries no actionable
information. Added it to `ignoredEvents` (same approach as #1667/#1461).
`refund.failed` deliberately stays fail-loud, since a refund failing
after it's ledgered is actionable.
## external-db-sync: fix enqueue deadlocks (STACK-BACKEND-16P)
`enqueueExternalDbSyncBatch` batch-inserts deduplication keys with `ON
CONFLICT DO NOTHING`; two concurrent batches inserting overlapping keys
in different orders could deadlock (Postgres 40P01, surfaced as an
empty-titled `PrismaClientKnownRequestError`). Worse than the noise: the
flag-clearing UPDATE and the enqueue run in separate transactions, so a
deadlocked enqueue silently lost that batch's sync trigger until the
next change for the tenancy. Fixed by deduplicating and inserting keys
in canonical (sorted) order, so the circular wait between two batches
can't form. Deliberately minimal: deadlocks against other
`OutgoingRequest` writers (e.g. `recoverStaleOutgoingRequests`) are
theoretically still possible but not evidenced in the Sentry events; if
40P01 reappears, a retry can be added then.
## Password reset: 404 instead of 500 for deleted users
(STACK-BACKEND-1JD)
Password reset codes embed the `user_id` at issuance time, so a code can
be redeemed after the user was deleted (observed in prod from a scripted
client replaying a reset code). The `usersCrudHandlers.adminUpdate` call
didn't declare `UserNotFound` via `allowedErrorTypes`, so the CRUD
handler wrapped it in `CrudHandlerInvocationError` and the endpoint
returned an internal 500. Now declares it and lets the client-safe
`USER_NOT_FOUND` KnownError propagate as a 404, matching the ~10 sibling
call sites that already do this.
## Testing
- New e2e test: resetting the password of a deleted user returns 404
`USER_NOT_FOUND` (`auth/password/reset.test.ts`) — verified passing
locally against the full stack
- Backend + e2e typecheck and lint pass
- No new tests for the other three: the ignore-list entry is covered by
`satisfies Stripe.Event.Type[]` and the existing unknown-type webhook
tests; the X fix would need the X API base URL to be injectable plus a
mock user-info endpoint (possible follow-up); the deadlock is a Postgres
timing race that can't be deterministically reproduced through the e2e
API surface
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Bug Fixes**
* Improved password reset handling when the account no longer exists.
* Added clearer guidance for X API configuration errors.
* Prevented unsupported Stripe refund update events from triggering
processing.
* Ensured external database synchronization requests are deduplicated
and consistently ordered.
* **Tests**
* Added coverage for password reset attempts involving deleted accounts.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
### Context
We were seeing the txn table and the customers tab under product page
OOM.
It turns out this was because the team icon when loaded would fetch all
of the teams.
<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Fixes OOM and renderer crashes in the transactions and product customers
tables by stopping per-row refetch storms and avoiding list‑all‑teams
calls. Infinite scroll is now robust, and shared avatar skeletons keep
table rendering smooth.
- **Bug Fixes**
- Data grid (`@hexclave/dashboard-ui-components` `use-data-source`):
queue `loadMore` while a fetch is in flight and replay only after a
successful settle; discard queued requests when pagination mode leaves
infinite; commit the cursor only after a result is delivered; skip
redundant refetches when inputs match a completed fetch; abort in‑flight
requests on unmount.
- Transactions table and product customers tab: wrap `User*`/`Team*`
avatar cells in `Suspense` with a shared `AvatarCellSkeleton` to prevent
per‑row fetch storms and suspend thrash.
- `serverApp.getTeam`/`useTeam` (in `@hexclave/shared` consumers): fetch
a single team by id via a cache; return null for invalid ids; keep
user‑scoped variants membership‑scoped; stabilize hook order. This
removes the “fetch all teams per row” behavior that triggered OOMs.
- Prefetching: cap `/projects/*/teams` to `useTeams({ limit: 1 })` and
remove the heavy owner‑team users prefetch.
- **Refactors**
- Add unit tests for infinite pagination in `use-data-source` (deferred
`loadMore`, aborted resets, error handling, and cursor continuity).
<sup>Written for commit 970abc0f03.
Summary will update on new commits.</sup>
<a
href="https://cubic.dev/pr/hexclave/hexclave/pull/1766?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>
<!-- End of auto-generated description by cubic. -->
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Bug Fixes**
* Added loading placeholders for customer avatar/name rendering across
payment and transaction customer tables to prevent jarring updates while
data loads.
* Improved infinite data loading to correctly queue and replay “load
more” after in-flight requests, handle abort/reset races, and avoid
stale cursor behavior; deferred requests are discarded when leaving
infinite mode.
* Improved user-scoped team lookups by validating team identifiers and
reliably returning `null` for missing/invalid teams.
* **Documentation**
* Clarified that user-level team lookups only return teams the user is a
member of.
* **Tests**
* Added/expanded coverage for infinite pagination cursor correctness,
race conditions, error handling, and mode transitions.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: aman <[email protected]>
DB migration compat / Back-compat — Current branch migrations with ${{ needs.check-migrations-changed.outputs.base_branch }} branch code (push) Has been cancelled
DB migration compat / Forward-compat — Current branch code with ${{ needs.check-migrations-changed.outputs.base_branch }} branch migrations (push) Has been cancelled
DB migration compat / Back-compat — Current branch migrations with ${{ needs.check-migrations-changed.outputs.base_branch }} branch code (push) Has been cancelled
DB migration compat / Forward-compat — Current branch code with ${{ needs.check-migrations-changed.outputs.base_branch }} branch migrations (push) Has been cancelled
## Summary
- Add an `AGENTS.md` guideline: write comments as if the reader is new
to the codebase but already familiar with the project's goal — explain
the local "why" and non-obvious decisions, not what the project is
trying to achieve.
- Replace `CLAUDE.md` (previously a 5-line stub) with a symlink to
`AGENTS.md` so both entrypoints share a single source of truth.
Link to Devin session:
https://app.devin.ai/sessions/899d319b4b5648d1bb930c2ada976e3f
Requested by: @mantrakp04
<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Add comment-writing guidance in AGENTS.md to explain local “why” and
non-obvious decisions for newcomers. Replace the previous `CLAUDE.md`
stub with a symlink to `AGENTS.md` to keep a single source of truth.
<sup>Written for commit 9bd9570c66.
Summary will update on new commits.</sup>
<a
href="https://cubic.dev/pr/hexclave/hexclave/pull/1725?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>
<!-- End of auto-generated description by cubic. -->
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Documentation**
* Updated guidance on writing comments to focus on local context and
non-obvious decisions for readers new to the codebase.
* Removed a list of documented command examples from the project notes.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: mantra <[email protected]>
Added functionality to log request timings in development mode. Introduced a WeakMap to track request start times and log the elapsed time along with the request method, pathname, and response status after each request. This improves observability during development.