fix: resolve review issues B1-B6 (color token alpha contract, Header contrast/budget B plan, Publications Overview page, N1-N8 cleanups) with 100% E2E PASS

This commit is contained in:
2026-08-20 22:42:26 +09:00
parent 9725c8ef66
commit 30e5bd8429
11 changed files with 372 additions and 135 deletions
@@ -117,7 +117,9 @@ def parse_members():
clean_item = re.sub(r'<.*?>', '', clean_item)
clean_item = clean_item.strip().replace('\n', ' ')
clean_item = re.sub(r'[:&\s]+$', '', clean_item)
if "Seok-Joo Koh" in clean_item or "고석주" in clean_item or "Professor" in clean_item:
if not clean_item:
continue
if re.search(r'^Seok-Joo Koh\b', clean_item) or "고석주" in clean_item:
en = "Seok-Joo Koh"
ko = "고석주"
degree = "Professor"
@@ -209,7 +211,7 @@ def parse_publications():
m_title = re.search(r'<U>(.*?)</U>', item, flags=re.S | re.I)
if m_title:
raw_t = re.sub(r'<br/?>', '', m_title.group(1), flags=re.I).replace('\n', ' ').strip()
title = re.sub(r'^(?:"|“|”|\s)+|(?:"|“|”|\s)+$', '', raw_t).strip()
title = re.sub(r'^[\s"“”]+|[\s"“”,]+$', '', raw_t).strip()
else:
title = ""
@@ -236,7 +238,7 @@ def parse_publications():
m_title = re.search(r'<U>(.*?)</U>', item, flags=re.S | re.I)
if m_title:
raw_t = re.sub(r'<br/?>', '', m_title.group(1), flags=re.I).replace('\n', ' ').strip()
title = re.sub(r'^(?:"|“|”|\s)+|(?:"|“|”|\s)+$', '', raw_t).strip()
title = re.sub(r'^[\s"“”]+|[\s"“”,]+$', '', raw_t).strip()
else:
title = ""
@@ -266,7 +268,7 @@ def parse_publications():
lines = [l.strip() for l in clean.split('\n') if l.strip()]
if not lines:
continue
title = lines[0]
title = re.sub(r'^[\s"“”]+|[\s"“”,]+$', '', lines[0]).strip()
inventors = ""
app_no = ""
app_date = None
@@ -54,6 +54,12 @@ def verify():
if "63246" not in d["ref"]:
errors.append(f"AC-32 Violation: CCIS project deliverable '{d['ref']}' does not belong to CCIS WG (IEC 63246)")
# N1: Title artifact check (No trailing quotes or commas in publication titles)
for p in intl_p + dom_p + pat_p:
t = p.get("title", "")
if re.search(r'["“”]|,$', t):
errors.append(f"N1 Title Artifact Violation in publication '{p.get('id')}': title '{t}' contains quotes or trailing comma")
# 1. Count checks
if len(active_m) != 16:
errors.append(f"Active Members count mismatch: got {len(active_m)}, expected 16")
+69 -39
View File
@@ -159,18 +159,15 @@ def test_unittest_suite():
return True
def test_layout_architecture():
print("\n--- Gate 8: Layout Architecture & No-Escape Gate (AC-25 / AC-26 / R-8.17) ---")
print("\n--- Gate 8: Layout Architecture & No-Escape Gate (AC-25 / AC-26 / AC-40 / AC-41 / R-8.17) ---")
# 1) Check HTML SSG pages for container-content inside main
routes_to_check = [
os.path.join(".next", "server", "app", "index.html"),
os.path.join(".next", "server", "app", "members.html"),
os.path.join(".next", "server", "app", "publications.html"),
os.path.join(".next", "server", "app", "lectures.html"),
os.path.join(".next", "server", "app", "standardization.html"),
]
# 1) Check HTML SSG pages for container-content inside main across ALL SSG routes (C2, AC-25)
routes_to_check = EXPECTED_SSG_ROUTES
main_hashes = {}
for rel_p in routes_to_check:
if not rel_p.endswith(".html"):
continue
full_p = os.path.join(REFER_DIR, rel_p)
if not os.path.exists(full_p):
print(f"❌ Missing SSG route HTML: {rel_p}")
@@ -178,46 +175,78 @@ def test_layout_architecture():
with open(full_p, "r", encoding="utf-8") as f:
html = f.read()
# Verify <main tag does NOT contain max-w- or px-
main_match = re.search(r'<main\s+class="([^"]*)"', html)
# Verify <main> tag exists and does NOT contain max-w- or px-
main_match = re.search(r'<main(?:\s+[^>]*)?>(.*?)</main>', html, flags=re.S)
if not main_match:
print(f"❌ <main> tag not found in {rel_p}")
return False
main_cls = main_match.group(1)
if "max-w-" in main_cls or "px-" in main_cls or "container-content" in main_cls:
print(f"❌ <main> tag in {rel_p} restricts width or padding ({main_cls}). Should be w-full flex-1 only.")
main_inner = main_match.group(1)
# C1: Verify child wrapper inside <main> has container-content
if "container-content" not in main_inner and "_not-found" not in rel_p and "404" not in rel_p:
print(f"❌ container-content missing inside <main> in {rel_p}")
return False
# Verify child wrapper has container-content
if "container-content" not in html:
print(f"❌ container-content missing in {rel_p}")
return False
# AC-41: Check for duplicate <main> normalized content hashes (except 404 pages)
if "404" not in rel_p and "_not-found" not in rel_p:
norm_content = re.sub(r'\s+', '', main_inner)
if norm_content in main_hashes:
print(f"❌ AC-41 Violation: Duplicate <main> content found between {rel_p} and {main_hashes[norm_content]}")
return False
main_hashes[norm_content] = rel_p
# 2) Check source for forbidden escaped arbitrary classes (AC-26)
forbidden_terms = ["w-screen", "-mx-[50vw]", "min-[1240px]:"]
for root, _, files in os.walk(os.path.join(REFER_DIR, "app")):
for fname in files:
if fname.endswith((".ts", ".tsx")):
fpath = os.path.join(root, fname)
with open(fpath, "r", encoding="utf-8") as f:
content = f.read()
for term in forbidden_terms:
if term in content:
print(f"❌ Forbidden term '{term}' found in {fpath}")
return False
for root_dir in [os.path.join(REFER_DIR, "app"), os.path.join(REFER_DIR, "components")]:
for root, _, files in os.walk(root_dir):
for fname in files:
if fname.endswith((".ts", ".tsx")):
fpath = os.path.join(root, fname)
with open(fpath, "r", encoding="utf-8") as f:
content = f.read()
for term in forbidden_terms:
if term in content:
print(f"❌ Forbidden term '{term}' found in {fpath}")
return False
for root, _, files in os.walk(os.path.join(REFER_DIR, "components")):
for fname in files:
if fname.endswith((".ts", ".tsx")):
fpath = os.path.join(root, fname)
with open(fpath, "r", encoding="utf-8") as f:
content = f.read()
for term in forbidden_terms:
if term in content:
print(f"❌ Forbidden term '{term}' found in {fpath}")
return False
print("✅ Gate 8 PASSED: Layout 3-tier architecture, route uniqueness (AC-41), and AC-25/AC-26 no-escape rule verified")
return True
print("✅ Gate 8 PASSED: Layout 3-tier architecture and AC-25/AC-26 no-escape rule verified")
def test_token_contracts():
print("\n--- Gate 9: Color Token Alpha Contract & Header Style Gate (AC-35 / AC-36 / AC-37) ---")
# AC-36: Verify zero commas in --*-rgb definitions in globals.css
globals_css = os.path.join(REFER_DIR, "app", "globals.css")
with open(globals_css, "r", encoding="utf-8") as f:
css_text = f.read()
rgb_lines = re.findall(r'--[a-z-]+-rgb:\s*([^;]+);', css_text)
for line in rgb_lines:
if "," in line:
print(f"❌ AC-36 Violation: Comma found in --*-rgb definition '{line}' in globals.css")
return False
# AC-35: Verify tailwind.config.ts has <alpha-value> for color tokens
tw_config = os.path.join(REFER_DIR, "tailwind.config.ts")
with open(tw_config, "r", encoding="utf-8") as f:
tw_text = f.read()
if "<alpha-value>" not in tw_text:
print("❌ AC-35 Violation: <alpha-value> placeholder missing in tailwind.config.ts")
return False
# AC-37: Verify Header.tsx has zero inline style={{ and zero opacity- in active badges
header_path = os.path.join(REFER_DIR, "components", "Header.tsx")
with open(header_path, "r", encoding="utf-8") as f:
header_text = f.read()
if "style={{" in header_text or "style={" in header_text:
print("❌ AC-37 Violation: Inline style attribute found in Header.tsx")
return False
if "opacity-" in header_text:
print("❌ AC-37 Violation: opacity- modifier found in Header.tsx active badge elements")
return False
print("✅ Gate 9 PASSED: Color token alpha contract, space separation (AC-36), and Header clean styling (AC-37) verified")
return True
def main():
@@ -235,6 +264,7 @@ def main():
success &= test_theme_tokens()
success &= test_unittest_suite()
success &= test_layout_architecture()
success &= test_token_contracts()
print("\n" + "-" * 70)
if success: