%% SCRAP: architecture/03-architecture/heartbeat-system/instrumentation-plan
%% SOURCE: docs/working/architecture/03-architecture/heartbeat-system/instrumentation-plan.md
%% STATUS: WORKING
%% FITS: dev-guide/ch-heartbeat
%% EDITORIAL: lifted — prose rewritten to press voice

\section{Per-Tick Heartbeat Instrumentation}

This plan captures seven metrics on every heartbeat tick (roughly a
one-millisecond interval) without disturbing timing accuracy. The strategy is a
lightweight circular buffer with minimal copying, decoupled from the core
heartbeat logic.

\subsection{The Tick Snapshot}

Each tick records a fixed-size snapshot. The buffer is sized for one hundred
thousand ticks---about one hundred seconds at 1~kHz.

\begin{lstlisting}[language=C]
typedef struct {
    uint32_t tick_number;           /* sequential counter */
    uint64_t elapsed_ns;            /* since run start */
    uint64_t tick_interval_ns;      /* interval from prior tick */

    /* core metrics */
    uint32_t cache_hits_delta;
    uint32_t bucket_hits_delta;
    uint32_t word_executions_delta;

    /* feedback signals */
    uint64_t hot_word_count;        /* words above heat threshold */
    double   avg_word_heat;         /* mean heat, Q48.16 / 65536 */
    uint32_t window_width;          /* rolling window size */

    /* derived */
    uint32_t predicted_label_hits;
    double   estimated_jitter_ns;   /* deviation from nominal tick */
} HeartbeatTickSnapshot;

#define HEARTBEAT_TICK_BUFFER_SIZE 100000
\end{lstlisting}

The \lstinline{Heartbeat} context gains the buffer, its size, a wrapping write
index, a monotonic total tick count, and the run-start reference time. The
buffer is allocated in \lstinline{vm_init()} and freed in
\lstinline{vm_cleanup()}.

\subsection{Capture and Injection}

A capture routine computes the elapsed time, derives the tick interval from the
prior slot in the circular buffer, and copies state from the most recent
heartbeat snapshot. The mean heat is converted from \Qtype{} fixed point by
dividing by $65536$. The call is injected at the end of
\lstinline{vm_heartbeat_run_cycle()}, after the tick, background decay, rolling
window service, and snapshot publication.

\begin{lstlisting}[language=C]
static void vm_heartbeat_run_cycle(VM *vm)
{
    if (!vm || !vm->heartbeat.heartbeat_enabled) return;
    vm_tick(vm);
    vm_tick_apply_background_decay(vm, sf_monotonic_ns());
    sf_mutex_lock(&vm->tuning_lock);
    rolling_window_service(&vm->rolling_window);
    sf_mutex_unlock(&vm->tuning_lock);
    heartbeat_publish_snapshot(vm);
    heartbeat_capture_tick_snapshot(vm);   /* NEW */
}
\end{lstlisting}

\subsection{Delta Metrics}

Accurate per-tick cache, bucket, and execution deltas require latching counter
values at the start of \lstinline{vm_tick()} and differencing them at the end.
This adds two or three counter fields to the VM struct---negligible memory.
At authoring time these deltas are left as \lstinline{%% TODO} stubs in the
capture routine pending that tracking.

\subsection{Export and Storage}

After a run, \lstinline{heartbeat_export_csv()} walks the circular buffer in
order and emits one CSV row per tick. Storage is the binding constraint:

\begin{itemize}
  \item 750 runs $\times$ 100k ticks $\approx$ 75 million rows, roughly 75~GB at
        about 1~KB per row.
  \item \textbf{Option A}---first and last 10k ticks plus a random sample
        ($\sim$10~GB, $\sim$500~MB compressed).
  \item \textbf{Option B}---every tenth tick, 10k rows per run ($\sim$7.5~GB).
  \item \textbf{Option C}---every tick in a binary format ($\sim$2--3~GB).
\end{itemize}

Option B is recommended for Phase 2 prototyping, with density increased later if
warranted.

\subsection{Overhead}

The instrumentation cost is dominated by a single monotonic clock read.

\begin{tabular}{lr}
\toprule
Operation & Cost \\
\midrule
Seven field assignments & $\sim$10~ns \\
One modulo (circular index) & $\sim$5~ns \\
One monotonic clock read & $\sim$100~ns \\
\midrule
Total per tick & $\sim$115~ns \\
\bottomrule
\end{tabular}

\medskip
\noindent Against a nominal $1{,}000{,}000$~ns tick that is roughly
$0.0115\%$---negligible, so the instrumentation does not perturb the timing it
measures.

\subsection{Status}

The \lstinline{HeartbeatTickSnapshot} structure and tick buffer are declared in
\lstinline{include/vm.h}, but \lstinline{heartbeat_export_csv()} is not yet
implemented and the delta counters remain to be wired.

%% TODO(bob): confirm current implementation status of heartbeat_export_csv()
%% and the cache/bucket/execution delta tracking before promotion.
