Add hosted conformance suite and close WP-0006 (T08)
tests/test_hosted_conformance.py (6 Docker-gated tests) addresses all
three requirements from the task description: the golden Phase example
(manifest + full ledger + all 4 extensions) replayed through the
hosted API reproduces exactly the offline-established outcome
(Development Credit 67000, Remission Credit 33000, Outstanding Target
0, MIT) including the hosted Attestation; two Phases under different
Licensors operate with interleaved appends and are proven isolated
both positively and negatively (cross-Licensor writes rejected); a
parametrized regression test across four ledger shapes (credits-only,
remission, reversal, admin corrections) confirms hosted-append-then-
offline-fold always matches expected totals.
WP-0006 is now finished - all 8 tasks (PRD, ADR-0002, registries,
ledger API, metrics, attestation, onboarding, conformance) done. T01's
flagged gap (no task owns hosting the Breach/Compliance Record
component from License V1C1 §7.4) remains open and unassigned.
2026-07-29 22:07:39 +02:00
|
|
|
"""Hosted-scale conformance suite (WP-0006-T08).
|
|
|
|
|
|
|
|
|
|
Extends WP-0002's offline conformance suite (`tests/test_*.py`, 36 tests)
|
|
|
|
|
to run against the actual hosted service, per the task's own three
|
|
|
|
|
requirements:
|
|
|
|
|
|
|
|
|
|
1. the golden Phase example (`examples/phase-001/`) replayed through the
|
|
|
|
|
hosted API end-to-end, not only the offline library;
|
|
|
|
|
2. multiple concurrent Phases across different Licensors, isolated from
|
|
|
|
|
one another;
|
|
|
|
|
3. a standing regression check that hosted and offline folds of the same
|
|
|
|
|
exported ledger always agree — generalized here across several ledger
|
|
|
|
|
shapes (development-credit, remission-credit, credit-reversal,
|
|
|
|
|
administrative corrections), not just the golden fixture's own shape.
|
|
|
|
|
|
|
|
|
|
Same ephemeral, disposable Postgres-via-Docker pattern as the other hosted
|
|
|
|
|
test modules (never the shared state-hub instance).
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
from __future__ import annotations
|
|
|
|
|
|
|
|
|
|
import shutil
|
|
|
|
|
import subprocess
|
|
|
|
|
import time
|
|
|
|
|
import uuid
|
|
|
|
|
from pathlib import Path
|
|
|
|
|
|
|
|
|
|
import pytest
|
|
|
|
|
|
|
|
|
|
psycopg = pytest.importorskip("psycopg")
|
|
|
|
|
pytest.importorskip("fastapi")
|
|
|
|
|
from fastapi.testclient import TestClient # noqa: E402
|
|
|
|
|
|
|
|
|
|
from conftest import golden_entries, golden_extension, golden_manifest # noqa: E402
|
|
|
|
|
|
|
|
|
|
REPO_ROOT = Path(__file__).resolve().parents[1]
|
|
|
|
|
MIGRATIONS = [
|
|
|
|
|
REPO_ROOT / "migrations" / "0001_registries.sql",
|
|
|
|
|
REPO_ROOT / "migrations" / "0002_ledger.sql",
|
|
|
|
|
REPO_ROOT / "migrations" / "0003_attestations.sql",
|
2026-07-29 22:23:41 +02:00
|
|
|
REPO_ROOT / "migrations" / "0004_breach_records.sql",
|
Add hosted conformance suite and close WP-0006 (T08)
tests/test_hosted_conformance.py (6 Docker-gated tests) addresses all
three requirements from the task description: the golden Phase example
(manifest + full ledger + all 4 extensions) replayed through the
hosted API reproduces exactly the offline-established outcome
(Development Credit 67000, Remission Credit 33000, Outstanding Target
0, MIT) including the hosted Attestation; two Phases under different
Licensors operate with interleaved appends and are proven isolated
both positively and negatively (cross-Licensor writes rejected); a
parametrized regression test across four ledger shapes (credits-only,
remission, reversal, admin corrections) confirms hosted-append-then-
offline-fold always matches expected totals.
WP-0006 is now finished - all 8 tasks (PRD, ADR-0002, registries,
ledger API, metrics, attestation, onboarding, conformance) done. T01's
flagged gap (no task owns hosting the Breach/Compliance Record
component from License V1C1 §7.4) remains open and unassigned.
2026-07-29 22:07:39 +02:00
|
|
|
]
|
|
|
|
|
EXTENSION_NAMES = [
|
|
|
|
|
"development-license",
|
|
|
|
|
"cost-plus-operations",
|
|
|
|
|
"phase-sponsorship",
|
|
|
|
|
"service-with-development-allocation",
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
pytestmark = pytest.mark.skipif(
|
|
|
|
|
shutil.which("docker") is None, reason="docker not available"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.fixture(scope="module")
|
|
|
|
|
def pg_container():
|
|
|
|
|
name = f"trf-test-pg-conformance-{uuid.uuid4().hex[:8]}"
|
|
|
|
|
subprocess.run(
|
|
|
|
|
[
|
|
|
|
|
"docker", "run", "--rm", "-d",
|
|
|
|
|
"--name", name,
|
|
|
|
|
"-e", "POSTGRES_PASSWORD=postgres",
|
|
|
|
|
"-e", "POSTGRES_DB=target_revenue_test",
|
|
|
|
|
"-p", "127.0.0.1::5432",
|
|
|
|
|
"postgres:16-alpine",
|
|
|
|
|
],
|
|
|
|
|
check=True, capture_output=True,
|
|
|
|
|
)
|
|
|
|
|
try:
|
|
|
|
|
port_out = subprocess.run(
|
|
|
|
|
["docker", "port", name, "5432/tcp"], check=True, capture_output=True, text=True
|
|
|
|
|
).stdout.strip()
|
|
|
|
|
host_port = port_out.split(":")[-1]
|
|
|
|
|
dsn = f"host=127.0.0.1 port={host_port} dbname=target_revenue_test user=postgres password=postgres"
|
|
|
|
|
|
|
|
|
|
for _ in range(60):
|
|
|
|
|
try:
|
|
|
|
|
with psycopg.connect(dsn, connect_timeout=1):
|
|
|
|
|
break
|
|
|
|
|
except psycopg.OperationalError:
|
|
|
|
|
time.sleep(0.5)
|
|
|
|
|
else:
|
|
|
|
|
raise RuntimeError("postgres container did not become ready in time")
|
|
|
|
|
|
|
|
|
|
with psycopg.connect(dsn) as conn:
|
|
|
|
|
for migration in MIGRATIONS:
|
|
|
|
|
conn.execute(migration.read_text(encoding="utf-8"))
|
|
|
|
|
conn.commit()
|
|
|
|
|
for token, licensor_id in [
|
|
|
|
|
("test-token-repo-a", "coulomb-loop"),
|
|
|
|
|
("test-token-repo-b", "net-kingdom"),
|
|
|
|
|
]:
|
|
|
|
|
conn.execute(
|
|
|
|
|
"INSERT INTO licensors (token, licensor_id) VALUES (%s, %s)",
|
|
|
|
|
(token, licensor_id),
|
|
|
|
|
)
|
|
|
|
|
conn.commit()
|
|
|
|
|
|
|
|
|
|
app_dsn = (
|
|
|
|
|
f"host=127.0.0.1 port={host_port} dbname=target_revenue_test "
|
|
|
|
|
f"user=trf_app password=changeme-in-deployment"
|
|
|
|
|
)
|
|
|
|
|
yield {"app_dsn": app_dsn, "token_a": "test-token-repo-a", "token_b": "test-token-repo-b"}
|
|
|
|
|
finally:
|
|
|
|
|
subprocess.run(["docker", "stop", name], capture_output=True)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.fixture()
|
|
|
|
|
def client(pg_container, monkeypatch):
|
|
|
|
|
monkeypatch.setenv("TRF_DATABASE_URL", pg_container["app_dsn"])
|
|
|
|
|
monkeypatch.setenv("TRF_SIGNING_KEY_HEX", "33" * 32)
|
|
|
|
|
from target_revenue.service import app as app_module
|
|
|
|
|
|
|
|
|
|
if hasattr(app_module.app.state, "pool"):
|
|
|
|
|
app_module.app.state.pool.close()
|
|
|
|
|
del app_module.app.state.pool
|
|
|
|
|
if hasattr(app_module.app.state, "signing_key"):
|
|
|
|
|
del app_module.app.state.signing_key
|
|
|
|
|
with TestClient(app_module.app) as c:
|
|
|
|
|
yield c
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def auth(token: str) -> dict[str, str]:
|
|
|
|
|
return {"Authorization": f"Bearer {token}"}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_golden_phase_replayed_through_hosted_api_matches_offline_library(client, pg_container):
|
|
|
|
|
"""Requirement 1: the golden Phase example, replayed through the
|
|
|
|
|
hosted API rather than the offline library, must reproduce exactly
|
|
|
|
|
the outcomes tests/test_conversion.py and tests/test_ledger_fold.py
|
|
|
|
|
already established offline (Development Credit 67000, Remission
|
|
|
|
|
Credit 33000, Outstanding Target 0, future_license MIT)."""
|
|
|
|
|
from target_revenue import conversion, fold
|
|
|
|
|
|
|
|
|
|
manifest = golden_manifest()
|
|
|
|
|
manifest["phase"]["id"] = manifest["phase"]["id"] + "-conformance-golden-" + uuid.uuid4().hex[:6]
|
|
|
|
|
phase_id = manifest["phase"]["id"]
|
|
|
|
|
|
|
|
|
|
resp = client.post("/phases", json=manifest, headers=auth(pg_container["token_a"]))
|
|
|
|
|
assert resp.status_code == 201, resp.text
|
|
|
|
|
|
|
|
|
|
for name in EXTENSION_NAMES:
|
|
|
|
|
ext = golden_extension(name)
|
|
|
|
|
ext_resp = client.post("/extensions", json=ext, headers=auth(pg_container["token_a"]))
|
|
|
|
|
# Extensions are shared/global, not per-Phase — a second replay in
|
|
|
|
|
# the same test session would collide; accept both outcomes here.
|
|
|
|
|
assert ext_resp.status_code in (201, 422)
|
|
|
|
|
|
|
|
|
|
for entry in golden_entries():
|
|
|
|
|
submitted = {k: v for k, v in entry.items() if k not in ("previous_entry_hash", "signature")}
|
|
|
|
|
submitted["phase"] = phase_id
|
|
|
|
|
entry_resp = client.post(f"/phases/{phase_id}/ledger", json=submitted, headers=auth(pg_container["token_a"]))
|
|
|
|
|
assert entry_resp.status_code == 201, entry_resp.text
|
|
|
|
|
|
|
|
|
|
exported_entries = client.get(f"/phases/{phase_id}/ledger").json()
|
|
|
|
|
hosted_result = fold.fold_outstanding_target(
|
|
|
|
|
manifest["phase"]["initial_target"]["amount"], exported_entries
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
offline_manifest = golden_manifest()
|
|
|
|
|
offline_status = conversion.conversion_status(offline_manifest, golden_entries())
|
|
|
|
|
|
|
|
|
|
assert hosted_result.development_credit == offline_status.development_credit == 67000
|
|
|
|
|
assert hosted_result.remission_credit == offline_status.remission_credit == 33000
|
|
|
|
|
assert hosted_result.outstanding_target == offline_status.outstanding_target == 0
|
|
|
|
|
assert hosted_result.is_converted is offline_status.is_converted is True
|
|
|
|
|
|
|
|
|
|
attestation_resp = client.get(f"/phases/{phase_id}/attestation")
|
|
|
|
|
assert attestation_resp.status_code == 200
|
|
|
|
|
hosted_attestation = attestation_resp.json()
|
|
|
|
|
assert hosted_attestation["final_development_credit"] == 67000
|
|
|
|
|
assert hosted_attestation["final_remission_credit"] == 33000
|
|
|
|
|
assert hosted_attestation["final_outstanding_target"] == 0
|
|
|
|
|
assert hosted_attestation["future_license"] == "MIT"
|
|
|
|
|
assert hosted_attestation["ledger_checkpoint"] == golden_entries()[-1]["id"]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_multiple_concurrent_phases_across_different_licensors_are_isolated(client, pg_container):
|
|
|
|
|
"""Requirement 2: two Phases, belonging to two different Licensors
|
|
|
|
|
(standing in for two different product-line repos, e.g. coulomb-loop
|
|
|
|
|
and net-kingdom), operate concurrently without cross-contamination —
|
|
|
|
|
each Licensor's writes and reads only ever affect its own Phase."""
|
|
|
|
|
manifest_a = golden_manifest()
|
|
|
|
|
manifest_a["phase"]["id"] = "trsl:phase:conformance-repo-a-" + uuid.uuid4().hex[:6]
|
|
|
|
|
manifest_a["phase"]["initial_target"]["amount"] = 10000
|
|
|
|
|
|
|
|
|
|
manifest_b = golden_manifest()
|
|
|
|
|
manifest_b["phase"]["id"] = "trsl:phase:conformance-repo-b-" + uuid.uuid4().hex[:6]
|
|
|
|
|
manifest_b["phase"]["initial_target"]["amount"] = 20000
|
|
|
|
|
|
|
|
|
|
assert client.post("/phases", json=manifest_a, headers=auth(pg_container["token_a"])).status_code == 201
|
|
|
|
|
assert client.post("/phases", json=manifest_b, headers=auth(pg_container["token_b"])).status_code == 201
|
|
|
|
|
|
|
|
|
|
def entry(phase_id: str, entry_id: str, amount: float) -> dict:
|
|
|
|
|
return {
|
|
|
|
|
"id": entry_id,
|
|
|
|
|
"phase": phase_id,
|
|
|
|
|
"type": "development-credit",
|
|
|
|
|
"amount": amount,
|
|
|
|
|
"currency": "USD",
|
|
|
|
|
"recognized_at": "2026-08-01T00:00:00Z",
|
|
|
|
|
"evidence_reference": f"confidential:evidence:{entry_id}",
|
|
|
|
|
"extension": {"id": "trsl:extension:development-license", "version": "1.0"},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# Interleaved appends across both Phases, simulating concurrent
|
|
|
|
|
# multi-repo activity rather than strictly sequential per-Phase use.
|
|
|
|
|
a1 = client.post(
|
|
|
|
|
f"/phases/{manifest_a['phase']['id']}/ledger",
|
|
|
|
|
json=entry(manifest_a["phase"]["id"], "trsl:entry:conformrepoa0001", 3000),
|
|
|
|
|
headers=auth(pg_container["token_a"]),
|
|
|
|
|
)
|
|
|
|
|
b1 = client.post(
|
|
|
|
|
f"/phases/{manifest_b['phase']['id']}/ledger",
|
|
|
|
|
json=entry(manifest_b["phase"]["id"], "trsl:entry:conformrepob0001", 5000),
|
|
|
|
|
headers=auth(pg_container["token_b"]),
|
|
|
|
|
)
|
|
|
|
|
a2 = client.post(
|
|
|
|
|
f"/phases/{manifest_a['phase']['id']}/ledger",
|
|
|
|
|
json=entry(manifest_a["phase"]["id"], "trsl:entry:conformrepoa0002", 2000),
|
|
|
|
|
headers=auth(pg_container["token_a"]),
|
|
|
|
|
)
|
|
|
|
|
assert a1.status_code == b1.status_code == a2.status_code == 201
|
|
|
|
|
|
|
|
|
|
# Cross-Licensor writes are rejected (isolation, not just non-interference).
|
|
|
|
|
cross = client.post(
|
|
|
|
|
f"/phases/{manifest_a['phase']['id']}/ledger",
|
|
|
|
|
json=entry(manifest_a["phase"]["id"], "trsl:entry:conformrepoacross", 1),
|
|
|
|
|
headers=auth(pg_container["token_b"]),
|
|
|
|
|
)
|
|
|
|
|
assert cross.status_code == 422
|
|
|
|
|
|
|
|
|
|
metrics_a = client.get(f"/phases/{manifest_a['phase']['id']}/metrics").json()
|
|
|
|
|
metrics_b = client.get(f"/phases/{manifest_b['phase']['id']}/metrics").json()
|
|
|
|
|
|
|
|
|
|
assert metrics_a["facts"]["cumulative_development_credit"] == 5000
|
|
|
|
|
assert metrics_b["facts"]["cumulative_development_credit"] == 5000 # only b1 applied to B
|
|
|
|
|
assert metrics_a["facts"]["outstanding_target"] == 5000
|
|
|
|
|
assert metrics_b["facts"]["outstanding_target"] == 15000
|
|
|
|
|
|
|
|
|
|
ledger_a = client.get(f"/phases/{manifest_a['phase']['id']}/ledger").json()
|
|
|
|
|
ledger_b = client.get(f"/phases/{manifest_b['phase']['id']}/ledger").json()
|
|
|
|
|
assert {e["id"] for e in ledger_a} == {"trsl:entry:conformrepoa0001", "trsl:entry:conformrepoa0002"}
|
|
|
|
|
assert {e["id"] for e in ledger_b} == {"trsl:entry:conformrepob0001"}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
|
|
|
"plan",
|
|
|
|
|
[
|
|
|
|
|
[("development-credit", 1000), ("development-credit", 500)],
|
|
|
|
|
[("development-credit", 2000), ("remission-credit", 300)],
|
|
|
|
|
[("development-credit", 5000), ("credit-reversal", 1000)],
|
|
|
|
|
[
|
|
|
|
|
("development-credit", 4000),
|
|
|
|
|
("administrative-correction-development", 250),
|
|
|
|
|
("administrative-correction-remission", 100),
|
|
|
|
|
],
|
|
|
|
|
],
|
|
|
|
|
ids=["credits-only", "with-remission", "with-reversal", "with-admin-corrections"],
|
|
|
|
|
)
|
|
|
|
|
def test_hosted_and_offline_fold_always_agree(client, pg_container, plan):
|
|
|
|
|
"""Requirement 3, generalized: for several distinct ledger shapes (not
|
|
|
|
|
only the golden fixture's own), appending through the hosted API and
|
|
|
|
|
folding the export offline must reproduce exactly the same
|
|
|
|
|
Development Credit, Remission Credit, and Outstanding Target the plan
|
|
|
|
|
implies by construction."""
|
|
|
|
|
from target_revenue import fold, hashing
|
|
|
|
|
|
|
|
|
|
manifest = golden_manifest()
|
|
|
|
|
manifest["phase"]["id"] = "trsl:phase:conformance-plan-" + uuid.uuid4().hex[:8]
|
|
|
|
|
manifest["phase"]["initial_target"]["amount"] = 100000
|
|
|
|
|
phase_id = manifest["phase"]["id"]
|
|
|
|
|
|
|
|
|
|
assert client.post("/phases", json=manifest, headers=auth(pg_container["token_a"])).status_code == 201
|
|
|
|
|
|
|
|
|
|
expected_dev = 0.0
|
|
|
|
|
expected_rem = 0.0
|
|
|
|
|
for i, (entry_type, amount) in enumerate(plan, start=1):
|
|
|
|
|
e = {
|
|
|
|
|
"id": f"trsl:entry:conformplan{uuid.uuid4().hex[:6]}{i:02d}",
|
|
|
|
|
"phase": phase_id,
|
|
|
|
|
"type": entry_type,
|
|
|
|
|
"amount": amount,
|
|
|
|
|
"currency": "USD",
|
|
|
|
|
"recognized_at": f"2026-08-{i:02d}T00:00:00Z",
|
|
|
|
|
"evidence_reference": f"confidential:evidence:plan-{i}",
|
|
|
|
|
}
|
|
|
|
|
if entry_type in ("development-credit", "remission-credit"):
|
|
|
|
|
e["extension"] = {"id": "trsl:extension:development-license", "version": "1.0"}
|
|
|
|
|
if entry_type == "credit-reversal":
|
|
|
|
|
e["reverses"] = "trsl:entry:conformplanseed"
|
|
|
|
|
resp = client.post(f"/phases/{phase_id}/ledger", json=e, headers=auth(pg_container["token_a"]))
|
|
|
|
|
assert resp.status_code == 201, resp.text
|
|
|
|
|
|
|
|
|
|
if entry_type == "development-credit":
|
|
|
|
|
expected_dev += amount
|
|
|
|
|
elif entry_type == "remission-credit":
|
|
|
|
|
expected_rem += amount
|
|
|
|
|
elif entry_type == "credit-reversal":
|
|
|
|
|
expected_dev -= amount
|
|
|
|
|
elif entry_type == "administrative-correction-development":
|
|
|
|
|
expected_dev += amount
|
|
|
|
|
elif entry_type == "administrative-correction-remission":
|
|
|
|
|
expected_rem += amount
|
|
|
|
|
|
|
|
|
|
exported = client.get(f"/phases/{phase_id}/ledger").json()
|
|
|
|
|
hashing.verify_chain(exported)
|
|
|
|
|
result = fold.fold_outstanding_target(manifest["phase"]["initial_target"]["amount"], exported)
|
|
|
|
|
|
|
|
|
|
assert result.development_credit == expected_dev
|
|
|
|
|
assert result.remission_credit == expected_rem
|
|
|
|
|
assert result.outstanding_target == max(
|
|
|
|
|
0.0, manifest["phase"]["initial_target"]["amount"] - expected_dev - expected_rem
|
|
|
|
|
)
|