Skip to content

Commit 1952f25

Browse files
authored
test(operator-trend): characterization golden for _build_resolution_trend assembled payload (T3-2 phase 8a) (#94)
Pins the exact 388-key payload _build_resolution_trend assembles (its 1,676-line payload.update) across a 4-case corpus exercising both the falsy- and truthy-primary_target branches. Safety net for the upcoming god-function decomposition: extracting the payload-assembly seam and collapsing the per-tier blocks must reproduce this byte-for-byte. Enumerator-generated (never hand-authored); regenerate via uv run python tests/golden/enumerate_resolution_trend_contract.py
1 parent 698b6fd commit 1952f25

3 files changed

Lines changed: 4888 additions & 0 deletions

File tree

Lines changed: 218 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,218 @@
1+
"""Characterization enumerator for ``_build_resolution_trend`` — the 1,852-line
2+
god-function in ``operator_resolution_trend`` whose 1,676-line ``payload.update({...})``
3+
assembles the full operator resolution-trend payload (320+ keys) from the
4+
apply-chain / summary-context stages.
5+
6+
The sibling enumerators pin the lower layers:
7+
* ``enumerate_recovery_state_contract.py`` — the pure ``(status:str)->str`` classifiers.
8+
* ``enumerate_composer_contract.py`` — the per-tier dict/list composers.
9+
Neither exercises the *top-level assembly* — how the god-function wires the
10+
apply-chain tiers and summary-context into the final payload dict the two real
11+
consumers (``operator_control_center`` and ``operator_decision_quality``) read.
12+
This enumerator captures that assembled payload across a representative input
13+
corpus into a frozen golden, so the upcoming decomposition of the god-function
14+
(extracting the payload-assembly seam, then collapsing the per-tier blocks onto a
15+
parametrized base) is provably byte-identical: re-run this, diff the JSON, and a
16+
clean diff proves the structure was preserved.
17+
18+
Safety: imports only the pure-computation module (verified free of import-time
19+
DB/IO side effects, same as the sibling enumerators) and calls
20+
``_build_resolution_trend`` on in-memory synthetic inputs. Never opens a database.
21+
22+
Regenerate the golden only with an intentional, reviewed behavior change::
23+
24+
uv run python tests/golden/enumerate_resolution_trend_contract.py
25+
"""
26+
27+
from __future__ import annotations
28+
29+
import json
30+
from pathlib import Path
31+
from typing import Any
32+
33+
import src.operator_resolution_trend as m
34+
35+
REPO = Path(__file__).resolve().parents[2]
36+
GOLDEN_PATH = REPO / "tests" / "golden" / "resolution_trend_contract.golden.json"
37+
38+
39+
def _item(
40+
item_id: str,
41+
*,
42+
lane: str,
43+
kind: str,
44+
repo: str,
45+
title: str,
46+
age_days: int,
47+
severity: float,
48+
) -> dict[str, Any]:
49+
"""A queue/snapshot item rich enough for target selection + class keying."""
50+
return {
51+
"item_id": item_id,
52+
"id": item_id,
53+
"lane": lane,
54+
"kind": kind,
55+
"repo": repo,
56+
"title": title,
57+
"age_days": age_days,
58+
"severity": severity,
59+
"score": severity,
60+
"recommended_next_step": f"Act on {title}.",
61+
"reason": f"{title} needs attention.",
62+
}
63+
64+
65+
def _snapshot(items: list[dict], *, generated_at: str) -> dict[str, Any]:
66+
"""A history snapshot keyed by ``_queue_identity`` (item_id when present)."""
67+
return {
68+
"snapshot": {
69+
"items": {it["item_id"]: it for it in items},
70+
"has_attention": any(it["lane"] in ("blocked", "urgent") for it in items),
71+
"generated_at": generated_at,
72+
}
73+
}
74+
75+
76+
def _ts(day: int) -> str:
77+
return f"2026-04-{day:02d}T12:00:00Z"
78+
79+
80+
# --------------------------------------------------------------------------- #
81+
# Corpus: each case is (label, queue, history, evidence_events,
82+
# confidence_calibration, current_generated_at). Designed to exercise the empty
83+
# branch (falsy primary_target -> IfExp false-branches) AND a stale-attention
84+
# target that survives the full apply-chain (truthy primary_target -> IfExp
85+
# true-branches + populated per-tier summaries/hotspots).
86+
# --------------------------------------------------------------------------- #
87+
def _corpus() -> list[tuple[str, list, list, list, dict, str]]:
88+
blocked = _item(
89+
"RepoA:Harden auth",
90+
lane="blocked",
91+
kind="security",
92+
repo="RepoA",
93+
title="Harden auth",
94+
age_days=12,
95+
severity=0.9,
96+
)
97+
urgent = _item(
98+
"RepoB:Ship migration",
99+
lane="urgent",
100+
kind="migration",
101+
repo="RepoB",
102+
title="Ship migration",
103+
age_days=9,
104+
severity=0.7,
105+
)
106+
ready = _item(
107+
"RepoC:Polish docs",
108+
lane="ready",
109+
kind="docs",
110+
repo="RepoC",
111+
title="Polish docs",
112+
age_days=2,
113+
severity=0.3,
114+
)
115+
116+
# A long stale-attention history so the blocked item climbs the apply chain.
117+
stale_history = [
118+
_snapshot([blocked, urgent, ready], generated_at=_ts(day))
119+
for day in range(1, 9)
120+
]
121+
122+
evidence = [
123+
{
124+
"item_id": "RepoA:Harden auth",
125+
"kind": "intervention",
126+
"outcome": "in-progress",
127+
"generated_at": _ts(7),
128+
"magnitude": 0.8,
129+
},
130+
{
131+
"item_id": "RepoA:Harden auth",
132+
"kind": "resolution",
133+
"outcome": "confirmed",
134+
"generated_at": _ts(8),
135+
"magnitude": 0.6,
136+
},
137+
]
138+
calibration = {
139+
"confidence": 0.62,
140+
"sample_size": 14,
141+
"reliability": "noisy",
142+
"recent_accuracy": 0.55,
143+
}
144+
145+
return [
146+
("empty", [], [], [], {}, _ts(9)),
147+
(
148+
"single_blocked_stale",
149+
[blocked],
150+
stale_history,
151+
evidence,
152+
calibration,
153+
_ts(9),
154+
),
155+
(
156+
"multi_class_attention",
157+
[blocked, urgent, ready],
158+
stale_history,
159+
evidence,
160+
calibration,
161+
_ts(9),
162+
),
163+
(
164+
"attention_no_history",
165+
[blocked, urgent],
166+
[],
167+
[],
168+
{},
169+
_ts(9),
170+
),
171+
]
172+
173+
174+
def _jsonable(value: Any) -> Any:
175+
"""Stable, lossless-enough JSON projection. Sets -> sorted lists; tuples ->
176+
lists; anything exotic -> its repr (recorded as part of the contract)."""
177+
if isinstance(value, dict):
178+
return {str(k): _jsonable(v) for k, v in value.items()}
179+
if isinstance(value, (list, tuple)):
180+
return [_jsonable(v) for v in value]
181+
if isinstance(value, set):
182+
return ["<<set>>", *sorted(_jsonable(v) for v in value)]
183+
if isinstance(value, (str, int, float, bool)) or value is None:
184+
return value
185+
return repr(value)
186+
187+
188+
def build_contract() -> dict[str, Any]:
189+
contract: dict[str, Any] = {}
190+
for label, queue, history, evidence, calibration, generated_at in _corpus():
191+
payload = m._build_resolution_trend(
192+
queue,
193+
history,
194+
evidence,
195+
confidence_calibration=calibration,
196+
current_generated_at=generated_at,
197+
)
198+
contract[label] = _jsonable(payload)
199+
return contract
200+
201+
202+
def main() -> None:
203+
contract = build_contract()
204+
GOLDEN_PATH.write_text(json.dumps(contract, indent=2, sort_keys=True) + "\n")
205+
# Operator-facing sanity print (not part of the contract).
206+
cases = len(contract)
207+
keysets = {label: len(rows) for label, rows in contract.items()}
208+
primary = {
209+
label: bool(rows.get("primary_target")) for label, rows in contract.items()
210+
}
211+
print(f"wrote {GOLDEN_PATH.relative_to(REPO)}")
212+
print(f"cases: {cases}")
213+
print(f"keys per case: {keysets}")
214+
print(f"truthy primary_target per case: {primary}")
215+
216+
217+
if __name__ == "__main__":
218+
main()

0 commit comments

Comments
 (0)