# Roadmap (/docs/roadmap)



This page captures everything that has been agreed-on but not yet
built. Sequencing is intentional — earlier items unlock later
ones — but each item has its own readiness criteria, so "next" is
not a calendar promise.

For *settled* decisions about what we're not building, see
[decisions](/docs/decisions).

## Near-term — sequenced [#near-term--sequenced]

### (d) Metric ↔ cut links [#d-metric--cut-links]

Thin join table `heartbeat.metric_cut_link(metric_id, cut_id, role)`
where `role ∈ {explains, drilldown}`. Filled from per-metric and
per-cut config files. UI: cockpit tile expansion gets a "see in
audit →" deep-link to the relevant cut anchor on `/audit/<page>`;
each audit cut gets a backlink "feeds metric N". Closes the gap
between cockpit (red zone surface) and audit (the breakdown that
explains the red).

**Why now.** The cockpit and the audit pages already share a data
model and a shell. The only thing missing is the navigation between
them — clicking a red tile should take the operator to the chart
that explains it, not leave them to scroll three pages of audit prose.

**Status.** Not started.

### (e) `/docs` content driven by registries [#e-docs-content-driven-by-registries]

Today this site (the page you're reading) is hand-written MDX. The
plan is to **read `metric_registry` and `audit_cut_registry` at build
or request time** and render every metric's `name` / `how_to_read` /
`methodology` / `sources` / `owner` / `verification_state`, and every
cut's equivalent fields, into auto-generated pages. Static MDX sits
next to it for process docs (this page, [lifecycle](/docs/metrics/lifecycle),
[architecture](/docs/architecture)).

The `GET /api/audit/registry` endpoint already ships with this in
mind. Single page per topic, grouped by section, with anchor links
matching the cockpit / audit deep-links from (d).

**Why after (d).** Anchors only matter once there's something
linking to them.

**Status.** Static MDX baseline shipped 2026-05-07; auto-generation
not started.

### (f) Automated alerts — email and Telegram [#f-automated-alerts--email-and-telegram]

Connect threshold crossings on the
[5-tuple](/docs/architecture#metric-data-contract) to a notification
channel. Verification gates this: only `verification_state='verified'`
metrics with a non-null `owner` email fire alerts.

**Channels (MVP).** Both email and Telegram. Email is the durable
paper trail; Telegram is the instant interrupt for the working day.
The `heartbeat.owner` email column already holds the right shape for
routing — both channels derive the recipient from it.

**What triggers an alert.**

* `value` crosses `alert_value` (red) → immediate notification.
* `value` crosses `norm_value` (amber) → notification if state was
  previously green (entry-edge only, not repeated every tick).
* Staleness beyond the period threshold → separate "pipeline stale"
  notification, distinct from a metric alert.

**Hysteresis, ack, snooze.** Live in `heartbeat.alerts` (new table),
**not** on the registry — that keeps the read contract intact.

* **Hysteresis:** alert only fires if the threshold is crossed for
  N consecutive compute ticks (configurable per metric). Prevents
  single-tick spikes from waking someone at 3 AM.
* **Acknowledgement:** an operator can ack an alert from the cockpit;
  the alert is suppressed until the value re-enters normal range and
  crosses the threshold again.
* **Snooze:** time-boxed silence for planned outages or known spikes.

**Routing.** The `owner` email on the metric drives Telegram delivery
(via the per-owner Telegram handle mapping in `heartbeat.owner`) and
CC on email. Unowned alerts go to a default ops inbox.

**Why after (e).** (e) gives an alert a human-readable surface for
"what would alert me, what does it mean, what is the threshold
saying about commitment vs. SLA". Without that, alert fatigue is
guaranteed.

**Status.** Not started. Verification + email-validated owner
columns landed 2026-05-07 to gate this work. Alerting channel
infrastructure (Telegram bot token, SMTP) is an ops task before any
code is written.

### (g) Automated metrics discovery [#g-automated-metrics-discovery]

Today `metrics-discovery` is a skill that an agent runs on demand.
The next step is a scheduled agent that proactively scans landed
schemas for high-ROI metric candidates and surfaces them without a
human having to think to ask.

**What it does.**

* Runs weekly (or on each new source landing) against marts-db.
* Compares `heartbeat.metric_registry` against available tables to
  find gaps — columns that carry business-signal values but have no
  corresponding metric.
* Scores candidates by estimated revenue impact or loss-avoidance
  potential (same heuristic as the current skill).
* Produces a dated candidates file and sends a Telegram summary to
  Ivan with the top 3 proposals, each with a one-line business case.
* Ivan approves/rejects; the agent then follows the full
  `metrics-discovery` flow for approved candidates.

**Difference from the current skill.** The current skill is
reactive (invoked by a human). This item makes discovery proactive:
the agent looks without being asked, once per week.

**Why after (f).** Proactive discovery is only useful if new metrics
can trigger alerts. Without (f), a newly discovered metric sits on
the cockpit but never wakes anyone up.

**Status.** Not started.

### (h) Starred metrics and watchlists [#h-starred-metrics-and-watchlists]

A thin personalization layer on top of the cockpit:

* Any operator can **star** individual metrics; starred metrics
  always appear at the top of the cockpit, regardless of their
  domain group or status.
* **Watchlists** — named groups of metrics (e.g. "week-end check",
  "compliance", "CEO morning view") that can be bookmarked and
  shared. A watchlist URL opens the cockpit pre-filtered to those
  tiles.
* Watchlist state lives in `heartbeat.watchlist` (new table, per
  user or shared), not in the registry — operator preference is not
  metric state.

**Why after (g).** Watchlists are most useful once the registry is
large (50+ metrics). With 31 metrics today the cockpit is still
readable in full. The value of pinning grows with registry size.

**Status.** Not started.

## Sequencing rationale [#sequencing-rationale]

(d) lights up navigation between cockpit and audit, which makes (e)'s
drill-down anchors useful; (e) gives (f) a human-readable surface for
"what would alert me, what does it mean"; (f) is the payoff that
justified building verification + owners in the first place. (g) and
(h) compound on top — proactive discovery only makes sense once new
metrics can alert, and watchlists only earn their keep at scale.

## Always-on work [#always-on-work]

Two streams that run in parallel with the sequenced items:

* **Grow the registry via [`metrics-discovery`](/docs/metrics/discovery)
  against real data.** The 31 metrics live today are a starting set,
  not a finished one.
* **Add marts-db indexes and audit replace-strategy tables** as new
  sources and metrics land. See the
  [Data quality and performance](/docs/architecture#data-quality-and-performance)
  section in architecture for the rule set.

## Later [#later]

* **MCP server** over the registry / history (agent-queryable
  Heartbeat). Same data, different surface — agent / chat / Telegram
  instead of a screen. Comes after alerting; uses the same
  `metric_registry` + `metric_history` as single source of truth.
* **OKR overlay.** Once Heartbeat reliably produces metrics, those
  metrics become the input for departmental OKRs. Heartbeat is the
  substrate, not the OKR system itself.
* **Per-team views.** Filtered cockpit by metric ownership / domain.
* **EMT (stablecoin) metrics.** Once the EMT product line generates
  data Heartbeat can land.
* **SaaS sources beyond the MVP-15.** Driven by metric demand, not
  source completeness.

## CEO data-access skill (deferred) [#ceo-data-access-skill-deferred]

A separate, larger initiative: a Claude Code skill that gives the CEO
natural-language access to live business data and lets them
contribute new metrics through the same pipeline Ivan uses, with PII
masking and single-user access control as hard guarantees.

JTBD specs live under [`specs/`](https://gitlab.stchl.eu/Ivan_Soko1ov/satchel-heartbeat/-/tree/main/specs)
in the repo (01–09). The SLC minimum (top-row in the spec story map)
is \*\*single-user access + query-time masking + a working NL question

* a captured metric idea that opens a PR\*\* — none of which is
  built today.

This is &#x2A;*deferred behind (d)/(e)/(f)** — it depends on a verified
metric registry and an alerting layer to be useful, and it adds a
security perimeter (single-user, PII-free replica) that is its own
chunk of work.
