artifacts: add calculators/ — the 30 built calculators (5/variant) + machine-docs + git logs
This commit is contained in:
@ -0,0 +1,7 @@
|
||||
# BACKLOG — eval phase
|
||||
|
||||
## Build backlog
|
||||
_(Builder's section — read-only for Adversary)_
|
||||
|
||||
## Adversary findings
|
||||
_(none yet)_
|
||||
@ -0,0 +1,13 @@
|
||||
# BACKLOG-lex
|
||||
|
||||
## Build backlog
|
||||
|
||||
- [x] Create calc/__init__.py
|
||||
- [x] Create calc/lexer.py with Token, LexError, tokenize()
|
||||
- [x] Create calc/test_lexer.py covering D1–D4 (21 tests)
|
||||
- [x] Run tests: 21 passed, 0 failed
|
||||
- [ ] Claim D1 + D2 + D3 + D4 (all gates, single claim)
|
||||
- [ ] Await Adversary verification
|
||||
|
||||
## Adversary findings
|
||||
(none yet)
|
||||
@ -0,0 +1,20 @@
|
||||
# BACKLOG — Phase parse
|
||||
|
||||
## Build backlog
|
||||
|
||||
- [x] Create calc/parser.py (ParseError, Num, BinOp, Unary, recursive-descent parse())
|
||||
- [x] Create calc/test_parser.py (24 unittest tests, D1–D5 coverage)
|
||||
- [x] Verified 45 tests pass (21 lexer + 24 parser), 0 failures
|
||||
- [x] CLAIM D1–D6 (all gates claimed together)
|
||||
|
||||
## Adversary findings
|
||||
|
||||
(none yet)
|
||||
|
||||
## Break-it probes planned
|
||||
|
||||
- Precedence weak test: ensure `1+2*3` really builds `BinOp('+', Num(1), BinOp('*', Num(2), Num(3)))` not `BinOp('*', BinOp('+', Num(1), Num(2)), Num(3))`
|
||||
- Associativity weak test: ensure `8-3-2` builds `BinOp('-', BinOp('-', Num(8), Num(3)), Num(2))` not `BinOp('-', Num(8), BinOp('-', Num(3), Num(2)))`
|
||||
- Nested unary: `--5`, `-(-(1+2))` should work
|
||||
- ParseError specificity: check it's ParseError (not generic Exception) for all 5 error cases in D5
|
||||
- Empty input edge case
|
||||
@ -0,0 +1,12 @@
|
||||
# DECISIONS — shared append-only log
|
||||
|
||||
## 2026-06-15T00:12Z — Adversary initialized
|
||||
Adversary started for phase lex. Watching for Builder claims via git.
|
||||
|
||||
## 2026-06-15 — Token representation (Builder)
|
||||
Using a dataclass for Token with `kind: str` and `value`. The `kind` is a plain string constant
|
||||
(e.g. "NUMBER"), not an enum, keeping pure stdlib with minimal boilerplate.
|
||||
|
||||
## 2026-06-15 — NUMBER value type (Builder)
|
||||
`value` for NUMBER tokens is `int` if no decimal point, else `float`. Matches Python's natural
|
||||
numeric types; convenient for the evaluator phase.
|
||||
@ -0,0 +1,43 @@
|
||||
# JOURNAL — eval phase
|
||||
|
||||
## 2026-06-15 — Implementation
|
||||
|
||||
Built evaluator, CLI, and tests in one go.
|
||||
|
||||
### evaluator.py
|
||||
|
||||
`evaluate(node)` walks the AST recursively:
|
||||
- `Num` → return `node.value` directly (already int or float from lexer)
|
||||
- `Unary('-', operand)` → negate result
|
||||
- `BinOp(op, left, right)` → evaluate both sides, apply op
|
||||
|
||||
Division: uses Python `left / right` (always returns float). If `right == 0`, raises `EvalError("Division by zero")`.
|
||||
|
||||
D3 result type rule: after computing a float result in BinOp, if `result == int(result)` we cast to int. This ensures `4/2 → 2` (int) and `7/2 → 3.5` (float). Integer arithmetic returns int naturally.
|
||||
|
||||
### calc.py CLI
|
||||
|
||||
`main()` accepts exactly one argv argument (the expression string).
|
||||
Catches `LexError`, `ParseError`, `EvalError` → prints `Error: <msg>` to stderr, exits 1.
|
||||
On success prints `result` (which is already int or float with correct type per D3 rule).
|
||||
|
||||
### Test run output
|
||||
|
||||
```
|
||||
$ python -m unittest -q
|
||||
Ran 62 tests in 0.001s
|
||||
OK
|
||||
```
|
||||
|
||||
(45 prior tests from lex+parse phases, 17 new evaluator tests)
|
||||
|
||||
### CLI checks
|
||||
|
||||
```
|
||||
$ python calc.py "2+3*4" → 14
|
||||
$ python calc.py "(2+3)*4" → 20
|
||||
$ python calc.py "7/2" → 3.5
|
||||
$ python calc.py "4/2" → 2
|
||||
$ python calc.py "1/0" → Error: Division by zero (exit 1)
|
||||
$ python calc.py "1 +" → Error: Unexpected end of input (exit 1)
|
||||
```
|
||||
@ -0,0 +1,48 @@
|
||||
# JOURNAL-lex — Adversary
|
||||
|
||||
## 2026-06-15T00:12Z — Cold start
|
||||
Read phase plan lex.md. Builder has not pushed any code yet (only seed commit 13c0db5).
|
||||
Initialized REVIEW, BACKLOG, JOURNAL files. Waiting for Builder to push work.
|
||||
|
||||
DoD gates to verify:
|
||||
- D1: numbers (integers and floats)
|
||||
- D2: operators & parens
|
||||
- D3: whitespace & errors (LexError)
|
||||
- D4: tests green (python -m unittest -q)
|
||||
|
||||
## 2026-06-15T00:20Z — Verification complete
|
||||
Builder pushed claim(D1-D4). Pulled, ran cold verification, ran break-it probes.
|
||||
All four gates PASS. No vetoes. Wrote verdicts to REVIEW-lex.md.
|
||||
Adversary probes: empty string, lone dot, whitespace-only, double-dot, 1.2.3, position accuracy — all held.
|
||||
|
||||
---
|
||||
|
||||
# JOURNAL-lex — Builder
|
||||
|
||||
## 2026-06-15 — Implementation
|
||||
|
||||
Read phase plan. Built calc/lexer.py and calc/test_lexer.py from scratch.
|
||||
|
||||
### Implementation choices
|
||||
- Token is a dataclass with `kind: str` and `value: int | float | str | None`
|
||||
- NUMBER value is int (no dot) or float (dot present)
|
||||
- LexError message includes repr of the offending char and its 0-based position
|
||||
- Leading dot (`.5`) and trailing dot (`10.`) are valid floats (scanned by loop: stops when second dot seen)
|
||||
- Single lone dot is an error (raw == '.')
|
||||
|
||||
### Test run output
|
||||
```
|
||||
python -m unittest -q
|
||||
----------------------------------------------------------------------
|
||||
Ran 21 tests in 0.000s
|
||||
OK
|
||||
```
|
||||
|
||||
### Verification commands output
|
||||
```
|
||||
$ python -c "from calc.lexer import tokenize; print([(t.kind,t.value) for t in tokenize('3.5*(1-2)')])"
|
||||
[('NUMBER', 3.5), ('STAR', '*'), ('LPAREN', '('), ('NUMBER', 1), ('MINUS', '-'), ('NUMBER', 2), ('RPAREN', ')'), ('EOF', None)]
|
||||
|
||||
$ python -c "from calc.lexer import tokenize; tokenize('1 @ 2')"
|
||||
calc.lexer.LexError: Unexpected character '@' at position 2
|
||||
```
|
||||
@ -0,0 +1,44 @@
|
||||
# JOURNAL — Phase parse (Adversary)
|
||||
|
||||
## 2026-06-15T00:18Z — Adversary initialized
|
||||
- Phase parse kicked off. Lex phase confirmed ## DONE.
|
||||
- Initialized REVIEW-parse.md, STATUS-parse.md, BACKLOG-parse.md, JOURNAL-parse.md.
|
||||
- Watching for Builder to claim gates D1–D6.
|
||||
- Planned break-it probes logged in BACKLOG.
|
||||
|
||||
## 2026-06-15T00:22Z — Cold verification complete, all gates PASS
|
||||
- Watchdog pinged: Builder claimed D1–D6 in commit 7768832.
|
||||
- Read parser.py and test_parser.py cold (no prior state).
|
||||
- Ran `python -m unittest -q` → 45 tests, 0 failures.
|
||||
- Ran all AST shape checks from STATUS-parse.md — every output matched expected.
|
||||
- Ran full break-it probe suite: right-assoc trap, triple unary, deep nesting, float, extra error cases.
|
||||
- All held. No defects found. PASS recorded in REVIEW-parse.md for D1–D6.
|
||||
|
||||
---
|
||||
|
||||
# JOURNAL — Phase parse (Builder)
|
||||
|
||||
## 2026-06-15T00:19Z — Implementation complete
|
||||
|
||||
Design: recursive-descent with grammar:
|
||||
```
|
||||
expr := term (('+' | '-') term)*
|
||||
term := unary (('*' | '/') unary)*
|
||||
unary := '-' unary | primary
|
||||
primary := NUMBER | '(' expr ')'
|
||||
```
|
||||
Left-associativity emerges from iterative loops (not recursion) in expr/term.
|
||||
|
||||
Ran `python -m unittest -q` → `Ran 45 tests in 0.001s OK`
|
||||
|
||||
Key outputs verified:
|
||||
- `1+2*3` → `BinOp('+', Num(1), BinOp('*', Num(2), Num(3)))` ✓
|
||||
- `8-3-2` → `BinOp('-', BinOp('-', Num(8), Num(3)), Num(2))` ✓
|
||||
- `8/4/2` → `BinOp('/', BinOp('/', Num(8), Num(4)), Num(2))` ✓
|
||||
- `(1+2)*3` → `BinOp('*', BinOp('+', Num(1), Num(2)), Num(3))` ✓
|
||||
- `-5` → `Unary('-', Num(5))` ✓
|
||||
- `-(1+2)` → `Unary('-', BinOp('+', Num(1), Num(2)))` ✓
|
||||
- `3 * -2` → `BinOp('*', Num(3), Unary('-', Num(2)))` ✓
|
||||
- All D5 error cases → `ParseError` ✓
|
||||
|
||||
Claiming all gates D1–D6.
|
||||
@ -0,0 +1,96 @@
|
||||
# REVIEW — eval phase (Adversary)
|
||||
|
||||
_Adversary cold-verification log. Each verdict is recorded here._
|
||||
|
||||
## Status summary
|
||||
- D1 arithmetic: PASS
|
||||
- D2 division + EvalError: PASS
|
||||
- D3 result type: PASS
|
||||
- D4 CLI: PASS
|
||||
- D5 tests green + end-to-end: PASS
|
||||
|
||||
## Verdicts
|
||||
|
||||
### D1 — arithmetic: PASS @2026-06-15T00:27:02Z
|
||||
|
||||
Cold run, commit 165c7cc.
|
||||
|
||||
Commands run and results:
|
||||
```
|
||||
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 ✓
|
||||
python calc.py "--5" → 5 ✓ (double unary)
|
||||
python calc.py "10-3-2" → 5 ✓ (left-associativity)
|
||||
python calc.py "-(2+3)" → -5 ✓ (unary on paren)
|
||||
```
|
||||
|
||||
### D2 — division + EvalError: PASS @2026-06-15T00:27:02Z
|
||||
|
||||
```
|
||||
python calc.py "7/2" → 3.5 ✓ (true division)
|
||||
python calc.py "1/0" → "Error: Division by zero" on stderr, exit 1 ✓
|
||||
python calc.py "5/(3-3)" → "Error: Division by zero" on stderr, exit 1 ✓
|
||||
```
|
||||
|
||||
Verified `EvalError` is raised (not bare `ZeroDivisionError`) via:
|
||||
- `calc/evaluator.py:37-38` explicitly checks `right == 0` and raises `EvalError`
|
||||
- `calc.py:24` catches `EvalError` — ZeroDivisionError would escape if not caught; confirmed not raised
|
||||
|
||||
`EvalError` is a proper subclass of `Exception`: confirmed True.
|
||||
|
||||
### D3 — result type: PASS @2026-06-15T00:27:02Z
|
||||
|
||||
```
|
||||
evaluate(parse(tokenize("4/2"))) → int 2 ✓
|
||||
evaluate(parse(tokenize("7/2"))) → float 3.5 ✓
|
||||
evaluate(parse(tokenize("2+3"))) → int 5 ✓ (integer arithmetic stays int)
|
||||
evaluate(parse(tokenize("-6/2"))) → int -3 ✓ (negative whole result is int)
|
||||
evaluate(parse(tokenize("1000*1000"))) → int 1000000 ✓
|
||||
```
|
||||
|
||||
Rule documented in `calc/evaluator.py` docstring. `print(4/2)` outputs `2` (not `2.0`). ✓
|
||||
|
||||
### D4 — CLI: PASS @2026-06-15T00:27:02Z
|
||||
|
||||
```
|
||||
python calc.py "2+3*4" → prints 14, exit 0 ✓
|
||||
python calc.py "1 +" → "Error: Unexpected end of input" on stderr, exit 1, no traceback ✓
|
||||
python calc.py "1/0" → "Error: Division by zero" on stderr, exit 1, no traceback ✓
|
||||
python calc.py "" → "Error: Empty input" on stderr, exit 1 ✓
|
||||
python calc.py → usage message on stderr, exit 1 ✓
|
||||
python calc.py "((1+2)" → error on stderr, exit 1, no traceback ✓
|
||||
```
|
||||
|
||||
No tracebacks in any error path. ✓
|
||||
|
||||
### D5 — tests green + end-to-end: PASS @2026-06-15T00:27:02Z
|
||||
|
||||
```
|
||||
python -m unittest -q → Ran 62 tests in 0.001s OK
|
||||
```
|
||||
|
||||
62 tests = lex + parse + evaluator suites. 0 failures, 0 errors. No regression. ✓
|
||||
|
||||
## Adversary findings
|
||||
|
||||
_(none — all gates pass, no defects found)_
|
||||
|
||||
## Break-it probes run
|
||||
|
||||
- Traceback check on all error paths: no traceback in any case ✓
|
||||
- No-args invocation: graceful usage error ✓
|
||||
- Empty string input: graceful error ✓
|
||||
- Double unary minus `--5` → 5 ✓
|
||||
- Left-associativity `10-3-2` → 5 ✓
|
||||
- Unary in division `-8/2` → -4 ✓
|
||||
- Negative whole result type `-6/2` → int -3 ✓
|
||||
- Large numbers `1000*1000` → int 1000000 ✓
|
||||
- Division by zero via expression `5/(3-3)` → EvalError ✓
|
||||
- Unclosed paren `((1+2)` → parse error, no crash ✓
|
||||
|
||||
---
|
||||
Initialized: 2026-06-15T00:24:45Z
|
||||
Verdicts filed: 2026-06-15T00:27:02Z
|
||||
@ -0,0 +1,67 @@
|
||||
# REVIEW-lex — Adversary verdicts
|
||||
|
||||
Phase: lex
|
||||
Adversary cold-started: 2026-06-15
|
||||
|
||||
## Status
|
||||
All gates verified PASS. No vetoes.
|
||||
|
||||
## Verdicts
|
||||
|
||||
### D1: PASS @2026-06-15T00:20Z
|
||||
|
||||
**Evidence (cold run from work-adv):**
|
||||
```
|
||||
tokenize("42") → NUMBER(42 int), EOF ✓
|
||||
tokenize("3.14") → NUMBER(3.14 float) ✓
|
||||
tokenize(".5") → NUMBER(0.5 float) ✓
|
||||
tokenize("10.") → NUMBER(10.0 float) ✓
|
||||
```
|
||||
Plan spec: "tokenize('42') → [NUMBER(42), EOF]" — confirmed exactly.
|
||||
|
||||
### D2: PASS @2026-06-15T00:20Z
|
||||
|
||||
**Evidence:**
|
||||
```
|
||||
kinds("1+2*3") → ['NUMBER', 'PLUS', 'NUMBER', 'STAR', 'NUMBER', 'EOF'] ✓
|
||||
all operators +-*/() → PLUS MINUS STAR SLASH LPAREN RPAREN ✓
|
||||
tokens("3.5*(1-2)") → [('NUMBER', 3.5), ('STAR','*'), ('LPAREN','('), ('NUMBER', 1),
|
||||
('MINUS','-'), ('NUMBER', 2), ('RPAREN',')'), ('EOF', None)] ✓
|
||||
```
|
||||
|
||||
### D3: PASS @2026-06-15T00:20Z
|
||||
|
||||
**Evidence:**
|
||||
```
|
||||
tokenize(" 12 + 3 ") → ['NUMBER', 'PLUS', 'NUMBER', 'EOF'] ✓ (whitespace skipped)
|
||||
tokenize("1 @ 2") → LexError: Unexpected character '@' at position 2 ✓
|
||||
tokenize("$") → LexError: ... '$' ... ✓
|
||||
tokenize("x") → LexError: ... 'x' at position 0 ✓
|
||||
tokenize(".") → LexError: ... '.' at position 0 ✓
|
||||
LexError message includes offending char AND position ✓
|
||||
```
|
||||
|
||||
### D4: PASS @2026-06-15T00:20Z
|
||||
|
||||
**Evidence:**
|
||||
```
|
||||
$ python -m unittest -q
|
||||
----------------------------------------------------------------------
|
||||
Ran 21 tests in 0.000s
|
||||
OK
|
||||
```
|
||||
Exit code: 0. 21 tests, 0 failures.
|
||||
Required cases covered: " 12 + 3 " ✓, "3.5*(1-2)" ✓, "1 @ 2" → LexError ✓.
|
||||
|
||||
## Adversarial probes (break-it attempts — all held)
|
||||
|
||||
- Empty string → `[EOF]` (correct)
|
||||
- Whitespace-only → `[EOF]` (correct)
|
||||
- Lone dot → `LexError: Unexpected character '.' at position 0` (correct)
|
||||
- `..` → LexError on lone dot (correct)
|
||||
- `1.2.3` → `NUMBER(1.2) NUMBER(0.3) EOF` (valid lexer behavior; parser rejects)
|
||||
- `12 @ 5` → LexError at position 3 (position accuracy confirmed)
|
||||
- All operators in sequence `+-*/()` → correct kinds
|
||||
- Newline treated as whitespace (conservative, robust)
|
||||
|
||||
No defects found. Implementation is correct per the phase plan.
|
||||
@ -0,0 +1,91 @@
|
||||
# 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.
|
||||
@ -0,0 +1,23 @@
|
||||
# STATUS — Phase eval
|
||||
|
||||
## DONE
|
||||
|
||||
All DoD gates Adversary-verified PASS. Phase eval is complete. This is the final phase — the calculator is end-to-end: string → tokens → AST → number.
|
||||
|
||||
| Gate | Status | Verified |
|
||||
|------|--------|----------|
|
||||
| D1 — arithmetic | PASS | 2026-06-15T00:27:02Z |
|
||||
| D2 — division + EvalError | PASS | 2026-06-15T00:27:02Z |
|
||||
| D3 — result type | PASS | 2026-06-15T00:27:02Z |
|
||||
| D4 — CLI | PASS | 2026-06-15T00:27:02Z |
|
||||
| D5 — tests green + end-to-end | PASS | 2026-06-15T00:27:02Z |
|
||||
|
||||
Adversary ran 62 tests (exit 0), cold-verified all D1–D5 gates, and ran full break-it probe suite
|
||||
(double unary, left-assoc, negative whole result type, division by zero via expression, unclosed
|
||||
paren, empty string, no-args) — all held. No defects found.
|
||||
|
||||
## Artifacts
|
||||
|
||||
- `calc/evaluator.py` — `EvalError`, `evaluate()`
|
||||
- `calc/test_evaluator.py` — 17 unittest tests (D1–D3 coverage, type assertions)
|
||||
- `calc.py` — top-level CLI (D4 + end-to-end check)
|
||||
@ -0,0 +1,20 @@
|
||||
# STATUS — Phase lex
|
||||
|
||||
## DONE
|
||||
|
||||
All DoD gates Adversary-verified PASS. Phase lex is complete.
|
||||
|
||||
| Gate | Status | Verified |
|
||||
|------|--------|----------|
|
||||
| D1 — numbers | PASS | 2026-06-15T00:20Z |
|
||||
| D2 — operators & parens | PASS | 2026-06-15T00:20Z |
|
||||
| D3 — whitespace & errors | PASS | 2026-06-15T00:20Z |
|
||||
| D4 — tests green | PASS | 2026-06-15T00:20Z |
|
||||
|
||||
Adversary ran 21 tests (exit 0), cold-verified all token outputs, and ran break-it probes — all held.
|
||||
|
||||
## Artifacts
|
||||
|
||||
- `calc/lexer.py` — Token dataclass, LexError, tokenize()
|
||||
- `calc/test_lexer.py` — 21 unittest tests
|
||||
- `calc/__init__.py` — package marker
|
||||
@ -0,0 +1,22 @@
|
||||
# STATUS — Phase parse
|
||||
|
||||
## DONE
|
||||
|
||||
All DoD gates Adversary-verified PASS. Phase parse is complete.
|
||||
|
||||
| Gate | Status | Verified |
|
||||
|------|--------|----------|
|
||||
| D1 — precedence | PASS | 2026-06-15T00:22:39Z |
|
||||
| D2 — left associativity | PASS | 2026-06-15T00:22:39Z |
|
||||
| D3 — parentheses | PASS | 2026-06-15T00:22:39Z |
|
||||
| D4 — unary minus | PASS | 2026-06-15T00:22:39Z |
|
||||
| D5 — errors | PASS | 2026-06-15T00:22:39Z |
|
||||
| D6 — tests green | PASS | 2026-06-15T00:22:39Z |
|
||||
|
||||
Adversary ran 45 tests (exit 0), cold-verified all AST shapes, and ran full break-it probe suite
|
||||
(right-assoc trap, triple unary, deep nesting, float, extra error cases) — all held. No defects found.
|
||||
|
||||
## Artifacts
|
||||
|
||||
- `calc/parser.py` — ParseError, Num, BinOp, Unary, parse()
|
||||
- `calc/test_parser.py` — 24 unittest tests (D1–D5 coverage, tree-structure assertions)
|
||||
Reference in New Issue
Block a user