---
name: stats-kpi-ops
description: >
  Collect and format the weekly/monthly tech KPIs of the « Suivi des indicateurs
  Opérations » sheet: uptime, API p95 latency, error ratios, error budget burn,
  P1/P2 incidents, velocity (weight, issues, lead time), AI cost per point,
  DORA team metrics. Runs `pysae-ai-tools stats kpi` and outputs the ready-to-paste
  column block. Use when the user says /stats-kpi-ops, /kpi, 'KPIs de la semaine',
  'remplis le sheet indicateurs', 'indicateurs opérations', 'mesure hebdo',
  'KPI tech', 'colonne du sheet ops', 'uptime de la semaine', 'consolide le mensuel',
  or wants to fill the operations indicators spreadsheet. Also trigger when the user
  mentions measuring or reporting tech KPIs for a given week or month, even without
  naming the sheet.
argument-hint: "[--weekly (default) | --monthly] [measure date YYYY-MM-DD] [--since YYYY-MM-DD] [--channel #channel-name]"
allowed-tools:
  - Bash
  - Read
  - Write
  - Glob
  - AskUserQuestion
---

Collect the tech KPIs of the « Suivi des indicateurs Opérations » sheet over a measurement window and output the column block ready to paste.

## Required tools

- `glab`

Run `pysae-ai-tools tools require glab || exit 1` before starting; the command exits non-zero with the install command on stderr if any tool is missing or out of date.

## Metric contract

Every value follows [references/kpi-definitions.md](references/kpi-definitions.md) — source, exact formula, window, mode (`auto` / `manual` / `semi-auto`) per sheet row. Read it before interpreting or debugging any value. Never substitute a formula on the fly: if a metric looks wrong, report it, don't redefine it.

## Parse arguments

- `--monthly` → monthly consolidation block (sheet rows 50-71). Anything else → weekly block (rows 44-48).
- A date (`YYYY-MM-DD`) → the measure date (window end, exclusive). Default: today.
- `--since YYYY-MM-DD` → force the window start. Default: resolved from history (see below).
- `--channel #name` → Slack channel to post the block to after confirmation.

## Determine the window

The sheet logic is « depuis dernière mesure » : the window starts where the previous one ended.

1. List `${CLAUDE_PLUGIN_DATA}/kpi/snapshot-weekly-*.json` (or `snapshot-monthly-*.json` for `--monthly`), take the most recent `until` as `since`.
2. No history and no `--since` → ask the user for the date of the last filled column (CI mode: default to 7 days back for weekly, first day of previous month for monthly).

## Collect

```bash
pysae-ai-tools stats kpi --since {SINCE} --until {UNTIL} [--ai-seats-monthly-usd {SEATS}]
```

Outputs a JSON snapshot: one entry per metric key with `value`, `unit`, `error`, `detail`. The command is best-effort — a failing source yields `error` on its metrics, the others are unaffected.

`--ai-seats-monthly-usd`: resolve from `$AI_SEATS_MONTHLY_USD` if set, otherwise omit (API cost only). Never hardcode a seats amount.

For `--monthly`, additionally pass `--no-skip-coverage` to collect test coverage (slow, ~1 min).

## Manual metrics

After collection, gather the `manual` values (defined in the contract). In CI mode skip the questions and emit `n/a`.

- **Weekly**: nothing — all weekly rows are auto.
- **Monthly**, ask only when relevant:
  - TTD / TTA / MTTR — only if `incidents_p1 + incidents_p2 > 0`. Ask in one question, minutes.
  - Consommation des ressources (€/mois, AWS + Atlas + Datadog)
  - Tech debt : temps vs. backlog estimé
  - Comprehension debt (churn %) — semi-auto: if the user has fresh local clones of `api` and `driver`, compute via the `comprehension-debt-audit` method; otherwise ask or `n/a`.

## Format the block

French number format (decimal **comma**, as in the sheet). One value per line, in the exact row order — blank lines where the sheet has section headers, so the block pastes directly onto the column.

A metric with `error` or an unanswered manual → `n/a` in the block, with the reason listed below the block (never invent or carry over a stale value).

**Weekly block (paste at row 44):**

```
99,995%
400,61
4XX 3,09% · 5XX 0,005%
1
5,0%
```

Rows: uptime, latence p95 (ms), ratio erreurs, incidents P1&P2 (sum; P1/P2 split in the comment), error budget burn.

**Monthly block (paste at row 50):**

```
{uptime mois}
{uptime trimestre}
{latence p95}
{ratio erreurs}

{incidents P1&P2}
{TTD min}
{TTA min}
{MTTR min}

{poids livré}
{issues fermées}
{lead time jours}
{coût IA $/point}

{déploiements (total · moy/sem)}
{cycle time jours}
{change failure rate %}
{couverture tests %}
{conso ressources}
{tech debt}
{comprehension debt churn %}
```

The blank lines map to the sheet's section header rows (54 « Incidents », 59 « Vélocité », 64 « MENSUEL INTERNE EQUIPE »).

## Output

Present, in this order:

1. The paste block in a single code fence (easy full copy).
2. A readable table: row label, value, source detail worth knowing (e.g. P1/P2 split, unweighted issues count, api vs seats cost split).
3. The `n/a` reasons, if any, with the fix (e.g. `pysae-ai-tools env resolve AIRTABLE_API_KEY`).

Then:

- Save the snapshot JSON (the full `stats kpi` output, plus the manual values under a `manual` key) to `${CLAUDE_PLUGIN_DATA}/kpi/snapshot-{weekly|monthly}-{UNTIL}.json` — this drives the next « depuis dernière mesure » window.
- If `--channel` was provided, post the block to Slack after confirmation (no confirmation in CI). Otherwise do not propose Slack — the destination is the sheet.

## Monthly consolidation checks

For `--monthly`, cross-check against the weekly history of the month: sum of weekly `incidents_p1+p2` vs the monthly count, and weekly uptimes consistent with the monthly value (the monthly is request-weighted, not an average of weeklies — small differences are normal, a large gap is a red flag to report).

## Rules

- **Never write to the sheet** — the user pastes the block; the skill's responsibility ends at the block.
- **No invented values** — `n/a` + reason beats a plausible number. These KPIs go to the direction.
- **Decimal comma** everywhere in the block (Google Sheets locale FR).
- **CI mode** (`$CI` set): no questions; manual metrics → `n/a`; post to the resolved channel if any.
- **Langue française** : respecter les [règles de rédaction en français](../references/french-writing-rules.md) pour tout texte généré.

## Gotchas

- **Latency is p95, not p99** — the sheet row label says « 99th percentile » but historical values (and this skill) measure p95, matching the Dev Ops dashboard widget. See the contract.
- **Window alignment** — windows are midnight-UTC aligned; historical columns were read manually on a sliding-window widget, so small deltas vs old columns are expected and fine.
- **Airtable incident counts** are biased low by the CS rule « toujours sous-estimer la criticité ». If the count looks off vs #cs-tech-support, say so instead of silently adjusting.
- **First run has no history** — the window question is expected; answer with the last filled column date.
- **`uptime_quarter_pct` ≈ `uptime_pct`** early in a quarter is normal (same data, mostly overlapping windows).

$ARGUMENTS
