vpp-ai-platform/skills-py/tests/test_fixtures.py
stewart hu f681e134cc M1: domain schemas, contracts pipeline, ledger and snapshot services
- packages/domain: zod schemas for the 07-scenario object set with a
  schemaRegistry driving schema export, fixture generation, and Python
  module naming; decimal-string/sha256/curve primitives enforce the
  docs/11 §3.3 representation rules at the type layer
- contracts/: 12 JSON Schemas (draft 2020-12), 12 golden fixtures, 3
  invalid fixtures crafted to fail on both sides (float money, bad
  digest, missing concurrency version)
- skills-py: generated pydantic models (committed, never hand-edited),
  regeneration script, mirror pytest using JSON-mode validation —
  dual-side contract tests agree on all 15 fixtures
- packages/services: content-addressed immutable snapshot store
  (memory + fs, rejects floats), LedgerService v1 with optimistic
  concurrency and the P7 constraint cascade (monthly position bounds
  day-ahead bids; no-anchor bids rejected), quality-gate stub
- cascade band shape is an OPEN-QUESTION A5 placeholder (pro-rata
  daily share ±band) — see ledger.ts checkCascade

All green: tsc typecheck, 41 TS tests, 15 Python tests.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019u5SLNweVio6ozJX7yfxQr

🔮 View transcript: https://logs.lojong.info/s/e8u90k3t33w590r7b5y7yzqh
2026-09-01 21:50:22 -04:00

38 lines
1.4 KiB
Python

"""Dual-side contract test (docs/11 §3.2): the same golden fixtures the TS side
validates must validate against the generated pydantic models, and the same
invalid fixtures must be rejected. Disagreement between sides fails CI."""
import importlib
from pathlib import Path
import pytest
from pydantic import BaseModel, ValidationError
ROOT = Path(__file__).resolve().parents[2] / "contracts"
def model_for(name: str) -> type[BaseModel]:
module = importlib.import_module(f"vpp_contracts.{name}")
class_name = "".join(part.capitalize() for part in name.split("_"))
return getattr(module, class_name)
def cases(dirname: str) -> list[tuple[str, Path]]:
out = []
for schema_dir in sorted((ROOT / dirname).iterdir()):
for f in sorted(schema_dir.glob("*.json")):
out.append((schema_dir.name, f))
return out
@pytest.mark.parametrize("name,path", cases("fixtures"), ids=lambda p: str(p))
def test_golden_fixture_validates(name: str, path: Path) -> None:
# JSON-mode validation — exactly how a skill service receives these objects.
model_for(name).model_validate_json(path.read_text())
@pytest.mark.parametrize("name,path", cases("fixtures-invalid"), ids=lambda p: str(p))
def test_invalid_fixture_rejected(name: str, path: Path) -> None:
with pytest.raises(ValidationError):
model_for(name).model_validate_json(path.read_text())