Skip to content

Scope, legal position, and the documentation and tests behind it - #26

Merged
Tratosca merged 36 commits into
mainfrom
chore/scope-legal-and-docs
Aug 22, 2026
Merged

Tratosca merged 36 commits into
mainfrom
chore/scope-legal-and-docs

Conversation

@Tratosca

@Tratosca Tratosca commented Aug 22, 2026

Copy link
Copy Markdown
Owner

Summary

Cuts the tree back to what the project actually does, states the legal position in one place, fixes a build problem that could stop the mod working entirely, reworks the root filesystem documentation after #23, and puts the documentation and the tests in order behind it.

Changes

  • The mod could load and do nothing at all. The compiler was quietly swapping in an instruction the player does not have, so the file on your stick was ignored and the deck behaved exactly as it always had: no error, nothing on screen, nothing to go on. Fixed, and a test now fails the build if it comes back (-fno-builtin-memcmp, tests/test_hook_symbols.py).

  • Preparing the material no longer needs Linux. Pioneer's published archive already contains the filesystem the app needs, so getting it is unzipping and unpacking, the same steps on Windows, macOS and Linux. WSL2 is now only for someone who wants to rebuild that filesystem rather than read it. Refs Key extraction: make_rootfs is not required to obtain initramfs.tar.gz #23.

  • The key no longer has to be retyped. RX3_KEY is read where the key is needed: make autoexec takes it when KEY= is absent, and the application opens with that path already filled in. Nothing writes the location down.

  • The on-screen lettering is closer to the deck's own. The face the player uses is now identified rather than guessed, from rekordbox's own files, and the labels are refitted against Pioneer's own captions. That face is licensed and is not shipped here, so what the mod draws is the nearest cut available on the machine that builds the stick. How close it looks on a deck is not verified yet.

  • The mod no longer reaches past the on-screen pad overlay. This is the row on the display that mirrors the eight rubber pads, not the pads themselves. The mod was picking its targets from the deck's window, which a deck shares with its info strip, so AUTO CUE, QUANTIZE and the tempo badges were being intercepted along with it. It now keys on the part of the display that owns that row, and paints it once per pass rather than once per drawing call.

  • The PATCHED badge is gone. The KEY and STEMS tabs already tell you the mod is running, so the header is Pioneer's again.

What a maintainer sees

  • The emulator and the scripts that model the player leave. About 1650 lines that no production path imported: the pitch and UI harnesses, the shifter measurement, the image-table model, the Ghidra scripts, and the resolver that fed them. They are kept with the emulator, which is not published. make payload replaces the emulator with a one-way payload directory that nothing here imports back.

  • A quarter of the hook never ran on a deck. The three largest emulator-only blocks move into their own headers, included at the point they used to sit and only under RX3_EMULATOR_BUILD. rx3_core_hook.c drops from 2981 lines to 2310. The two teardown paths, which each carried their own copy of the same twenty calls, become one function. Both libraries hash the same before and after every one of these changes, so nothing on a deck can tell the difference.

  • The test suite goes from 143 tests to 64, from 3807 lines to 2424, and from fifteen seconds to six. What stays fails when a deck would misbehave, when a stick or a track would be damaged, when the mod would load and silently do nothing, or when a commitment in LEGAL.md would break. What went was coverage: an estimator for a progress bar, a matrix of accelerator profiles restating a table the code reads, window theming, and interface closures replaying a dependency resolution pinned elsewhere.

  • Five documents and the app README fold into REFERENCES.md, which also gains the 146-entry ui::KeyInput::KeyCode table and Pioneer's bitmap font format. Every document carries its licence line, paragraphs are one line each, prose is keyboard characters only, and diagrams are mermaid.

Legal

LEGAL.md sets out what the project is for, what is not distributed, and on what basis. The update-container codec is removed from the code and from the prose, with one test asserting the symbols stay gone and another failing the build if the format is described again. tests/test_names.py fails the build on any tracked path or Python name that asserts where a file came from.

On #23, the last step of the report locates the decryption key inside the unpacked filesystem. That step is not included: LEGAL.md commits this project to not pointing anyone at material of that kind. The document stops at an unpacked filesystem, and states that a manufacturer-built archive stays on the machine that unpacked it.

Testing

make test (64 tests) and make preflight (202 files) pass.

Two things are not verified. Whether initramfs.tar.gz is present in a copy of the source package, and where: that section is written as a search whose outcome decides which of the two paths the reader takes. And the teardown factorisation changes the generated code, so the acceptance sequence in CONTRIBUTING.md applies to it before this ships. Every other change to the hook produces byte-identical libraries.

@Tratosca
Tratosca force-pushed the chore/scope-legal-and-docs branch from 1c240cb to a434817 Compare August 22, 2026 20:17
@Tratosca Tratosca changed the title Scope, legal position, and the documentation behind it Scope, legal position, and the documentation and tests behind it Aug 22, 2026
@Tratosca
Tratosca force-pushed the chore/scope-legal-and-docs branch 2 times, most recently from 1e9ac8e to 5d218fc Compare August 22, 2026 21:07
At -O2 clang rewrites `memcmp(a, b, n) == 0` into a call to bcmp, which rbp's
libc does not export. The hook then fails to load: no link error, no warning,
because the rewrite happens in the optimiser, after every diagnostic the front
end could have produced.

The symptom looked nothing like the cause. The emulator painted 17 730
non-black pixels -- exactly the stock figure -- which reads as a startup
failure rather than a mod that never loaded.

-fno-builtin-memcmp suppresses the rewrite. tests/test_hook_symbols.py reads
the .dynsym of both builds with its own small ELF parser, so no external tool
is needed, and fails on bcmp, on any import outside the set rbp is known to
export, and on the flag being dropped from the Makefile.

Second time an unresolved symbol has cost this project a long debugging round.
First time a test will catch it.
NS_FONT_ID_ISO8859_w.bin has no header and no offset table. It is a flat array
of 189-byte cells: 14x27 pixels at 4 bpp, high nibble first, coverage 0..15.
422 glyphs indexed by `codepoint - 0x20`, covering ASCII, Latin-1, Greek,
Cyrillic and the euro sign. The file is 42 bytes short of 422 full cells
because the last glyph's all-zero descender rows are not written.

The cell height was what earlier attempts missed: 210 leading zero bytes look
like a 30-row cell, but they are a 27-row space glyph followed by the first
three blank rows of `!`.

The typeface is Helvetica Neue LT W1G, named rather than guessed. rekordbox 7
declares font-family="HelveticaNeueLTW1G" in three of its own skin SVGs, and
W1G -- Linotype's Latin/Greek/Cyrillic glyph set -- is exactly the repertoire
of the firmware's font file. It is licensed and not shipped: scanning all 2144
files in the rekordbox bundle for genuine sfnt table directories finds four,
all Chromium's SpiderSymbol icon font.

The generator moves to Regular 22 from Light 24, fitted per glyph against
nineteen of Pioneer's own capitals segmented out of the BEAT FX captions in
imagedata.dat -- 29.3 mean absolute error against 61.3. The earlier fit matched
whole-word ink extents, a weaker signal because weight and size trade against
each other and still fit a box.

The .bin is a condensed cut and is NOT the caption face: 39x19 on FILTER
against the artwork's 76x16. It is what rbp draws live for browse lists, while
the captions beside the KEY/STEMS controls are pre-rendered artwork.

The 87 generated labels are committed because regenerating them needs
Helvetica Neue, which is macOS-only; the artwork is ours, not Pioneer's.
UiObjectManager::init() completes and startUp() runs. The blocker every other
limitation hung from was one wrong byte in the shim: common::GpioManager reads
/dev/gpiodrv, and GPIOs 0x7e and 0xcc are the USB over-current inputs, which
are active-low. Our fake node read 0 -- a permanent fault raised during
construction, from which init() never returned. Filling it with 1 is the whole
fix, and it matches what a running RX3 reports over telnet.

rbp now opens 13 devices instead of 8, including both subucom micros and the
touch panel: opens #62-64 of the reference trace captured on hardware.

The window is watchable. With Pillow the framebuffer is unpacked in C and
handed to Tk in memory, 3.5 ms a frame against 220 ms; the stdlib path stays
as the fallback so a clean clone gains no dependency. A measured correction
table keeps the two identical across all 65 536 RGB565 words.

A front panel underneath: the physical keys above the screen, the pad-mode
selectors and the eight pads per deck, injected through rbp's own dispatch
rather than a synthesised device. --duration 0 leaves a session open.

Browse keys now finish the way rbp does. BrowseUiIf::InputKey marks the record
with UiKey_KeyPush and posts an eventflag with set_flg; Ui_EventTask consumes
it and runs BrowseKeyProcessing inside the rest of the transaction, including
the KeyComplete/repaint that the mod's direct call was skipping. The hook posts
the flag, falls back to the pump when the flag id looks uncreated, and
--pump {0,1} forces either route. Whether this moves the screen is not yet
demonstrated; CHANGELOG records exactly what was and was not measured.

Also: 146 key codes and the LED table extracted statically to
docs/rx3-key-codes.md, and the emulator-only rbp patch lives outside
tools/rx3_patcher/ so it cannot reach a device by construction.
… codec

The toolkit authors one thing: the autoexec.bin image the player's own
maintenance path already looks for. Reading and writing the manufacturer's
update container was never on that path -- tools/rx3_runtime/build.py has only
ever used load_key, crypt, read_autoexec, write_autoexec and the ISO metadata
helpers -- so it goes.

Removed: build, split, cmd_encrypt, cmd_decrypt, cmd_verify, their argparse
subcommands, the MODEL and TRAILER constants, and the container description in
the module docstring. zlib went with them; struct and subprocess stay, both
still used by the ISO authoring path.

test_firmware_image.py asserts the symbols are gone rather than assuming it,
because a future change would most plausibly reintroduce them by copying an
older revision back in.
The emulator moves to its own repository. What stays here is the format it
consumes and nothing else: `make payload` assembles a directory holding a
manifest.toml, the preloaded hook under lib/, and the assets, which is all the
toolkit needs to know about how anything runs it.

Removed: tools/rx3_emulator/, tools/rx3_system_emulator/, docs/emulator.md,
their two test modules, and the emulator-image, emulator-hook, emulate,
emulate-system, emulate-system-fast and emulate-system-window targets. No
import, no path and no target reaches for either package now.

The second hook build keeps its flags and loses its name: librx3_core_emulator
becomes librx3_core_payload, since what makes it a variant is the payload it
ships in, not who runs it.
The eight scattered documents become one REFERENCES.md, minus the emulation
sections, which leave with the code. Every pointer into the old files is
retargeted -- the hook's key-code comment, the font note in build_labels.py,
both README tables.

Three passages said something other than what the work does:

- "Cloning, not styling" is now "Reusing the host's typeface at run time",
  which is the operation: a control wears the face of the model it is drawn
  from, resolved on the device, at run time. The body is unchanged.
- The README's setup step is "Building a root filesystem", because that is the
  task in front of the reader: building one from the GPL sources Pioneer
  publishes for this player. It no longer names the file that build leaves.
- extract-initramfs.md keeps its body -- it describes running a build script
  the GPLv2 obliges the manufacturer to provide -- and takes a title matching
  it.

CONTRIBUTING's file table no longer describes a container format nothing in
the tree can read. tests/test_docs_hygiene.py fails the build if that
description comes back: prose outlives code, and a specification for a format
whose codec was deleted is still a specification. The autoexec format stays
documented, and a test asserts that too, since it is what the toolkit builds.
… from

emulate_image_info_hook.py resolved its input from a hardcoded path whose every
component asserted a provenance -- an extraction, of a firmware, of a version.
A path is a place on a disk. It is not a provenance record, and it should not
read as one.

tools/rx3_artifacts.py resolves a role instead: the role's environment
variable, then the [artifacts] table of a gitignored artifacts.toml, then
local/artifacts/<profile>/<role>. The module has nowhere to write an origin and
does not ask for one.

A missing file names the role, says what that file has to be, and points at
docs/artifacts.md. It does not say where to obtain one -- that is outside what
this project does, and a test pins the role vocabulary against the words that
would put it back.
Interoperability and study of a device its owner has bought, under directive
2009/24 art. 5(3) and 6 and art. L.122-6-1 CPI; no key, image, manufacturer
binary or licensed typeface distributed, here or in the history; the mechanism
used is the manufacturer's own maintenance path, which guards a service route
rather than a work, and so falls outside L.331-5 CPI; the modification is made
in RAM on the owner's device and is undone by removing the medium.

Also a contact address and an undertaking to look at any complaint on its
merits, whether or not it arrives as a formal notice.
… out

The root-password paragraph now carries the date of the finding, 10 August
2026, and says what has been done with it: not reported to the manufacturer, no
report planned. Left to inference it reads as an omission; written down it is
just the state of things. The hash and the plaintext stay unpublished.

The Unreleased section held roughly 290 lines of emulator engineering notes for
a tool that is no longer in this repository. They never appeared in a tagged
release, so nothing published points at them, and they leave with the code --
the extracted text goes to rx3-emulator's changelog. Two entries were split
instead of moved, because the hook they also describe stays here: the
performance-row geometry test, and the browse-key eventflag route.

What remains is toolkit work, with the three pointers into deleted documents
retargeted at REFERENCES.md, plus entries for this cleanup: the codec removal,
role-addressed artifacts, and the emulator's departure. The known-issue about
the palette now says plainly what the prepared tab bitmaps are still doing in
the tree and what would retire them.
…ange it

The published source package ships the built initramfs.tar.gz beside the
sources it came from, so obtaining the filesystem is archive handling that
macOS, Linux and Windows all do natively. make_rootfs, and with it WSL2, moves
to its own section and is presented for what it is: the path for changing what
goes into the filesystem, or for a source tree that does not carry the archive.

The document still stops at an unpacked filesystem. It does not identify what
inside it the app is later pointed at, and it states that an archive built by
the manufacturer stays on the machine that unpacked it — unpacking it for a
device you own is not the act of passing it on.

Reported in #23.
@Tratosca
Tratosca force-pushed the chore/scope-legal-and-docs branch from 5d218fc to 6f25c23 Compare August 22, 2026 21:09
@Tratosca
Tratosca marked this pull request as ready for review August 22, 2026 21:25
@Tratosca
Tratosca merged commit 3ca5923 into main Aug 22, 2026
14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant