1010 MANIFEST_TYPE ,
1111 build_weekly_manifest ,
1212 parse_weekly_manifest ,
13+ parse_weekly_manifest_bytes ,
1314 serialize_weekly_manifest ,
1415 validate_weekly_manifest ,
1516 write_weekly_manifest ,
@@ -36,6 +37,19 @@ def test_weekly_manifest_is_deterministic_and_round_trips():
3637 encoded = serialize_weekly_manifest (contract )
3738 assert encoded == serialize_weekly_manifest (parse_weekly_manifest (json .loads (encoded )))
3839 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 ))
3953
4054
4155@pytest .mark .parametrize ("field,value" , [
@@ -53,6 +67,14 @@ def test_manifest_contract_tamper_is_rejected(field, value):
5367 validate_weekly_manifest (manifest , contract )
5468
5569
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+
5678def test_manifest_feed_partial_and_shape_tamper_fail_closed ():
5779 contract = parse_weekly_contract (contract_payload ())
5880 manifest = build_weekly_manifest (contract )
0 commit comments