bitspire/docs/adr/001-hal-architecture.md
Padreug 53b0d382e8 docs: finish the LNbits-era doc sweep across docs/ + .claude/skills/
Second + final batch of the doc refresh. README + CLAUDE went out in
8c9ae29; deploy/nixos/README + obsolete-flow flags in 924844f. This
commit covers everything left.

docs/machine-installation.md
  Was describing a manual AppImage scp deploy + a `lamassu-kiosk`
  systemd unit that hasn't been the deployment path for months.
  Replaced with a high-level "what the pipeline does and why"
  overview that points at deploy/nixos/README.md for the full
  command-by-command walkthrough. Includes the BATM3 chassis-mod
  note (custom Dell OptiPlex retrofit, not a stock Dell).

docs/architecture-comparison.md
  Rewrote the comparison to be lamassu-server (≤ v8.1.5) vs bitSpire
  (LNbits-backed) instead of the original lamassu-server vs LP-backed
  lamassu-next framing. Updated the cash-out + cash-in flow diagrams
  to show the actual nostr-transport path (LNbits-bundled nostrrelay
  extension at ws://<host>:5001/nostrrelay/test, no separate strfry
  container). Replaced the migration-path section with a softer
  "when to choose what" framing that includes Lamassu's current
  commercial offering as a legitimate third option. Added a header
  pointer to the Acknowledgements section.

docs/business-model.md
  Light touch-ups: Lightning.Pub → LNbits where it appeared, swapped
  the [[ndebit-cash-in-flow]] link for [[architecture-comparison]],
  noted the kind-30078 service beacon for availability broadcasts.

docs/device-configuration.md
  Dropped "Lamassu" branding from the machine-model headings
  (Sintra / tejo / douro / batm3 are referenced by hardware identity
  here, not by Lamassu's product line). Added the Sintra-specific
  ttyS4-vs-placeholder-ttyS1..3 gotcha we hard-learned during the
  first flash. Corrected the BATM3 entry: stock GeneralBytes chassis
  with a Dell OptiPlex 9030 AIO motherboard physically grafted in,
  NOT a Dell out of the box. Updated the example /dev/ttyJ* symlink
  output to match what a healthy Sintra actually shows.

docs/adr/001-hal-architecture.md
  ADRs are historical artifacts — kept the original decision text
  intact. Added a postscript noting:
    - The package rename @lamassu/hal → @bitSpire/hal
    - The v8.1.5 boundary on any lamassu-machine source-tree
      references (Lamassu's 2024-01-26 license transition)
    - That the "Remaining Work" list is complete and the first
      successful Sintra hardware integration ran on 2026-05-13

.claude/skills/lightning-check.md
  Rewrote end-to-end. Was Lightning.Pub-flavoured with CLINK kinds
  21001/21002 as the primary flows; now validates the LNbits nostr-
  transport surface (kind-21000 envelope, NIP-44 v2 encryption,
  subscribe_payments filter discipline, lnurlw link composition).
  Preserved a --clink mode for the still-live kind-21003 operator-
  management surface. Includes a "what to check" rubric for cash-out
  vs cash-in flows that mirrors the actual code in
  apps/machine/src/services/lightning.ts.

.claude/skills/hal-check.md
  Two pivots: (1) acknowledge ADR-001's TypeScript-not-Rust choice
  and reframe all the safety checklists in TS-flavour (type safety,
  discriminated unions, single-writer serial, bounded emitters)
  instead of Rust-flavour (unsafe, borrow checker). (2) Add explicit
  v8.1.5 provenance boundary plus a "forbidden operations" section
  that prohibits diffing or porting from v8.1.6+ lamassu-machine
  source. Updated the port-validation source-reference table to
  list TS file paths under packages/hal/ instead of Rust paths.

.claude/skills/docs.md
  @lamassu/* → @bitSpire/*. Replaced the Lightning.Pub mermaid
  diagram with a current cash-out flow showing the nostr-transport
  RPC + subscribe_payments push path. Left the createOffer noffer
  example in the API-docs template section since it's illustrative
  ("here's what a good TSDoc block looks like") rather than current
  reference documentation.

.claude/skills/test.md
  One-line: @lamassu/nostr-client → @bitSpire/nostr-client in the
  pnpm-filter example.

deploy/nixos/README.md
  Single touch-up: clarified the douro/batm3 hardware-module comments
  to reflect that BATM3 is a custom-installed Dell board in a
  GeneralBytes BATM3 chassis (not a Dell OEM).

Files NOT touched in this sweep (intentionally):
  - packages/hal/src/**/*.ts attribution comments — those reference
    "lamassu-machine" in their port-source headers. Those are
    factually accurate (the drivers ARE ported from there, up to
    v8.1.5) and constitute necessary license/attribution metadata.
    Editing them would erase the provenance trail.
  - .claude/skills/{nostr-check,security}.md — already protocol-
    neutral, no LP/lamassu references to clean up.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-01 19:08:03 +02:00

157 lines
6 KiB
Markdown

# ADR-001: Hardware Abstraction Layer Architecture
**Status:** Accepted
**Date:** 2026-01-26
**Context:** Lamassu Next ATM proof of concept
## Decision
We will use **TypeScript HAL drivers extracted from lamassu-machine** rather than rewriting in Rust, and use **Electron instead of Tauri** for the kiosk application.
## Context
The Lamassu Next project needs to control ATM hardware (bill validators, dispensers) on Lamassu Sintra machines. Initial plans considered:
1. Rust HAL with Tauri backend
2. TypeScript HAL with Tauri (IPC bridge)
3. TypeScript HAL with Electron (direct integration)
### Hardware Target: Lamassu Sintra
- **Platform:** Aaeon UP Board (Intel Atom x5-Z8350, x86 Linux)
- **Bill Validator:** JCM iVIZION using ID003 protocol
- **Bill Dispenser:** Fujitsu F53/F56
- **Serial:** `/dev/ttyJ5` (validator), `/dev/ttyJ7` (dispenser)
- **Protocol:** RS-232, 9600 baud, 8 data bits, even parity, 1 stop bit
## Options Considered
### Option 1: Rust HAL + Tauri
**Pros:**
- Native Tauri integration
- Memory safety guarantees
- Single backend language
**Cons:**
- Requires full protocol reimplementation
- Two debugging environments (Rust + TypeScript)
- Serial at 9600 baud doesn't benefit from Rust performance
- Significant time investment with uncertain payoff
### Option 2: TypeScript HAL + Tauri
**Pros:**
- Reuse battle-tested lamassu-machine drivers
- TypeScript throughout application code
**Cons:**
- IPC boundary between Tauri (Rust) and HAL (Node.js)
- Serialization overhead and complexity
- Two processes to manage and debug
### Option 3: TypeScript HAL + Electron (Selected)
**Pros:**
- Direct `serialport` npm access in main process
- Single debugging environment (Chrome DevTools)
- All packages run natively (state-machine, HAL, lightning, clink)
- Mature ecosystem, well-documented edge cases
- Fastest path to working proof of concept
**Cons:**
- Larger binary size (~150MB vs ~10MB)
- Higher memory usage than Tauri
- Bundles Chromium
## Decision Rationale
### Why not Rust?
The JavaScript drivers in lamassu-machine have run in production for years. The complexity is in the protocol state machines (ID003 FSM, F56 DLE/STX framing), not raw performance. Serial communication at 9600 baud is trivial - Rust's performance benefits are irrelevant here.
Adding Rust creates a language boundary that requires:
- IPC serialization/deserialization
- Two build systems
- Two debugging environments
- Potential for bugs at the boundary
For a proof of concept, minimizing unknowns is critical.
### Why Electron over Tauri?
Tauri's benefits (small binary, low RAM) optimize for end-user desktop apps where download size matters. An ATM is a single-purpose kiosk:
- Binary size irrelevant - installed once on dedicated hardware
- RAM sufficient - Sintra has 2-4GB, not competing with other apps
- Development speed critical - proof of concept needs fast iteration
Electron allows the Vue UI, state machine, HAL, and Lightning packages to all run in the same Node.js environment with unified debugging.
## Implementation Status
### Completed
- `@lamassu/hal` package created with:
- ID003 bill validator driver (JCM iVIZION)
- F56 bill dispenser driver (Fujitsu F53/F56)
- TypeScript types for all interfaces
- Extracted from lamassu-machine, fully typed
### Remaining Work
1. Convert `apps/machine` from Tauri to Electron
2. Wire HAL to state machine services:
- `dispenseCash` → F56Dispenser.dispense()
- Bill events → state machine events
3. Add device configuration (serial port paths)
4. Test on physical Sintra hardware
## Consequences
### Positive
- Faster proof of concept development
- Easier debugging during hardware integration
- Reuse of proven driver code
- Single language throughout
### Negative
- Larger deployment size (acceptable for kiosk)
- Cannot leverage Rust safety guarantees (mitigated by mature JS drivers)
### Future Considerations
If a compelling reason for Rust emerges (it likely won't), the HAL interface is abstracted - drivers could be reimplemented without changing the state machine integration. The Vue UI works with either Electron or Tauri.
## References
- `packages/hal/` — TypeScript HAL implementation
- `packages/state-machine/src/types.ts` — ATMServices interface
- `deploy/nixos/hardware/upboard.nix` — Sintra device paths and udev rules
- lamassu-machine `lib/id003/`, `lib/f56/` — Original JS drivers (v8.1.5 release line and earlier; see postscript below)
---
## Postscript (2026-05-13)
This ADR is still in effect — TypeScript HAL in Electron remains the right call for the same reasons documented above. A few clarifications for readers in 2026 and beyond:
1. **Package naming.** The HAL package was originally `@lamassu/hal` (per the line above in "Completed"). It was renamed to `@bitSpire/hal` during the project rename from `lamassu-next` to `bitSpire` (commit `924844f` in the 2a sweep). All references to the package scope should now read `@bitSpire/hal`.
2. **Source-tree provenance, post-Lamassu license change.** The "Original JS drivers" reference above refers to lamassu-machine's `lib/id003/` and `lib/f56/` directories in the **v8.1.5 release line and earlier**, which were published under a fully-open license. Lamassu Industries AG transitioned to a proprietary source-available license on 2024-01-26 (v8.1.6+). bitSpire incorporates no code from v8.1.6 or later; the protocol-level reimplementations we have are derived from v8.1.5 + protocol specs published by JCM, Fujitsu, etc. See [CLAUDE.md → Provenance + legal status](../../CLAUDE.md#provenance--legal-status) for the operating rules going forward.
3. **Implementation status.** The "Remaining Work" list above is complete:
- `apps/machine` runs on Electron (the original Tauri scaffolding was removed early on)
- HAL is wired to the state machine via the ATMServices interface
- Device configuration ships via `deploy/nixos/hardware/upboard.nix` + the `services.bitspire` NixOS module
- First successful Sintra hardware integration test ran on 2026-05-13 (cash-out flow verified end-to-end against a regtest LNbits instance)