Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -507,9 +507,13 @@ payload is lookup labels plus non-negative aggregate counts -- never
source SQL, a DSN, a raw record, or a provider body. After `make seed`,
Demo Analyst and Demo Admin see "Lineage reconstruction · Succeeded ·
Demo Corp" with "3 documents" and Pending / Running / Succeeded times,
the designed A-100 fork as clickable reconstructed edges, and
"TEPP measurement · Failed · Demo Corp" whose detail history ends
in Failed / `tepp_not_available`.
the designed A-100 fork as clickable reconstructed edges, Claimed
then Delivered outbox times, and "TEPP measurement · Failed · Demo
Corp" whose detail history ends in Failed / `tepp_not_available`.
Seed also records "Period report · Succeeded · Demo Corp" on that
same snapshot after the calibrated report tables are written
(ADR 0024). Open that row to confirm the cutoff posts; mean θ stays
on the period-report panel. Start stays 422.
A run-bearing registry is emptied only after an unrevoked
`analysis_run_retention_grant` and `GRANT analysis_run_retention_admin`,
then `purge_analysis_run_registry('approved-retention-purge')`
Expand Down
4 changes: 4 additions & 0 deletions CHANGELOG.d/0.95.0-analysis-run-outbox-delivery.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# 0.95.0 Analysis-run outbox delivery history

Open a seeded Succeeded lineage run to see Claimed then Delivered.
Stream ids stay off the payload.
4 changes: 4 additions & 0 deletions CHANGELOG.d/0.96.0-seed-period-report-run.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# 0.96.0 Seeded period-report analysis run

After `make seed`, open **Period report · Succeeded · Demo Corp**.
Mean θ stays on the period-report panel. No theta is copied.
19 changes: 19 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,25 @@ All notable changes to this project are documented here. Format follows
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/); versioning follows
[Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.96.0] - 2026-08-17

### Added

- `make seed` now records **Period report · Succeeded · Demo Corp** on
the shared snapshot after the calibrated report tables are written
(ADR 0024). Open that row to confirm the cutoff posts. Mean θ stays
on the period-report panel. Start stays 422. No TEPP theta is
invented.

## [0.95.0] - 2026-08-17

### Added

- Analysis-run detail now lists labeled outbox delivery: Claimed then
Delivered (ADR 0023). After `make seed`, open the Demo Corp lineage
run to see those times. Stream entry ids stay off the payload. No
TEPP theta is invented.

## [0.94.0] - 2026-08-17

### Added
Expand Down
8 changes: 5 additions & 3 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@ back 0020 then 0018. The published phrase is not a secret. Do not
retention grant to the application `DATABASE_URL` login. ADR 0019
is the R&R catalog-id bind, not this purge.

## Analysis-run seed (v0.85.0)
## Analysis-run seed (v0.96.0)

`make seed` writes a Demo Corp lineage run and a TEPP run on the same
snapshot (ADR 0013). The TEPP path goes through `tepp_client`. A missing
`make seed` writes a Demo Corp lineage run, a TEPP run, and a Succeeded
period-report run on the same snapshot (ADR 0013 / ADR 0024). The TEPP path goes through `tepp_client`. A missing
transport or an unused accepted envelope is Failed
(`tepp_not_available` / `tepp_result_not_persisted`). Do not invent a
theta or a local psychometric substitute. The home list caption stays
Expand All @@ -40,3 +40,5 @@ frozen cutoff bag (ADR 0021 / ADR 0023) or submits TEPP through
envelope is Failed. Failed TEPP is terminal — request a new run,
then start. Do not invent a theta. Hover the Result prefix to read
the parent-choice digest.
After `make seed`, open **Period report · Succeeded · Demo Corp**
to confirm the cutoff posts; mean θ stays on the period-report panel.
40 changes: 40 additions & 0 deletions backend/app/analysis_run_ingestion.py
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,45 @@ async def _status_history(
return history


async def fetch_outbox_deliveries(
conn: asyncpg.Connection,
analysis_run_id: str,
) -> list[dict[str, Any]]:
"""Labeled claim/delivery events for one already-visible run.

Missing outbox tables mean migration 0023 is not applied. Stream
entry ids stay off the payload -- they are not buyer evidence.
"""
try:
rows = await conn.fetch(
"""
select delivery_ordinal, delivery_status_code, occurred_at
from analysis_run_outbox_delivery
where analysis_run_id = $1::uuid
order by delivery_ordinal
""",
analysis_run_id,
)
except asyncpg.UndefinedTableError:
return []
labels = await labels_for_codes(
conn,
[row["delivery_status_code"] for row in rows],
)
return [
{
"delivery_ordinal": int(row["delivery_ordinal"]),
"delivery_status_code": row["delivery_status_code"],
"delivery_status_label": labels.get(
row["delivery_status_code"],
row["delivery_status_code"],
),
"occurred_at": _iso(row["occurred_at"]),
}
for row in rows
]


async def _serialize_runs(
conn: asyncpg.Connection,
rows: list[asyncpg.Record],
Expand Down Expand Up @@ -256,6 +295,7 @@ async def fetch_visible_analysis_run(
if row["failure_code"]:
detail["failure_code"] = row["failure_code"]
detail["status_history"] = await _status_history(conn, analysis_run_id)
detail["outbox_deliveries"] = await fetch_outbox_deliveries(conn, analysis_run_id)
detail["visible_posts"] = await fetch_visible_scope_posts(
conn,
row["scope_kind_code"],
Expand Down
5 changes: 4 additions & 1 deletion docs/adr/0013-normalized-analysis-run-registry.md
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,10 @@ Acceptance requires:
`tepp_client` on the frozen snapshot; a persistable measurement
remains a later slice. A missing or unused TEPP envelope must stay
Failed (`tepp_not_available` / `tepp_result_not_persisted`) and must
not write a local psychometric substitute.
not write a local psychometric substitute. Seed also records a
Succeeded `analysis_run_report` on that snapshot after the
period-report tables are written (ADR 0024); the registry row does
not copy a theta.
5. Execute private actual-data analysis and store only signed aggregate and
reproducibility manifests outside public source control.
6. Run browser E2E through real OIDC, product navigation, and evidence drill-down.
Expand Down
7 changes: 4 additions & 3 deletions docs/adr/0014-authorized-analysis-run-read.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,10 @@ LineageWeave owns a fail-closed read projection of the #89 registry:

## Consequences

`make seed` writes one synthetic Demo Corp lineage run and one TEPP
run on the same snapshot so the existing React home page can show both
kinds without a second application. The TEPP run is Failed /
`make seed` writes one synthetic Demo Corp lineage run, one TEPP
run, and one Succeeded period-report run on the same snapshot so the
existing React home page can show all three kinds without a second
application (ADR 0024). The TEPP run is Failed /
`tepp_not_available` when the default transport is missing -- the list
keeps that machine code off the caption (this decision) and instead
tells the operator to open the TEPP run, then connect the measurement
Expand Down
7 changes: 4 additions & 3 deletions docs/adr/0023-analysis-run-outbox.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,10 @@ before the registry rows.
## Consequences

Start survives a crash after Running. Refreshing a queued run finishes
the same work item. Valkey is a wake-up, not a source of truth. Do not
invent a theta, and do not stamp Succeeded from a missing reconstruct
library.
the same work item. Valkey is a wake-up, not a source of truth. Detail
lists labeled Claimed / Delivered events; stream entry ids stay off
the payload. Do not invent a theta, and do not stamp Succeeded from a
missing reconstruct library.

## References — APA 7th

Expand Down
67 changes: 67 additions & 0 deletions docs/adr/0024-seed-period-report-analysis-run.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# ADR 0024 — Seed records the built period report on the shared snapshot

**Decision status:** Accepted on this active PR; not protected-main truth until merge
**Date:** 2026-08-17
**Depends on:** ADR 0013 normalized analysis-run registry; ADR 0003
fast-mlsirm report integration; ADR 0014 authorized analysis-run read
**Refs:** Issue #79 (Milestone 2 parent). After `make seed`, lineage and
TEPP registry rows were visible on home Analysis runs, but the
calibrated period report lived only on the separate report panel.
ADR 0022 is authorized TEPP start. ADR 0023 is the durable start
outbox. This decision is the next free slot.

## Context

Seed already scores Demo Corp week-2/week-3 reports through
`fast-mlsirm` and persists them on the report tables. The analysis-run
registry already has `analysis_run_report`. Operators who opened
Analysis runs after `make seed` could retry a Failed TEPP transport or
inspect a Succeeded lineage tree, then had no registry row for the
report they could already see on the period-report panel.

A fake Failed report row would contradict the built report. Copying
mean θ onto `analysis_run` would invent a psychometric field the
registry is not allowed to store (ADR 0013). Starting a period-report
run through the lineage/TEPP outbox would invent a calibrated score
on a path that is not allowed to (ADR 0021 / ADR 0022 / ADR 0023).

## Decision

- `_seed_demo_period_report` still builds the calibrated report first.
- `_seed_demo_report_run` then inserts `analysis_run_report` on the
same Demo Corp snapshot, scoped to the same corporate entity.
- The lifecycle is Pending → Running → Succeeded because the report
tables already hold the scored period. The run row stores only
registry digests and counts — never a theta, item bank, or provider
body.
- Home next-action copy for a Succeeded report stays empty. Failed
report fixtures still say rebuild the period report.
- `POST /api/analysis-runs` stays lineage-or-TEPP (ADR 0017).
`POST /api/analysis-runs/{id}/start` stays 422 for this kind.
This slice does not add a Request period-report button, does not
enqueue outbox work, and does not call TEPP.

## Consequences

After `make seed`, Demo Analyst opens Analysis runs and sees
**Period report · Succeeded · Demo Corp** next to the lineage and TEPP
rows. Opening it shows the cutoff posts. Mean θ remains on the
period-report panel. Re-seed is idempotent on
`demo-report-seed-2026-w02`.

## References — APA 7th

American Educational Research Association, American Psychological
Association, & National Council on Measurement in Education. (2014).
*Standards for educational and psychological testing*. American
Educational Research Association.

International Organization for Standardization. (2019). *ISO 8601-1:2019:
Date and time—Representations for information interchange—Part 1: Basic
rules* (confirmed 2024; Amendment 1:2022).

Moreau, L., & Missier, P. (Eds.). (2013). *PROV-DM: The PROV data model*.
World Wide Web Consortium. https://www.w3.org/TR/prov-dm/

World Wide Web Consortium. (2022). *Time ontology in OWL* (W3C
Recommendation). https://www.w3.org/TR/owl-time/
4 changes: 2 additions & 2 deletions docs/doctoring/ANALYSIS_RUN_REGISTRY_REFERENCES.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@

**Status:** Active PR evidence; not protected-main truth until merge.
**Scope:** Migrations 0018–0023, ADR 0013 / 0017 / 0020 / 0021 / 0022 /
0023, rollback, and real-PostgreSQL contract tests.
0023 / 0024, rollback, and real-PostgreSQL contract tests.

## Standards mapped to implementation

| Source | Product implication | Implemented evidence |
|---|---|---|
| W3C PROV-DM and PROV-O | Preserve identifiable entities, activities, agents, generation/use, and derivation without flattening provenance into display-only edges. | `analysis_source_snapshot`, `analysis_run`, authenticated requester, append-only status events, immutable digests; later product bindings continue to use the separate `provenance_*` layer from ADR 0011. |
| W3C Time Ontology in OWL | Keep temporal concepts explicit and avoid collapsing distinct clocks. | Evidence availability and snapshot capture remain on `analysis_source_snapshot`; analysis knowledge cutoff and request time remain on `analysis_run`; status occurrence and database record time remain distinct. `GET /api/analysis-runs/{id}` visible posts apply `created_at <= knowledge_cutoff` (ADR 0016). Detail compares live `updated_at` with that cutoff and marks titles rewritten after the run. |
| W3C Time Ontology in OWL | Keep temporal concepts explicit and avoid collapsing distinct clocks. | Evidence availability and snapshot capture remain on `analysis_source_snapshot`; analysis knowledge cutoff and request time remain on `analysis_run`; status occurrence and database record time remain distinct. `GET /api/analysis-runs/{id}` visible posts apply `created_at <= knowledge_cutoff` (ADR 0016). Detail compares live `updated_at` with that cutoff and marks titles rewritten after the run. Seed records the built period report as a later Succeeded run on that same snapshot (ADR 0024) without copying a theta onto the registry row. |
| W3C Accessible Name and Description Computation 1.1 | Do not let `aria-label` replace visible text the operator must hear. | Analysis-run digest prefixes live in a labeled group; the prefixes remain the accessible contents and the full digest is on `title` for hover verification. |
| ISO 8601-1:2019 | Use unambiguous timestamp representation and timezone-aware persistence. | PostgreSQL `timestamptz` for availability, capture, cutoff, request, occurrence, and record clocks; tests use explicit `Z` offsets. |
| PostgreSQL 18 constraints and trigger contracts | Put integrity close to durable truth and use constraints for row shape while triggers enforce cross-row state and serialization. | Digest/check constraints, category allowlists, account-scoped uniqueness, shape constraints, immutable-row triggers, shared snapshot-row locking, and serialized status transitions. |
Expand Down
2 changes: 1 addition & 1 deletion frontend/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "frontend",
"private": true,
"version": "0.94.0",
"version": "0.96.0",
"type": "module",
"scripts": {
"dev": "vite",
Expand Down
Loading