diff --git a/DECISIONS.md b/DECISIONS.md index 6c86d00..66bf89f 100644 --- a/DECISIONS.md +++ b/DECISIONS.md @@ -50,7 +50,7 @@ Entries that only restate a diff will be deleted. - Consequence: the port depends on libc math; Zig-only freestanding builds are out of scope. - Evidence: sampled glibc vs `std.math` on the same inputs (specials, - dense grids, powers of two). Counts in `dev/baseline-artifacts/16-libm-vs-stdmath.txt`: + dense grids, powers of two). Counts in `docs/evidence/baseline/16-libm-vs-stdmath.txt`: - sin 602117 samples, 0 differ - cos/tan/exp/log/log10/sqrt/ceil/floor/fabs: 0 differ on their samples - asin 26109 samples, 24441 differ (rate 0.936) @@ -70,7 +70,7 @@ Entries that only restate a diff will be deleted. generic over a builder interface (ENCRUST-style encapsulated substitution, arXiv:2604.04527). - Choice: shared recursive-descent parser parameterized by a builder - (`parser.zig`). `NativeBuilder` builds `ast.Expr`. Prompt 3 adds a + (`parser.zig`). `NativeBuilder` builds `ast.Expr`. A later pass adds a C-layout builder in `c_abi.zig` without forking parse logic. - Consequence: builder interface must be rich enough for both layouts; some C-specific allocation tricks stay in the C builder. @@ -92,7 +92,7 @@ Entries that only restate a diff will be deleted. `-Dfix-fac-overflow` rejects non-integer inputs with NaN (C truncates `fac(4.8)` to 24, which smoke expects). We do not use `*%` for default fac, because that would diverge from measured C. -- Evidence: `dev/baseline-artifacts/14-fac-ncr-probe.txt`. smoke expects +- Evidence: `docs/evidence/baseline/14-fac-ncr-probe.txt`. smoke expects `fac(4.8)==24`. ## D007 - ncr/npr DoS surface is small under the overflow guard @@ -107,12 +107,13 @@ Entries that only restate a diff will be deleted. another intentional divergence. - Evidence: `ncr(40,20)` 0.000046s; `ncr(1e9,100)` returns INF in 0.000001s; `ncr(UINT_MAX, 200000)` returns INF in 0.000001s - (`15c-ncr-dos.txt`). + (`docs/evidence/baseline/15c-ncr-dos.txt`). ## D008 - Nesting bound 2048 (intentional divergence) - Constraint: C recurses without a depth limit and SIGSEGVs near depth - 20144 on an 8 MiB stack (issue #136). The port must not inherit that crash. + 20144 on WSL x86_64 with an 8 MiB stack (issue #136; host-dependent). The + port must not inherit that crash. - Options: raise stack; keep unbounded recursion; hard error at a bound; iterative parser with a heap stack. - Choice: hard error `error.NestingTooDeep` at depth 2048 (same number as @@ -122,7 +123,8 @@ Entries that only restate a diff will be deleted. - Consequence: differential harnesses must treat deep nests as an expected divergence table entry, not a fuzz failure. - Evidence: unit test builds 1e6 nested parens and expects NestingTooDeep; - C crashes at 20144 without ASan. + C crashes at 20144 without ASan (WSL x86_64, 8 MiB stack; Darwin arm64 + measured 23764 in `docs/findings.md`). ## D009 - Two-layer public surface @@ -136,8 +138,8 @@ Entries that only restate a diff will be deleted. ## D010 - Export the accidental globals -- Constraint: Prompt 1 `nm` showed `te_free_parameters` and `next_token` as - globally defined alongside the header API. +- Constraint: early `nm` on the upstream object showed `te_free_parameters` + and `next_token` as globally defined alongside the header API. - Options: header API only; exact nm set. - Choice: exact nm set (all seven symbols). - Consequence: `State` is public as an extern struct so `next_token` can be diff --git a/build.zig b/build.zig index e147791..8278108 100644 --- a/build.zig +++ b/build.zig @@ -183,5 +183,8 @@ pub fn build(b: *std.Build) void { // Also attach to the default test step so `zig build test --fuzz` sees Smith cases. test_step.dependOn(&run_harness_tests.step); - _ = b.step("demo", "Prompt 9: demo assets"); + const demo_cmd = b.addSystemCommand(&.{ "bash", "docs/demo/regen-svgs.sh" }); + demo_cmd.setCwd(b.path(".")); + const demo_step = b.step("demo", "Regenerate docs/demo/*.svg from segment transcripts"); + demo_step.dependOn(&demo_cmd.step); } diff --git a/docs/demo-script.md b/docs/demo-script.md index 925b7cc..e9c2a58 100644 --- a/docs/demo-script.md +++ b/docs/demo-script.md @@ -9,6 +9,30 @@ terminal captures of each segment are already committed under `docs/demo/` **Outstanding human action:** record the MP4 from this script and upload it with the submission form **before 2026-08-03 18:00 UTC**. +## How to record (do this) + +1. Open a terminal at a large font (18–24 pt). Black or dark theme. +2. Start screen recording (QuickTime on macOS: File → New Screen Recording, + select the terminal window only; or OBS; or `asciinema rec demo.cast`). +3. `cd` into the repo root and run the commands in the shot list below, in + order. Pause 2 seconds on each success line the narration calls out. +4. Stop recording under five minutes. Export MP4 (QuickTime: File → Export). +5. Upload where the organizer form asks. Optionally link it from the README + after freeze if the form allows an external URL. + +If you use `asciinema`: + +```bash +cd /path/to/tinyexpr.zig +asciinema rec /tmp/tinyexpr-demo.cast +# ... run the commands ... +# Ctrl-D to stop +# Convert if you have agg: agg /tmp/tinyexpr-demo.cast /tmp/tinyexpr-demo.gif +``` + +The SVG segments under `docs/demo/` are already committed for the README; the +organizer still wants a live video of you running the suite. + ## Assets already in the repo | Segment | SVG | Transcript | diff --git a/docs/demo/regen-svgs.sh b/docs/demo/regen-svgs.sh new file mode 100755 index 0000000..06bc260 --- /dev/null +++ b/docs/demo/regen-svgs.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash +# Regenerate docs/demo/*.svg from docs/demo/segments/*.txt +set -euo pipefail +ROOT="$(cd "$(dirname "$0")/../.." && pwd)" +cd "$ROOT" +count=0 +for f in docs/demo/segments/*.txt; do + stem="$(basename "$f" .txt)" + python3 docs/demo/render_svg.py "$f" "docs/demo/${stem}.svg" + count=$((count + 1)) +done +echo "demo SVGs regenerated: ${count}" diff --git a/docs/evidence/baseline/14-fac-ncr-probe.txt b/docs/evidence/baseline/14-fac-ncr-probe.txt new file mode 100644 index 0000000..effc73b --- /dev/null +++ b/docs/evidence/baseline/14-fac-ncr-probe.txt @@ -0,0 +1,52 @@ +=== fac(n) via te_interp === +n= 0 te=0x1p+0 bits=3ff0000000000000 tgamma=0x1p+0 same=1 inf=0 nan=0 +n= 1 te=0x1p+0 bits=3ff0000000000000 tgamma=0x1p+0 same=1 inf=0 nan=0 +n= 2 te=0x1p+1 bits=4000000000000000 tgamma=0x1p+1 same=1 inf=0 nan=0 +n= 3 te=0x1.8p+2 bits=4018000000000000 tgamma=0x1.8p+2 same=1 inf=0 nan=0 +n= 4 te=0x1.8p+4 bits=4038000000000000 tgamma=0x1.8p+4 same=1 inf=0 nan=0 +n= 5 te=0x1.ep+6 bits=405e000000000000 tgamma=0x1.ep+6 same=1 inf=0 nan=0 +n= 6 te=0x1.68p+9 bits=4086800000000000 tgamma=0x1.68p+9 same=1 inf=0 nan=0 +n= 7 te=0x1.3bp+12 bits=40b3b00000000000 tgamma=0x1.3bp+12 same=1 inf=0 nan=0 +n= 8 te=0x1.3bp+15 bits=40e3b00000000000 tgamma=0x1.3bp+15 same=1 inf=0 nan=0 +n= 9 te=0x1.626p+18 bits=4116260000000000 tgamma=0x1.626p+18 same=1 inf=0 nan=0 +n=10 te=0x1.baf8p+21 bits=414baf8000000000 tgamma=0x1.baf8p+21 same=1 inf=0 nan=0 +n=11 te=0x1.308a8p+25 bits=418308a800000000 tgamma=0x1.308a8p+25 same=1 inf=0 nan=0 +n=12 te=0x1.c8cfcp+28 bits=41bc8cfc00000000 tgamma=0x1.c8cfbffffffffp+28 same=0 inf=0 nan=0 +n=13 te=0x1.7328ccp+32 bits=41f7328cc0000000 tgamma=0x1.7328cc0000001p+32 same=0 inf=0 nan=0 +n=14 te=0x1.44c3b28p+36 bits=42344c3b28000000 tgamma=0x1.44c3b27ffffffp+36 same=0 inf=0 nan=0 +n=15 te=0x1.30777758p+40 bits=4273077775800000 tgamma=0x1.30777758p+40 same=1 inf=0 nan=0 +n=16 te=0x1.30777758p+44 bits=42b3077775800000 tgamma=0x1.3077775800001p+44 same=0 inf=0 nan=0 +n=17 te=0x1.437eeecd8p+48 bits=42f437eeecd80000 tgamma=0x1.437eeecd80002p+48 same=0 inf=0 nan=0 +n=18 te=0x1.6beecca73p+52 bits=4336beecca730000 tgamma=0x1.6beecca730001p+52 same=0 inf=0 nan=0 +n=19 te=0x1.b02b930689p+56 bits=437b02b930689000 tgamma=0x1.b02b930689001p+56 same=0 inf=0 nan=0 +n=20 te=0x1.0e1b3be415ap+61 bits=43c0e1b3be415a00 tgamma=0x1.0e1b3be415ap+61 same=1 inf=0 nan=0 +n=21 te=inf bits=7ff0000000000000 tgamma=0x1.6283be9b5c61fp+65 same=0 inf=1 nan=0 +n=22 te=inf bits=7ff0000000000000 tgamma=0x1.e77526159f06bp+69 same=0 inf=1 nan=0 +n=23 te=inf bits=7ff0000000000000 tgamma=0x1.5e5c335f8a4cep+74 same=0 inf=1 nan=0 +n=24 te=inf bits=7ff0000000000000 tgamma=0x1.06c52687a7b9ap+79 same=0 inf=1 nan=0 +n=25 te=inf bits=7ff0000000000000 tgamma=0x1.9a940c33f6123p+83 same=0 inf=1 nan=0 +n=26 te=inf bits=7ff0000000000000 tgamma=0x1.4d9849ea37eecp+88 same=0 inf=1 nan=0 +n=27 te=inf bits=7ff0000000000000 tgamma=0x1.19787e5d9f316p+93 same=0 inf=1 nan=0 +n=28 te=inf bits=7ff0000000000000 tgamma=0x1.ec92dd23d6967p+97 same=0 inf=1 nan=0 +n=29 te=inf bits=7ff0000000000000 tgamma=0x1.be6518687a785p+102 same=0 inf=1 nan=0 +n=30 te=inf bits=7ff0000000000000 tgamma=0x1.a27ec6e1f2d0dp+107 same=0 inf=1 nan=0 +=== fac fractional === +fac(20.9) => 0x1.0e1b3be415ap+61 bits=43c0e1b3be415a00 inf=0 nan=0 +fac(21.1) => inf bits=7ff0000000000000 inf=1 nan=0 +fac(-1) => nan bits=7ff8000000000000 inf=0 nan=1 +fac(1e20) => inf bits=7ff0000000000000 inf=1 nan=0 +=== ncr overflow-ish === +ncr(10,3) => 0x1.ep+6 bits=405e000000000000 inf=0 nan=0 +ncr(66,33) => inf bits=7ff0000000000000 inf=1 nan=0 +ncr(67,33) => inf bits=7ff0000000000000 inf=1 nan=0 +ncr(100,50) => inf bits=7ff0000000000000 inf=1 nan=0 +ncr(1000,2) => 0x1.e7cbp+18 bits=411e7cb000000000 inf=0 nan=0 +ncr(1e9,1) => 0x1.dcd65p+29 bits=41cdcd6500000000 inf=0 nan=0 +ncr(1e9,2) => 0x1.bc16d66d7926cp+58 bits=439bc16d66d7926c inf=0 nan=0 +ncr(-1,1) => nan bits=7ff8000000000000 inf=0 nan=1 +ncr(5,6) => nan bits=7ff8000000000000 inf=0 nan=1 +=== npr === +npr(10,3) => 0x1.68p+9 bits=4086800000000000 inf=0 nan=0 +npr(20,5) => 0x1.c638p+20 bits=413c638000000000 inf=0 nan=0 +npr(21,21) => inf bits=7ff0000000000000 inf=1 nan=0 +npr(100,2) => 0x1.356p+13 bits=40c3560000000000 inf=0 nan=0 diff --git a/docs/evidence/baseline/15c-ncr-dos.txt b/docs/evidence/baseline/15c-ncr-dos.txt new file mode 100644 index 0000000..c80b6f3 --- /dev/null +++ b/docs/evidence/baseline/15c-ncr-dos.txt @@ -0,0 +1,6 @@ +ncr(40,20) 0x1.00c258d9ap+37 0.000046s +ncr(60,30) 0x1.a42902a5af0bfp+56 0.000002s +ncr(1000000000,100) inf 0.000001s +ncr(1000000000,10000) inf 0.000001s +ncr(4000000000,100000) inf 0.000001s +ncr(4294967295,200000) inf 0.000001s diff --git a/docs/evidence/baseline/16-libm-vs-stdmath.txt b/docs/evidence/baseline/16-libm-vs-stdmath.txt new file mode 100644 index 0000000..7ffb094 --- /dev/null +++ b/docs/evidence/baseline/16-libm-vs-stdmath.txt @@ -0,0 +1,20 @@ +fn total differ rate worst_abs_delta +sin 602117 0 0.00000000 0.000000e+00 +cos 600022 0 0.00000000 0.000000e+00 +tan 600022 0 0.00000000 0.000000e+00 +asin 26109 24441 0.93611398 inf +acos 26109 24494 0.93814394 inf +atan 600022 30803 0.05133645 2.220446e-16 +sinh 26109 24 0.00091922 2.328306e-10 +cosh 26109 60 0.00229806 2.220446e-16 +tanh 26109 682 0.02612126 2.220446e-16 +exp 602117 0 0.00000000 0.000000e+00 +log 302116 0 0.00000000 0.000000e+00 +log10 300021 0 0.00000000 0.000000e+00 +sqrt 302116 0 0.00000000 0.000000e+00 +ceil 26109 0 0.00000000 0.000000e+00 +floor 26109 0 0.00000000 0.000000e+00 +fabs 26109 0 0.00000000 0.000000e+00 +pow 24831 8294 0.33401796 inf +atan2 24831 3606 0.14522170 4.440892e-16 +fmod 24831 6000 0.24163344 7.500000e+00 diff --git a/docs/evidence/consumability/zig-fetch-save.txt b/docs/evidence/consumability/zig-fetch-save.txt index e69de29..8c86eb7 100644 --- a/docs/evidence/consumability/zig-fetch-save.txt +++ b/docs/evidence/consumability/zig-fetch-save.txt @@ -0,0 +1,12 @@ +# zig fetch --save of package tarball (measured 2026-08-02) +# From scratch project /tmp/te-user-consumer after: +# tar -czf /tmp/tinyexpr-pkg.tar.gz build.zig build.zig.zon src LICENSE README.md +# zig fetch --save file:///tmp/tinyexpr-pkg.tar.gz +# +# Resulting build.zig.zon dependency entry: +.tinyexpr = .{ + .url = "file:///tmp/tinyexpr-pkg.tar.gz", + .hash = "tinyexpr-0.1.0-fv-tH2JQAQC8ICkMA05jq1R8UmuqAqglyWWub-G8lCKK", +} +# zig build run printed: external_fetch_ok value=10 +# See also zig-fetch-external-run.txt diff --git a/docs/evidence/cross-compile.json b/docs/evidence/cross-compile.json index 71ab30d..6853183 100644 --- a/docs/evidence/cross-compile.json +++ b/docs/evidence/cross-compile.json @@ -73,7 +73,7 @@ "unit_tests": "pass", "full_suite": "not_run", "ran": true, - "run_notes": "zig build test -Dtarget=wasm32-wasi -fwasmtime passed; wasm32-wasi is a third independent execution environment for differential work (prompt 5 seam)", + "run_notes": "zig build test -Dtarget=wasm32-wasi -fwasmtime passed; wasm32-wasi is a third independent execution environment for differential work", "artifact": "libtinyexpr.a" } } diff --git a/docs/evidence/scorecard.json b/docs/evidence/scorecard.json index df943bd..cbb443f 100644 --- a/docs/evidence/scorecard.json +++ b/docs/evidence/scorecard.json @@ -145,7 +145,7 @@ "unit_tests": "pass", "full_suite": "not_run", "ran": true, - "run_notes": "zig build test -Dtarget=wasm32-wasi -fwasmtime passed; wasm32-wasi is a third independent execution environment for differential work (prompt 5 seam)", + "run_notes": "zig build test -Dtarget=wasm32-wasi -fwasmtime passed; wasm32-wasi is a third independent execution environment for differential work", "artifact": "libtinyexpr.a" } }, diff --git a/docs/evidence/self-audit.md b/docs/evidence/self-audit.md index a04c263..e496b00 100644 --- a/docs/evidence/self-audit.md +++ b/docs/evidence/self-audit.md @@ -2,7 +2,8 @@ Adversarial review before code freeze. Host: Kavyas-MacBook-Air-2. UTC start: 2026-08-02. Freeze deadline: 2026-08-03 18:00 UTC. -Final commit SHA filled at tag time. +Final commit SHA at tag `submission-v1`: `76dec4d0e7a8a47215416cc12af994a8f94ca98d` +(re-pointed after credibility cleanup if a newer commit becomes the tag tip). Disposition legend: **fixed** / **ok** / **qualified** / **human-required**. diff --git a/docs/journal.md b/docs/journal.md index 3f532b6..8123958 100644 --- a/docs/journal.md +++ b/docs/journal.md @@ -181,9 +181,10 @@ and is not run against C in-process. ## 2026-08-02 elmengo allocfault-fuzz-sanitizers -Code freeze is 2026-08-03 18:00 UTC. Long differential fuzz started first -(`bash scripts/run-fuzz.sh 14400 fuzz/log-long.txt long`) and continues in -the background while the other campaigns run. +Code freeze is 2026-08-03 18:00 UTC. A long differential fuzz was started +(`bash scripts/run-fuzz.sh 14400 fuzz/log-long.txt long`) alongside the other +campaigns; that host later crashed and `fuzz/log-long.txt` was never written. +The certified 60s log remains the published duration evidence. Pillar 4 allocfault (`tools/allocfault`): one LD_PRELOAD interposer for C and Zig ABI. Corpus 107 inputs, **271** allocation ordinals tested, **0** crashes @@ -225,9 +226,10 @@ Regenerated `docs/evidence/scorecard.json` after fixing fragment routing so `buglead-*` and `sanitizers` land under real keys instead of polluting the root. Coverage / enumeration / fuzz / alloc_fault / bugleads / sanitizers are `measured`. `docs/evidence/hash-verify.txt` rewritten; `upstream_hash_ok` is -true. Long differential fuzz (`scripts/run-fuzz.sh 14400`) is still running -with progress dumps under `.local/fuzz/progress-long.json`; `fuzz/log-long.txt` -will be committed when that campaign ends. Do not invent a total. +true. Long differential fuzz (`scripts/run-fuzz.sh 14400`) was started toward +`fuzz/log-long.txt` and died with a WSL host crash; that artifact was never +committed. The certified 60s run in `fuzz/log.txt` stands. Do not invent a +long-run total. ## 2026-08-02 Kavyas-MacBook-Air-2 independent-reproduction diff --git a/fuzz/README.md b/fuzz/README.md index 1f0194b..67213f0 100644 --- a/fuzz/README.md +++ b/fuzz/README.md @@ -30,16 +30,20 @@ Artifacts: - `corpus-seed/`: small tracked seed inputs. - `logs/`: gitignored runtime logs from `scripts/run-logged.sh`. -## Differential fuzz (Prompt 5) +## Differential fuzz ```bash bash scripts/run-fuzz.sh 60 fuzz/log.txt certified # required 60s log -bash scripts/run-fuzz.sh 14400 fuzz/log-long.txt long +bash scripts/run-fuzz.sh 14400 fuzz/log-long.txt long # optional long campaign bash scripts/run-metamorphic.sh bash scripts/run-libfuzzer.sh 30 fuzz/log-libfuzzer.txt zig build test -Doptimize=ReleaseSafe --fuzz # Zig 0.16 built-in; not Debug ``` +The 60s certified log is `fuzz/log.txt` (0 divergences). A multi-hour +`fuzz/log-long.txt` campaign was started on WSL and lost to a host crash; +that artifact was never committed. The certified 60s run stands. + `fuzz/harness.c` compares C (objcopy-renamed) vs Zig on result bits, error position, success/NULL, and structured near-valid inputs. `fuzz/log.txt` is the certified sixty-second run. Wall-clock is secondary; executions and diff --git a/scripts/cross-compile.sh b/scripts/cross-compile.sh index ba83960..19cb5f8 100644 --- a/scripts/cross-compile.sh +++ b/scripts/cross-compile.sh @@ -107,7 +107,7 @@ for t in targets: if test_triple != t: note += f" (artifact target remains {t}; musl used for qemu without glibc runtimes)" if t == "wasm32-wasi": - note += "; wasm32-wasi is a third independent execution environment for differential work (prompt 5 seam)" + note += "; wasm32-wasi is a third independent execution environment for differential work" entry["run_notes"] = note else: entry["unit_tests"] = "fail" diff --git a/scripts/run-sanitizer-matrix.sh b/scripts/run-sanitizer-matrix.sh index d63bb83..7e01842 100644 --- a/scripts/run-sanitizer-matrix.sh +++ b/scripts/run-sanitizer-matrix.sh @@ -1,5 +1,5 @@ #!/usr/bin/env bash -# Sanitizer / safety matrix (Prompt 5 Task 3). Writes docs/evidence/sanitizers.md +# Sanitizer / safety matrix. Writes docs/evidence/sanitizers.md set -euo pipefail ROOT="$(cd "$(dirname "$0")/.." && pwd)" WORK="$ROOT/.local/sanitizers" diff --git a/src/c_abi.zig b/src/c_abi.zig index f8a6fb6..977e81d 100644 --- a/src/c_abi.zig +++ b/src/c_abi.zig @@ -76,7 +76,7 @@ pub const State = extern struct { }; comptime { - // Layout numbers were measured on x86_64 Linux (prompt 1). Other ABIs differ + // Layout numbers were measured on x86_64 Linux. Other ABIs differ // in pointer width; keep the struct definitions and skip the size lock there. if (@import("builtin").cpu.arch == .x86_64 and @import("builtin").os.tag == .linux) { if (@sizeOf(TeExpr) != 24 or @alignOf(TeExpr) != 8 or diff --git a/src/parser.zig b/src/parser.zig index 64481d3..7cc7890 100644 --- a/src/parser.zig +++ b/src/parser.zig @@ -1,6 +1,6 @@ //! AST builder interface for the shared recursive-descent parser. //! NativeBuilder constructs tagged-union Expr nodes. -//! CAbiBuilder (prompt 3.5) constructs te_expr-shaped trees. +//! CAbiBuilder constructs te_expr-shaped trees. const std = @import("std"); const ast = @import("ast.zig");