docs: correct CLAUDE.md against the tree - #17
Conversation
The file pointed at a tests/ directory that has never existed, documented a
bit64 API that bit64 does not have, and gave a 64-bit literal that the accessors
reject outright.
- Drop the tests/ tree; tests are embedded selftest() driven by run_tests.sh.
- mask is bit16/bit32 only and to_unsigned is bit32 only; the modules do not
share one API. Document bit64's Int64 constructors and accessors.
- {high, low} pairs carry a private metatable. The documented bare literal fails
is_int64 and raises from to_number, which bit64's own selftest asserts.
- _compat dispatches on a capability probe, not a version: LuaJIT rolling
releases parse 'a & b' but return signed 32-bit, so a syntax test misroutes
them. require('bit') is tried before bit32.
- raw_* match the wrapped ops only for in-range inputs; the wrapped ones mask.
- Benchmark iterations are 100000, not 10000.
- CI runs make test-all under the workflow 'Lua Tests' on main and master, and
the check job runs typecheck, which the CI section omitted entirely.
- Style flags are Makefile CLI flags over src/ only; there is no .stylua.toml.
The annotations are LuaCATS, not LuaDoc.
- Document make check as the gate and note that make all is not it.
Also states that the typecheck grep targets a lua-language-server source
checkout rather than this repo, and drops the survey of which sibling repos
care about runtime.version, which rots on the other repos' commits.
derek-miller
left a comment
There was a problem hiding this comment.
Approving. I checked this against the tree rather than reading it, because a wrong CLAUDE.md misleads every future session silently — and the corrections here are exactly the class that was doing that.
Verified accurate:
- No
tests/directory. Confirmed absent; the old tree diagram invented three files. maskis bit16/bit32 only,to_unsignedis bit32 only. Enumerated all three modules — correct, and this is the most useful fix in the PR. The old "each module provides the same API" was actively wrong, and the failure mode is a nil-index at runtime.raw_*in bit32 and bit64, none in bit16. Both expose all ten.bit64aliasesxor/shr/lsl/asrexist (bit64.lua:379-388).- The Int64 error string
"Value is not a valid Int64HighLow pair"matches bit64.lua:337. check: format-check lint typecheckandall: format lint test build— the warning thatallis not a substitute forcheckis right, and worth stating sincealllooks like the bigger target.- Benchmarks: 3 warmup, default 100, modules pass 100000. The old doc said 10000; it is 100000.
- CI: workflow name is
Lua Tests, LLS pinned to3.19.0, jobs runmake checkandmake test-all. - stylua has no config file — invoked as
--indent-type Spaces --column-width 120 --line-endings Unix src/from the Makefile, andluacheck src/, so "src only" is right. - The local/CI matrix asymmetry is real and I would not have guessed it.
run_tests_matrix.shpins5.1.5 5.2.4 5.3.6 5.4.8 luajit-2.1-dev; CI runs 5.1-5.4 plus luajit-2.0 and 2.1. So "a green local matrix is a weaker signal than a green CI one" is precisely true, and that is the kind of thing people learn the hard way.
Twice I thought you had it wrong and I was the one who was wrong. I read bit32 as exposing only raw_add, and bit64 as having no compat aliases — both because I grepped for ^function and missed that those are plain assignments. Worth recording only because it is a reason to trust the rest: the claims that looked most falsifiable held up under a second, better check.
The two rewrites that add the most:
The _compat section going from a version table to "probes behaviour, not version" is the substantive one. The old text described a version ladder that is not what the code does, and the LuaJIT-2026 detail — parses a & b but returns signed 32-bit, so a compile-only test routes it into the native branch and skips to_unsigned() — is the reason the probe has to exist. That belongs in a file agents read before touching _compat.
The Int64 metatable note is the other. "The bitwise operations index [1]/[2] directly and so happen to accept a bare literal; the accessors do not" describes a genuine trap: a bare {hi, lo} works until it suddenly doesn't, and the divergence is silent until an accessor raises.
LuaDoc → LuaCATS is also correct, given typecheck runs lua-language-server.
Part of AGENT-44 (audit the CLAUDE.md files that exist). One PR per repo.
Provenance matters for reading this diff. Only the
### typechecksection wastouched in the 2026-08-08 sweep; it verifies clean. Everything else in the file
dates to January and had not been revisited in six months, and that is where
all the findings are.
Wrong
A
tests/directory that has never existed. The file sends readers totests/test_bit16.lua,test_bit32.lua,test_bit64.lua. There is notests/directory; every module carries an embeddedselftest()driven byrun_tests.sh. Highest-impact item here, since it is three dead paths."Each bit module provides the same API" — it does not, in both directions.
maskis bit16/bit32 only andbit64has none;to_unsignedis bit32 only.Meanwhile
bit64's own surface (new,is_int64,to_hex,to_number,from_number,eq,is_zero, and the aliasesxor/shr/lsl/asr) wasentirely undocumented. For a library that four other repos vendor, that is the
most consequential gap after the next item.
The documented 64-bit literal is rejected by the code.
bit64.newattaches a private metatable andbit64.is_int64tests for it, sothis bare literal raises
"Value is not a valid Int64HighLow pair"fromto_number. The repo's own selftest asserts that error. The subtle part, nowdocumented: the bitwise ops index
[1]/[2]directly and so accept theliteral, while the accessors reject it — the two paths diverge silently until
something raises.
Benchmark iterations: documented as "modules use 10000", actually 100000.
CI section omitted typecheck (while line 122 of the same file asserted
"Part of
check, so CI enforces it"), named the wrong trigger branches, andsaid the test job runs
make test-matrixwhen it runsmake test-all.Imprecise
_compatdispatches on a capability probe, not a version. It compilesa & band checksfn(0xFFFFFFFF, 0xFFFFFFFF) == 0xFFFFFFFF. The reason is anoutside fact the file omitted and the source comment carries: LuaJIT rolling
releases from 2026 parse
a & bbut return signed 32-bit, so a syntax testwould misroute them into the native branch and skip
to_unsigned(). Alsorequire("bit")is tried beforebit32, so a 5.1 install with LuaBitOptakes the LuaJIT path and reports
is_luajit = true.raw_*"behave identically to regular operations" on non-LuaJIT — only forin-range inputs. The wrapped versions also mask their arguments; the raw ones do
not.
.stylua.tomldoes not exist. The values are right but live as Makefile CLIflags, and cover
src/only. The annotations are LuaCATS, not LuaDoc — whichthe file's own typecheck section already called LuaCATS.
Added
make checkas the actual gate, and an explicit line thatmake allisformat lint test buildand is not it. Also that the localtest-matrixomits LuaJIT 2.0 while CI covers it, so a green local matrix is the weaker signal.
Two changes inside the shared typecheck block
Both apply to the sibling repos too; flagging them rather than burying them.
grephad nowhere to run. It targetsscript/core/diagnostics/*.luawith no indication those paths are inside alua-language-server source checkout rather than this repo. Run at the repo root
it matches nothing. Now says so.
indifferent to
runtime.version(naming lua-noiseprotocol, lua-bthome-ble,lua-protobuf). That is a claim about three other trees, in a public repo, that
rots on their commits and not this one's. Kept the observed behaviour — the pin
is load-bearing here because of the
math.powandunpackshims — anddropped the attribution.
Verification
make typecheckwith the CI-pinned lua-language-server 3.19.0: clean.source, including the
bit64function list and the selftest that pins theInt64 error.
make test,make build. No Lua source changed.