#!/usr/bin/env python3
"""verify-svg-xml-both-ways.py — prove the gate both ways (mirror of the
08:59 wake's three-way desc-gate verification).

1. honest estate  -> verify-svg-xml.check_all() fails 0
2. planted broken SVG (mismatched tag, the ring's own 08:59 shape)
                     -> fails 1, named by file
3. planted tag-like word in a desc (the coda's own shape: '<desc>' inside
   a text node)     -> fails 1, named by file
4. empty surface    -> fails 1 (the wall is never idle)

THE PARSE'S OWN COMMENT-READING (2026-08-17 — the seed Q102's 09:57 wake
left open, closed this wake): the desc wall's readers learned at 04:45 that
a '<desc' inside an XML comment is words, not a tag; the img reader learned
the same at 09:57; the claim patterns at 08:12. The FILES' wall
(verify-svg-xml.py) parses with ElementTree, whose expat parser is
comment-aware BY CONSTRUCTION — but the wall's own proof never showed it:
the harness planted mismatched tags and tag-like words in text nodes,
never a tag-like word inside a comment. A tag-like word inside a comment
is words, not markup — the file must still parse (exit 0); a comment the
file cannot close (an unclosed '<!--') is a broken file — the wall must
fail it, named by file (exit 1). The comment boundary is real in both
directions: comments are words, and a comment that never ends is a ghost
in the drawing itself.

5. planted tag-like word inside a COMMENT (the coda's own shape, spoken
   about the markup)  -> fails 0 (a comment is words, not markup — the
                         parse reads the comments the desc wall skips)
6. planted UNCLOSED comment ('<!-- ...' with no '-->')
                       -> fails 1, named by file (a comment the file
                          cannot close is a broken file — the comment
                          boundary is real)
"""
import shutil
import sys
import tempfile
from pathlib import Path

import importlib.util as _ilu
_spec = _ilu.spec_from_file_location(
    'verify_svg_xml', '/home/exedev/hq/members/vigo/site/tools/verify-svg-xml.py')
_v = _ilu.module_from_spec(_spec)
_spec.loader.exec_module(_v)
v = _v

ok = True

# 1. honest estate
failed, lines = v.check_all()
print("== 1. honest estate")
print("\n".join(lines))
if failed == 0:
    print("PASS honest: 0 failed")
else:
    print(f"FAIL honest: {failed} failed")
    ok = False

# 2/3/4. hostile estate — copy site into tmp, plant a broken file
tmp = Path(tempfile.mkdtemp(prefix="svgxml-test-"))
shutil.copytree(v.SITE, tmp / "site", ignore=shutil.ignore_patterns("*.png"))
site2 = tmp / "site"

# 2. mismatched tag, the ring's own 08:59 shape
ring = site2 / "assets" / "the-vocabularys-ring.svg"
data = ring.read_text()
ring.write_text(data.replace("</svg>", "<unclosed></svg>"))
_old_site = v.SITE
v.SITE = site2
f2, l2 = v.check_all()
v.SITE = _old_site
print("\n== 2. planted mismatched tag")
print("\n".join(l2))
if f2 >= 1 and any("the-vocabularys-ring.svg" in x for x in l2):
    print("PASS hostile-1: mismatched tag fails, named by file")
else:
    print(f"FAIL hostile-1: expected >=1 failure named by file, got {f2}")
    ok = False

# 3. tag-like word inside a desc text node (the coda's own shape — a
# LITERAL tag typed into the desc, which is what made the ring's XML
# malformed at 08:59; an escaped &lt;desc&gt; is valid XML and must pass)
ring.write_text(data)  # restore pristine ring, then plant
ring.write_text(data.replace("</desc>", "<desc> in prose</desc>"))
v.SITE = site2
f3, l3 = v.check_all()
v.SITE = _old_site
print("\n== 3. planted tag-like word in desc")
print("\n".join(l3))
if f3 >= 1 and any("the-vocabularys-ring.svg" in x for x in l3):
    print("PASS hostile-2: tag-like word in desc fails, named by file")
else:
    print(f"FAIL hostile-2: expected >=1 failure named by file, got {f3}")
    ok = False

# 4. empty surface
site3 = tmp / "site-empty"
(site3 / "assets").mkdir(parents=True)
old = v.SITE
v.SITE = site3
f4, l4 = v.check_all()
v.SITE = old
print("\n== 4. empty surface")
print("\n".join(l4))
if f4 >= 1:
    print("PASS hostile-3: empty surface fails (the wall is never idle)")
else:
    print(f"FAIL hostile-3: expected failure on empty surface, got {f4}")
    ok = False

# 5. planted tag-like word inside a COMMENT (the coda's own shape, spoken
#    ABOUT the markup — '<desc> in prose' wrapped in <!-- … -->). The desc
#    wall's readers learned at 04:45, the img reader at 09:57, the claim
#    patterns at 08:12: a comment's words are words, not markup. The files'
#    wall (expat by construction) must read the same boundary — the file
#    still parses (exit 0): the parse reads the comments the desc wall
#    skips.
ring.write_text(data)  # restore pristine ring, then plant
ring.write_text(data.replace("</svg>", "<!-- <desc> in prose --></svg>"))
v.SITE = site2
f5, l5 = v.check_all()
v.SITE = _old_site
print("\n== 5. planted tag-like word inside a comment")
print("\n".join(l5))
if f5 == 0:
    print("PASS hostile-4: tag-like word inside a comment is words, not markup — the file still parses")
else:
    print(f"FAIL hostile-4: expected 0 failures (comment is words), got {f5}")
    ok = False

# 6. planted UNCLOSED comment ('<!-- …' with no '-->') — the boundary in
#    the other direction. A comment the file cannot close swallows the
#    closing tags after it; the root never closes; the wall must fail it,
#    named by file. The comment boundary is real in both directions.
ring.write_text(data)  # restore pristine ring, then plant
ring.write_text(data.replace("</svg>", "<!-- <desc> in prose"))
v.SITE = site2
f6, l6 = v.check_all()
v.SITE = _old_site
print("\n== 6. planted unclosed comment")
print("\n".join(l6))
if f6 >= 1 and any("the-vocabularys-ring.svg" in x for x in l6):
    print("PASS hostile-5: unclosed comment fails, named by file (a comment that never ends is a ghost in the drawing itself)")
else:
    print(f"FAIL hostile-5: expected >=1 failure named by file, got {f6}")
    ok = False

shutil.rmtree(tmp, ignore_errors=True)
print("\nRESULT:", "ALL PASS" if ok else "SOME FAILED")
sys.exit(0 if ok else 1)
