Release: staging -> main (privacy controls, insights, AI investigation pipeline)#492
Conversation
- Replace `cn` implementation in packages/ui, apps/dashboard, apps/docs
with a re-export from cnfast (drop-in, byte-identical output).
- Drop tailwind-merge from all three workspaces and the catalog. Drop
clsx from packages/ui and apps/docs (apps/dashboard still imports it
directly).
- Pin apps/dashboard `radix-ui` from `latest` to `^1.4.3` (matches the
apps/docs pin and currently resolved version). The `latest` sentinel
was a re-resolve time bomb: any `bun install` pulled radix-ui@1.6.0
and cascade-bumped every @radix-ui/* transitive, which introduced a
`--radix-${string}` CSS index signature that breaks @hello-pangea/dnd
typing in edit-funnel-dialog.tsx.
Addresses cubic review findings on PR #491. - Visitor country for "auto" anonymization now derives from extractTrustedClientIp(request) (gated on IP_HEADER_VERIFIED), not the raw extractIpFromRequest result. Forged client IP headers could previously flip auto-mode events out of anonymization and store raw visitor IDs. Default-safe: missing trusted IP -> undefined country -> shouldAnonymizeVisitorIds returns true. (P1) - Extracts getVisitorCountryForAutoMode into @utils/ip-geo so basket and track routes share one implementation. Removes the duplicate inline path in track.ts and the redundant insertCustomEvents branching. (P3) - Applies the same trusted-country gate to processTrackEventData, insertTrackEvent, insertOutgoingLink, and the batch route's getBatchVisitorCountry closure (same root cause, same file). - Tracker errors.ts: move anonymizeVisitorIds after the ...error spread so an error payload carrying that key cannot silently overwrite tracker-level privacy config. (P2) - Add anonymizeVisitorIds to the legacy webVitalsEventSchema payload so v1-format clients no longer silently drop the flag. (P2) - Make anonymizeVisitorIds .nullable().optional() and transform null -> undefined at the schema boundary across analytics, errors, web-vitals, and custom-events. Matches every other optional field and keeps downstream types as boolean | "auto" | undefined. (P3) - Rewrite the "ignores object-not-found rejection noise" test as a deterministic noise+sentinel assertion (was a 250ms waitForTimeout + assert false, racy). (P2)
Follow-up to 3716b58. The integration test suite asserts insertCustomEvents is called with a single events arg when no event opted into auto-mode anonymization. Restoring the existing `if (visitorCountry === undefined)` branch in both routes keeps the call signature compatible, and adds the new getVisitorCountryForAutoMode export to the @utils/ip-geo mock so 18 vitest cases that previously crashed with `undefined is not a function` pass again.
…anching Desloppify pass on the trust-gate changes from 3716b58 / f8ca22e. - insertTrackEvent, insertOutgoingLink, processTrackEventData all take request: Request now. The parameter was already passed by every caller; the `?` was defensive sloppy typing, and forced `request &&` guards before extractTrustedClientIp(request) at three call sites. - Drop the `if (visitorCountry === undefined)` branch in basket.ts and track.ts. insertCustomEvents(events, undefined) is identical to insertCustomEvents(events); the conditional was over-specified test surface, not behavior. Updates the 6 integration assertions to call toHaveBeenCalledWith([...], undefined). - insertOutgoingLink: extractTrustedClientIp already returns null when IP_HEADER_VERIFIED is false, so the `request ? ... : null` ternary was redundant.
- security.ts: applyVisitorIdPrivacy now throws when salt is undefined but anonymizeVisitorIds is true. The previous `salt ?? ""` fallback silently produced a deterministic, day-invariant hash that defeated daily salt rotation. All current callers fetch the salt before calling, so this is a future-regression guard. - event-service.ts: drop unused ip param from insertOutgoingLink; it now derives the trusted IP from request via extractTrustedClientIp, matching insertTrackEvent. - basket.ts: drop ip from /vitals, /errors, /events validateRequest destructuring (no longer used after the getVisitorCountryForAutoMode refactor); update insertOutgoingLink call sites for the dropped param. - cockpit-signals.tsx: client-side "Newest" sort now uses resolvedAt ?? createdAt, matching the server's COALESCE(resolvedAt, createdAt) default sort. Without this, picking "Newest" reordered resolved insights vs the default load order. - Format: long imports auto-wrapped by biome.
…cy-cleanup-staging Fix insights scan issues and resolution UI
Replace NEVER_STOP with a stepCountIs(24) ceiling so agent runs converge before per-step latency exhausts the wall-clock budget.
Each phase of the investigation brief now fans out its independent queries in a single turn instead of one tool call per step. Halves agent steps (15 to 7) and brings wall time inside the budget.
A synthesis timeout or invalid object previously threw away the entire agent run. Fall back to a low-confidence memo built from the agent's findings so the expensive investigation isn't lost.
…iring Narrow the try/catch around generateObject so render and receipt errors propagate instead of being mislabeled as synthesis failures. Add a wiring test that drives runInvestigation through both the success and synthesis-throw paths.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
1 Skipped Deployment
|
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Repository UI Review profile: ASSERTIVE Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
The latest updates on your projects. Learn more about Unkey Deploy
|
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
There was a problem hiding this comment.
2 issues found across 55 files
Confidence score: 4/5
- In
packages/rpc/src/routers/insights.ts, switching history sorting tocoalesce(resolved_at, created_at)without a matching index can cause slower queries as org data grows, which could show up as higher latency in insights/history endpoints after release — add an expression index (or a persisted sortable column) before merging to de-risk regression. - In
apps/docs/app/(home)/pricing/_pricing/estimator.tsx, the new CTA tracking helper now diverges from existing pricing tracking logic, which can lead to inconsistent analytics payloads between estimator and table placements and noisier reporting — extract a shared helper that acceptsplacementand reuse it in both components before merge (or immediately after as a follow-up).
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="packages/rpc/src/routers/insights.ts">
<violation number="1" location="packages/rpc/src/routers/insights.ts:546">
P2: History query switched to expression-based ORDER BY without a matching index, which can regress latency on large orgs. Add an expression index (or equivalent sortable column) for `coalesce(resolved_at, created_at)` scoped by org/website filters.</violation>
</file>
Architecture diagram
sequenceDiagram
participant Tracker as Browser Tracker
participant NodeSDK as Node/Vue SDK
participant Basket as Basket API
participant Security as Security Module
participant Geo as IP Geo Utils
participant DB as ClickHouse
participant AI as AI Investigation
participant Dashboard as Dashboard UI
participant Docs as Docs Site
Note over Tracker,Docs: Visitor Privacy Controls
Tracker->>Tracker: emit event with anonymizeVisitorIds setting
Tracker->>Basket: POST /track, /errors, /web-vitals, /outgoing_link
Note over Basket: extract request from payload
Basket->>Geo: extractTrustedClientIp(request)
Geo-->>Basket: trusted IP or null
alt Trusted IP present
Basket->>Geo: getGeo(trustedIp, request)
Geo-->>Basket: geoData (country)
end
Basket->>Security: shouldAnonymizeVisitorIds(setting, country)
Security-->>Basket: boolean decision
alt anonymizeVisitorIds = true or "auto" with non-US country
Basket->>Security: getDailySalt()
Security-->>Basket: daily salt
Basket->>Security: applyVisitorIdPrivacy(rawId, true, salt)
Security-->>Basket: salted/hashed ID
else anonymizeVisitorIds = false or "auto" with US country
Basket->>Security: applyVisitorIdPrivacy(rawId, false)
Security-->>Basket: raw ID unchanged
end
Basket->>DB: insert event with processed ID
Note over Tracker,Docs: Error & Vitals Filtering
Tracker->>Tracker: onerror / onunhandledrejection handler
Tracker->>Tracker: filter browser runtime noise patterns
Tracker->>Tracker: filter extension source errors
Tracker->>Basket: POST with filtered errors + anonymizeVisitorIds
Note over AI: Investigation Pipeline
AI->>AI: runInvestigation()
AI->>AI: build phase-batched queries
loop per phase (max 24 steps)
AI->>AI: batch all independent queries in 1 turn
AI->>AI: emit parallel tool calls
end
AI->>AI: generateObject() for memo synthesis
alt synthesis succeeds
AI-->>AI: structured memo
else synthesis fails
AI->>AI: buildFallbackMemo(answer)
AI-->>AI: low-confidence fallback memo
end
AI-->>Dashboard: investigation result
Note over Dashboard: Insights & Resolution
Dashboard->>DB: query insights with COALESCE(resolvedAt, createdAt) sort
DB-->>Dashboard: insights including status, resolvedAt, resolvedReason
Dashboard->>Dashboard: render status labels (Recovered/Archived)
Dashboard->>Dashboard: filter resolved insights count
Note over Docs: Pricing Click Tracking
Docs->>NodeSDK: track("pricing_plan_clicked", {plan, placement})
NodeSDK->>Basket: POST /track with anonymizeVisitorIds config
Shadow auto-approve: would not auto-approve because issues were found.
Re-trigger cubic
…n tests Ultracite-format stop-conditions.ts and investigate.ts to satisfy CI lint. Spread the real `ai` and `run-agent` modules in the wiring test instead of replacing them wholesale, which dropped the `createGateway` export and crashed the package test suite at load. Restore both modules in afterAll to contain the mock within this file.
Extract trackPricingPlanClick(planId, placement) so the comparison table and estimator emit identical pricing_plan_clicked payloads, removing the duplicate inline trackers that could drift. Addresses cubic P3 on PR #492.
…d_at) The history query orders by coalesce(resolved_at, created_at) desc but every existing index sorts on created_at, so large orgs fall back to a sort. Add org- and website-scoped expression indexes matching the query. Addresses cubic P2 on PR #492.
There was a problem hiding this comment.
1 issue found across 17 files (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="apps/api/src/routes/health.ts">
<violation number="1" location="apps/api/src/routes/health.ts:22">
P2: Unthrottled error-level logging in health check probe failures can generate log storms during outages. Health endpoints are polled frequently by load balancers and orchestrators; without throttling, sampling, or deduplication, every failed probe emits an error log, creating high-volume repetitive noise that increases log costs and obscures actionable signals.</violation>
</file>
Shadow auto-approve: would not auto-approve because issues were found.
Tip: Review your code locally with the cubic CLI to iterate faster.
Re-trigger cubic
There was a problem hiding this comment.
0 issues found across 2 files (changes from recent commits).
Shadow auto-approve: would not auto-approve. Auto-approval blocked by 1 unresolved issue from previous reviews.
Re-trigger cubic
There was a problem hiding this comment.
0 issues found across 3 files (changes from recent commits).
Shadow auto-approve: would not auto-approve. Auto-approval blocked by 1 unresolved issue from previous reviews.
Re-trigger cubic
Summary
Staging -> main release. 18 commits across two themes:
Visitor privacy + tracker (basket/tracker/sdk/validation)
insertCustomEvents1-arg call when no auto country; drops defensive request optionalityDashboard / insights / docs / CI / deps
tailwind-merge+clsxforcnfast, pinradix-uiAI investigation pipeline (packages/ai)
generateObjectonly; cover the fallback wiring with testsTest plan
packages/aitypecheck clean; investigate + wiring tests 20/20check-typesgreen (34/34 via pre-commit hook)Summary by cubic
Release staging to main with end-to-end visitor ID privacy (“auto” gated by verified client IP), resolved insights with labels/sorting, refreshed goals/settings, and a faster, more reliable investigation pipeline. Also ships safer public/docs error responses with restricted status codes, normalized
@databuddy/rpcand OpenAPI output (new monitor/status-page scopes and Uptime routes), redacted logging across services, and a cataloged ingest error schema.New Features
read:monitors,write:monitors,read:status_pages,write:status_pages; expose Uptime routes; improve tags/description and show required scopes per operation.Bug Fixes
"auto"visitor-ID decisions using verified client IP; support per-eventanonymizeVisitorIdswith tracker-level precedence; return sanitized per-item schema errors; catalog stable error codes.@databuddy/auth/permissionssubpath and fix export init race.databuddyEvlogRedactionand typed wide-event fields across services.Written for commit 261fab5. Summary will update on new commits.