Repository navigation
feat(ptbr-tools): the ptbr-writer plugin's runtime scripts as one static Rust binary - #132
Merged
Merged
Conversation
…tic Rust binary New lab. It ports ask_levels.py (the UserPromptSubmit hook), reading_time.py and route.py (+ routes.tsv) of h0ffmann/ptbr-writer to Rust, std only, no crates. One multi-call binary, `ptbr`, runs as ptbr-ask-levels, ptbr-reading-time or ptbr-route (symlinks, or `ptbr <command>`). The static musl build is 570 112 bytes; three separate binaries were 1 431 776 bytes in total, so the lab ships the multi-call one. Same flags, outputs and exit codes as the Python, with a minimal TOML reader, a minimal JSON reader/writer, a table-based accent fold and hand-written versions of the regular expressions. The self-tests are ported to cargo test and --self-test still works. checks: build + tests, clippy -D warnings, fmt, lab-json, a size ceiling (+10%), and the aarch64 static build. Tested: nix flake check --no-update-lock-file in labs/ptbr-tools (build+cargo test, clippy, fmt, lab-json, size, static-aarch64 ok); nixpkgs-fmt, statix, deadnix with the lab's pinned nixpkgs ok; actionlint ok; reuse lint ok; 2297 differential comparisons against the Python originals, 8 differ only where Python crashes with a traceback; aarch64 binary built, not run Co-Authored-By: Claude <[email protected]>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
New lab
labs/ptbr-tools. It ports the three runtime scripts of ptbr-writer from Python to Rust:ask_levels.py(theUserPromptSubmithook),reading_time.pyandroute.py(withroutes.tsv). The crate uses std only and has no dependencies. The plugin can ship the result as a small static binary.Binary layout
I built both layouts and kept the smaller one.
ptbr-ask-levels,ptbr-reading-time,ptbr-route)ptbr(runs as the name of the file, or asptbr <command>)xz -9)The lab ships the multi-call binary.
packages.statichasbin/ptbrand three symlinks to it. Other builds: aarch64 static musl 528 696 bytes (built, not run), glibc 480 176 bytes with a 47.4 MiB closure. The closure of the static build is 557.8 KiB.Checks
nix flake check --no-update-lock-filein the lab: build andcargo test(14 tests; every self-test case of the three scripts is ported, and--self-teststill works),clippy -D warnings,cargo fmt --check,lab-json,size(fails if the static binary grows more than 10% over 570 112 bytes), and the aarch64 static build.nixpkgs-fmt,statixanddeadnixare clean with the lab's pinned nixpkgs (same rev aslabs/ptbr-pdf).actionlintandreuse lintare clean.Differential test against the Python originals
Python 3.11 is an external tool for this test. The harness is not committed. It ran the originals (
python3 -I) and the static Rust binary on the same inputs and compared stdout, stderr and the exit code byte for byte: 2 297 comparisons.reading_time, 1 208 runs: the.mdfiles ofh0ffmann/ptbr-writer(34, fetched withgh api), the self-test texts, 40 hand-made edge texts (fences with~~~and with 4 spaces, unclosed fences, tables, rules, images,<url>links, CRLF, lone CR, front matter, Unicode spaces, U+2028), 400 random texts made of Markdown fragments, each with--lang pt-BR|enand--json; also file arguments,-, a missing file, a directory, usage errors.ask_levels, 829 runs: 66 prompts (triggers, non-triggers, level names with and without accents, decomposed accents,ste100forms,reconfigurar, escapes, emoji), 9SKILL.mdvariants (the real ones, CRLF, no section, empty section), 4 defaults-file variants, about 45 project configs in temp dirs (valid, comments, multi-line arrays, tables, bad values, a folder with.., floats, inline tables, broken TOML) with and without a user config in a tempHOME, 15 hook-JSON stdin variants (invalid JSON, BOM,NaN, duplicate keys, surrogate pairs), argument counts, 300 random prompts, and--self-test.route, 260 runs: 35 requests and 200 random ones against the realroutes.tsvandSKILL.md,--checkwith 7 driftedroutes.tsv/SKILL.mdpairs, a CRLFroutes.tsv, a bad row, a missing file,--self-test.Result: all outputs are identical, except in these cases. They are on purpose or are Python crashes:
READING_TIMEargument that does not end in.pydoes not get thepython3 -Iprefix in the instruction text, so the text names a command that Claude can run. With a.pypath the text is identical.ptbr-writer.tomlthat is not UTF-8 (Rust reports "cannot read") and a list inside a list inlevels(TypeError: unhashable type). For the crashes where both exit with code 1 (non-object JSON, a non-stringprompt, too few arguments, a missingroutes.tsv), the exit codes are equal.route --check: Python walks aset, so its order changes between runs. The harness sorts these lines.Known gaps (⚠, written in the code with
shortcut:comments and in the lab README): the accent fold is a table of Portuguese letters plus a drop of U+0300..U+036F, not a full NFD; the TOML reader does not read dates, multi-line strings, dotted keys or[[arrays]](the hook then reports "cannot read", as it does for a broken file); a lone-surrogate JSON escape becomes U+FFFD.Not verified (⚠)
packages.static-aarch64is built and checked as a file type; it was not run (no emulator on this machine).just --listran with just 1.58; the justfile uses only plain syntax, but I did not parse it with just 1.21.bin/ptbrwith the three symlinks and call them instead ofpython3 -I.ptbr-routefindsroutes.tsvfrom the path it is started with, so it must sit in<skill>/scripts/.Other files
README.md: one row in the labs table and one in "Who uses picasso" (ptbr-writer, pending its PR)..github/workflows/ci.yml:ptbr-toolsis in thelabsmatrix, in both lists (the lab is light, so it also runs on push).AGENTS.mdis not changed: its lab table does not list every lab (viz,paperandgleam-websiteare missing).What a consumer has to do
Nothing yet. No lab changes its exported shape. After this lands, the ptbr-writer PR pins this lab.