test(render): этап 5 ревью — base-anchored fragment oracle + §3.13 boundary (#32)

Golden-oracle DO: the fragment snapshot (media_fragments.json) was a
circular self-snapshot generated from the refactored code. Regenerated
it from the pre-refactor BASE post_parser.py (old ladders) so it holds
base bytes — byte-identical to base for all 24 cases. The only 2 §3.14
deltas (file_unique_id_none, webpage_without_photo) moved to a new
REGISTERED_DELTAS registry in media_fragment_replay.py; the fragment
test asserts base bytes for 22 cases and the registered 5b value for 2.
Docstrings corrected to describe base-anchoring (no overclaim); a
WARNING in generate_snapshot() notes it must run against base code only.

Test-coverage DO: added test_exactly_100mb_object_is_collected pinning
the §3.13 guard as strictly '>' (exactly 100MB is still collected).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-06 18:55:51 +03:00
parent c8e741ca41
commit a0387425e1
4 changed files with 55 additions and 9 deletions
+33 -3
View File
@@ -4,9 +4,15 @@
Captures the raw `_generate_html_media` output (BEFORE sanitize) for every media
render kind and edge branch, as a SEPARATE oracle layer from the stage-0 feed goldens
(spec §4: "два слоя эталонов, не смешивать"). The 5a refactor (MEDIA_SOURCES table +
renderers) must reproduce these fragments byte-for-byte; 5b intentionally changes two
of them (§3.13 large-file guard is collection-only, §3.14 unclosed-div close).
(spec §4: "два слоя эталонов, не смешивать").
`media_fragments.json` is the PRE-REFACTOR BASE reference: it was captured by running
THIS harness against the BASE `post_parser.py` checkout (the pre-refactor code), NOT
against stage-5 code — so it is a genuine base-anchored golden layer, not a circular
self-snapshot of the refactor. The 5a refactor (MEDIA_SOURCES table + renderers) must
reproduce these base fragments byte-for-byte. The ONLY 5b-registered changes vs the base
are the two entries in REGISTERED_DELTAS (§3.14 unclosed-div close); the §3.13 large-file
guard is collection-only and changes no fragment bytes.
Cases whose type exists in the recorded corpus could be pulled from it, but the media
FRAGMENT is a pure function of a single Message, so deterministic hand-built mocks give
@@ -125,6 +131,27 @@ def build_cases():
return cases
# --------------------------------------------------------------------------- #
# Registered 5b deltas vs the pre-refactor base snapshot.
#
# Spec §3.14: the empty <div class="message-media"> container is now CLOSED in every
# render branch. The base (pre-refactor) code left it OPEN whenever the selected media
# object had no usable file_unique_id, so the base snapshot captured an unbalanced div
# for exactly these two cases. `collected` is byte-identical to the base; only `html`
# differs by the added `</div>`. These are the ONLY fragments the 5b registered fixes
# change relative to the pre-refactor base — every other case reproduces base bytes.
REGISTERED_DELTAS = {
"file_unique_id_none": {
"collected": [],
"html": "<div class=\"message-media\">\n</div>",
},
"webpage_without_photo": {
"collected": [],
"html": "<div class=\"message-media\">\n</div>\n<div class=\"webpage-preview\">\n<div class=\"webpage-preview\" style=\"border-left: 3px solid #ccc; padding-left: 10px; margin: 10px 0;\">\n<div class=\"webpage-title\" style=\"font-weight:bold; margin:5px 0;\">\n<a href=\"https://example.com\" target=\"_blank\">Example</a></div>\n<div class=\"webpage-url\" style=\"color:#666; font-size:0.9em;margin-bottom:5px;\">https://example.com</div>\n</div>\n</div>",
},
}
# --------------------------------------------------------------------------- #
# Capture / compare.
# --------------------------------------------------------------------------- #
@@ -167,6 +194,9 @@ def _bootstrap_standalone():
def generate_snapshot():
# WARNING: this MUST be run against the BASE (pre-refactor) `post_parser.py`, never
# against stage-5 code. Regenerating from stage-5 output would make the oracle a
# circular self-snapshot instead of a base-anchored golden layer (spec §4).
from url_signer import KeyManager
KeyManager.signing_key = FRAGMENT_SIGNING_KEY
data = capture_fragments()
+2 -2
View File
@@ -65,7 +65,7 @@
},
"file_unique_id_none": {
"collected": [],
"html": "<div class=\"message-media\">\n</div>"
"html": "<div class=\"message-media\">"
},
"live_photo": {
"collected": [
@@ -213,6 +213,6 @@
},
"webpage_without_photo": {
"collected": [],
"html": "<div class=\"message-media\">\n</div>\n<div class=\"webpage-preview\">\n<div class=\"webpage-preview\" style=\"border-left: 3px solid #ccc; padding-left: 10px; margin: 10px 0;\">\n<div class=\"webpage-title\" style=\"font-weight:bold; margin:5px 0;\">\n<a href=\"https://example.com\" target=\"_blank\">Example</a></div>\n<div class=\"webpage-url\" style=\"color:#666; font-size:0.9em;margin-bottom:5px;\">https://example.com</div>\n</div>\n</div>"
"html": "<div class=\"message-media\">\n<div class=\"webpage-preview\">\n<div class=\"webpage-preview\" style=\"border-left: 3px solid #ccc; padding-left: 10px; margin: 10px 0;\">\n<div class=\"webpage-title\" style=\"font-weight:bold; margin:5px 0;\">\n<a href=\"https://example.com\" target=\"_blank\">Example</a></div>\n<div class=\"webpage-url\" style=\"color:#666; font-size:0.9em;margin-bottom:5px;\">https://example.com</div>\n</div>\n</div>"
}
}
+9 -4
View File
@@ -5,8 +5,10 @@
Two layers:
* 5a — the MEDIA_SOURCES table + renderers reproduce the three old ladders
(_get_file_unique_id, _save_media_file_ids, _generate_html_media) byte-for-byte:
a fragment-level snapshot oracle (tests/test_data/media_fragments.json) plus
(_get_file_unique_id, _save_media_file_ids, _generate_html_media). The fragment
snapshot (tests/test_data/media_fragments.json) is the PRE-REFACTOR BASE reference,
captured against the base post_parser.py; the 5a code reproduces it byte-for-byte
(two fragments carry registered §3.14 deltas — see fr.REGISTERED_DELTAS). Plus
table/selector/invariant unit tests.
* 5b — the registered fixes (§3.13 large-file guard for every object, §3.14 the
message-media div is closed in every branch) live in test_stage5b_media_fixes.py.
@@ -54,8 +56,11 @@ def test_media_fragment_matches_snapshot(parser, case_name):
parser._pending_media_ids = []
html = parser._generate_html_media(factory())
collected = [[c, p, f] for c, p, f, _ in parser._pending_media_ids]
assert html == snapshot[case_name]["html"], f"fragment HTML diverged for {case_name}"
assert collected == snapshot[case_name]["collected"], f"collection diverged for {case_name}"
# The snapshot is the pre-refactor BASE reference; the two §3.14 fragments carry a
# registered 5b delta (the now-closed message-media div), so expect their 5b bytes.
expected = fr.REGISTERED_DELTAS.get(case_name, snapshot[case_name])
assert html == expected["html"], f"fragment HTML diverged for {case_name}"
assert collected == expected["collected"], f"collection diverged for {case_name}"
def test_snapshot_covers_every_spec_case():
+11
View File
@@ -120,6 +120,17 @@ def test_small_non_video_object_still_collected(parser, media_type, attr):
assert [(c, p, f) for c, p, f, _ in parser._pending_media_ids] == [("testchan", 11, "small")]
def test_exactly_100mb_object_is_collected(parser):
# §3.13 boundary: the guard is strictly `>` 100MB, so an object of exactly 100MB is
# still collected. Pins the operator — a mutation to `>=` would drop this and fail.
obj = SimpleNamespace(file_unique_id="edge", file_id="f",
file_size=100 * 1024 * 1024, mime_type="image/png")
msg = _msg(14, MessageMediaType.PHOTO, photo=obj)
parser._pending_media_ids = []
parser._save_media_file_ids(msg)
assert [(c, p, f) for c, p, f, _ in parser._pending_media_ids] == [("testchan", 14, "edge")]
def test_large_video_still_not_collected(parser):
# Regression: the video case (the only one guarded before 5b) still works.
msg = _msg(12, MessageMediaType.VIDEO,