Skip to content

Commit 7c4104d

Browse files
Pigbibicodex
andauthored
feat: integrate political event weekly manifest (#27)
* feat: add weekly manifest integration Co-Authored-By: Codex <noreply@openai.com> * fix: enforce canonical weekly manifest wire Co-Authored-By: Codex <noreply@openai.com> --------- Co-authored-by: Codex <noreply@openai.com>
1 parent f9fd69e commit 7c4104d

2 files changed

Lines changed: 185 additions & 0 deletions

File tree

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
"""Pure deterministic manifest integration for ``political_event_weekly.v1``."""
2+
from __future__ import annotations
3+
4+
import json
5+
from collections.abc import Mapping
6+
from pathlib import Path
7+
8+
from .weekly_contract import WeeklyContractError, WeeklySourceContract, parse_weekly_contract, serialize_weekly_contract
9+
10+
MANIFEST_TYPE = "political_event_weekly_manifest"
11+
_MANIFEST_KEYS = frozenset({"manifest_type", "contract"})
12+
13+
14+
def build_weekly_manifest(contract: WeeklySourceContract) -> dict[str, object]:
15+
if not isinstance(contract, WeeklySourceContract):
16+
raise WeeklyContractError("manifest_contract_invalid")
17+
try:
18+
contract_payload = json.loads(serialize_weekly_contract(contract))
19+
except (TypeError, ValueError, UnicodeError):
20+
raise WeeklyContractError("manifest_contract_invalid") from None
21+
return {"manifest_type": MANIFEST_TYPE, "contract": contract_payload}
22+
23+
24+
def parse_weekly_manifest(value: Mapping[str, object]) -> WeeklySourceContract:
25+
if not isinstance(value, Mapping) or set(value) != _MANIFEST_KEYS or value.get("manifest_type") != MANIFEST_TYPE:
26+
raise WeeklyContractError("manifest_shape_invalid")
27+
contract = value.get("contract")
28+
if not isinstance(contract, Mapping):
29+
raise WeeklyContractError("manifest_contract_invalid")
30+
return parse_weekly_contract(contract)
31+
32+
33+
def parse_weekly_manifest_bytes(wire: bytes) -> WeeklySourceContract:
34+
if type(wire) is not bytes:
35+
raise WeeklyContractError("manifest_wire_invalid")
36+
37+
def pairs(items: list[tuple[str, object]]) -> dict[str, object]:
38+
result: dict[str, object] = {}
39+
for key, item in items:
40+
if key in result:
41+
raise WeeklyContractError("manifest_duplicate_key")
42+
result[key] = item
43+
return result
44+
45+
try:
46+
value = json.loads(wire.decode("utf-8"), object_pairs_hook=pairs)
47+
except WeeklyContractError:
48+
raise
49+
except (UnicodeError, json.JSONDecodeError, TypeError, ValueError, RecursionError):
50+
raise WeeklyContractError("manifest_wire_invalid") from None
51+
if not isinstance(value, Mapping):
52+
raise WeeklyContractError("manifest_shape_invalid")
53+
contract = parse_weekly_manifest(value)
54+
if serialize_weekly_manifest(contract) != wire:
55+
raise WeeklyContractError("manifest_noncanonical")
56+
return contract
57+
58+
59+
def validate_weekly_manifest(value: Mapping[str, object], expected: WeeklySourceContract) -> WeeklySourceContract:
60+
if not isinstance(expected, WeeklySourceContract):
61+
raise WeeklyContractError("manifest_expected_invalid")
62+
parsed = parse_weekly_manifest(value)
63+
if parsed != expected:
64+
raise WeeklyContractError("manifest_contract_mismatch")
65+
if build_weekly_manifest(parsed) != dict(value):
66+
raise WeeklyContractError("manifest_noncanonical")
67+
return parsed
68+
69+
70+
def serialize_weekly_manifest(contract: WeeklySourceContract) -> bytes:
71+
payload = build_weekly_manifest(contract)
72+
try:
73+
return json.dumps(payload, ensure_ascii=False, sort_keys=True, separators=(",", ":")).encode("utf-8")
74+
except (TypeError, ValueError, UnicodeError):
75+
raise WeeklyContractError("manifest_serialization_invalid") from None
76+
77+
78+
def write_weekly_manifest(contract: WeeklySourceContract, output_path: str | Path) -> Path:
79+
content = serialize_weekly_manifest(contract)
80+
output = Path(output_path)
81+
try:
82+
output.parent.mkdir(parents=True, exist_ok=True)
83+
output.write_bytes(content)
84+
except (OSError, TypeError, ValueError):
85+
raise WeeklyContractError("manifest_write_invalid") from None
86+
return output

tests/test_weekly_manifest.py

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
from __future__ import annotations
2+
3+
import json
4+
from pathlib import Path
5+
6+
import pytest
7+
8+
from political_event_tracking_research.weekly_contract import WeeklyContractError, parse_weekly_contract
9+
from political_event_tracking_research.weekly_manifest import (
10+
MANIFEST_TYPE,
11+
build_weekly_manifest,
12+
parse_weekly_manifest,
13+
parse_weekly_manifest_bytes,
14+
serialize_weekly_manifest,
15+
validate_weekly_manifest,
16+
write_weekly_manifest,
17+
)
18+
19+
20+
def contract_payload(**overrides: object) -> dict[str, object]:
21+
value: dict[str, object] = {
22+
"schema_version": "1", "contract_version": "political_event_weekly.v1", "cadence": "weekly",
23+
"as_of": "2026-07-12", "period_start": "2026-07-06", "period_end_exclusive": "2026-07-13",
24+
"generated_at": "2026-07-13T00:00:00.123456Z", "run_mode": "manual", "producer_ref": "a" * 40,
25+
"source_provenance": "official_political_event_tracking_research_v1",
26+
"source_artifacts": [{"path": "data/live/political_events.csv", "sha256": "b" * 64, "row_count": 11}],
27+
"feed_status": {"feed_count": 12, "successful_feed_count": 12, "failed_feed_count": 0, "stale_feed_count": 0, "missing_feed_count": 0, "complete": True},
28+
}
29+
value.update(overrides)
30+
return value
31+
32+
33+
def test_weekly_manifest_is_deterministic_and_round_trips():
34+
contract = parse_weekly_contract(contract_payload())
35+
manifest = build_weekly_manifest(contract)
36+
assert manifest["manifest_type"] == MANIFEST_TYPE
37+
encoded = serialize_weekly_manifest(contract)
38+
assert encoded == serialize_weekly_manifest(parse_weekly_manifest(json.loads(encoded)))
39+
assert parse_weekly_manifest(manifest) == contract
40+
assert parse_weekly_manifest_bytes(encoded) == contract
41+
42+
43+
@pytest.mark.parametrize("wire", [
44+
lambda encoded: b" " + encoded,
45+
lambda encoded: encoded.replace(b'"contract":', b'"contract" :'),
46+
lambda encoded: encoded.replace(b'"manifest_type":', b'"manifest_type":"x","manifest_type":'),
47+
])
48+
def test_manifest_wire_must_be_exact_canonical_bytes(wire):
49+
contract = parse_weekly_contract(contract_payload())
50+
encoded = serialize_weekly_manifest(contract)
51+
with pytest.raises(WeeklyContractError):
52+
parse_weekly_manifest_bytes(wire(encoded))
53+
54+
55+
@pytest.mark.parametrize("field,value", [
56+
("as_of", "2026-07-13"),
57+
("generated_at", "2026-07-12T23:59:59Z"),
58+
("producer_ref", "c" * 40),
59+
("source_provenance", "official_other_v1"),
60+
("source_artifacts", [{"path": "data/live/political_events.csv", "sha256": "c" * 64, "row_count": 12}]),
61+
])
62+
def test_manifest_contract_tamper_is_rejected(field, value):
63+
contract = parse_weekly_contract(contract_payload())
64+
manifest = build_weekly_manifest(contract)
65+
manifest["contract"][field] = value
66+
with pytest.raises(WeeklyContractError):
67+
validate_weekly_manifest(manifest, contract)
68+
69+
70+
def test_mapping_with_alias_or_unknown_shape_fails_closed():
71+
contract = parse_weekly_contract(contract_payload())
72+
manifest = build_weekly_manifest(contract)
73+
manifest["contract"]["generatedAt"] = manifest["contract"].pop("generated_at")
74+
with pytest.raises(WeeklyContractError):
75+
validate_weekly_manifest(manifest, contract)
76+
77+
78+
def test_manifest_feed_partial_and_shape_tamper_fail_closed():
79+
contract = parse_weekly_contract(contract_payload())
80+
manifest = build_weekly_manifest(contract)
81+
manifest["contract"]["feed_status"]["failed_feed_count"] = 1
82+
with pytest.raises(WeeklyContractError):
83+
parse_weekly_manifest(manifest)
84+
manifest = build_weekly_manifest(contract)
85+
manifest["extra"] = True
86+
with pytest.raises(WeeklyContractError):
87+
parse_weekly_manifest(manifest)
88+
89+
90+
def test_write_validates_before_creating_output(tmp_path: Path):
91+
contract = parse_weekly_contract(contract_payload())
92+
output = tmp_path / "manifest.json"
93+
write_weekly_manifest(contract, output)
94+
assert json.loads(output.read_text(encoding="utf-8"))["manifest_type"] == MANIFEST_TYPE
95+
96+
invalid = tmp_path / "invalid.json"
97+
with pytest.raises(WeeklyContractError):
98+
write_weekly_manifest(object(), invalid) # type: ignore[arg-type]
99+
assert not invalid.exists()

0 commit comments

Comments
 (0)