# Recording and Log View This document defines the activity state machine, ownership, and lifecycle of Recording, log loading, and Log view. Metric fields, units, aggregation calculations, and JSON Lines schemas remain normative in [metrics.md](metrics.md). Tracking intent and working-list behavior remain in [tracking-and-history.md](tracking-and-history.md). ## Activities The application has three user-visible activities: Live, Recording, and Log view. The Log list is a modal selection step, not a fourth activity. ```mermaid stateDiagram-v2 [*] --> Live Live --> Recording: choose path and start Recording --> Recording: request stop / continue Recording --> Live: confirm TUI stop / flush and close Recording --> Live: explicit exact-session MCP stop / flush and close Recording --> Live: duration limit / flush and close Live --> LogList: open log list LogView --> LogList: open log list LogList --> LogView: select valid log LogList --> Live: close when opened from Live LogList --> LogView: close when opened from Log view LogView --> Live: return to Live Recording --> Recording: log-list request rejected Recording --> Recording: Tracking List edit rejected LogView --> LogView: recording request rejected Live --> Exiting: quit Recording --> Exiting: quit / flush and close LogView --> Exiting: quit Exiting --> [*] ``` Recording and Log view are mutually exclusive at both user-action and asynchronous-result boundaries. A completed background log load is rejected if Recording began while it was in flight. ## Recording Scope Starting Recording requires at least one process name in the working Tracking List. It does not require a currently matching process. The start dialog shows the fixed tracked names and the matching-process count from the latest Live sample, independently of display pause, filters, and Tracked-only. The names can be inspected with vertical and horizontal scrolling, including long names and lists. It explains that visible rows do not define scope and that zero matches still records system metrics and includes matching processes appearing later. Inspection and starting preserve display preferences. `RecordingSession` owns a copy of the explicit root names, their normalized lookup set, and an independent identity-based tracking scope. It seeds membership from already observed live members, including descendants whose ancestors have exited. Each sample extends membership to matching roots and observed descendants, using the rules in [Tracking and Live History](tracking-and-history.md#effective-tracking-scope). Session metadata records only the fixed explicit names; frames contain effective member identities. Exited membership is released after aggregation, while serialized definitions and samples preserve recorded lifetimes. Tracking List edits are rejected until the session ends; Tracked-only remains available because it changes only the display. When no effective member is live, frames still contain system metrics and an empty process array. Surviving inherited descendants remain in scope even when no explicit root is live. A tracked process name, a currently matching process, and one `(PID, name, start_time)` identity must remain distinct. ## Aggregation Live sampling and Live history remain at one-second resolution. Recording independently selects a `1s`, `2s`, `5s`, or `10s` aggregation interval and owns the pending accumulator. The current selector value is the default for the next Recording and is stored once as an app setting. Opening or saving an Investigation Profile never changes it. Profile opening and saving are unavailable during Recording, and opening is unavailable in Log view. Profile deletion does not affect activity state. Available values are averaged independently per process identity and GPU adapter. Missing values and absent processes do not contribute zero. Stopping, quitting, or reaching the duration limit flushes a partial final window before the clean end record. The exact calculations, rounding rules, and schema fields are defined in [metrics.md](metrics.md). ## Stop, Quit, and Duration Limit Opening the interactive TUI stop confirmation does not pause sampling or aggregation. Continuing dismisses the confirmation without changing the session; confirmed Stop flushes the pending aggregate, writes the end record, flushes the writer, closes the log, and returns to Live. Interactive quit uses the same cleanup path rather than nesting another stop flow. Windows console close, logoff, shutdown, `Ctrl+C`, and `Ctrl+Break` request bounded cleanup through the main loop. Each session lasts for at most 24 hours measured with a monotonic clock. At the limit, the application dismisses Recording-only dialogs, writes an end record with reason `duration_limit`, flushes and closes the log, and returns to Live without waiting for another sample. ## Failure Handling Recording lifecycle failures are visible application state, not transient status messages. - Create or open failure leaves the start dialog available behind the error. The error owns input and hides the underlying path caret; dismissal restores the unchanged draft and insertion position. Overwrite confirmation follows the same cursor ownership. - Header, frame, end-record, newline, or flush failure ends the active session and preserves the partial file. - Cleanup failure during quit cancels the quit so the error remains visible. The application never deletes a partial log solely because Recording failed. ## Log List and Loading The Log list scans supported `*.log` files on a background worker. Only one full load can be in flight; additional open requests are ignored until its result is applied. Schema versions 2 and 3 are listed and loadable. Malformed supported logs produce visible errors without crashing the UI. The schema-v3 loader resolves process and GPU IDs through preceding definition records while reconstructing snapshots and histories. The loader retains the session interval and complete frame-time sequence so Log view can identify aggregated values and split Graph lines across missing process or metric windows. ## Log View Semantics Log view is not frame playback. Processes shows the final process snapshot, while Graphs, Samples, Process Info, and A/B comparison inspect histories reconstructed from all complete frames. All process identities present in recorded frames are in Log-view scope, including descendants absent from the session root-name metadata. Root-name metadata distinguishes explicit and inherited indicators; no parentage is reconstructed, and Log view remains Flat. Log view does not allow Tracking List edits or pruning of the hidden Live history. Tracked-only filtering remains available and does not change the Live Tracking List or recorded tracking scope. Loaded histories are not pruned to Live-history capacities. Missing process or metric intervals remain gaps rather than being connected or replaced with nearby values. Process-specific live collectors remain disabled as described in [Process Investigation](process-investigation.md). ## Invariants - Recording and Log view are never active together. - One session uses one fixed Tracking List scope and one fixed aggregation interval. - Opening a profile never changes either the current session interval or the default interval for a future Recording. - Missing values and absent processes are never converted to zero. - A partial final aggregation window is flushed before a clean end record. - Recording ends and returns to Live after at most 24 hours of monotonic elapsed time. - Stop and quit flush and close the writer; cleanup failure remains visible. - Partial logs remain available after interruption or failure. - Log view reconstructs histories but never plays frames over time. In Log view, the footer provides shortcuts to return to Live and to add a metric to Graphs. Returning to Live is separate from quitting; users add Graphs explicitly. The Recording progress indicator remains visible and advances while the display is paused, independently of the frozen process snapshot. The log browser previews the selected recording's tracked process names, recorded interval and time range from cached summaries. Selection performs no file reads or history reconstruction; the existing background summary scan reads recording metadata and the tail. Older metadata omissions appear as `--`, and invalid-file indications are retained. Log-open failures appear in a persistent, scrollable error overlay containing the complete path and error chain. Dismissal restores the browser directory and selection; users can retry or choose another file. Opening always runs full validation on the background loader, even when the cached preview reports an error, so a repaired file can be retried without relying on stale metadata. Failure and browser dismissal preserve the current activity and previously loaded data. Closing or refreshing the browser (including changing directory) drops its pending result receivers, preventing older requests from changing a replacement browser or workspace. Workers remain nonblocking. ## MCP recording and saved-log analysis MCP Recording uses the locally configured last Recording directory, a generated create-new filename, and the existing session-owned scope and aggregation. It returns an opaque session ID and log ID. An explicit MCP stop requires the exact active session ID and an operation ID, and proceeds without local confirmation. It completes only after the pending aggregate and end record are written and the writer is flushed and closed. Stale session IDs are rejected, identical retries retain their original outcome, and a replay cannot stop a replacement session. An accepted stop dismisses stale Recording-only stop/fixed-tracking notices. Interactive TUI stopping retains its confirmation: Enter/Esc/n continues and y stops. Disconnect does not stop an accepted session. Failures remain visible in the TUI and operation outcome. Independent MCP log-load jobs reuse schema-v2/v3 reconstruction without entering Log view. Only server-listed IDs in the configured root are accepted. The external loader checks cancellation, deadline, and conservative memory reservation before record/definition expansion. It reports missing end records or an unfinished invalid final line as partial, retains complete readable frames, and rejects malformed complete records. Its references cannot target live process inspection. The interactive loader retains its existing behavior.