Skip to content

Commit 71618dd

Browse files
committed
feat: pwm-tui ratatui demo proving the real checkpoint locally (closes #200)
A new unpublished pwm-tui crate runs the run-real.sh path natively, no Docker: sha256-pinned download + cache of the checkpoint and the real lerobot/pusht episode (--cache-dir > PWM_CACHE_DIR > platform default), uv-orchestrated network-free export with NDJSON progress, then the in-process prove/verify/tamper of the real weights, rendered live (stage rail, op histogram, commitments, verdicts) with --headless --json for CI and cache path|ls|clear management. A warm bundle cache skips Python entirely. The pwm prove-predictor computation moved into pwm_testkit::report so the CLI and the TUI render one computation; the exporter gained LEWM_JSON_EVENTS and LEWM_PUSHT_PARQUET/MP4 overrides (Docker path unchanged). deny.toml carries a documented ignore for the informational paste advisory (ratatui 0.29; 0.30 needs Rust 1.88 > MSRV 1.85).
1 parent 468a6c0 commit 71618dd

25 files changed

Lines changed: 3843 additions & 257 deletions

File tree

.github/workflows/release.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -143,11 +143,11 @@ jobs:
143143
lake exe cache get
144144
lake build
145145
146-
# Package the publishable crates (pwm-testkit is publish=false). The whole
146+
# Package the publishable crates (pwm-testkit and pwm-tui are publish=false). The whole
147147
# workspace is packaged together so inter-crate deps resolve among the set.
148148
- name: Package crates
149149
run: |
150-
cargo package --workspace --exclude pwm-testkit --no-verify --locked
150+
cargo package --workspace --exclude pwm-testkit --exclude pwm-tui --no-verify --locked
151151
ls -1 target/package/*.crate
152152
153153
- name: Extract release notes

.github/workflows/tui-smoke.yml

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
# SPDX-License-Identifier: Apache-2.0
2+
#
3+
# Headless smoke for the pwm-tui real-checkpoint demo (no Docker). Separate from
4+
# the merge gate because it downloads external Hugging Face assets and a torch
5+
# environment. Runs on demand and weekly on main.
6+
name: TUI Smoke
7+
8+
on:
9+
workflow_dispatch:
10+
schedule:
11+
- cron: "41 5 * * 1"
12+
13+
permissions:
14+
contents: read
15+
16+
jobs:
17+
tui-headless:
18+
name: pwm-tui headless real demo
19+
runs-on: ubuntu-latest
20+
timeout-minutes: 60
21+
env:
22+
NO_COLOR: "1"
23+
PWM_CACHE_DIR: ${{ github.workspace }}/.pwm-cache
24+
steps:
25+
- uses: actions/checkout@v6
26+
27+
- name: Install uv
28+
uses: astral-sh/setup-uv@v8
29+
30+
- name: Build pwm-tui
31+
run: cargo build -p pwm-tui --release --locked
32+
33+
- name: Cold run (downloads pinned assets, exports, proves)
34+
run: |
35+
set -euo pipefail
36+
./target/release/pwm-tui --headless --json | tee tui-cold.log
37+
tail -n 1 tui-cold.log > tui-summary.json
38+
python3 - <<'PY'
39+
import json
40+
s = json.load(open("tui-summary.json"))
41+
assert s["ok"] is True, s
42+
r = s["report"]
43+
assert r["accepted"] is True
44+
assert r["weights_root_source"] == "export-bundle"
45+
assert float(r["float_error"]) <= float(r["float_tolerance"])
46+
assert r["tamper"]["rejected_with"], "tamper must be rejected"
47+
print("cold run ok:", r["weights_root"][:16], r["z_out_head"])
48+
PY
49+
50+
- name: Warm run (offline, bundle cache hit, pure Rust)
51+
run: |
52+
set -euo pipefail
53+
./target/release/pwm-tui --headless --offline --json | tee tui-warm.log
54+
grep -q "skipped: bundle cache hit" tui-warm.log
55+
tail -n 1 tui-warm.log | python3 -c "import json,sys; s=json.load(sys.stdin); assert s['ok'] is True"
56+
57+
- name: Cache management commands
58+
run: |
59+
set -euo pipefail
60+
./target/release/pwm-tui cache path
61+
./target/release/pwm-tui cache ls
62+
./target/release/pwm-tui cache clear --yes
63+
./target/release/pwm-tui --headless --offline > offline-cold.log 2>&1 && exit 1 || true
64+
grep -q "offline" offline-cold.log
65+
66+
- name: Upload logs
67+
if: always()
68+
uses: actions/upload-artifact@v7
69+
with:
70+
name: tui-smoke-${{ github.run_id }}
71+
path: |
72+
tui-cold.log
73+
tui-warm.log
74+
offline-cold.log
75+
if-no-files-found: warn
76+
retention-days: 14

AGENTS.md

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ non-reproducible attention. There is no proving circuit and no arithmetization.
4141

4242
## Layout
4343

44-
Five small crates, one trust anchor. The verifier depends on neither the exporter
44+
Six small crates, one trust anchor. The verifier depends on neither the exporter
4545
nor any Python or float runtime.
4646

4747
- `pwm-core`: fields (M31 value, Fp61 audit), fixed point, tensors, Merkle
@@ -55,7 +55,12 @@ nor any Python or float runtime.
5555
- `pwm-verifier`: CPU, `no_std`, float-free. Freivalds-check the linears,
5656
recompute the rest, check rollout, cost, argmin.
5757
- `pwm-testkit`: golden vectors, accept and reject suites, the mutation harness,
58-
the `pwm` demo CLI (`crates/pwm-testkit/src/bin/pwm.rs`).
58+
the `pwm` demo CLI (`crates/pwm-testkit/src/bin/pwm.rs`), and the shared
59+
`report` module: the single load -> prove -> verify -> tamper computation that
60+
every demo front end renders.
61+
- `pwm-tui`: the ratatui demo front end. Proves the real checkpoint locally with
62+
no Docker, with sha256-pinned checkpoint/dataset/bundle caching and a
63+
`--headless --json` mode for CI. Demo only; not published.
5964

6065
## Run the demo
6166

@@ -68,13 +73,22 @@ docker compose --profile compact up --build prover verifier # tiny two-part
6873
Without Docker:
6974

7075
```bash
76+
cargo run -p pwm-tui --release # REAL checkpoint, TUI, cached
7177
cargo run -p pwm-testkit --bin pwm --release -- prove-predictor # synthetic
7278
cargo run -p pwm-testkit --bin pwm --release -- prove-predictor <bundle> # real weights
7379
cargo test --workspace # accept + reject suites
7480
bash ci/check-local.sh quick # fast local quality loop
7581
bash ci/check-local.sh full # local merge-gate mirror
7682
```
7783

84+
`pwm-tui` mirrors `./demo/run-real.sh` natively: it downloads and pin-verifies
85+
the checkpoint plus a real episode into a cache (`--cache-dir`, then
86+
`PWM_CACHE_DIR`, then the platform default), runs the exporter via `uv`
87+
(network-free, NDJSON progress through `LEWM_JSON_EVENTS`), and proves the real
88+
weights in-process. A warm bundle cache skips Python entirely. `--offline`,
89+
`--refresh`, `--re-export`, and `cache path|ls|clear` manage the cache; the
90+
Docker paths are unchanged.
91+
7892
The `pwm` CLI prints a five-stage pipeline (LOAD, INFER, COMMIT, VERIFY, TAMPER); it
7993
honors `NO_COLOR` and `--json`.
8094

CHANGELOG.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,27 @@ entry.
1313

1414
## [Unreleased]
1515

16+
### Added
17+
18+
- **`pwm-tui`: a ratatui demo that proves the REAL pretrained checkpoint end to
19+
end locally, with no Docker** (#200): downloads and sha256-pin-verifies the
20+
`quentinll/lewm-pusht` checkpoint and a real `lerobot/pusht` episode into a
21+
configurable cache (`--cache-dir` > `PWM_CACHE_DIR` > platform default), runs
22+
the PyTorch exporter via `uv` network-free, then proves, verifies, and
23+
tamper-checks the real weights in-process with live per-stage progress, the
24+
op histogram, the commitments, and the verdicts. A warm bundle cache skips
25+
Python entirely; `--offline`, `--refresh`, `--re-export`, `--headless --json`,
26+
and `cache path|ls|clear` manage the cache. Exit code 0 means the honest proof
27+
was accepted and the forged one rejected.
28+
- The Python exporter emits NDJSON progress events when `LEWM_JSON_EVENTS` is
29+
set (pretty log moves to stderr; the Docker path is unchanged) and accepts
30+
`LEWM_PUSHT_PARQUET` / `LEWM_PUSHT_MP4` local file overrides so a caching
31+
front end can make the export stage network-free.
32+
- The `pwm prove-predictor` demo computation moved into the shared
33+
`pwm_testkit::report` module (`build_predictor_report`, `PredictorReport`,
34+
with phase callbacks); the CLI and the TUI render the same single computation,
35+
so their numbers cannot drift.
36+
1637
## [0.1.0] - 2026-06-11
1738

1839
### Security

0 commit comments

Comments
 (0)