We need to add robust, privacy-conscious performance telemetry to ASTRA before attempting responsiveness fixes.
Repo: /Users/alvaro/.codex/worktrees/0fd5/astra
Context:
Users with many workspaces, many threads, and long threads report severe responsiveness degradation: slow chat opening, slow chat scrolling, sidebar/search sluggishness, and occasional nonresponsive app behavior. Prior investigation found likely hot paths where SwiftUI/UI code reads full durable relationships (task.events, task.runs, run.output, all tasks) in places that should be cheap.
Goal:
Implement a telemetry-only slice that gives us a much better picture of real app performance on large ASTRA instances. Do not optimize behavior yet except for tiny helper extraction needed for clean instrumentation. The deliverable is measurement, not the fix.
Important constraints:
- Follow AGENTS.md: avoid monoliths, preserve single responsibility, find root causes, write relevant tests.
- Keep telemetry privacy-safe. Do not log task titles, goals, event payloads, run output, file contents, or full paths.
- Use stable IDs only in already-established abbreviated form when useful, e.g. first 8 chars of UUID.
- Avoid logging on every SwiftUI body pass without throttling/thresholding.
- Prefer a reusable telemetry helper over scattered ad hoc string construction.
- Existing telemetry lives in
Astra/Services/Diagnostics/PerformanceTelemetry.swift.
- Existing logs are under
~/Library/Logs/Astra and ~/Library/Logs/AstraDev.
Add telemetry for these missing performance surfaces:
-
Store/app scale snapshot
- On app startup or first ContentView load, log counts:
- workspace_count
- task_count
- run_count
- event_count
- artifact_count
- max_events_per_task
- max_runs_per_task
- max_run_output_chars or bucket
- maybe p50/p95-ish buckets if simple and cheap
- This should be a cheap query-based snapshot, not relationship-walking all models in memory if avoidable.
-
Chat/task opening path
Instrument the selected-task/chat-open path with a correlated interaction id if practical:
- selected task changed
TaskThreadViewModel.reset(for:)
TaskThreadViewModel.refreshSnapshot(for:)
TaskThreadSnapshotTrigger(task:)
TaskThreadSnapshotInput(task:maxRuns:)
TaskThreadSnapshotWindow
- existing
thread_snapshot_build
Fields should include counts/buckets:
- event_count
- visible_event_count
- run_count
- latest_run_output_bucket/chars
- snapshot_input_events
- snapshot_input_runs
- omitted_events
- omitted_runs
- conversation_item_count where available
-
Sidebar/index path
Instrument:
SidebarTaskIndexInvalidation.signature(for:)
SidebarTaskIndex.init(tasks:searchText:)
- visible workspace filtering/sorting
- pinned/unread/review counts
Fields:
- task_count
- workspace_count
- review_task_count
- pinned_task_count
- unread_task_count
- search_active boolean
- duration_ms
-
Search panel
Instrument:
- recent task calculation
- filtered task calculation
- filtered workspace calculation
Add debounce/throttle only if needed to avoid telemetry spam, but avoid changing product behavior.
Fields:
- query_length only, not query text
- task_count
- workspace_count
- result counts
- duration_ms
-
Plan-state/cache path
Instrument:
TaskPlanStateCacheSignature(task:)
refreshPlanStateCache()
- plan reconstruction if reachable through
TaskPlanService
Fields:
- event_count
- run_count
- output bucket
- plan_event_count
- duration_ms
-
Run finalization/compaction path
Instrument:
AgentRuntimeRunPersistence.finalizeAndPersist
AgentRuntimeRunPersistence.fields
AgentEventCompactor.compactEvents
- auto-export/save if there is an existing service boundary
Fields:
- event_count
- run_event_count
- artifact_count
- compacted_count / kept_count
- duration_ms
Implementation guidance:
- Add a small helper layer if needed, for example
PerformanceTelemetry.measure(...) overloads or a PerformanceFields helper for safe count/bucket formatting.
- Consider adding a
PerformanceTelemetry.measureMainActorGate style helper only if it makes call sites clearer.
- Use thresholds so normal tiny operations do not flood logs. Suggested default threshold: 8ms for UI-frame-sensitive paths; maybe 20ms for startup/store scale snapshots.
- Keep field names consistent and grep-friendly.
- Prefer event names like:
store_scale_snapshot
chat_open_selected_task
thread_snapshot_trigger
thread_snapshot_input
thread_snapshot_window
sidebar_index_signature
sidebar_index_build
sidebar_visible_workspaces
search_panel_filter_tasks
search_panel_filter_workspaces
plan_state_signature
plan_state_refresh
run_finalize_persist
event_compaction
- Where possible, also keep/extend os signposts for Instruments, but file logs are the primary deliverable.
Tests:
- Add focused tests for telemetry field privacy/sanitization/bucketing helpers.
- Add regression tests for any extracted pure helpers.
- If adding store scale query logic, test it against an in-memory SwiftData container with synthetic workspaces/tasks/events/runs.
- Run the narrowest meaningful tests, then
git diff --check.
Deliverable:
- Code changes only for telemetry and tests.
- A short doc or final note explaining:
- what events are now logged
- where to find logs
- exact grep commands to collect performance lines
- a recommended reproduction script for large-instance testing
We need to add robust, privacy-conscious performance telemetry to ASTRA before attempting responsiveness fixes.
Repo: /Users/alvaro/.codex/worktrees/0fd5/astra
Context:
Users with many workspaces, many threads, and long threads report severe responsiveness degradation: slow chat opening, slow chat scrolling, sidebar/search sluggishness, and occasional nonresponsive app behavior. Prior investigation found likely hot paths where SwiftUI/UI code reads full durable relationships (
task.events,task.runs,run.output, all tasks) in places that should be cheap.Goal:
Implement a telemetry-only slice that gives us a much better picture of real app performance on large ASTRA instances. Do not optimize behavior yet except for tiny helper extraction needed for clean instrumentation. The deliverable is measurement, not the fix.
Important constraints:
Astra/Services/Diagnostics/PerformanceTelemetry.swift.~/Library/Logs/Astraand~/Library/Logs/AstraDev.Add telemetry for these missing performance surfaces:
Store/app scale snapshot
Chat/task opening path
Instrument the selected-task/chat-open path with a correlated interaction id if practical:
TaskThreadViewModel.reset(for:)TaskThreadViewModel.refreshSnapshot(for:)TaskThreadSnapshotTrigger(task:)TaskThreadSnapshotInput(task:maxRuns:)TaskThreadSnapshotWindowthread_snapshot_buildFields should include counts/buckets:
Sidebar/index path
Instrument:
SidebarTaskIndexInvalidation.signature(for:)SidebarTaskIndex.init(tasks:searchText:)Fields:
Search panel
Instrument:
Add debounce/throttle only if needed to avoid telemetry spam, but avoid changing product behavior.
Fields:
Plan-state/cache path
Instrument:
TaskPlanStateCacheSignature(task:)refreshPlanStateCache()TaskPlanServiceFields:
Run finalization/compaction path
Instrument:
AgentRuntimeRunPersistence.finalizeAndPersistAgentRuntimeRunPersistence.fieldsAgentEventCompactor.compactEventsFields:
Implementation guidance:
PerformanceTelemetry.measure(...)overloads or aPerformanceFieldshelper for safe count/bucket formatting.PerformanceTelemetry.measureMainActorGatestyle helper only if it makes call sites clearer.store_scale_snapshotchat_open_selected_taskthread_snapshot_triggerthread_snapshot_inputthread_snapshot_windowsidebar_index_signaturesidebar_index_buildsidebar_visible_workspacessearch_panel_filter_taskssearch_panel_filter_workspacesplan_state_signatureplan_state_refreshrun_finalize_persistevent_compactionTests:
git diff --check.Deliverable: