Implement public metrics service (WP-0006-T05)
src/target_revenue/metrics.py: compute_metrics(manifest, entries, as_of)
is pure/deterministic like fold.py, reusing fold.py/conversion.py
unchanged. Returns facts/calculations/forecasts as three explicitly
separated blocks (TrustServicePRD TS-FR-5), covering the mandatory Q9
set plus the recommended velocity/forecast tier - forecasts are always
null rather than populated once a Phase has converted or velocity is
non-positive, so nothing disguises a projection as a fact.
Adds GET /phases/{id}/metrics (unauthenticated per FR-9/FR-10).
tests/test_metrics.py (6 tests) needs no Docker/Postgres and runs
under plain system Python. One new Docker-gated test in
test_ledger_hosting.py proves the hosted /metrics response exactly
matches compute_metrics() run offline against the same export.
This commit is contained in:
parent
b7be3d3512
commit
dfc1d90c28
6 changed files with 287 additions and 3 deletions
|
|
@ -18,7 +18,7 @@ from fastapi import Depends, FastAPI, HTTPException, Request
|
|||
from psycopg import Connection
|
||||
from psycopg_pool import ConnectionPool
|
||||
|
||||
from .. import ledger, registry
|
||||
from .. import ledger, metrics, registry
|
||||
from . import keys
|
||||
|
||||
app = FastAPI(title="Target Revenue Trust Service — Registries", version="0.1.0")
|
||||
|
|
@ -140,3 +140,16 @@ def read_ledger(
|
|||
if registry.get_phase_manifest(conn, phase_id) is None:
|
||||
raise HTTPException(status_code=404, detail="phase not found")
|
||||
return ledger.get_ledger(conn, phase_id)
|
||||
|
||||
|
||||
@app.get("/phases/{phase_id}/metrics")
|
||||
def read_metrics(
|
||||
phase_id: str, conn: Connection = Depends(get_connection)
|
||||
) -> dict[str, Any]:
|
||||
"""Public, unauthenticated per FR-9/FR-10 — see `target_revenue.metrics`
|
||||
for the fact/calculation/forecast labeling this response preserves."""
|
||||
manifest = registry.get_phase_manifest(conn, phase_id)
|
||||
if manifest is None:
|
||||
raise HTTPException(status_code=404, detail="phase not found")
|
||||
entries = ledger.get_ledger(conn, phase_id)
|
||||
return metrics.compute_metrics(manifest, entries, metrics.utcnow())
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue