docs: audit README against the tree and correct every stale claim - #104
Merged
Conversation
Every factual claim in README.md re-verified against the source, the
build output, or a measured run. Corrections, with how each was checked:
- Binary sizes / label counts: 38 KB + 1738/1816 labels -> 47,105 B /
2292 (ip65) and 62,977 B / 2400 (uci), from `make clean && make
[BACKEND=uci]` plus `grep -c '^al ' build/labels.txt`.
- Architecture diagram named `.asm` files the ca65 conversion removed
(`http.asm`, `tls13.asm`, `tls_record.asm`, `tls_handshake.asm`,
`hkdf.asm`). Only `src/constants.asm` and `src/entropy.asm` survive,
and neither is built.
- Diagram said "ECDHE P-256"; the ClientHello carries exactly one group,
0x001D x25519.
- `src/net_abi.inc` was described as the interface TLS/HTTP consume
networking through. Nothing `.include`s it; declared and used surfaces
overlap in 6 of 17 symbols; ip65 exports none of `net_dhcp_acquire`,
`net_tcp_set_recv_cb`, `net_local_ip`, `net_resolved_ip`,
`net_last_error`, `net_tcp_state`.
- Memory map predated the W1 hot/cold split and presented one layout as
universal. Replaced with per-backend maps read from
`build/c64-https.map`; the quarter-square table is at $BC00, not $7800.
- max_fragment_length "512 or 1024" -> always value 1 = 512.
- X25519 "~3.6 min/op" / "12,782 jiffies" -> measured 12,635 jiffies =
211 s (3.5 min), 13.9 s wall under warp, via tools/bench_x25519.py.
- "253 tests across 11 suites" -> 266 across 11, measured twice.
x25519 71 -> 73; `--slow` is now a no-op. `--skip-slow` "~5s" -> ~45 s;
full run "~5 min" -> ~2 min.
- ECDSA verify wall-clock ("~85 s/op", "~60-70 min at 1 MHz") and the
ip65 e2e "~2-3 h" replaced with the measured figures from CLAUDE.md,
each tagged with the libs/nistcurves v0.6.0 pin they were taken at.
- "The Makefile automatically builds ip65 ... into a blob" contradicted
the prerequisites block and is false: `.incbin` is invisible to make.
- Added the `make clean`-between-flags trap, the two currently broken
build flags (USE_X25519_SIBLING, P-384) with their exact ld65 errors,
and the v0.2.0 release link.
- Relative sibling-repo links (`../c64-wireguard` etc.) never resolved on
GitHub; replaced with real URLs and split into vendored vs. not.
The "I just want to run it" and "Before you build or test" blocks are
unchanged apart from the release link.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>JC-000 added a commit
that referenced
this pull request
Aug 15, 2026
…st measurement Two deferred follow-ups, both left with reasons recorded by earlier lanes. PR #111 renamed tests/test_*.py -> tests/rig_*.py because those files wear pytest's discovery convention while collecting zero tests, so a bare `pytest` overstates coverage. It explicitly deferred the identical problem in tools/uci/, whose blast radius runs through CLAUDE.md. This is that change: six scripts renamed, following #111's precedent exactly. `norecursedirs` already closed the default-invocation path, but the rename is what holds from an arbitrary working directory, since `testpaths` only applies at the rootdir. Both halves are now pinned by the guard rather than one. tools/test_pytest_boundary.py grows a RIG_DIRS tuple covering both directories and a new test_norecursedirs_covers_every_rig_dir. Probed in both directions: a stray tools/uci/test_*.py fails test_rig_dirs_hold_no_pytest_named_files, and dropping tools/uci from norecursedirs fails the new check. Bare `pytest` is now 31 passed / exit 0; `pytest tests/` and `pytest tools/uci/` both exit 5 with an explanation naming the right README. New tools/uci/README.md mirrors tests/README.md. Reference sweep covers CLAUDE.md, README.md, conftest.py, pytest.ini, tests/README.md, both phase_f docs, tools/https_e2e/, tools/package/listener/, and the cross-invocations (rig_https_print_body and rig_https_local_p384 both delegate to rig_https_local; import-checked after the rename). Zero references exist in c64-test-harness or any other sibling c64-* repo, and no open issue or PR in the org names any of the six. README was audited claim-by-claim in #104; CLAUDE.md never was. Every item below was confirmed by running a command, not by reading: - The ip65 blob section contradicted itself and the Makefile. It claimed `ip65-blob` is phony with "no rule connecting the two" and that a fresh clone dies at the `.incbin`. Measured: deleting the blob and running plain `make` rebuilds it byte-identically (6,951 B, cf1a5ff7...) and links the usual 47,105 B PRG. The real fresh-clone blocker is the missing ip65 .lib archives, which fail at the blob's ld65 step. `make ip65-blob` is not a required step. Fixed here and in README. - "the committed blob" / `touch ip65-build/ip65-c64.bin` advice: the blob is gitignored, so on a fresh clone there is nothing to touch. - Fence macro: 17 bytes per site, not 14 (counted from the macro body). 26 sites, not 24 — 11 write + 14 read + 1 pre-loop settle at net.s:199. - uci_drain_resp/uci_drain_status: 22 call sites in net.s, not 13. All 22 still `bcs` out, so that half was right. - CIA1 TOD read order is HOUR -> TENTHS; MIN and SEC are never read and have no equate in uci_cmd.s. - UCI memory table: NET_CODE is $2000-$3B65 and NET_BSS_TAIL $3B66-$41FF (cfg grew NET_CODE by $40 for the C64U WiFi iface-fallback loop). UCI_BSS_REGION is size 0, so quoting a 512 B span contradicted its own label and overlapped NET_BSS_TAIL. - src/exports.s no longer exports ip65_init/ip65_process; those moved to src/net/ip65/exports.s. Named the real backend-agnostic set instead. - KEEP_DEBUG_ON_PASS is the env var; UCI_DEBUG_KEEP_ON_PASS is only the Python variable name, so the documented spelling did nothing. - rig_https_local_p384.py defaults to 90 minutes (5400 s), not 30. - C64_SKIP_BUILD: 15 scripts, not 14 (ran the recipe the file itself quotes). - EMBED_P256_OVERLAY's stated mutual exclusions have no $(error) guard: one is a silent auto-disable, the other is unguarded. Only the USE_NISTCURVES_ONCHIP exclusions are hard errors. - "All in-tree VICE-driven tests go through default_vice_config()" is false: 8 suites do, 15 other files still build ViceConfig directly — including run_all_tests.py, which hand-spells the REU flags. - Smoke-test list is 8 entries, not 7, and the 97/97 total predates test_finished_verify.py joining it. - pytest counts 30 -> 31; src/boot.s:107-114 -> 110-117. Wall-clock figures are labelled rather than re-measured, per instruction: a pin-vs-commit table resolves 2ceb5b1 / f0127a0 / cb6eab4 to libs/nistcurves v0.6.0 (verified with git ls-tree), every table states the pin it was taken at, and "at HEAD" captions that no longer refer to HEAD are gone. No hardware was used and no benchmark was re-run. Deliberately NOT included: the x25519 sibling failure. It is measured and understood (both backends exit 2 on a duplicate reu_mul_tables_init export, not the overflow CLAUDE.md records), but PR #113 rewrites the same spans and fixes the underlying collision, so the prose belongs there. Details handed to that lane. docs/library-ingestion-architecture.md's two stale references are owned and taken by the contract lane. Python and docs only — no .s, no .cfg, no Makefile, so no PRG changes. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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 freeto 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.
Audit-and-correct pass over
README.md. Every factual claim was checkedagainst the tree, the build output, or a measured run; nothing was kept
because it read plausibly. One commit, claim-by-claim below.
Environment: fresh worktree off
origin/master(fc82ad5), submodules--init --recursive,make ip65-libs && make ip65-blob, cc65 fromHomebrew, macOS.
make cleanbefore every backend/flag change.Claims changed
Sizes and label counts
make clean && make;ls -l build/c64-https.prg,grep -c '^al ' build/labels.txtmake clean && make BACKEND=uci, same commandsAdded a sentence noting that much of both PRGs is deliberate
fill = yeszero padding, so neither number is a code-size measurement.
Source file names
The architecture diagram and prose named
http.asm,tls13.asm,tls_record.asm,tls_handshake.asm,hkdf.asm.git ls-files '*.asm'returns exactly two files —
src/constants.asmandsrc/entropy.asm—and neither is in
$(TOP_SRCS)(the Makefile wildcardssrc/*.s). Allfive names corrected to
.s.Crypto claims
supported_groups/key_sharecarry only 0x001D (src/tls_handshake.s:204), and ServerHello is checked for 0x001D at:494cipher_suites_length = 0x0002, one entry 0x1303 (:77-86), echo-checked at:380src/crypto/"ls src/crypto/tools/bench_x25519.py: 12,635 jiffies, 13.9 s wall, warp 15.1x, correctness PASSlibs/nistcurvesP-256 lineMakefilelinksbuild/lib/nistcurves-p256.a;src/crypto/ecdsa_verify.sis the dispatcher../c64-wireguard,../c64-aes256-ecdsalinksgh repo view JC-000/<repo>→ PUBLIC for all of them; relative../links do not resolve on GitHubnet_abi.incThe README said TLS/HTTP "consume networking only through
src/net_abi.inc". Replaced with the measured position, matching whatCLAUDE.mdnow says:grep -rn 'net_abi' src/ tools/ cfg/ Makefile tests/returns onlycomments — no
.include, so none of its 12.imports is checked.grep -h '\.import.*net_' src/boot.s src/http.s src/tls*.s);intersection 6, union 17.
.exportlist (src/net/ip65/net.s,net_banner.s) has noneof
net_dhcp_acquire,net_tcp_set_recv_cb,net_local_ip,net_resolved_ip,net_last_error,net_tcp_state; UCI's has all six.Memory map
The old block was a single pre-W1 layout presented as universal, with
crypto at $4000-$5FFF and the quarter-square table at $7800. Replaced
with two per-backend tables read out of
build/c64-https.mapafter aclean build of each, plus a small "common to both" block. Spot checks
from
build/labels.txt:sqtab_lo= $BC00 (not $7800),sqtab_hi=$BE00,
cert_buf= $A000,tcp_recv_buf= $C000.Also corrected: "we negotiate max_fragment_length … 512 or 1024 bytes" →
the extension always sends value 1 = 512 (
src/tls_handshake.s:281-297),and
TLS_RECORD_MAX = 512insrc/constants.inc.Zero page table
Was missing $1E-$21 (TLS record layer) and stopped
$FB-$FEa byteshort of
zp_count's two bytes;$22-$3Clumped ECDSA, fe25519 andx25519 together. Split per
src/constants.inc, which is now cited asthe authority.
Build section
false, and it contradicted the prerequisites block three sections
above.
.incbinis invisible to make's dependency graph. Rewritten,with the deterministic blob size/hash (6,951 B,
cf1a5ff7…, which Ireproduced in this worktree).
make clean-between-BACKEND=/flag rule and why (includepath, not
-D), and the PRG-vs-object hash point.make USE_NISTCURVES_ONCHIP=1andmake package, since therelease table above them refers to onchip images.
Known Issues
CLAUDE.md, each explicitly tagged as taken at thelibs/nistcurvesv0.6.0 pin — HEAD is v0.9.1 and the sweep has not been re-runlibs/nistcurvesis the shipped P-256make p384-overlayfrom clean →No rule to make target 'build/labels.txt'; after a main build →Segment 'LIB_NISTCURVES_SHA384_TABLES' overflows memory area 'OVERLAY_REGION' by 1536 bytesUSE_X25519_SIBLING=1links on neither backendld65: Error: Duplicate external identifier: 'reu_mul_tables_init'. Note for the CLAUDE.md owners: CLAUDE.md still describes the v0.6.0-eraX25519_RODATA/P256_CODEoverflows; at the current v0.10.0 pin the failure has moved and is a duplicate-symbol error instead. I did not touch CLAUDE.md in this PR.Test automation
tools/run_all_tests.py --workers 4, run twice, 266/266 both timestools/test_x25519.py:708makes--slowan accepted no-optimeon the full run: 2:05timeon--skip-slow: 46.2 s, 255/255test_finished_verify.py(18/18 measured),test_ecdsa_kat_oracle.py(6 vectors, 3 valid + 3 negative, counted inKAT_VECTORS),test_package_verify.py(31 passed, measured)scripts/setup-bridge-tap.shin this reposcripts/; this repo has the bridge script../c64-test-harness/docs/bridge_networking.mdhttps_listener.pyrowgrep -n 'def start_https_listener'etc.CLAUDE.md"ip65 / stock-C64 wall-clock"Added a short paragraph naming the macOS feth/pcap rig
(
tools/rig-up-macos.sh, patched VICE) since that is where the ip65number comes from and the section previously described only the Linux
bridge.
UCI section
TURBO_MHZ=1"~2-3 h total" → the handshake+GET itself measured1,157.7 s (~19 min); the 2-3 h figure was the timeout budget, not a
runtime.
600 * (48 / TURBO_MHZ)→600 * max(1, 48 / TURBO_MHZ)(
tools/uci/test_https_local.py:229).EXTERNAL_LISTENER/EXTERNAL_HOST/EXTERNAL_PORT(:253-258).test_https_bad_finished.pyto the script list with a note onwhy the evil listener is hand-rolled.
release table.
Release
Added the v0.2.0 link to "I just want to run it". Confirmed against
gh release view v0.2.0: 12 assets, four.prg, six.d64,c64-https-listener.py,MANIFEST.txt— the section's file names allmatch. Nothing else in that section changed.
Preserved deliberately
re-checked its claims incidentally, because this worktree started with
uninitialised submodules and no blob: the flow it prescribes is what I
had to run, and
src/net/ip65/ip65_blob.s:22is indeed the.incbinline the quoted error names.
release link.
Not verified — left alone
the FPGA-fence rework." Needs U64E LAN access.
macOS; I removed the unqualified "All three phases pass" wording rather
than assert or deny it, and left the scripts documented.
is queue-shared and each run is ~20 min at 1 MHz, and the C64U is
offline. Every such figure now carries its pin (v0.6.0) and the note
that HEAD (v0.9.1) has not been re-swept.
historical note about a fixed harness bug; left as-is.
🤖 Generated with Claude Code