Skip to content

Conversation

sawka
Copy link
Member

@sawka sawka commented Aug 26, 2025

No description provided.

Copy link
Contributor

coderabbitai bot commented Aug 26, 2025

Walkthrough

Adds telemetry collection and plumbing: server populates app:counts events with user-set counts for custom widgets, custom AI presets, and custom settings. Telemetry structs (Go and TypeScript) gain three settings count fields and an app:firstday boolean. RecordTEvent sets app:firstday when TosAgreed is within 24 hours using a cached TosAgreed timestamp helper. Config gains APIs to count custom widgets, AI presets, and settings. Block creation and layout code introduce CreateBlockWithTelemetry and a recordTelemetry flag; starter layouts disable telemetry while normal tab creation enables it. Minor comment and small error-handling tweak included.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Tip

🔌 Remote MCP (Model Context Protocol) integration is now available!

Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch sawka/starterlayout-no-tevent

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.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (8)
pkg/wconfig/settingsconfig.go (3)

748-755: Prefix check for default widgets is fine; consider centralizing the prefix

Logic is correct. Small nit: the "defwidget@" prefix appears as a magic string here. Consider a shared const (e.g., DefaultWidgetPrefix = "defwidget@") to avoid drift if the prefix ever changes.


760-767: Custom AI preset filter works; consider future-proofing reserved IDs

The exclusions "ai@global" and "ai@wave" are hard-coded. If more reserved IDs appear, this will under/over-count. Optional: maintain a small reserved set/map or derive from defaults to keep it in sync.


769-788: Docstring overclaims “from the defaults”

The implementation counts keys present in the user’s settings.json (excluding telemetry:enabled) without comparing against defaults. If that’s intended, tighten the wording; otherwise, implement an actual diff vs defaults.

Apply this minimal doc fix:

-// CountCustomSettings returns the number of settings the user has customized from the defaults.
-// This excludes telemetry:enabled which doesn't count as a customization.
+// CountCustomSettings returns the number of keys present in the user's settings.json,
+// excluding "telemetry:enabled".

Optionally, if you do want a true “diff vs defaults,” I can provide a small helper that loads defaults via ReadDefaultsConfigFile(SettingsFile) and excludes keys whose values match defaults.

pkg/wcore/workspace.go (1)

144-145: Don't silently discard DBFindWindowForWorkspaceId errors (future-proof for real errors).

Today, DBFindWindowForWorkspaceId never returns an error, but if it does in the future, we’ll silently ignore it here. Safer to log non-nil errors and proceed.

- windowId, _ := wstore.DBFindWindowForWorkspaceId(ctx, workspaceId)
+ windowId, findErr := wstore.DBFindWindowForWorkspaceId(ctx, workspaceId)
+ if findErr != nil {
+   log.Printf("error finding window for workspace %s: %v\n", workspaceId, findErr)
+   windowId = ""
+ }
pkg/telemetry/telemetry.go (1)

215-224: Optional: avoid DB hit on every event.

If we only need AppFirstDay for a short window, cache a bool in-process (e.g., atomic.Value) until it expires to skip DBGetSingleton on each RecordTEvent call.

pkg/wcore/layout.go (1)

129-156: Good separation: recordTelemetry param makes layout application telemetricly explicit.

Using CreateBlockWithTelemetry with a per-call flag keeps UX-driven flows (starter vs user actions) clean. One nit: the debug log prints the full layout, which may include URLs/paths; consider reducing verbosity or guarding by a debug flag.

- log.Printf("ApplyPortableLayout, tabId: %s, layout: %v\n", tabId, layout)
+ // Consider trimming or gating this log to avoid noisy/PII-ish output.
+ log.Printf("ApplyPortableLayout, tabId: %s, actions=%d\n", tabId, len(layout))
pkg/wcore/block.go (2)

63-105: Safer to capture BlockView before launching goroutine to avoid pointer races.

recordBlockCreationTelemetry reads from blockDef.Meta inside a goroutine. While unlikely mutated, capturing the view upfront avoids any future concurrency hazards.

- if recordTelemetry {
-   go recordBlockCreationTelemetry(blockDef)
- }
+ if recordTelemetry {
+   blockView := blockDef.Meta.GetString(waveobj.MetaKey_View, "")
+   if blockView != "" {
+     go recordBlockCreationTelemetry(blockView)
+   }
+ }

And update the helper signature accordingly (see next comment).


107-126: Refactor helper to accept the computed view string.

Decouples the goroutine from the original BlockDef pointer and simplifies the function.

-func recordBlockCreationTelemetry(blockDef *waveobj.BlockDef) {
+func recordBlockCreationTelemetry(blockView string) {
   defer func() {
     panichandler.PanicHandler("CreateBlock:telemetry", recover())
   }()
-  blockView := blockDef.Meta.GetString(waveobj.MetaKey_View, "")
-  if blockView == "" {
-    return
-  }
   tctx, cancelFn := context.WithTimeout(context.Background(), 2*time.Second)
   defer cancelFn()
   telemetry.UpdateActivity(tctx, wshrpc.ActivityUpdate{
     Renderers: map[string]int{blockView: 1},
   })
   telemetry.RecordTEvent(tctx, &telemetrydata.TEvent{
     Event: "action:createblock",
     Props: telemetrydata.TEventProps{
       BlockView: blockView,
     },
   })
 }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between d47b9f2 and 12faedb.

📒 Files selected for processing (9)
  • cmd/server/main-server.go (1 hunks)
  • frontend/types/gotypes.d.ts (2 hunks)
  • pkg/telemetry/telemetry.go (4 hunks)
  • pkg/telemetry/telemetrydata/telemetrydata.go (2 hunks)
  • pkg/waveobj/wtype.go (1 hunks)
  • pkg/wconfig/settingsconfig.go (1 hunks)
  • pkg/wcore/block.go (2 hunks)
  • pkg/wcore/layout.go (2 hunks)
  • pkg/wcore/workspace.go (2 hunks)
🧰 Additional context used
🧬 Code graph analysis (6)
cmd/server/main-server.go (3)
pkg/wconfig/filewatcher.go (1)
  • GetWatcher (33-57)
pkg/wconfig/settingsconfig.go (1)
  • CountCustomSettings (771-788)
pkg/telemetry/telemetrydata/telemetrydata.go (1)
  • TEventUserProps (47-64)
pkg/wcore/layout.go (2)
pkg/waveobj/wtype.go (3)
  • LayoutActionData (204-214)
  • BlockDef (241-244)
  • RuntimeOpts (264-267)
pkg/wcore/block.go (1)
  • CreateBlockWithTelemetry (63-105)
pkg/telemetry/telemetrydata/telemetrydata.go (1)
pkg/telemetry/telemetry.go (1)
  • AutoUpdateChannel (85-88)
pkg/wcore/block.go (6)
pkg/waveobj/wtype.go (3)
  • BlockDef (241-244)
  • Block (279-287)
  • Block (289-291)
pkg/panichandler/panichandler.go (1)
  • PanicHandler (25-43)
pkg/waveobj/metaconsts.go (1)
  • MetaKey_View (9-9)
pkg/telemetry/telemetry.go (2)
  • UpdateActivity (269-358)
  • RecordTEvent (203-230)
pkg/wshrpc/wshrpctypes.go (1)
  • ActivityUpdate (713-737)
pkg/telemetry/telemetrydata/telemetrydata.go (2)
  • TEvent (33-45)
  • TEventProps (66-99)
pkg/telemetry/telemetry.go (2)
pkg/wstore/wstore_dbops.go (1)
  • DBGetSingleton (102-105)
pkg/waveobj/wtype.go (2)
  • Client (125-133)
  • Client (135-137)
pkg/wcore/workspace.go (2)
pkg/wstore/wstore_dbops.go (1)
  • DBFindWindowForWorkspaceId (396-403)
pkg/wcore/layout.go (2)
  • ApplyPortableLayout (129-156)
  • GetNewTabLayout (82-91)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: Analyze (go)
  • GitHub Check: Build for TestDriver.ai
🔇 Additional comments (9)
pkg/waveobj/wtype.go (1)

130-131: Clarifying unit on TosAgreed is helpful

Explicitly documenting that TosAgreed is in Unix milliseconds reduces ambiguity when doing time math elsewhere. LGTM.

frontend/types/gotypes.d.ts (2)

827-834: Additions align with backend telemetry payloads

The new props (settings:customwidgets, settings:customaipresets, settings:customsettings, app:firstday) match the Go JSON tags and look correct. LGTM.


869-872: User props additions look consistent

TEventUserProps entries for custom settings/presets/widgets match the server’s $set usage. LGTM.

pkg/telemetry/telemetrydata/telemetrydata.go (2)

61-64: New user-prop fields are well-scoped

Adding settings:customwidgets, settings:customaipresets, settings:customsettings as ints with omitempty is appropriate. They’ll drop out when zero. LGTM.


73-74: Confirmed AppFirstDay logic is correct
The RecordTEvent implementation in pkg/telemetry/telemetry.go sets AppFirstDay only when:

  • client.TosAgreed is non-zero, and
  • the difference between time.Now().UnixMilli() and client.TosAgreed is at most 24 hours (24 × 60 × 60 × 1000 ms).

No further changes are required.

pkg/wcore/workspace.go (1)

222-229: All ApplyPortableLayout calls updated to include telemetry flag

  • Verified that there are no remaining calls to ApplyPortableLayout using the old three-argument signature; the only invocation in pkg/wcore/workspace.go now has four arguments (ctx, tab.OID, GetNewTabLayout(), true) as intended.

LGTM—thanks for making the telemetry flag explicit for user-created layouts.

pkg/telemetry/telemetry.go (1)

21-22: LGTM: waveobj import is required for Client lookup.

Necessary for DBGetSingleton[*waveobj.Client]. No issues.

pkg/wcore/layout.go (1)

187-190: LGTM: starter layout correctly disables telemetry.

Setting recordTelemetry=false for BootstrapStarterLayout matches the PR’s objective to avoid first-run telemetry noise.

pkg/wcore/block.go (1)

59-61: LGTM: CreateBlock remains as a thin wrapper; defaulting to telemetry-on preserves behavior.

Wrapper preserves API while routing to the new function. Good for incremental adoption.

Comment on lines +149 to +159
fullConfig := wconfig.GetWatcher().GetFullConfig()
customWidgets := fullConfig.CountCustomWidgets()
customAIPresets := fullConfig.CountCustomAIPresets()
customSettings := wconfig.CountCustomSettings()

props.UserSet = &telemetrydata.TEventUserProps{
SettingsCustomWidgets: customWidgets,
SettingsCustomAIPresets: customAIPresets,
SettingsCustomSettings: customSettings,
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Potential nil-pointer if the config watcher failed to initialize

wconfig.GetWatcher() can return nil (e.g., fsnotify initialization failure), leading to a panic on .GetFullConfig(). Add a nil-guard and fall back to wconfig.ReadFullConfig().

Apply this diff:

-	fullConfig := wconfig.GetWatcher().GetFullConfig()
-	customWidgets := fullConfig.CountCustomWidgets()
-	customAIPresets := fullConfig.CountCustomAIPresets()
-	customSettings := wconfig.CountCustomSettings()
+	watcher := wconfig.GetWatcher()
+	var fullConfig wconfig.FullConfigType
+	if watcher != nil {
+		fullConfig = watcher.GetFullConfig()
+	} else {
+		// fallback without watcher (e.g., fsnotify unavailable)
+		fullConfig = wconfig.ReadFullConfig()
+	}
+	customWidgets := fullConfig.CountCustomWidgets()
+	customAIPresets := fullConfig.CountCustomAIPresets()
+	customSettings := wconfig.CountCustomSettings()
 
 	props.UserSet = &telemetrydata.TEventUserProps{
 		SettingsCustomWidgets:   customWidgets,
 		SettingsCustomAIPresets: customAIPresets,
 		SettingsCustomSettings:  customSettings,
 	}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
fullConfig := wconfig.GetWatcher().GetFullConfig()
customWidgets := fullConfig.CountCustomWidgets()
customAIPresets := fullConfig.CountCustomAIPresets()
customSettings := wconfig.CountCustomSettings()
props.UserSet = &telemetrydata.TEventUserProps{
SettingsCustomWidgets: customWidgets,
SettingsCustomAIPresets: customAIPresets,
SettingsCustomSettings: customSettings,
}
watcher := wconfig.GetWatcher()
var fullConfig wconfig.FullConfigType
if watcher != nil {
fullConfig = watcher.GetFullConfig()
} else {
// fallback without watcher (e.g., fsnotify unavailable)
fullConfig = wconfig.ReadFullConfig()
}
customWidgets := fullConfig.CountCustomWidgets()
customAIPresets := fullConfig.CountCustomAIPresets()
customSettings := wconfig.CountCustomSettings()
props.UserSet = &telemetrydata.TEventUserProps{
SettingsCustomWidgets: customWidgets,
SettingsCustomAIPresets: customAIPresets,
SettingsCustomSettings: customSettings,
}
🤖 Prompt for AI Agents
In cmd/server/main-server.go around lines 149-159, guard against a nil
wconfig.GetWatcher() before calling .GetFullConfig(): retrieve watcher :=
wconfig.GetWatcher(); if watcher == nil, call fullConfig :=
wconfig.ReadFullConfig(); otherwise call fullConfig := watcher.GetFullConfig();
then compute customWidgets, customAIPresets and customSettings from that
fullConfig (use fullConfig.CountCustomWidgets(),
fullConfig.CountCustomAIPresets(), fullConfig.CountCustomSettings() or the
appropriate fullConfig methods) and populate props.UserSet as before so the code
won’t panic when the watcher failed to initialize.

Comment on lines +827 to 834
"settings:customwidgets"?: number;
"settings:customaipresets"?: number;
"settings:customsettings"?: number;
"activity:activeminutes"?: number;
"activity:fgminutes"?: number;
"activity:openminutes"?: number;
"app:firstday"?: boolean;
"action:initiator"?: "keyboard" | "mouse";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Ensure the TS generator is updated, since this file is generated

This file is marked as generated. Please confirm cmd/generate/main-generatets.go (or related generator) includes these new fields to avoid losing them on the next regen.

Run this to verify generator references exist:


🏁 Script executed:

#!/bin/bash
# Look for new telemetry fields in the generator sources
rg -n --hidden -C2 -g 'cmd/generate/**' -e 'settings:customwidgets|settings:customaipresets|settings:customsettings|app:firstday'

Length of output: 280


It looks like the original ripgrep glob didn’t match any files. Let’s explicitly locate the TS generator and search it for the new fields:


🏁 Script executed:

#!/bin/bash
# 1. Locate the TypeScript generator file
gen_file=$(fd --hidden --full-path 'main-generatets.go' || echo "")

if [ -z "$gen_file" ]; then
  echo "⚠️ Generator file main-generatets.go not found under cmd/generate or elsewhere."
  exit 0
fi

echo "🔍 Found generator at: $gen_file"
echo "🔎 Searching for new telemetry fields in the generator…"

# 2. Search for the new telemetry keys
rg -n 'settings:customwidgets|settings:customaipresets|settings:customsettings|activity:activeminutes|activity:fgminutes|activity:openminutes|app:firstday|action:initiator' "$gen_file" || \
  echo "❌ No references to the new fields were found in the TS generator."

Length of output: 731


TS generator missing new telemetry fields

I verified that cmd/generatets/main-generatets.go does not reference the newly added keys in frontend/types/gotypes.d.ts. Without updating the generator, these fields will be dropped on the next regeneration. Please add support for the following telemetry keys in the TS generator:

  • settings:customwidgets
  • settings:customaipresets
  • settings:customsettings
  • activity:activeminutes
  • activity:fgminutes
  • activity:openminutes
  • app:firstday
  • action:initiator
🤖 Prompt for AI Agents
In frontend/types/gotypes.d.ts around lines 827-834, the TS generator
cmd/generatets/main-generatets.go is missing the newly added telemetry keys so
they will be dropped on regen; update the generator by adding entries for these
keys to the telemetry/field mapping (or schema list) with the correct types:
settings:customwidgets -> number, settings:customaipresets -> number,
settings:customsettings -> number, activity:activeminutes -> number,
activity:fgminutes -> number, activity:openminutes -> number, app:firstday ->
boolean, action:initiator -> union "keyboard" | "mouse"; after adding those
mappings, run the generator to confirm the keys appear in the produced
frontend/types/gotypes.d.ts.

Comment on lines 215 to 224

// Set AppFirstDay if within first day of TOS agreement
client, err := wstore.DBGetSingleton[*waveobj.Client](ctx)
if err == nil && client != nil && client.TosAgreed != 0 {
now := time.Now().UnixMilli()
oneDayMs := int64(24 * 60 * 60 * 1000)
if now-client.TosAgreed <= oneDayMs {
tevent.Props.AppFirstDay = true
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix first-day check: negative time skew incorrectly sets app:firstday.

If system clock is behind TosAgreed, now - TosAgreed is negative and currently satisfies <= oneDayMs, incorrectly setting AppFirstDay=true. Guard for non-negative deltas.

- // Set AppFirstDay if within first day of TOS agreement
- client, err := wstore.DBGetSingleton[*waveobj.Client](ctx)
- if err == nil && client != nil && client.TosAgreed != 0 {
-   now := time.Now().UnixMilli()
-   oneDayMs := int64(24 * 60 * 60 * 1000)
-   if now-client.TosAgreed <= oneDayMs {
-     tevent.Props.AppFirstDay = true
-   }
- }
+ // Set AppFirstDay if within first day of TOS agreement
+ client, err := wstore.DBGetSingleton[*waveobj.Client](ctx)
+ if err == nil && client != nil && client.TosAgreed != 0 {
+   diff := time.Since(time.UnixMilli(client.TosAgreed))
+   if diff >= 0 && diff <= 24*time.Hour {
+     tevent.Props.AppFirstDay = true
+   }
+ }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Set AppFirstDay if within first day of TOS agreement
client, err := wstore.DBGetSingleton[*waveobj.Client](ctx)
if err == nil && client != nil && client.TosAgreed != 0 {
now := time.Now().UnixMilli()
oneDayMs := int64(24 * 60 * 60 * 1000)
if now-client.TosAgreed <= oneDayMs {
tevent.Props.AppFirstDay = true
}
}
// Set AppFirstDay if within first day of TOS agreement
client, err := wstore.DBGetSingleton[*waveobj.Client](ctx)
if err == nil && client != nil && client.TosAgreed != 0 {
diff := time.Since(time.UnixMilli(client.TosAgreed))
if diff >= 0 && diff <= 24*time.Hour {
tevent.Props.AppFirstDay = true
}
}
🤖 Prompt for AI Agents
In pkg/telemetry/telemetry.go around lines 215 to 224, the first-day check can
be true when system clock is behind TosAgreed (now-TosAgreed negative); change
the condition to ensure the delta is non-negative and within oneDayMs (e.g.,
require TosAgreed <= now AND now - TosAgreed <= oneDayMs, or explicitly check
delta >= 0 && delta <= oneDayMs) before setting tevent.Props.AppFirstDay = true.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (1)
pkg/telemetry/telemetry.go (1)

236-241: Fix first-day check: handle clock skew and don't treat unknown TosAgreed as first-day.

  • Negative deltas (system clock behind TosAgreed) currently pass the check and incorrectly set AppFirstDay=true.
  • Treating tosAgreedTs == 0 (unknown/unset) as first day will mislabel long-time users who don't have TosAgreed populated.

Apply this safer check:

-	// Set AppFirstDay if within first day of TOS agreement
-	tosAgreedTs := GetTosAgreedTs()
-	if tosAgreedTs == 0 || (tosAgreedTs != 0 && time.Now().UnixMilli()-tosAgreedTs <= int64(24*60*60*1000)) {
-		tevent.Props.AppFirstDay = true
-	}
+	// Set AppFirstDay only if TosAgreed is known and within 24h (guard against negative deltas)
+	tosAgreedTs := GetTosAgreedTs(ctx)
+	if tosAgreedTs > 0 {
+		if d := time.Since(time.UnixMilli(tosAgreedTs)); d >= 0 && d <= 24*time.Hour {
+			tevent.Props.AppFirstDay = true
+		}
+	}
🧹 Nitpick comments (2)
pkg/telemetry/telemetry.go (2)

31-31: Expose a test-only helper to reset the cached TosAgreed timestamp.

Atomic cache is process-wide; tests may leak state across cases. Provide a test-only reset to ensure deterministic tests.

Example (new file pkg/telemetry/telemetry_testhelpers.go):

//go:build test

package telemetry

func ResetTosAgreedCacheForTest() {
	cachedTosAgreedTs.Store(0)
}

33-48: Add a doc comment for exported GetTosAgreedTs.

Public identifiers should have GoDoc. Add a brief comment describing cache semantics and ctx usage (nil => short timeout).

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 3036946 and d2861d9.

📒 Files selected for processing (1)
  • pkg/telemetry/telemetry.go (6 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
pkg/telemetry/telemetry.go (2)
pkg/wstore/wstore_dbops.go (1)
  • DBGetSingleton (102-105)
pkg/waveobj/wtype.go (2)
  • Client (125-133)
  • Client (135-137)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: Build for TestDriver.ai
  • GitHub Check: Analyze (go)
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: Build Docsite
  • GitHub Check: merge-gatekeeper
🔇 Additional comments (2)
pkg/telemetry/telemetry.go (2)

242-246: Confirm whether AppFirstDay should be persisted on app:activity events.

RecordTEvent sets tevent.Props.AppFirstDay, but updateActivityTEvent merges only minute counters (mergeActivity) before storing, so AppFirstDay may be dropped for app:activity rows. If downstream expects AppFirstDay on app:activity, consider carrying it through (e.g., OR it into curActivity before writing) or emitting a separate lightweight event when true.


159-159: No-op formatting change.

Blank line changes; nothing to review.

Also applies to: 175-175

Comment on lines +33 to +48
func GetTosAgreedTs() int64 {
cached := cachedTosAgreedTs.Load()
if cached != 0 {
return cached
}

ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel()
client, err := wstore.DBGetSingleton[*waveobj.Client](ctx)
if err != nil || client == nil || client.TosAgreed == 0 {
return 0
}

cachedTosAgreedTs.Store(client.TosAgreed)
return client.TosAgreed
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Make GetTosAgreedTs context-aware and avoid unconditional background work.

Use the caller's context so RecordTEvent's 2s budget is respected and cancellations propagate. Keep a bounded timeout only when ctx is nil.

-func GetTosAgreedTs() int64 {
+// GetTosAgreedTs returns the cached TosAgreed timestamp (unix ms) if available.
+// If not cached, it reads it from the store using the provided context. If ctx is nil,
+// a short timeout is used to avoid blocking telemetry paths.
+func GetTosAgreedTs(ctx context.Context) int64 {
 	cached := cachedTosAgreedTs.Load()
 	if cached != 0 {
 		return cached
 	}
 
-	ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
-	defer cancel()
+	if ctx == nil {
+		var cancel context.CancelFunc
+		ctx, cancel = context.WithTimeout(context.Background(), 2*time.Second)
+		defer cancel()
+	}
 	client, err := wstore.DBGetSingleton[*waveobj.Client](ctx)
 	if err != nil || client == nil || client.TosAgreed == 0 {
 		return 0
 	}
 
 	cachedTosAgreedTs.Store(client.TosAgreed)
 	return client.TosAgreed
 }

Follow-up: update the sole call site in RecordTEvent (see separate comment) to pass ctx.

Run this to confirm no other call sites exist and the signature update compiles cleanly:


🏁 Script executed:

#!/bin/bash
# Find calls to GetTosAgreedTs (old signature) that need ctx
rg -nP '\bGetTosAgreedTs\s*\(' -C2

Length of output: 696


Make GetTosAgreedTs context-aware and update its sole call site

To ensure timeouts and cancellations propagate from the caller, change GetTosAgreedTs to accept a context.Context and only synthesize a background timeout when none is provided. This is a breaking signature change—update the one call site in RecordTEvent to pass its ctx.

• File pkg/telemetry/telemetry.go, lines 33–48:

-func GetTosAgreedTs() int64 {
+// GetTosAgreedTs returns the cached TosAgreed timestamp (unix ms) if available.
// If not cached, it reads it from the store using the provided context.
// If ctx is nil, a 2s background timeout is used.
+func GetTosAgreedTs(ctx context.Context) int64 {
     cached := cachedTosAgreedTs.Load()
     if cached != 0 {
         return cached
     }

-    ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
-    defer cancel()
+    if ctx == nil {
+        var cancel context.CancelFunc
+        ctx, cancel = context.WithTimeout(context.Background(), 2*time.Second)
+        defer cancel()
+    }

     client, err := wstore.DBGetSingleton[*waveobj.Client](ctx)
     if err != nil || client == nil || client.TosAgreed == 0 {
         return 0
     }

     cachedTosAgreedTs.Store(client.TosAgreed)
     return client.TosAgreed
 }

• File pkg/telemetry/telemetry.go, around line 237 (in RecordTEvent):

-   tosAgreedTs := GetTosAgreedTs()
+   tosAgreedTs := GetTosAgreedTs(ctx)

With only this one call site, the change will compile cleanly once updated.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
func GetTosAgreedTs() int64 {
cached := cachedTosAgreedTs.Load()
if cached != 0 {
return cached
}
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel()
client, err := wstore.DBGetSingleton[*waveobj.Client](ctx)
if err != nil || client == nil || client.TosAgreed == 0 {
return 0
}
cachedTosAgreedTs.Store(client.TosAgreed)
return client.TosAgreed
}
// pkg/telemetry/telemetry.go
// GetTosAgreedTs returns the cached TosAgreed timestamp (unix ms) if available.
// If not cached, it reads it from the store using the provided context.
// If ctx is nil, a 2s background timeout is used.
func GetTosAgreedTs(ctx context.Context) int64 {
cached := cachedTosAgreedTs.Load()
if cached != 0 {
return cached
}
- ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
if ctx == nil {
var cancel context.CancelFunc
ctx, cancel = context.WithTimeout(context.Background(), 2*time.Second)
defer cancel()
}
client, err := wstore.DBGetSingleton[*waveobj.Client](ctx)
if err != nil || client == nil || client.TosAgreed == 0 {
return 0
}
cachedTosAgreedTs.Store(client.TosAgreed)
return client.TosAgreed
}
Suggested change
func GetTosAgreedTs() int64 {
cached := cachedTosAgreedTs.Load()
if cached != 0 {
return cached
}
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel()
client, err := wstore.DBGetSingleton[*waveobj.Client](ctx)
if err != nil || client == nil || client.TosAgreed == 0 {
return 0
}
cachedTosAgreedTs.Store(client.TosAgreed)
return client.TosAgreed
}
// pkg/telemetry/telemetry.go, inside RecordTEvent (around original line 237)
tosAgreedTs := GetTosAgreedTs(ctx)
🤖 Prompt for AI Agents
In pkg/telemetry/telemetry.go around lines 33–48 change GetTosAgreedTs to accept
a context.Context parameter (breaking change) and use that context when calling
wstore.DBGetSingleton; if the passed ctx is nil, synthesize a background context
with a 2s timeout (use context.WithTimeout(context.Background(), 2*time.Second)
and defer cancel), otherwise use the caller's ctx directly so
timeouts/cancellations propagate; also update the single caller in
pkg/telemetry/telemetry.go around line 237 (RecordTEvent) to pass its ctx into
the new GetTosAgreedTs(ctx) signature so the code compiles.

@sawka sawka merged commit b81b824 into main Aug 26, 2025
9 of 10 checks passed
@sawka sawka deleted the sawka/starterlayout-no-tevent branch August 26, 2025 23:08
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.

1 participant