git.pack — clone the kernel from a URI arg, then tag-hop the worktree, git as the oracleJAB-020 collapses the clone path to one git.pack(fd, buf, shard, opts) call, and its own TODO demands "a real jab get of a large repo, not a unit probe". This ticket builds that probe: a JS treadmill under be/test/mill/, run by hand (never in ctest), that clones a repo named BY A URI ARGUMENT and then walks its worktree tag by tag, diffing against a parallel git clone at every step. The linux kernel IS the target — ~6.3 GB pack, 11.7M objects, the case where a per-object JS boundary dies and a one-call binding must not. Ports the shell beagle/beagle/test/mill*.sh family to JS, run as jab be/test/mill/<script>.js <uri> … (jab takes a script path — be/main.js is invoked the same way). Method Issues.
beagle/beagle/test/mill-tags.sh is the shape to port: clone at a tag, git checkout the same tag in a reference tree, rsync -rlcni --delete the two, count failures; mill-last10.sh adds timings, mill-toy.sh a synthesized 10-tag repo.REPO=$HOME/src/git and the keeper's HOME-relative //host/path form — TEST-004 takes a URI arg instead, so the same script runs against a local mirror or a github URL.work/KEEP-006: the libdog loop repacked the 6.33 GB linux pack from a PIPE, 11,690,992 shas matching git — that run was manual and unrepeatable; this ticket makes it a script.be/test/ today is data-driven <verb>/<case>/run.sh globbed into CTest by be/test/CMakeLists.txt — the treadmill must NOT land in that glob (it would join ctest -j16 and hang the suite for an hour).git, not native be — a git worktree comparison is the intended ground truth, not a stale-native view parity.A manually-invoked JS treadmill that proves git.pack ingests a kernel-sized pack correctly and that the resulting worktree is byte-identical to git's at every tag.
jab be/test/mill/clone.js <uri> [opts] — clone the repo at <uri> into a scratch worktree; report objects, bytes, wall time, peak RSS.jab be/test/mill/tags.js <uri> [opts] — clone at the first tag, then get each subsequent tag, comparing the worktree to a git reference clone after each hop.<uri> is a POSITIONAL ARG, no default and no $HOME/src/git fallback: be://localhost/…, file:/… and https://github.com/torvalds/linux all valid, resolved through resolve_hash like any other URI.git checkout in a parallel clone plus a full-content diff — identical trees or the hop FAILS, per JAB-020's end-to-end rule.--tags v6.1,v6.2 / --last N / all), because the kernel has ~900 tags and nobody runs them all.be/test/mill/, excluded from the be/test/*/*/run.sh CTest glob and from ninja test; a be/test/mill/README.mkd states how to run it.be/ has zero async/await/Promise (JAB-020 §Design decisions) — the treadmill is plain synchronous JS on the jab runtime, driving git/rsync as subprocesses.$HOME/tmp (ext4), never under the source tree — be walks up for a .be anchor and a scratch wt inside the project glues onto the project's own store (be/test/CMakeLists.txt).Settled with gritzko 2026-07-27 when the ticket was ordered.
mill-toy.sh/be/test/get/* already are.be:///file: vs curl/https).mill-tags.sh uses, not a cheaper tree-hash shortcut.jab <script.js>* — jab resolves a script path arg (jab be/main.js <verb> is the existing precedent), so no new runner is needed.be/test/mill/ — outside the CTest glob, invoked by a person or a CI job that opted in.pack.js, added 2026-07-27* once git.pack(fd, buf, shard, opts) landed in jab (build 22bec7d6): it calls the binding DIRECTLY, so JAB-020's one-call surface is exercised before jab get is converted to route through it.clone.js/tags.js stay CLI-driven* and therefore measure whatever the clone path does today (the per-object JS loop) — that is the baseline, not a defect..be/ shield: pre-seeding .be/ makes the first jab get throw (see Blockers). Isolation rides the .be firewall FILE above the scratch instead.--serve (test/mill/serve.py)* wraps a local git repo in git upload-pack over smart-HTTP — the box has no sshd by default, a bare git path is not a remote, and be:/file: want a beagle store, so without it a local git mirror is unclonable.be/test/mill/ dir + README.mkd (how to run, disk/time footprint, which transports reach the kernel).be/test/mill/lib.js: $HOME/tmp scratch + firewall, subprocess runner over pol, per-step timeout, wall + VmHWM sampling, output cap, cleanup-unless-kept.<uri> positional + --tags/--last/--keep/--cap/--mode/--serve — scheme read through the URI lexer (shared/uri.js → new URI), never a regex.clone.js: one jab get <uri>, wall/peak-RSS/store bytes/file count; git ls-remote tip check, or --ref-clone for the full rsync oracle plus a git-vs-jab wall/RSS table.tags.js: git reference clone (--no-checkout), then per tag jab get <uri>?tags/<TAG> + git checkout + rsync compare; tally, non-zero exit on any failure. Verified 4/4 on a tagged toy repo, each hop landing its OWN sha.pack.js: git.pack direct — objects vs git count-objects, raw+ofs+ref == objects, inBytes == pack - 20, logs under the cap, REF present whenever it rotated, and FILE vs PIPE byte-identical.pack.js --thin: feed a THIN pack (REF_DELTA bases by construction) and pin today's plain-words refusal, so the case flips to a pass when ingest learns REF_DELTA input (see Blockers).be/test/mill/ up (no */*/run.sh match) and ninja test stays the same length.curlRun fd handover).jab get of a large repo" to this ticket.mill*.sh family gets retired or kept as the native-be counterpart — report, do not delete here.Three product findings the treadmill surfaced on its first outing, each now its own ticket; none is a treadmill defect.
REPACK.c:308 refuses a REF_DELTA that ARRIVES in the source pack, so pack.js currently only covers all-OFS input (which is what git's own repack emits). pack.js --thin stays a TODO here until that lands..be/ makes the FIRST jab get throw ToBigInt in hashlet60FromBytes; the treadmill uses bare scratch dirs to dodge it, which is a workaround to revert once fixed.curlRun drops argv[0], so curl never gets -sSf — its progress meter pollutes every http run and HTTP errors do not fail the fetch.time -v's rusage, NOT /proc polling: pol.run blocks until the watched fd is ready, so a quiet child yields no sample points and the process is gone by EOF.jab get cannot reach the kernel over any transport on this box: https buffers the whole body in the JS heap (KEEP-006 §Blockers), a bare git path is not a remote, and be:/file: want a beagle store. pack.js bypasses the wire; clone.js/tags.js need a beagle-store mirror or --serve (small repos).Built and run 2026-07-27 in //TEST-004 (off ///be/, base 45ad875a); UNCOMMITTED per the no-post order. Suggested commit: TEST-004: manual JS treadmills for git.pack and jab get.
be/test/mill/: lib.js, pack.js, clone.js, tags.js, serve.py, README.mkd. Not in the CTest glob (*/*/run.sh), so ninja test is unchanged.pack.js over git.git at a 128 MB cap: *417,182/417,182 objects, 3 logs, 57,609 REF* — the KEEP-006 prototype's number to the record (57,609 predicted, 57,609 emitted), FILE and PIPE runs byte-identical, 1m13s / 672 MiB peak each.tags.js over a 4-tag repo through --serve: 4/4 hops, each landing its OWN sha, every worktree rsync-identical to git checkout.ssh://localhost, git vs beagle on an idle box, two runs: *git 20-21s / 111 MiB peak, jab 1m35-37s / 780 MiB peak — 4.6-4.7x wall, 7x RSS*, both landing 4,842 files and a 297 MiB store. That is the pre-JAB-020 per-object JS path; the number to beat.git clone --recurse-submodules plus UNANCHORED .git/.be excludes it comes down to exactly THREE differences: compat/vcbuild/*.bat. git.git's .gitattributes carries *.bat text eol=crlf, so git checks out CRLF while beagle writes the raw LF blob — beagle's checkout is not .gitattributes-aware. Everything else in git.git, submodule included, is byte-identical.$HOME/src/linux, 6.33 GB pack, 11,690,992 objects — matching KEEP-006 exactly): reached 6.75M objects and 2 logs before being stopped to free the box for the clone benchmark. Not yet a completed pass.