blob: dbc19559481a6fda99007de9ea6eac33e067a828 [file] [view] [edit]
# `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