Changes since (repo start):
- Initial commit
- Implement SL Link protocol layer for the SL88 MK2
- Record hardware verification status in CLAUDE.md
- Phase 0: establish how MainStage device-script integration works
- Add MainStage device script and installer (Phase 1)
- Add MainStage virtual endpoint and bridge codec (Phase 2)
- Fix patch-selection encoding: MSB=set, LSB=patch, channel 16
- Fix MainStage process detection: bundle id is com.apple.mainstage3
- Spike: virtual MIDI device registration for the MainStage bridge (blocked)
- Record device-script route as blocked, correct Phase 0 overstatement
- docs: Phase 0 v2 spike — outport cannot deliver from a USB-ID-matched script
- Record MainStage bridge status and resume points
- Re-test io.open in the MainStage device script, fix wrong install path
- Match MainStage script to the real SL88, switch bridge transport to files
- Add scoped sandbox entitlement so the app can read the MainStage bridge files
- File-poll bridge + SL88 screen paint work end to end; io.open confirmed dead in MainStage
- Rule out matching method as the outbound-MIDI blocker; switch to generic matching
- Retest CTRL patiently: same result, ruling out loading-noise as the cause
- Complete the outport sweep: DAW, LINK, and SL all reproduce CTRL's dead end
- Exhaust outport sweep against a real working reference; fix stale file header
- Reframe doc language: not found yet, not exhausted/dead
- Correct the outbound test method: rounds 4-10 were unobserved, not negative
- SOLVED: outbound MIDI from the script works — outport needs the SHORT port name
- Lua-only SL Link session: identifies, stays alive, draws patch name on the SL88
- Find the real display constraint: a byte-length ceiling, not a message limit
- Multi-line SL88 display working: don't send Clear Screen
- Add plan for full SL88 <-> MainStage functionality (draft for revision)
- Plan: answer Q1 and Q4 from the references, add button suggestions
- Plan: encoders 1-4 also show a value pop-up; make it one shared component
- Plan: long-press resets to 0 dB on channel encoders and B
- Plan: B short-press mutes the main fader; clarify 0 dB means default position
- Plan: Zone Select buttons decided as solo for channels 1-4
- Plan: record what the encoder "rings" can actually do
- Plan: fix the Phase 5 ring section that failed to apply
- Plan: Zoom button toggles list vs single-patch display mode
- Plan: port the proven Swift encoder handling rather than re-deriving it
- Add test-mainstage-script and lua-harness skills
- Add a reusable guide to implementing SL Link from spec
- Add a reusable guide to writing MainStage Lua device scripts
- Document the Launchkey MK3 findings as a case study
- Add working-efficiently notes to CLAUDE.md; fix stale entitlements claim
- Add model-routing guidance to both skills
- Shrink what a session loads: archive the log, trim config.lua header, point CLAUDE.md at the guides
- Route open-ended exploration to subagents
- Pace display messages; add single-patch screen
- Diagnose session drop: re-init collides with its own stale registration
- Retry same instance ID before bumping; widen big-font wrap to 20
- Record: self-heal repaint never fires while app is off screen
- Single-line zoom screen; pad text to clear stale tails
- Prove the SL88 ignores draws from a de-selected app
- Stop incoming notes starving the session clock
- Widen patch name limit to 25 chars
- Widen patch name limit to 27 chars
- Widen set name limit to 36 chars
- Clear name lines with an erase rect instead of space padding
- Continuous patch list, NEXT line, Zoom button
- Record what is deployed but unverified on hardware
- Cut display latency and stop repaints starving the keepalive
- Fix patch-change latency and mode-switch remnants on hardware
- Merge pull request #1 from jeroenvv/feature/mainstage-bridge
- Add install and usage instructions to the README
- Merge pull request #2 from jeroenvv/docs/readme-install
- Spike Q1a: inbound substitution reaches MainStage, addressing does not
- Close Q1a: patchselector is unreachable from a device script
- Every SL88 control emits a mappable CC
- Merge pull request #3 from jeroenvv/feature/phase2-navigation
- Confirm CC mapping holds under a fast encoder sweep
- Add full-screen encoder value popup
- Merge pull request #4 from jeroenvv/feature/encoder-value-popup
- Add a checked-in offline harness for config.lua
- Delete six dead symbols from config.lua
- Correct false comments in config.lua
- Move config.lua's history into docs, keep its constraints
- Record the refactor's hardware verification
- Normalise config.lua formatting
- Merge pull request #5 from jeroenvv/feature/lua-maintainability
- Correct the "two script instances" claim
- Document the Lua suite and the built-in bitmap library
- Merge pull request #6 from jeroenvv/fix/single-instance-finding
- Add Plot Bitmap support and a Knob icon probe
- Record the Knob bitmap hardware verification
- Draw the popup dial with the native Knob bitmap
- Lower MODE_SWITCH_SETTLE_TICKS from 3 to 1
- Confirm the lower settle on hardware
- Merge pull request #7 from jeroenvv/feature/knob-bitmap
- Lower FLUSH_SOON_MS from 50 to 35
- Confirm 35 on hardware and lower FLUSH_SOON_MS to 25
- Back out 25 and settle the sweep at 35
- Centre the zoom screen with the device, not an estimate
- Confirm the zoom centring fix on hardware
- Merge pull request #8 from jeroenvv/perf/flush-soon-sweep
- Remove the Swift app; main is the device script only
- Reframe the docs for a script-only repo
- Add semantic versioning at 1.0.0
- chore: add the release pipeline and version automation
- docs: refresh the status doc after the sweep and centring work
- Merge pull request #9 from jeroenvv/chore/script-only-repo