| # `fx worktree` Telemetry & Metrics | |
| `fx worktree` tracks developer worktree utilization over time to understand | |
| average checkout usage, capacity requirements, resource consumption, and the | |
| proportion of checkouts built recently vs. not built recently. | |
| To avoid running background daemons while providing continuous statistical | |
| precision, `fx worktree` uses **local piecewise-constant time integration** | |
| combined with a **24-hour periodic snapshot upload**. | |
| --- | |
| ## Architecture Overview | |
| 1. **Local State Accumulation (`.fx/metrics/worktree_metrics.json`):** | |
| - Whenever any `fx worktree` command executes, the tracker records the | |
| current number of total, leased, built recently (built in the last 7 days), | |
| and not built recently worktrees. | |
| - The elapsed time since the previous state change is integrated into a | |
| running Riemann sum. | |
| - Running minimum and maximum (peak) counts are updated across all four | |
| dimensions. | |
| 2. **Daily Snapshot Upload:** | |
| - On the first `fx worktree` command executed after 24 hours have passed | |
| since `period_start_ts`, the tracker finalizes the 24-hour time-weighted | |
| statistics. | |
| - A single custom telemetry event is dispatched to Fuchsia's Google | |
| Analytics 4 (GA4) pipeline via | |
| `tools/devshell/lib/metrics_custom_report.sh`. | |
| - The metrics file is rotated with a fresh 24-hour window starting at the | |
| current timestamp and state. | |
| --- | |
| ## Mathematical Formulation: Time-Weighted Average | |
| Worktree counts change only at discrete events (`add`, `remove`, `lease`, | |
| `release`, build activity). Between events, the count remains constant. Over | |
| any interval $[T_0, T_{\text{upload}}]$, the time-weighted average $\bar{N}$ | |
| is given by: | |
| $$ | |
| \bar{N} = \frac{1}{T_{\text{upload}} - T_0} | |
| \int_{T_0}^{T_{\text{upload}}} N(t)\,dt | |
| = \frac{\sum_{i=1}^{k} N_i \cdot \Delta t_i}{T_{\text{upload}} - T_0} | |
| $$ | |
| Where: | |
| - $N_i$ is the count during step $i$. | |
| - $\Delta t_i = t_i - t_{i-1}$ is the duration spent in that state. | |
| - $T_{\text{upload}} - T_0$ is the total elapsed time of the measurement window. | |
| This ensures accurate representation of developer usage across overnight and | |
| multi-day periods without active polling. | |
| --- | |
| ## Local State Schema | |
| The state file is stored at `.fx/metrics/worktree_metrics.json` in the root | |
| checkout directory, ensuring that all worktrees in the pool share and update the | |
| same state: | |
| ```json | |
| { | |
| "period_start_ts": 1756740000.0, | |
| "last_change_ts": 1756783200.0, | |
| "current_total": 4, | |
| "current_leased": 2, | |
| "current_built_recently": 3, | |
| "current_not_built_recently": 1, | |
| "accumulated_total_seconds": 345600.0, | |
| "accumulated_leased_seconds": 172800.0, | |
| "accumulated_built_recently_seconds": 259200.0, | |
| "accumulated_not_built_recently_seconds": 86400.0, | |
| "min_total": 2, | |
| "max_total": 5, | |
| "min_leased": 0, | |
| "max_leased": 3, | |
| "min_built_recently": 1, | |
| "max_built_recently": 4, | |
| "min_not_built_recently": 0, | |
| "max_not_built_recently": 2 | |
| } | |
| ``` | |
| ### Field Descriptions | |
| - `period_start_ts`: Epoch timestamp (seconds) when the current 24-hour | |
| measurement window began. | |
| - `last_change_ts`: Epoch timestamp (seconds) when the count was last updated or | |
| sampled. | |
| - `current_total`: Current total number of physical worktree slots in the pool. | |
| - `current_leased`: Current number of worktrees actively leased by a task or | |
| developer. | |
| - `current_built_recently`: Current number of worktrees that have been built | |
| within the last 7 days. | |
| - `current_not_built_recently`: Current number of worktrees that are unbuilt or | |
| whose last build occurred > 7 days ago (`current_total - current_built_recently`). | |
| - `accumulated_total_seconds`: Integrated time-area product | |
| ($\sum N_{\text{total}} \cdot \Delta t$) in second-units. | |
| - `accumulated_leased_seconds`: Integrated time-area product | |
| ($\sum N_{\text{leased}} \cdot \Delta t$) in second-units. | |
| - `accumulated_built_recently_seconds`: Integrated time-area product | |
| ($\sum N_{\text{built\_recently}} \cdot \Delta t$) in second-units. | |
| - `accumulated_not_built_recently_seconds`: Integrated time-area product | |
| ($\sum N_{\text{not\_built\_recently}} \cdot \Delta t$) in second-units. | |
| - `min_*` / `max_*`: Minimum and peak counts observed across each category | |
| within the measurement window. | |
| --- | |
| ## Telemetry Event & GA4 Attribution | |
| When the 24-hour window expires, `fx worktree` emits a custom event via | |
| `tools/devshell/lib/metrics_custom_report.sh`: | |
| - **Subcommand:** `worktree` | |
| - **Action:** `daily_snapshot` | |
| - **Label Structure (compact JSON with short keys):** | |
| ```json | |
| {"at":3.0,"mnt":2,"mxt":4,"al":2.0,"mnl":1,"mxl":3,"abr":2.0,"mnbr":1,"mxbr":3,"anbr":1.0,"mnnbr":1,"mxnbr":1} | |
| ``` | |
| - `at`, `mnt`, `mxt`: Average, min, and max total worktrees | |
| - `al`, `mnl`, `mxl`: Average, min, and max leased worktrees | |
| - `abr`, `mnbr`, `mxbr`: Average, min, and max worktrees built recently | |
| - `anbr`, `mnnbr`, `mxnbr`: Average, min, and max worktrees not built recently | |
| ### Seamless Pipeline Attribution | |
| Because `metrics_custom_report.sh` forwards the open metrics stream (file | |
| descriptor 10) from `scripts/fx`, the event is automatically joined in the same | |
| batch with: | |
| - **Client ID (`client_id`):** Persistent anonymized `METRICS_UUID`. | |
| - **Cross-Tool ID (`other_uuid`):** Correlation UUID for `ffx`, `zxdb`, and | |
| VS Code tools. | |
| - **User Properties:** `internal` (Googler vs external), `is_cog` (Cloud Cog vs | |
| local workstation), `os`, `arch`, and `nproc`. | |
| --- | |
| ## Privacy and Data Governance | |
| In compliance with Fuchsia's [Analytics Policy][analytics-policy]: | |
| - Only aggregate statistical numbers (averages, minimums, peaks) are uploaded. | |
| - No local paths, branch names, worktree identifiers, or task IDs are collected | |
| or transmitted. | |
| - Telemetry strictly honors user opt-out preferences (`fx metrics disable` or | |
| `ffx config analytics disable`). | |
| [analytics-policy]: | |
| //docs/contribute/governance/policy/analytics_collected_fuchsia_tools.md |