ThePirateRay/docs/adr/0002-reuse-rayforge-and-balormk.md

136 lines
7.1 KiB
Markdown

# ADR 0002: Prove reuse of Rayforge and BalorMK before building an app
- Status: Accepted
- Date: 2026-10-17
- Accepted: 2026-10-24
## Context
The initial roadmap assumed that The Pirate Ray would define its own offline
application core and would later research the JCZ protocol. Ecosystem research
found two MIT-licensed projects that substantially change that assumption:
- Rayforge already implements most of the desired cross-platform desktop
product and has an addon/driver architecture, LightBurn import, simulation,
material recipes, pre-flight validation, and MOPA-relevant operation fields.
- MeerK40t's BalorMK already implements the EZCAD2-compatible JCZ controller
protocol, MOPA pulse width, a mock connection, and the exact USB VID/PID
independently observed in our installer evidence.
Creating another editor, geometry stack and controller implementation would
duplicate large, safety-relevant bodies of work and permanently increase the
maintenance burden.
## Decision
Do not begin independent desktop product implementation. First run three
offline, version-pinned proofs:
1. evaluate stock MeerK40t with BalorMK's mock controller as the shortest
route to a usable product;
2. prove that an external Rayforge addon can register a binary no-device
driver and survive packaging on Windows;
3. translate one synthetic Rayforge operation stream to JCZ/Balor commands and
compare it with a BalorMK mock trace.
The proofs pass at the offline architecture boundary. Build the product as a
Rayforge JCZ addon and retain pinned BalorMK behavior as the controller-level
oracle. Adapt only the narrowest necessary implementation after licensing and
attribution allow it. Packaged Windows interaction remains an M1 release gate,
not a reason to defer the host-architecture decision.
An independent desktop application requires a later ADR showing concrete,
tested gaps in both existing applications.
No copied upstream source enters this repository until the project license is
chosen and exact commit-level copyright/license attribution is recorded.
## Proof obligations
- All experiments are mock/no-I/O and cannot enumerate or open USB devices.
- Frequency and pulse-width units and defaults survive end-to-end.
- Galvo coordinates, correction, timing, list buffering, framing, cancel and
status semantics fit the host abstraction or their required extensions are
explicit.
- The adapter emits deterministic traces suitable for golden tests.
- Hardware transport is optional, disabled by default, and separated from
encoding.
- Machine/source/lens/profile mismatch fails closed.
- Windows driver switching is excluded from automatic setup.
- Upstream contribution feasibility and API stability are assessed before a
permanent fork is accepted.
## Consequences if accepted
- The project becomes an integration, validation and safety effort rather
than a general CAD application effort.
- M1 is shortened to ecosystem validation and a JCZ vertical slice.
- Protocol capture is a fallback used only for unresolved behavior, not the
first discovery method.
- The eventual public repository may primarily contain an addon, machine
profiles, tests, fixtures and documentation.
- Project license selection becomes a prerequisite for adapted code. MIT is
the simplest compatibility candidate, but this ADR does not select it.
## Rejection criteria
Reject the proposed Rayforge route if the addon seam cannot support a binary
galvo driver without maintaining invasive core changes, or if the operation
model loses required galvo/MOPA semantics. Reject the stock MeerK40t route if
the tested application cannot provide a safe and maintainable workshop
workflow. Record evidence before choosing a standalone app.
## Research basis
See [Open-source landscape](../research/open-source-landscape.md) for the
candidate matrix, inspected commits, risks and detailed spike plan.
Subsequent offline evidence:
- [MeerK40t mock MOPA spike](../research/meerk40t-mock-mopa-spike.md):
deterministic controller-level frequency, pulse-width and square encoding;
- [MeerK40t hatch cut-plan and mock-spooler spike](../research/meerk40t-hatch-cutplan-spike.md):
stock planning and spooling preserve a synthetic hatch and MOPA settings on
forced mock transport;
- [Rayforge addon spike](../research/rayforge-addon-spike.md): external binary
driver load and lifecycle are viable, with a documented registry API gap.
- [Rayforge-to-JCZ equivalence spike](../research/rayforge-jcz-equivalence-spike.md):
the required MOPA and geometry semantics survive a real Rayforge `Ops`
stream and match the pinned BalorMK mock trace.
- [JCZ negative cases](../research/rayforge-jcz-negative-cases.md): the encoder
boundary rejects profile mismatch, invalid values, out-of-field geometry and
unsupported commands without a transport.
- [JCZ 12-byte record spike](../research/rayforge-jcz-packet-spike.md): the
external encoder deterministically packs controller-shaped command records
matching the pinned BalorMK mock values, while retaining no transport.
- [Synthetic LightBurn MOPA import spike](../research/rayforge-lightburn-mopa-import-spike.md):
geometry and common settings survive, but frequency is not mapped to the
workflow and pulse-width representation still lacks fixture evidence.
- [Graphical workflow model spike](../research/rayforge-graphical-workflow-spike.md):
Rayforge's generated settings contract exposes frequency and pulse width,
preserves them through step serialization and supplies preview Ops without
transport; packaged GTK interaction remains untested.
- [LightBurn-to-Rayforge UX capability map](../research/lightburn-rayforge-ux-capability-map.md):
the casual-maker workflow maps mostly to existing Rayforge product seams;
the remaining UX gaps are narrow, testable extensions rather than evidence
for a separate desktop application.
- [Rayforge layer visibility and output spike](../research/rayforge-layer-model-spike.md):
canvas visibility and job participation are already independent serialized
states; LightBurn-style layer Output is a narrow aggregate UI concern, not a
new pipeline or document-model requirement.
- [M1 no-device acceptance checkpoint](../research/m1-no-device-acceptance.md):
the public regression suite and leak guard now form one transport-free gate
over addon lifecycle, workflow, layers, recipes, encoding, negative cases,
cancellation/recovery and synthetic imports. Packaged Windows interaction
remains a release gate.
- [Upstream contract and license audit](../research/upstream-contract-and-license-audit.md):
both pins and license notices are now machine-verifiable; the documented
addon lifecycle is usable, but driver registration and cleanup still rely
on an internal registry seam that should be replaced upstream.
Three operator-verified private projects subsequently established the
project-level `frequency` and `QPulseWidth` serialization needed to implement
the disabled-output import seam. Together, the evidence satisfies the host
architecture decision. It does not authorize hardware access or claim that the
packaged Windows interaction and import-promotion release gates have passed.