safe_eval
  2+3*4      -> 14
  (2+3)*4    -> 20
  7//2       -> 3
  -5+2       -> -3
  2**10      -> 1024
  6/4        -> 3/2
  rejected __import__('os')   (node Call)
  rejected 9**9**9            (exponent)
  rejected 1/0                (zero division)
  rejected 2**0.5             (node Constant)
  rejected abs(3)             (node Call)
  rejected [1]                (node List)
  rejected 3 if 1 else 2      (node IfExp)
  rejected 10**19             (too large)
  rejected x+1                (node Name)
  rejected 1+                 (syntax)

arithmetic_reward  (correct, well-formed)
  'so <answer>2+3*4</answer>'                      target 14: (1.0, 1.0)
  '<answer>20</answer>'                            target 14: (0.0, 1.0)
  'answer is 14'                                   target 14: (0.0, 0.0)
  '<answer>14</answer><answer>14</answer>'         target 14: (0.0, 0.0)
  "<answer>__import__('os')</answer>"              target 14: (0.0, 1.0)
  '<answer>28/2</answer>'                          target 14: (1.0, 1.0)

run_tests  (results per test; the harness is a separate process)
  correct                          [1, 1, 1, 1]    0.05 s
  partially wrong                  [1, 0, 1, 0]    0.03 s
  syntax error                     [0, 0, 0, 0]    0.03 s
  raises                           [0, 0, 0, 0]    0.03 s
  infinite loop                    [0, 0, 0, 0]    2.03 s
  memory bomb                      [0, 0, 0, 0]    0.03 s
  calls exit                       [0, 0, 0, 0]    0.03 s
  prints a forged report           [0, 0, 1, 0]    0.03 s
  forges report, then exits        [1, 1, 1, 1]    0.03 s
  hard-codes the visible tests     [1, 1, 1, 1]    0.03 s
  tries to read env                [1, 1, 1, 1]    0.03 s

same programs on held-out tests
  correct                          [1, 1, 1]
  hard-codes the visible tests     [0, 0, 0]
  forges report, then exits        [0, 0, 0]

all assertions passed
