Files
agent-orchestrator-benchmark/calculators/builder-adversary/run-01/machine-docs/REVIEW-parse.md

3.5 KiB

REVIEW — Phase parse (Adversary)

Status

All gates PASS. Ready to approve ## DONE.

Gate verdicts

Gate Verdict Timestamp Evidence
D1 — precedence PASS 2026-06-15T00:22:39Z See below
D2 — left associativity PASS 2026-06-15T00:22:39Z See below
D3 — parentheses PASS 2026-06-15T00:22:39Z See below
D4 — unary minus PASS 2026-06-15T00:22:39Z See below
D5 — errors PASS 2026-06-15T00:22:39Z See below
D6 — tests green PASS 2026-06-15T00:22:39Z Ran 45 tests in 0.001s OK

Cold-verification evidence

D6 — tests green

python -m unittest -q
Ran 45 tests in 0.001s
OK

21 lexer + 24 parser tests, 0 failures.

D1 — precedence (cold AST shape check)

1+2*3  → BinOp('+', Num(1), BinOp('*', Num(2), Num(3)))   ✓ (* binds tighter)
2*3+4  → BinOp('+', BinOp('*', Num(2), Num(3)), Num(4))   ✓
10-6/2 → BinOp('-', Num(10), BinOp('/', Num(6), Num(2)))  ✓

Independently derived: 1+2*3 must have + at root with * in right child — confirmed.

D2 — left associativity (cold AST shape check)

8-3-2  → BinOp('-', BinOp('-', Num(8), Num(3)), Num(2))   ✓ (left-assoc)
8/4/2  → BinOp('/', BinOp('/', Num(8), Num(4)), Num(2))   ✓
1+2+3  → BinOp('+', BinOp('+', Num(1), Num(2)), Num(3))  ✓
2*3*4  → BinOp('*', BinOp('*', Num(2), Num(3)), Num(4))  ✓
1-2-3  → BinOp('-', BinOp('-', Num(1), Num(2)), Num(3))  ✓ (break-it: not right-assoc)

Iterative while-loop in _expr/_term enforces left-assoc by construction.

D3 — parentheses (cold AST shape check)

(1+2)*3  → BinOp('*', BinOp('+', Num(1), Num(2)), Num(3))       ✓
3*(1+2)  → BinOp('*', Num(3), BinOp('+', Num(1), Num(2)))       ✓
((4))    → Num(4)                                                  ✓
8-(3-2)  → BinOp('-', Num(8), BinOp('-', Num(3), Num(2)))        ✓
((((1+2)))) → BinOp('+', Num(1), Num(2))                         ✓ (deep nesting)

D4 — unary minus (cold AST shape check)

-5        → Unary('-', Num(5))                                      ✓
-(1+2)    → Unary('-', BinOp('+', Num(1), Num(2)))                 ✓
3 * -2    → BinOp('*', Num(3), Unary('-', Num(2)))                 ✓
--5       → Unary('-', Unary('-', Num(5)))                          ✓
1 + -2    → BinOp('+', Num(1), Unary('-', Num(2)))                 ✓
---5      → Unary('-', Unary('-', Unary('-', Num(5))))              ✓ (break-it: triple unary)
6 / -2    → BinOp('/', Num(6), Unary('-', Num(2)))                 ✓ (break-it: unary in denom)

_unary is right-recursive: '-' _unary | _primary — correct for unary.

D5 — errors (cold: all five plan cases + extras)

'1 +'  → OK ParseError
'(1'   → OK ParseError
'1 2'  → OK ParseError
')('   → OK ParseError
''     → OK ParseError
'*'    → OK ParseError  (break-it)
')'    → OK ParseError  (break-it)
'1+2)' → OK ParseError  (break-it)
'((1+2)' → OK ParseError  (break-it)

All raise ParseError specifically, not a generic exception.

Break-it probes run

  • Right-assoc trap (1-2-3, 8-3-2, 8/4/2): held — correctly left-assoc
  • Deep nesting ((((1+2)))): held
  • Triple unary ---5: held
  • Unary in denominator 6/-2: held
  • Float literal 3.14 → Num(3.14): parsed fine
  • Trailing ) after valid expr 1+2): ParseError ✓
  • Solo operator *: ParseError ✓
  • Double-unclosed paren ((1+2): ParseError ✓

Adversary findings

None. No defects found. All probes held.