from __future__ import annotations from pathlib import Path import re import sys import zipfile root = Path(__file__).resolve().parent if (root / 'docs').exists(): design = root / 'docs/superpowers/specs/2026-08-14-websocket-realtime-connection-platform-design.md' stable = root / 'docs/superpowers/plans/2026-08-14-websocket-realtime-connection-platform-implementation-plan.md' advanced = root / 'docs/superpowers/plans/2026-08-14-websocket-advanced-capabilities-expansion-plan.md' else: design = Path('/mnt/data/websocket-realtime-connection-platform-design.md') stable = Path('/mnt/data/websocket-realtime-connection-platform-implementation-plan.md') advanced = Path('/mnt/data/websocket-advanced-capabilities-expansion-plan.md') checks = [] def check(name, condition): checks.append((name, bool(condition))) for path in (design, stable, advanced): check(f'exists:{path.name}', path.exists()) if not path.exists(): continue text = path.read_text(encoding='utf-8') check(f'code-fence:{path.name}', text.count('```') % 2 == 0) check(f'no-placeholders:{path.name}', not re.search(r'\b(TODO|TBD|FIXME)\b', text)) check(f'nontrivial:{path.name}', len(text.splitlines()) > 300) stable_text = stable.read_text(encoding='utf-8') advanced_text = advanced.read_text(encoding='utf-8') design_text = design.read_text(encoding='utf-8') stable_tasks = [int(n) for n in re.findall(r'^### Task (\d+):', stable_text, re.M)] advanced_tasks = [int(n) for n in re.findall(r'^### Task (\d+):', advanced_text, re.M)] check('stable-task-sequence', stable_tasks == list(range(1, 54))) check('advanced-task-sequence', advanced_tasks == list(range(1, 23))) for label, text, expected in [('stable', stable_text, 53), ('advanced', advanced_text, 22)]: sections = re.split(r'(?=^### Task \d+:)', text, flags=re.M)[1:] check(f'{label}-task-count', len(sections) == expected) for idx, section in enumerate(sections, 1): for token in ['**Files:**', '**Interfaces:**', '**Implementation requirements:**', 'Step 1:', 'Step 2:', 'Step 3:', 'Step 4:', 'Step 5:', 'git commit -m']: check(f'{label}-task-{idx}-{token}', token in section) create_pattern = re.compile(r'^- Create: `([^`]+)`', re.M) stable_paths = create_pattern.findall(stable_text) advanced_paths = create_pattern.findall(advanced_text) check('stable-create-unique', len(stable_paths) == len(set(stable_paths))) check('advanced-create-unique', len(advanced_paths) == len(set(advanced_paths))) check('stable-advanced-create-disjoint', set(stable_paths).isdisjoint(set(advanced_paths))) required_design = [ 'Inbound Evidence', 'Outbound Evidence', 'Connection Evidence', 'hyeonworks.realtime.v1.json', 'ONE_TIME_TICKET', 'APPLICATION_COMMITTED', 'WRITTEN_LOCALLY', 'Outbound Queue·Backpressure', 'Nginx', 'Tomcat', 'Jetty', 'Reactor Netty', 'WebSocket exactly-once', 'Appendix A' ] for token in required_design: check(f'design-token:{token}', token in design_text) required_stable = [ 'Commit 후 Response Loss', 'Slow Consumer', 'Browser Matrix', 'MVC·WebFlux Stack 상호 배타성', 'Stable Release Gate' ] for token in required_stable: check(f'stable-token:{token}', token in stable_text) required_advanced = [ 'Resume Token', 'Messaging 기반 Durable Replay', 'STOMP 1.2', 'RabbitMQ STOMP Broker Relay', 'HTTP/3 WebSocket Experimental', 'GraphQL WebSocket Transport Bridge' ] for token in required_advanced: check(f'advanced-token:{token}', token in advanced_text) failed = [name for name, ok in checks if not ok] print(f'checks={len(checks)} passed={len(checks)-len(failed)} failed={len(failed)}') for name in failed: print('FAIL', name) sys.exit(1 if failed else 0)