AletheiaFact / AletheiaFact/aletheia

[Epic] Instrumentation & data — unlock cycle-time measurement

Aperta
#2,489 1 commento 0 reazioni 0 assegnatari Vedi su GitHub
backlog epic performance server
Lingua principale
TypeScript
Stelle
55
Fork
20
Merge medio
2g 6h
PR unite (30g)
2

Descrizione

**Epic A · Instrumentation & data** — unlock cycle-time measurement.
_Derived from the fact-checking cycle analysis (v2, 2026-07-03). Production numbers are namespace `main` unless noted._

# 🎯 Strategic Context

## Why Now?
> _Owner: CTO_

We are being asked — by funders, IFCN reporting, and our own hub-expansion plan — to state how fast and how reliably the platform fact-checks. Today we **cannot answer from data without a manual reconstruction**. The v2 analysis had to parse **163 MB of `histories`** and rebuild each task's timeline by hand, and even then two headline figures were wrong: the "98.7% cross-check adoption" was a storage artifact, and "2024 was 3× faster" was an artifact of 57% of 2024 claims being test/workshop tasks with a ~0 h cycle. As we onboard the 10 institutional hubs, every one of those measurements gets *more* contaminated, not less. Instrumenting now is the difference between a roadmap driven by numbers and one driven by anecdote.

## Problem Statement
> _Owner: CTO, Design Lead, PE_

#### For Fact-Checking Teams (front-line reviewers):
Reviewers have no visibility into where a check actually spends its time. "78% of the cycle is queue, not work" is a plausible aggregate, but it is not measured per stage — only `draft` emits work signals (gaps between saves, N=64). A reviewer cannot see whether their own throughput is improving, and leads cannot tell a slow *stage* from a slow *person*.

#### For Platform Operators & Institutional Partners (hubs):
Operators cannot separate a healthy queue from dead weight. ~215 open tasks look identical whether they are abandoned or in-progress, so any WIP, SLA, or coverage number an operator reports to a partner is unreliable. Cadence metrics silently blend `main` with workshop/test namespaces and blend the fast 2024 cohort with 2025–26, so partner-facing dashboards would misstate the present.

#### Impact:
- **Every cadence metric is currently un-trustworthy** — the two documented distortions inflate/deflate medians by roughly 2× (3.2 h blended vs 6.6 h `main`-only).
- **~12 median days** between the internal `published` state and the public claim review are invisible today (only 231/443 tasks with history have a linked claim review).
- Each new measurement request costs an analyst a **multi-hour manual reconstruction** and is error-prone (the first pass got two figures wrong).

## Solution Hypothesis
> _Owner: CTO, Design Lead, PE_

Materialize the data the metrics need, at the moment state changes, instead of reconstructing it after the fact. A single `transitionState()` helper writes a typed `stateHistory[]` and recomputes `stageDurations`/`cycleMetrics`; namespace and cohort tags (`isCore`, `namespaceType`) let every query filter out non-production noise; canonical timestamps (`claimSubmittedAt`, `publishedAt`, `claimReviewId`) fix the ambiguous start and the invisible publish gap; the three classifications are persisted so adoption becomes auditable. **Evidence it works:** the backfill/reconstruction already ran during the analysis, so we know the fields are derivable and the migration is feasible. **Assumption:** historical `histories` are complete enough for a one-time backfill (validated for the sample analyzed).

## What We're Claiming (Narrative)
> _Owner: CTO_

Aletheia can now tell you, from data and in seconds, exactly how long a fact-check takes — start to public publication, broken down by stage, filtered to real production work. Where we used to reconstruct timelines by hand and occasionally get them wrong, cycle time, backlog health, reviewer adoption, and cross-check coverage are now first-class, always-fresh numbers on a dashboard. Any partner hub can see its own throughput and coverage without an analyst in the loop. We stopped guessing how our own pipeline performs and started measuring it.

## Success Outcomes
> _Owner: CTO, Product Ops, PE_

Success = the metrics the analysis had to hand-reconstruct become **flat, queryable, always-fresh fields**, and the two documented distortions can never silently recur.

| Outcome | Type | Target | Why Realistic | Measurement | Comments |
| --- | --- | --- | --- | --- | --- |
| Time-per-stage without reconstruction | Quant | 100% of tasks carry `stateHistory[]` + `stageDurations` | Backfill already proven in the analysis | DB query: `% tasks with populated fields` | Retires the 163 MB parse |
| Cadence metrics de-noised | Quant | 100% of cadence queries default to `isCore:true` | `nameSpace` already exists; derivation is trivial | Code review + query audit | Removes the ~2× namespace distortion |
| Publish gap made visible | Quant | 100% of published tasks have `publishedAt` + `claimReviewId` | Canonical fields, never overwritten | DB query on new tasks post-ship | Surfaces the ~12-day gap |
| Adoption auditable | Quant | 3 classifications stored for 100% of new tasks | Initial value already exists transiently | DB query; compare initial↔cross↔final | Recovers the metric lost to the 98.7% artifact |
| Dashboard freshness | Quant | ≤ 24 h (scheduled `$merge`) | Standard Atlas Scheduled Trigger cadence | Trigger run log | Feeds INST-8 |
| Analyst reconstruction effort | Qual | New cadence questions answered by query, not manual rebuild | Fields become flat | Analyst confirmation | Baseline: multi-hour manual pass |

---

# 📋 Scope and Implementation Plan
> _Owner: CTO, Product Lead, Design Lead, Engineering Lead_

### Epic Release Timeline
Five sequenced waves. Waves 1–3 are the critical spine (one materialization pass turns cycle-time, backlog, and adoption into flat fields); waves 4–5 build dashboards and the harder effort/onboarding signals on top. INST-9 runs in parallel (independent).

- [ ] #2491 — INST-1 · `isCore` / `namespaceType` flag isolating `main` — 🔴 S — **Wave 1**
- [ ] #2492 — INST-2 · Materialize `stateHistory[]` + `stageDurations` — 🔴 M (migration) — **Wave 1**
- [ ] #2494 — INST-4 · Explicit lifecycle state + `abandoned`/`archived` (+ backlog decomposition) — 🔴 P/M (migration) — **Wave 2**
- [ ] #2493 — INST-3 · Canonical timestamps + reviewTask ↔ claimReview link — 🟡 P/M — **Wave 2**
- [ ] #2507 — INST-5a · Persist the reviewer's initial classification (quick win) — 🔴 P — **Wave 3**
- [ ] #2508 — INST-5b · Store all three classifications + `agreement.*` booleans — 🟡 M — **Wave 3**
- [ ] #2498 — INST-8 · `reviewTaskMetrics` + Scheduled Trigger + Atlas Charts — 🟢 M — **Wave 4**
- [ ] #2505 — INST-10 · Live cross-check coverage metric (measure, not restore) — 🟡 P/M — **Wave 4**
- [ ] #2506 — INST-11 · Cohort-segmented timing reporting convention — 🟢 P — **Wave 4**
- [ ] #2496 — INST-6 · `workSessions` (time-series) — active effort per stage — 🟠 high-leverage, L — **Wave 5** (needs INST-2)
- [ ] #2497 — INST-7 · Onboarding milestones on the user — 🟡 P/M — **Wave 5**
- [ ] #2504 — INST-9 · Institution/affiliation as a first-class field — 🟡 M — **Parallel**

**Sequencing & dependencies:** INST-2 → INST-6, TECH-1. INST-4 → PROC-2a/2b, TECH-4/5. INST-8 depends on INST-1..5 and exposes INST-10 + INST-11. INST-5b needs INST-5a. Two composition confounders need two fixes: INST-1 (namespace) and INST-11 (time cohort).

> 💡 For ideas outside this scope, open a feature request so we can track and revisit them in a future iteration.

---

# ❓ Outstanding Questions
> _Owner: CTO, PE, Lead Engineer, Design Lead, Product Ops, Data Lead_

**Q:** Are the historical `histories` complete enough to backfill `stateHistory[]` for *all* tasks, or only from a certain date? (Sample validated; full-range not.)
**Q:** What is the canonical definition of `publishedAt` when a claim review is edited/republished — first publication or latest?
**Q:** Do we set calendar dates for the waves, or keep them as a dependency-ordered sequence? (Currently sequenced, not dated.)
**Q:** For `isCore`, are there production namespaces other than `main` that should count as core (e.g. active partner hubs)?

---

# ⚠️ Risks
> _Owner: PE, Lead Engineer_

| Risk | Likelihood | Impact | Mitigation |
| --- | --- | --- | --- |
| Backfill mis-maps generic `details.after.value` (where the first analysis erred) | Medium | High | Reuse the validated reconstruction script; diff backfilled `stageDurations` against the analysis sample before writing |
| Migration on `reviewTask` at production scale causes downtime | Medium | Medium | Run as background/idempotent migration; `needs-migration` review; off-peak window |
| `transitionState()` helper missed by a code path, so new tasks skip `stateHistory[]` | Medium | High | Centralize all transitions through the helper; add a test asserting no direct state writes |
| Dashboards ship before INST-1..5, re-introducing blended/contaminated numbers | Low | Medium | Gate INST-8 on 1–5; default every query to `isCore:true` |

Guida per i contributori

Nessuna guida per i contributori indicizzata per questo repository

Valutazione

Questa issue non è ancora stata valutata.

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.