Implement Phase 0b base project against the frozen test contract

All seven services (gateway, ledger, fraud, sanctions, insights, notifier,
audit), db/schema.sql plus optional_indexes.sql, scripts/seed.py and
smoke.py, the gateway-served frontend, and docker-compose.yml. Plain-text
stdlib logging and a weak manual X-Request-Id only -- no observability yet,
by design, per test_no_observability.py. Implements all 13 named chaos-flag
pathologies from docs/PATHOLOGIES.md behind Redis-backed runtime flags.

make smoke and make test-contract pass; make test-baseline and
make test-pathology pass except for a handful of load-sensitive tests
documented in tests/README.md rather than papered over.
This commit is contained in:
Movses Aslanyan
2026-09-05 08:12:30 +03:30
parent ccf1783779
commit 91afea92a1
51 changed files with 2757 additions and 0 deletions
+75
View File
@@ -0,0 +1,75 @@
"""Shared low-level access to the `chaos:flags` Redis hash.
This is infrastructure (a Redis hash reader/writer), not pathology behaviour --
the mechanism each flag triggers lives in that service's own chaos.py, per
phase-0-base-project-spec.md §7 ("each pathology lives in a clearly named
chaos.py module inside its owning service"). Every service re-reads the hash
on every request; nothing here is cached in-process.
"""
import random
import time
from .redis_client import redis_client
FLAGS_KEY = "chaos:flags"
ALL_FLAGS = [
"slow_sanctions",
"sanctions_errors",
"n_plus_one",
"pool_starvation",
"row_lock_contention",
"blocking_event_loop",
"retry_storm",
"no_batching",
"unbounded_cache",
"slow_consumer",
"cold_cache",
"poison_data",
"chatty_health",
]
NAMED_PROFILES = {
"clean": set(),
"light": {"slow_sanctions", "cold_cache"},
"nightmare": set(ALL_FLAGS),
}
async def get_flags() -> dict:
raw = await redis_client.hgetall(FLAGS_KEY)
return {flag: raw.get(flag) == "1" for flag in ALL_FLAGS}
async def is_enabled(flag: str) -> bool:
return await redis_client.hget(FLAGS_KEY, flag) == "1"
async def set_flag(flag: str, enabled: bool) -> None:
if flag not in ALL_FLAGS:
raise ValueError(f"unknown flag {flag!r}")
await redis_client.hset(FLAGS_KEY, flag, "1" if enabled else "0")
async def set_profile(profile: str) -> dict:
if profile == "random":
# Seed derived from time.time(), never logged -- the active set lives
# only in the `chaos:flags` hash, per §7's "random" profile note.
rng = random.Random(time.time())
chosen = set(rng.sample(ALL_FLAGS, k=rng.randint(3, 6)))
elif profile in NAMED_PROFILES:
chosen = NAMED_PROFILES[profile]
else:
raise ValueError(f"unknown profile {profile!r}")
mapping = {flag: ("1" if flag in chosen else "0") for flag in ALL_FLAGS}
await redis_client.hset(FLAGS_KEY, mapping=mapping)
return await get_flags()
async def flags_fingerprint() -> str:
"""A short, stable string identifying the current flag combination. Used
to key the insights summary cache so a live flag change (G5) is never
masked by a stale cache entry written under a different chaos state."""
flags = await get_flags()
return "".join("1" if flags[f] else "0" for f in ALL_FLAGS)