# REVIEW — Phase lex (Adversary) ## Verdicts ### D1: PASS @2026-06-15T06:26:41Z Cold run evidence: ``` NUMBER 42 int ✓ (integer, value==42, isinstance int) NUMBER 3.14 float ✓ NUMBER 0.5 float ✓ (leading dot) NUMBER 10.0 float ✓ (trailing dot) ``` Structure check: `tokenize("42")` → 2 tokens, `[NUMBER(42), EOF]`. Exact match. Break-it probes: bare `.` raises `ValueError` (not `LexError`) — see Adversary finding AF-1 below. Not a DoD blocker (bare dot not in spec), logged as defect. ### D2: PASS @2026-06-15T06:26:41Z Cold run evidence: ``` tokenize("1+2*3") → ['NUMBER', 'PLUS', 'NUMBER', 'STAR', 'NUMBER', 'EOF'] ✓ tokenize("+-*/()") → ['PLUS','MINUS','STAR','SLASH','LPAREN','RPAREN','EOF'] ✓ ``` All 6 operator/paren kinds verified. ### D3: PASS @2026-06-15T06:26:41Z Cold run evidence: ``` tokenize(" 12 + 3 ") → ['NUMBER', 'PLUS', 'NUMBER', 'EOF'] ✓ tokenize("1\t+\t2") → ['NUMBER', 'PLUS', 'NUMBER', 'EOF'] ✓ tokenize("1 @ 2") → calc.lexer.LexError: unexpected character '@' at position 2 ✓ tokenize("abc") → calc.lexer.LexError: unexpected character 'a' at position 0 ✓ tokenize("$") → calc.lexer.LexError: unexpected character '$' at position 0 ✓ ``` LexError message contains offending char and its position. ### D4: PASS @2026-06-15T06:26:41Z Cold run evidence: ``` Ran 15 tests in 0.000s OK ``` Plan's exact commands: ``` tokenize('3.5*(1-2)') → [('NUMBER', 3.5), ('STAR', '*'), ('LPAREN', '('), ('NUMBER', 1), ('MINUS', '-'), ('NUMBER', 2), ('RPAREN', ')'), ('EOF', '')] ✓ tokenize('1 @ 2') → calc.lexer.LexError: unexpected character '@' at position 2 ✓ ``` Tests cover D1–D3 including all plan-required cases: `" 12 + 3 "`, `"3.5*(1-2)"`, `"1 @ 2"`. --- ## Adversary Findings ### AF-1 (non-blocking): bare `.` leaks `ValueError` instead of `LexError` **Repro:** `python -c "from calc.lexer import tokenize; tokenize('.')"` **Actual:** `ValueError: could not convert string to float: '.'` **Expected:** `LexError` (or at minimum, not a raw `ValueError` from Python internals) **Impact:** The DoD does not list bare dot as a required error case. Not blocking DONE, but future parser phases may hit this if they ever pass a stray `.` to the lexer. Recommend wrapping in a try/except and re-raising as LexError. **Status:** OPEN (non-blocking) --- ## No VETO All DoD gates (D1, D2, D3, D4) verified PASS. Builder may write `## DONE` to STATUS-lex.md.