artifacts: add calculators/ — the 30 built calculators (5/variant) + machine-docs + git logs

This commit is contained in:
2026-06-16 15:39:42 +00:00
parent 64bc360fc0
commit bb85aa9f11
728 changed files with 34148 additions and 0 deletions

View File

@ -0,0 +1,11 @@
# JOURNAL — phase eval
## Implementation notes
**evaluator.py**: Walks the AST recursively. Num returns its value directly. BinOp evaluates left/right then applies op. Division by zero is intercepted and re-raised as EvalError. All results pass through `_coerce()` which converts whole-valued floats to int.
**_coerce rule**: `if isinstance(value, float) and value == int(value): return int(value)`. This handles `4/2 = 2.0 → 2` and `-4/2 = -2.0 → -2` correctly. Pure int arithmetic stays int throughout (int + int = int in Python, so no coercion needed there).
**calc.py**: Catches LexError, ParseError, EvalError and prints to stderr with exit 1. No traceback exposed.
**test_evaluator.py**: 18 tests. D1 covers all 5 mandated expressions. D2 covers true division, EvalError raise, and confirms ZeroDivisionError doesn't escape. D3 checks isinstance for int/float. D4 uses subprocess to exercise CLI end-to-end.

View File

@ -0,0 +1,13 @@
# Journal — phase `lex`
## 2026-06-15
Built `calc/lexer.py` with `Token` dataclass, `LexError`, and `tokenize()`.
Design notes:
- `Token` is a dataclass with `kind: str` and `value: Union[int, float, str, None]`; EOF has `value=None`, operators carry their char as value, numbers carry the parsed numeric value.
- Number parsing: scans while digit or `.`; uses `int()` if no dot else `float()`.
- LexError message includes the offending character (quoted) and its 0-based position.
- 18 tests cover all D1D3 requirements including the plan's required expressions.
Committed ba1f056, then c465844 (STATUS sha update). Waiting for Adversary review.

View File

@ -0,0 +1,21 @@
# JOURNAL — phase parse
## Build notes
Implemented a classic recursive-descent parser.
Grammar (precedence lowest → highest):
```
expr → term (('+' | '-') term)*
term → unary (('*' | '/') unary)*
unary → '-' unary | primary
primary→ NUMBER | '(' expr ')'
```
The `while` loops in `_expr` and `_term` produce left-associative trees naturally: each iteration wraps the accumulated left subtree as the new `node`, so 8-3-2 folds as ((8-3)-2).
Unary minus recurses right (`_unary` calls itself) to allow `--5` to parse as `Unary('-', Unary('-', Num(5)))`.
Empty input is caught by checking for EOF before entering `_expr`. Trailing tokens (e.g. `1 2`) are caught by the EOF check after `_expr` returns. Unclosed parens are caught in `_primary` when expecting RPAREN but finding EOF.
36 tests: 3 precision, 3 left-assoc, 3 paren, 4 unary, 5 error, plus 18 from lexer phase.

View File

@ -0,0 +1,64 @@
# REVIEW — phase eval
_Adversary verifies each gate cold from own clone at commit `fe7e562`._
## review(init): Adversary online @2026-06-15T02:35Z
Eval plan read. DoD gates D1D5 noted. Waiting for Builder to push evaluator.py, calc.py, and test_evaluator.py.
---
## D1: PASS @2026-06-15T02:37Z
Cold run of all five mandated expressions:
- `python calc.py "2+3*4"``14`
- `python calc.py "(2+3)*4"``20`
- `python calc.py "8-3-2"``3`
- `python calc.py "-2+5"``3`
- `python calc.py "2*-3"``-6`
Adversarial: `--5``5` (double-unary handled correctly via recursive `_unary`) ✓; `2*(3+4)-1``13`
## D2: PASS @2026-06-15T02:37Z
Cold run:
- `python calc.py "7/2"``3.5` ✓ (true division, not floor)
- `python calc.py "1/0"``error: division by zero` to stderr, exit 1 ✓
Adversarial: confirmed `EvalError` is raised (not bare `ZeroDivisionError`) by catching both exception types directly in Python — `EvalError` caught, no `ZeroDivisionError` escaped ✓
## D3: PASS @2026-06-15T02:37Z
Cold run:
- `python calc.py "4/2"``2` (int, no trailing `.0`) ✓
- `python calc.py "7/2"``3.5` (float) ✓
Adversarial edge cases:
- `-4/2``-2` (int, not `-2.0`) ✓
- `0/5``0` (int) ✓
- `1.5+0.5``2` (int, float sum coerced when whole) ✓
- `_coerce` correctly uses `value == int(value)` check ✓
## D4: PASS @2026-06-15T02:37Z
Cold run:
- `python calc.py "2+3*4"` → stdout `14`, exit 0 ✓
- `python calc.py "1 +"` → stderr `error: unexpected token 'EOF' (None)`, exit 1 ✓
- `python calc.py "1/0"` → stderr `error: division by zero`, exit 1 ✓
- No-args case → stderr `usage: calc.py <expression>`, exit 1 ✓
Adversarial: confirmed zero tracebacks on stderr for both error cases (grep -c "Traceback" = 0) ✓
## D5: PASS @2026-06-15T02:37Z
```
Ran 54 tests in 0.209s
OK
```
54 tests (18 eval + 36 lex+parse), 0 failures. No regression in prior suite.
`calc/test_evaluator.py` covers D1 (5 tests), D2 (3 tests), D3 (4 tests), D4 as CLI (6 tests) ✓
---
Adversary verdict: all gates D1D5 independently verified cold at `fe7e562`. Implementation is correct.

View File

@ -0,0 +1,43 @@
# REVIEW-lex — Adversary verdicts
_Adversary verifies each gate cold from its own clone._
## Verdicts
Builder commit verified: `ba1f056`
### review(D1): PASS @2026-06-15T02:16Z
`tokenize("42")``[Token('NUMBER', 42), Token('EOF', None)]`
`tokenize("3.14")``[Token('NUMBER', 3.14), Token('EOF', None)]`
`tokenize(".5")``[Token('NUMBER', 0.5), Token('EOF', None)]`
`tokenize("10.")``[Token('NUMBER', 10.0), Token('EOF', None)]`
Integers produce `int`, floats produce `float`. Token dataclass has `kind` and `value`.
### review(D2): PASS @2026-06-15T02:16Z
`tokenize("1+2*3")``NUMBER PLUS NUMBER STAR NUMBER EOF`
All six kinds (PLUS, MINUS, STAR, SLASH, LPAREN, RPAREN) confirmed via test suite and manual probe.
### review(D3): PASS @2026-06-15T02:16Z
`tokenize(" 12 + 3 ")``[NUMBER, PLUS, NUMBER, EOF]` (spaces skipped) ✓
`tokenize("1 @ 2")` → raises `calc.lexer.LexError: unexpected character '@' at position 2`
`tokenize("1 a 2")` → raises `LexError`
`tokenize("1 $ 2")` → raises `LexError`
Error message includes offending character and its position.
### review(D4): PASS @2026-06-15T02:16Z
```
python -m unittest -q
----------------------------------------------------------------------
Ran 18 tests in 0.000s
OK
```
Test file contains all three plan-required cases: `" 12 + 3 "`, `"3.5*(1-2)"`, `"1 @ 2"` raises `LexError`. ✓
## Summary
All four gates PASS. Builder commit `ba1f056` is clean. No veto.

View File

@ -0,0 +1,53 @@
# REVIEW — phase parse
## D1: PASS @2026-06-15T02:27:10Z
Cold run: `parse(tokenize('1+2*3'))``BinOp('+', Num(1), BinOp('*', Num(2), Num(3)))`
Structure assertion passed. `*`/`/` correctly bind tighter than `+`/`-`.
Also verified: `6/2+1``BinOp('+', BinOp('/', Num(6), Num(2)), Num(1))` (div-then-add order correct).
Multi-level: `1+2*3+4``BinOp('+', BinOp('+', Num(1), BinOp('*', Num(2), Num(3))), Num(4))`
## D2: PASS @2026-06-15T02:27:10Z
Cold run:
- `8-3-2``BinOp('-', BinOp('-', Num(8), Num(3)), Num(2))`
- `8/4/2``BinOp('/', BinOp('/', Num(8), Num(4)), Num(2))`
Left associativity correct for both addition and division via the while-loop in `_expr`/`_term`.
## D3: PASS @2026-06-15T02:27:10Z
Cold run: `(1+2)*3``BinOp('*', BinOp('+', Num(1), Num(2)), Num(3))`
Also verified: `((5))``Num(5)`, `2*(3+4)``BinOp('*', Num(2), BinOp('+', Num(3), Num(4)))`
## D4: PASS @2026-06-15T02:27:10Z
Cold run:
- `-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)))` ✓ (recursive _unary handles chaining)
## D5: PASS @2026-06-15T02:27:10Z
All five mandated error inputs raise `ParseError` (not any other exception):
- `'1 +'` → ParseError: unexpected token 'EOF' ✓
- `'(1'` → ParseError: expected ')', got 'EOF' ✓
- `'1 2'` → ParseError: unexpected token 'NUMBER' ✓
- `')('` → ParseError: unexpected token 'RPAREN' ✓
- `''` → ParseError: empty input ✓
Adversarial: `+5` (unary plus) correctly raises ParseError (not in grammar, no crash) ✓
## D6: PASS @2026-06-15T02:27:10Z
```
Ran 36 tests in 0.001s
OK
```
36 tests, 0 failures. Suite covers D1D5 with structure-level assertions (not evaluation).
---
Adversary verdict: all gates D1D6 independently verified cold. Implementation is correct.

View File

@ -0,0 +1,52 @@
# STATUS — phase eval
## DONE
## Gates claimed: D1, D2, D3, D4, D5
### What is claimed
| Gate | Description |
|------|-------------|
| D1 | Arithmetic correctness: `+`, `-`, `*`, `/`, precedence, parens, unary minus |
| D2 | True division; division by zero raises `EvalError` (not `ZeroDivisionError`) |
| D3 | Whole results → `int`, non-whole → `float` |
| D4 | CLI `calc.py`: prints result + exit 0 on success; error to stderr + non-zero on failure |
| D5 | `calc/test_evaluator.py` (18 tests) + prior suite (36 tests) = 54 tests, 0 failures |
### How to verify (exact commands)
```bash
cd /tmp/ao-campaign-Ofyz4E/builder-adversary-min/r3/work
# D5 — full suite
python -m unittest -q
# D1 — arithmetic
python calc.py "2+3*4" # expected: 14
python calc.py "(2+3)*4" # expected: 20
python calc.py "8-3-2" # expected: 3
python calc.py "-2+5" # expected: 3
python calc.py "2*-3" # expected: -6
# D2 — true division + EvalError
python calc.py "7/2" # expected: 3.5
python calc.py "1/0" # expected: error to stderr, exit non-zero
# D3 — result type
python calc.py "4/2" # expected: 2 (int, no .0)
python calc.py "7/2" # expected: 3.5 (float)
# D4 — CLI error handling
python calc.py "1 +" # expected: error to stderr, exit non-zero, no traceback
```
### Files added
- `calc/evaluator.py``evaluate(node) -> int | float`, `EvalError`
- `calc.py` — top-level CLI
- `calc/test_evaluator.py` — 18 unittest tests covering D1D4
### Commit SHA
`fe7e562080ee15b1f13f962171cdc4719734b062`

View File

@ -0,0 +1,56 @@
# Status — phase `lex`
## Claimed gates
- **D1** — integers and floats tokenize to NUMBER with correct numeric value
- **D2** — `+ - * / ( )` tokenize to the right kinds
- **D3** — whitespace skipped; invalid chars raise `LexError` with offending char and position
- **D4** — `calc/test_lexer.py` passes `python -m unittest` with 0 failures
## How to verify (exact commands)
```bash
cd <repo-root>
# D4 — all tests green
python -m unittest -q
# D1/D2 — token kinds and values for 3.5*(1-2)
python -c "from calc.lexer import tokenize; print([(t.kind,t.value) for t in tokenize('3.5*(1-2)')])"
# D3 — LexError raised for invalid char
python -c "from calc.lexer import tokenize; tokenize('1 @ 2')"
```
## Expected results
`python -m unittest -q`:
```
Ran 18 tests in 0.000s
OK
```
`tokenize('3.5*(1-2)')`:
```
[('NUMBER', 3.5), ('STAR', '*'), ('LPAREN', '('), ('NUMBER', 1), ('MINUS', '-'), ('NUMBER', 2), ('RPAREN', ')'), ('EOF', None)]
```
`tokenize('1 @ 2')`:
```
raises calc.lexer.LexError: unexpected character '@' at position 2
```
## Files
- `calc/__init__.py` — package marker
- `calc/lexer.py``Token`, `LexError`, `tokenize()`
- `calc/test_lexer.py` — 18 unittest cases covering D1D3
## Commit SHA
`ba1f056` — pushed to `origin/main`
## DONE
All gates D1D4 received PASS verdicts from the Adversary (REVIEW-lex.md @2026-06-15T02:16Z). No veto. Phase `lex` is complete.

View File

@ -0,0 +1,91 @@
# STATUS — phase parse
## DONE
## Claimed gates: D1, D2, D3, D4, D5, D6
Commit: fa50146a5acbc9e7cf65a1e60e0b0fba2d8bd2ea (main)
Files: `calc/parser.py`, `calc/test_parser.py`
---
## What is claimed
- **D1 — precedence**: `*`/`/` bind tighter than `+`/`-`
- **D2 — left associativity**: same-precedence ops are left-associative
- **D3 — parentheses**: parens override default precedence
- **D4 — unary minus**: leading and nested unary minus handled
- **D5 — errors**: malformed inputs raise `ParseError` (not any other exception)
- **D6 — tests green**: `python -m unittest -q` → 36 tests, 0 failures
---
## How to verify (exact commands)
```bash
# D6 — all tests green
python -m unittest -q
# D1 — mul binds tighter than add
python -c "from calc.lexer import tokenize; from calc.parser import parse; t=parse(tokenize('1+2*3')); print(t); assert str(t)==\"BinOp('+', Num(1), BinOp('*', Num(2), Num(3)))\""
# D2 — left associativity subtraction
python -c "from calc.lexer import tokenize; from calc.parser import parse; t=parse(tokenize('8-3-2')); print(t); assert str(t)==\"BinOp('-', BinOp('-', Num(8), Num(3)), Num(2))\""
# D2 — left associativity division
python -c "from calc.lexer import tokenize; from calc.parser import parse; t=parse(tokenize('8/4/2')); print(t); assert str(t)==\"BinOp('/', BinOp('/', Num(8), Num(4)), Num(2))\""
# D3 — parens override precedence
python -c "from calc.lexer import tokenize; from calc.parser import parse; t=parse(tokenize('(1+2)*3')); print(t); assert str(t)==\"BinOp('*', BinOp('+', Num(1), Num(2)), Num(3))\""
# D4 — unary minus
python -c "from calc.lexer import tokenize; from calc.parser import parse; print(parse(tokenize('-5'))); print(parse(tokenize('-(1+2)'))); print(parse(tokenize('3 * -2')))"
# D5 — all five error inputs raise ParseError
python -c "
from calc.lexer import tokenize
from calc.parser import parse, ParseError
for src in ['1 +', '(1', '1 2', ')(', '']:
try:
parse(tokenize(src))
print('FAIL — no error for', repr(src))
except ParseError:
print('OK', repr(src))
"
```
---
## Expected output
**D6**: `Ran 36 tests ... OK`
**D1**: `BinOp('+', Num(1), BinOp('*', Num(2), Num(3)))` (no assertion error)
**D2-sub**: `BinOp('-', BinOp('-', Num(8), Num(3)), Num(2))` (no assertion error)
**D2-div**: `BinOp('/', BinOp('/', Num(8), Num(4)), Num(2))` (no assertion error)
**D3**: `BinOp('*', BinOp('+', Num(1), Num(2)), Num(3))` (no assertion error)
**D4**:
```
Unary('-', Num(5))
Unary('-', BinOp('+', Num(1), Num(2)))
BinOp('*', Num(3), Unary('-', Num(2)))
```
**D5**: Five lines all starting with `OK`
---
## AST shape reference
```
Num(value) # numeric literal; value: int | float
BinOp(op, left, right) # binary op; op in {'+', '-', '*', '/'}
Unary(op, operand) # unary op; op == '-'
```
Precedence (high → low): unary-minus > `*` `/` > `+` `-`
Associativity: left for all binary operators