Skip to content

logs #131

Description

@aandresalvarez

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:

  1. 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.
  2. 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
  3. 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
  4. 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
  5. 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
  6. 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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions