Skip to content

Release 2026-10-06: Arena Console v11, Pattern Icon Generator v1.5, Pattern Designer v0.13, Arena Studio v0.95 - #247

Merged
mbreiser merged 21 commits into
mainfrom
release/2026-10-06
Oct 18, 2026
Merged

mbreiser merged 21 commits into
mainfrom
release/2026-10-06

Conversation

@mbreiser

@mbreiser mbreiser commented Oct 6, 2026 •

Copy link
Copy Markdown
Contributor

Release candidate 2026-10-06 rc5 · candidate commit a4a2a9c829 · built on main 7c68dfcee8

Live on Next: https://reiserlab.github.io/webDisplayTools/next/

Tool Version
Arena Console v10 → v11
Pattern Icon Generator v1.4 → v1.5
Pattern Designer v0.12 → v0.13
Arena Studio v0.94 → v0.95
PR Title Head CI Release notes
#245 fix(studio): ISP time estimate ~5 s/panel, not ~20 s (#244) 5b0b30dcce green Arena Studio
#246 Pattern Designer + Studio: partial-arena °/px and 3D/2D mapping, unmirrored icons, short SD-safe filenames, upload name checks (LAB-295) 84daa996a1 green Pattern Designer, Arena Studio
#248 Studio: first command after Connect no longer waits ~60 s behind the thumbnail download (LAB-298) 546d9c6256 green Arena Studio, Arena Console
#250 Studio: Console → Qwiic peripherals, rig peripherals:, live Console sliders, firmware-sized test display + color banks (LAB-214) 6bbd8d1b36 pending Arena Studio, Pattern Designer

Promotion checklist

  • CI green on this PR and on every constituent PR (pixi run release checks)
  • Validated on a rig between sessions — comment Validated a4a2a9c … (pixi run tiers -- validate --rig … --by …). Any change to a constituent PR = rebuild (rc+1) = validate again.
  • Release window: Slack heads-up posted; nobody is mid-experiment (release lists recent rig runs — advisory)
  • After merge: rigs hard-refresh between sessions; if fictrac-bridge/ changed, rig PCs git pull + restart the bridge

Promote with pixi run release (merges with a merge commit — never squash — and tags release-2026-10-06). Manifest: releases/2026-10-06.json.

🤖 Generated with Claude Code release tooling (scripts/tiers/candidate.py)

mbreiser and others added 8 commits October 2, 2026 14:57
The Program set confirm said ~8 min for a 20-panel arena; the batch on
rig5-mr (2026-09-30) took ~2 min: ~4.4 s program + reboot and ~1 s
verify + STOP per panel. Use 5 s + 1 s for the estimate and fix the
"~20 s" in the dialog and the Flash / Program set tooltips.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ial arenas

getDegreesPerPixel() divided 360 deg by the INSTALLED pixel columns instead of the
full circumference. On G4 3x12of18 (the IAS talk arena) that gave 1.875 deg/px
instead of 1.25, so the px<->deg helper labels were wrong and a spatial period typed
in pixels generated the wrong grating (24 px came out as 45 deg, 36 frames). A step
size typed in degrees was off the same way. G6 3x12of18 (1.5 -> 1.0 deg/px) and
G6 2x8of10 (2.25 -> 1.8) had the same bug; full arenas were already right.

The generator already used the full circle (arenaCoordinates numCircle = num_cols).
The pitch now lives in one shared place, PatternGenerator.getDegreesPerPixel(), and
getArenaDimensions() reports circleCols / azimuthPixels, which the three spherical
generators also read, so the editor and generator cannot drift apart again.
Also fixes the Animate tab's frame-shift hint on partial arenas ("360 deg = 192 px"
-> "240 deg = 192 px"), and cache-busts generator.js because the editor's init now
calls the new helper.

tests/test-pattern-degrees-per-pixel.js runs the editor's own conversion functions
(extracted from pattern_editor.html) for every standard config, plus end-to-end
gratings typed in px and deg; it failed 15 checks before the fix.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…olumn

A partial arena's PAT stores only the installed columns, in columns_installed order
(block k = physical column columns_installed[k], the icon generator's convention).
ThreeViewer looked pixels up by the PHYSICAL column instead. Harmless when the
installed columns start at 0 (G4/G6 3x12of18), but on G6 2x8of10 (columns 1-8)
the whole pattern showed one panel to the side, pattern panel 1 never appeared, and
physical column 8 read block 0 of the next pixel row (the lookup wrapped at the full
circle, past the 160-px pattern width).

_getPatternColumnMap() maps physical column -> block from the CONFIGURED columns
(never the preview-visible set, so the CSHL 8/18 gap still doesn't shift the address
map); each LED ref carries patternCol; the lookup wraps inside the pattern width.
Shared by the Pattern Designer and the replay viewer, so the cache token moves to
1006-partial-cols in both (and the tests that pin it).

tests/test-three-viewer-partial-columns.js loads the viewer with Three.js stubbed and
checks every LED of every standard config reads its own block and row; against main's
viewer it fails only on G6_2x8of10 (column 1 showed block 2).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
renderCylindricalIconToCanvas drew math angles (y up) straight onto the canvas (y down),
so every icon was the 3D "Top Down" view mirrored: the gap (behind the fly) at the TOP and
the columns running counter-clockwise. TESTING.md always expected the gap at the bottom.
Angles are now negated at the drawing step (toCanvas), so icons match the 3D viewer and
MATLAB design_arena: south at the bottom, column 0 at the south boundary, columns clockwise
from above. The misleading "row 0 = top of arena" comment is corrected (row 0 is the
bottom; it maps to the inner ring, as in a perspective view from above).

Shared by the Studio, Console and Pattern Designer thumbnails. No export changes.
tests/test-icon-orientation.js records the canvas arcs and checks column 1 and 2 of every
standard config against the 3D viewer's placement; the old code failed 21 of 27 checks
(G6 2x10 column 1 drawn at -18 deg instead of -162 deg).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…zimuth axis

Panel numbers: the 2D overlay labelled pattern blocks as if they were physical columns and
looped over every num_cols (drawing labels past the right edge on partial arenas). It now
labels each block with its physical panel through physicalPanelNumber() (block k =
columns_installed[k], G6 row-major / older generations column-major), the same numbers as
the 3D overlay: on G6 2x8of10 the first pattern panel reads 2/12, not 1/11.

Azimuth axis: a degree scale under the 2D grid (its own canvas, so edit-mode hit-testing
and captures are unchanged), in pattern coordinates: 0 deg = straight ahead at the middle,
negative to the fly's left; same values as the Mollweide view and the generator. Ticks
pick 15/30/45/60/90 deg to keep labels apart (G4 3x12of18: -120..+120 every 30 deg).

CLAUDE.md gains the three partial-arena rules (full-circle pitch, block k =
columns_installed[k], 0 deg = middle of the pattern) and points at LAB-296 for hardware.
tests/test-pattern-2d-view.js runs the extracted helpers against every standard config,
the 3D overlay's numbering and the Mollweide longitudes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…F color code

Color variants of one grating used to share a name (the filename carried only the layout
tag), and re-saves stacked tags (_4c_rir). Names now:
- record the ON/OFF choice used to GENERATE the frames, stamped at generate time:
  PanelColor.filenameColorCode -> '_4c-B' (ON blue), '_4c-B-G' (ON blue, OFF green),
  '_4c-VB', '_4c-F80A' (custom levels, one hex digit per channel); nothing extra for the
  default (ON all / OFF dark), so default names are unchanged apart from the words below;
- normalize the layout tag on save (PanelColor.stripColorTag): replaced, never stacked;
- use short words: grat/star/edge/sine/offon/anim, rot/exp/trans, Ndot, _img, comb,
  hcw/hccw/vup/vdown.

The controller keeps pattern names in a 64-byte buffer: <= 63 characters, plain ASCII,
and <= 58 so a same-name re-upload (stored as X001_<name>) keeps its .pat. Nothing in the
Designer checked this. js/pattern-set.js gains the shared rule (checkSdFilename,
sanitizeSdFilename, fitSdFilename; both tools load it), and the Designer fits every saved
and renamed name (fitPatternFilename: cleans characters, shortens only the descriptive
middle, keeps the arena prefix and the color tag; the rename prompt says what it changed).
The longest name Generate can produce is now 54 characters with the worst-case tag.

Helpers are typeof-guarded, so a stale cached panel-color.js / pattern-set.js only means
the old naming until a refresh.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ads, 0x85 label

- sdUploadOne runs PatternSet.checkSdFilename BEFORE sending the bytes: a name the
  controller can't store (non-ASCII, > 63 chars, no .pat) fails at once instead of after
  the whole upload (which left the data on the card as pattern.temp), and is not retried.
  59-63 characters log a warning (a re-upload would lose .pat).
- An upload never overwrites: the firmware stores a same-name re-upload as X001_<name>.
  sdLogicalName now strips that prefix, so the copy shows as a DUPLICATE of the original
  (onSdListing warns; protocols refuse to guess) instead of a separate pattern while the
  picker kept playing the old file. The upload also warns up front when the name is
  already on the card.
- The upload opcode is SET_PATTERN_FILE 0x85; the Studio's error text ("write rejected"),
  tooltips and comments said 0x8D, which the firmware doesn't have (also fixed in the
  Console comment and CLAUDE.md's quiesce list).

CLAUDE.md records the filename rule. tests/test-sd-filenames.js covers the shared rule,
the Designer's names (every arena prefix + worst-case tag <= 58), withColorTag /
fitPatternFilename, sdLogicalName and the upload order.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…l-G6 warning

From the adversarial review of candidate 2026-10-06 rc1 (Claude + Codex):
- The shared SD name rule (PatternSet.checkSdFilename) refused anything outside
  [A-Za-z0-9._-], so the Studio blocked uploads that worked before: spaces and
  parentheses are legal FAT long-name characters (e.g. a browser's "… (1).pat").
  It now errors only on what the card can't store (non-printable/non-ASCII, \ / : * ? " < > |,
  > 63 chars, no .pat, leading "."); the Designer still writes tidy names
  (SD_TIDY_CHARS) and says so when it changes one.
- Cache tokens (?v=1006-partial-cols) on every consumer of the changed shared modules:
  icon-generator.js (Designer, Studio, Console, v3 designer, icon tool), pattern-set.js
  (Designer, Studio, Console, v3 designer), panel-color.js (Designer) — so the fixes reach
  browsers holding an old copy. Pinned in tests.
- Partial-G6 warning (never blocks): current firmware ignores the panel mask and rejects
  any grid other than its own at load. The Designer says so once per session when a
  partial-G6 pattern is saved; the Studio upload warns when the session rig is a partial
  arena, when a file carries a partial panel mask, or when its grid differs from the rig's
  (PatternSet.g6HeaderGrid / g6PlaybackWarning; Studio.rigArena()).
- 2D panel numbers: a block past the installed list labels its own number, never NaN.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@mbreiser
mbreiser force-pushed the release/2026-10-06 branch from 0e4c49b to 123a1d2 Compare October 6, 2026 22:54
@mbreiser mbreiser changed the title Release 2026-10-06: Arena Console v11, Pattern Designer v0.13, Arena Studio v0.95 Release 2026-10-06: Arena Console v11, Pattern Icon Generator v1.5, Pattern Designer v0.13, Arena Studio v0.95 Oct 6, 2026
@mbreiser

mbreiser commented Oct 6, 2026

Copy link
Copy Markdown
Contributor Author

Adversarial review of candidate 2026-10-06 rc1. Reviewers: Claude (independent), Codex GPT-5.5 standard and Codex GPT-5.5 adversarial.

No blockers. No reviewer found a correctness problem in the partial-arena geometry or a regression on full arenas.

Fixed in rc2 (#246 at 84daa99, candidate 123a1d24a9):

  • The SD name rule now matches the card. rc1 refused anything outside [A-Za-z0-9._-], which blocked uploads that used to work. Spaces and parentheses (e.g. a browser's … (1).pat) upload again. The rule still refuses non-ASCII, \ / : * ? " < > |, names over 63 characters, a missing .pat and a leading ..
  • Cache tokens on every consumer of the changed shared modules: icon-generator.js, pattern-set.js and panel-color.js, pinned in tests. Without them, a browser holding an old copy would silently keep the old behavior.
  • Partial-G6 warning, never blocking. The Designer warns once per session when a partial-G6 pattern is saved. The Studio upload warns when the rig is a partial arena, when a file carries a partial panel mask, or when the file's grid differs from the rig's.
  • 2D panel numbers never show "NaN".

Deliberately not changed: the upload name check stays fail-open if pattern-set.js fails to load. Failing closed would block every upload.

Follow-ups (not in this candidate):

  • one shared module for the partial-arena addressing rules, which are now spread across the generator, the 3D viewer, the 2D view and the icon;
  • a replace / upload anyway / cancel choice when a name is already on the card;
  • LAB-229 parsing the _4c-… filename codes;
  • partial-G6 playback on hardware (LAB-296).

Bench checks still to do:

  • the 4-color patterns on the 2×10, after re-uploading them;
  • a double upload of the same name, to see the duplicate warning;
  • a 64-character name, refused before any data is sent.

…he thumbnail download (LAB-298)

Bench 2026-10-07 (rig cshl_g6_2x10_ball, 24 patterns on the card): the first
TRIAL_PARAMS after Connect was acknowledged 57 s late. The SD listing auto-picks
pattern 1 and the picker thumbnail downloaded the whole file (0x84). With
Chrome's default 255-byte Web Serial read buffer the body arrived 901 bytes
short, and the one-at-a-time link waited out the read's 60 s timeout with the
GET_PATTERN_INFO sweep and the user's command queued behind it. Firmware ruled
out from Python (listing + 24x 0x88 in 48 ms, 81 KB download in 6 ms).

- arena-link.js: open the port with a 1 MiB bufferSize; a background lane
  (`{ background: true }`) that waits while any foreground send is queued; a
  bulk body fails after idleTimeoutMs (5 s) without a byte instead of waiting
  out timeoutMs.
- Studio: the GET_PATTERN_INFO sweep (cardPatternInfo, also caches file size)
  and the picker thumbnail fetch use the background lane; a card-only
  thumbnail downloads only when PatPreview.liveFetchVerdict allows it (size
  known, <= 1 MiB, no run). Frame counts for the closed-loop resolver (#201)
  are still filled for every pattern. Tooltip explains a thumbnail refused
  while the display runs (status 10).
- Tests: link buffer/stall/lanes, liveFetchVerdict, Studio call sites.

Verified on hardware: first TRIAL_PARAMS ack 2 ms (was 57,013 ms); 81 KB
thumbnail download 7 ms; 24 frame counts done 197 ms after Connect.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@mbreiser
mbreiser force-pushed the release/2026-10-06 branch from 123a1d2 to b4f9ebf Compare October 7, 2026 16:32
mbreiser and others added 6 commits October 12, 2026 16:17
…ipherals (LAB-214, Studio v0.96)

- js/arena-wire-g6.js: GET_I2C_SCAN 0xB0 / I2C_TRANSFER 0xB1 encoders + decoders
  (status text, "No Qwiic jack" detection) with golden tests.
- js/qwiic-drivers.js (new): host register maps ported from the firmware repo's
  tests/qwiic_sensors.py + qwiic_peripherals.py — SHT4x (two-leg read, CRC),
  LSM6DSOX (tilt, latched bump: LIR + INT_CLR_ON_READ + INT1 routing), TSL2591,
  VEML7700, AS7343 (releases the bus while integrating), PCA9685 (ALLCALL off,
  servo pulse), PCA9548; an async bus mutex; all-call shadow decided from MODE1;
  the KINDS registry is the one place to add or drop a part.
- js/studio-qwiic.js (new): rig `peripherals:` parser (tolerant, warnings), the
  scan-vs-YAML check in both directions (declared-but-missing = error,
  attached-but-undeclared = warning), setup, chip, "Copy as rig YAML".
- arena_studio.html: one Console "Qwiic" window (Scan → device dropdown → one
  device's readout in display units; bump check; servo go-to-position), a
  connect-time setup scan and a top-bar chip. Every I2C command is gated on the
  0xC2 qwiic_i2c feature bit: controllers without the jack are never sent any.
  Test only — nothing is written to run logs (that is PR 2).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nection columns, no sticky "live" status (LAB-214)

Bench feedback (all six boards working on the 12-18):
- The scan table is the picker: one radio row per identified device (click the
  row or its button); the dropdown is gone.
- Each row names its category (Servo / PWM, Temp / humidity, Accel / tilt / bump,
  Light (broadband / lux / spectral), I2C mux) — KINDS.category, one place.
- "where" is now "connection": direct (on the controller's own chain) or
  "mux 0x70 · ch N" (behind a PCA9548 channel).
- Stopping Live restores the scan summary; a tick in flight at Stop no longer
  re-writes "live · N Hz".
- Table text left-aligned (it inherited the analog table's right alignment).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…-214)

- js/arena-configs.js regenerated (scripts/generate-arena-configs.js) from the
  maDisplayTools branch feat/arenas-1x12of18-3x10of14: G6 arena IDs 7
  (G6_1x12of18) and 8 (G6_3x10of14). angle_offset_deg centers the gap at the back
  so the installed panels sit centered at the front in the 3D view and icons
  (Mercator/Mollweide center the installed arc by construction).
- configs/rigs/g6_1x12of18_bench.yaml: the arena_12-18 bench, one row, with the
  six-board Qwiic chain declared under peripherals:; g6_3x10of14.yaml with
  peripherals: [] until its chain is known. Both added to configs/rigs/index.json.
- tests: geometry, IDs, centering, index entries, clean peripherals parse.

The maDisplayTools change must merge first: the sync-arena-configs workflow
regenerates arena-configs.js from maDisplayTools main.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…s, color-bank figure; Qwiic read-on-select (LAB-214)

- Qwiic: clicking a device reads it immediately; Live keeps running across device
  changes (each tick reads the selected device); the servo follows its slider while
  dragging.
- Console sliders act while dragging — Test display level/duty re-send the last
  figure, LED power sets the LED — through liveSender(): single-flight, latest
  value wins, nothing sent while a run owns the link, one log line on release.
- Test display streams at the CONTROLLER's frame geometry (0xCB rows×cols; fw
  panel_count_per_frame) instead of refusing every non-20-panel rig: the rig figure
  is placed in the firmware frame (installed columns from the left, rig rows
  repeated up), so the 1×12 bench drives a 4×12 build. Wire.streamFrameBytes +
  encodeStreamFrame(payload, {panels}) with golden tests; .bin/.pat file streaming
  stays 20-panel.
- Test display → color A–D: light one LED bank (T0–T3) at a time via the shared
  PanelColor.bankAt (100 of 400 LEDs per panel).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…commit bumps; notes live in the PR body

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@mbreiser

Copy link
Copy Markdown
Contributor Author

Adversarial review of candidate 2026-10-06 rc4 (af9ffef)

Diff: origin/main...release/2026-10-06 (47 files, 8,419 diff lines). Candidate = main 7c68dfc + #245, #246, #248, #250.
Reviewed by: Claude (independent, written before reading Codex), Codex GPT-5.5 standard, Codex GPT-5.5 adversarial
Date: 2026-10-13
Focus: #250 (Qwiic, live sliders, firmware-sized test display, color banks) and where it meets the other three. The rc1 review found no blockers in #245/#246/#248.

Verdict: hold rc4. Fix #250, rebuild rc5, then validate.

One blocking defect in #250. Claude and Codex-adversarial found it independently; Codex-standard found no defects.

1. Where at least two reviewers agree

Blocking

  • Studio: Console → Qwiic peripherals, rig peripherals:, live Console sliders, firmware-sized test display + color banks (LAB-214) #250: test-display frames ignore columns_installed when placed in the firmware frame [Claude / Codex-adv]
    • Where: arena_studio.html, activeArenaGeom() and toFirmwareGrid().
    • Cause: activeArenaGeom() now counts installed columns, and toFirmwareGrid() copies that installed-width grid into firmware columns from 0.
    • On the CSHL cshl_g6_2x8 rig (G6_2x8of10, columns_installed [1..8]):
      • with 0xCB firmware, every figure is shifted one panel: column 0 lights, physical column 8 goes dark, and the panel map is off by one;
      • with pre-0xCB firmware (most course rigs), the rig is no longer 20 panels, so every figure is refused, although it worked before.
    • The same change mis-numbers the ISP progress map (genIspStatusFrame) and changes the paste-modal dimensions on that rig.
    • Fix: keep activeArenaGeom() as the full arena grid, as on main. In streamTarget()/toFirmwareGrid(), map grid column c to firmware column c, and require only that every installed column fits the firmware's column count. With that, 2×10, 2×8of10 and pre-0xCB firmware behave exactly as before, and 1×12of18 still streams to the 4×12 build.

Significant

(none with two votes)

Minor

(none with two votes)

2. Where Codex disagrees with Claude

Codex raised, Claude missed

Claude raised, Codex didn't

  • Live test-display sliders can interleave with an ISP batch (significant) — liveOk() / Studio.restreamLast()
    • My point: they gate on connected and not-running, but not on Studio.ispBatchRunning() or Studio._activePostmortem. Dragging level or duty during a batch flash sends STREAM_FRAME, which makes the display active, and the next 0xC8/0xC9 is then refused (the display-quiesce rule).
    • Possible reason Codex skipped it: it needs the firmware's ISP-quiesce rule, which isn't in the diff.
  • The connect-time Qwiic setup is awaited before the controller reads and the SD listing (significant) — initFromController()
  • Minor:
    • With the full-grid fix, the orientation figure's "R" falls on an uninstalled column on 1×12of18.
    • The actuator auto-read skips the inFlight guard; the bus mutex already orders it, so it's harmless.
    • An unreferenced PCA9548 gets flagged "undeclared", but "Copy as rig YAML" emits nothing for it.
    • The bus mutex is held across sensor configure sleeps; PR 2's per-trial snapshot will need a time budget.

Direct contradictions

3. Where Codex's two reviews disagree

  • Overall: the standard pass found nothing beyond a docs nit. The adversarial pass would not merge rc4 until the partial-stream mapping and lane teardown are fixed. The standard pass ran the unit suites, which pass but don't exercise a partial rig on firmware-sized frames. The bench-facing risk sits exactly in that gap.

4. Open questions

5. Proposed fix list for rc5 (all in #250 unless noted)

  1. Blocking: full-grid activeArenaGeom() + physical-column mapping in toFirmwareGrid(). Add tests for 2×10 = identity, 2×8of10 = columns 1..8, and pre-0xCB firmware = the old 20-panel rule.
  2. Live gate: add ispBatchRunning() and _activePostmortem.
  3. Qwiic connect setup: after the controller reads, and the SD listing doesn't wait for it.
  4. Docs: drop "v0.96" from CLAUDE.md and the parity ledger.
  5. Orientation glyphs within the installed span; best-effort servo allOff() on an intentional disconnect.
  6. (Studio: first command after Connect no longer waits ~60 s behind the thumbnail download (LAB-298) #248, optional) _sendOne() rejects when !_connected || _closing; fail queued lanes on teardown.

Raw outputs (session-local)

  • Claude: .codex-review/claude-analysis-20261013-093015.md
  • Codex standard / adversarial: .codex-review/codex-diff-review-20261013-093025-70088/{standard,adversarial}.md

mbreiser and others added 6 commits October 13, 2026 11:51
…n), live gates, deferred Qwiic setup (LAB-214)

From the adversarial review of candidate 2026-10-06 rc4 (PR #247 comment):
- BLOCKING: test figures are drawn on the rig's FULL arena grid again
  (activeArenaGeom = num_rows × num_cols); grid column c → firmware column c and
  only the installed columns must fit the firmware frame. rc4 collapsed partial
  arenas to installed width and left-aligned them, which shifted every figure one
  panel on G6_2x8of10 (columns 1–8) with 0xCB firmware and refused it outright on
  pre-0xCB firmware; it also mis-numbered the ISP progress map and changed the
  paste dimensions. Mapping now lives in js/studio-stream-geometry.js with Node
  tests (2×10 / 2×8of10 identity on both firmware kinds, 1×12of18 → 4×12).
- Live slider re-streams and Qwiic reads pause during an ISP batch and a
  post-mortem (a stream re-activates the display; 0xC8/0xC9 need it stopped).
- Connect-time Qwiic setup starts after the controller reads and is not awaited,
  so its sensor configure waits never delay the SD listing.
- Orientation glyphs sit inside the installed span (1×12of18's "R").
- Best-effort servo release (PCA9685 all off) on an intentional disconnect.
- Docs: drop the stale "v0.96" (the release commit owns versions).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…apping, unmirrored icons, short SD-safe filenames, upload name checks (LAB-295)
…ve Console sliders, firmware-sized test display + color banks (LAB-214)
…1.5, Pattern Designer v0.13, Arena Studio v0.95

Candidate for Production. PRs: #245, #246, #248, #250.

Release-Manifest: releases/2026-10-06.json
@mbreiser

Copy link
Copy Markdown
Contributor Author

✅ Validated a4a2a9c — candidate 2026-10-06 rc5 — on bergamo by Michael Reiser

Validated a4a2a9c by proxy. The #254 branch head c2a1c5e (which contains this rc5 tree through its merge of origin/next) ran real experiments on ww18 (2026-10-15: closed loop + BIAS, 10-min soak, idx mismatch 0.00 %) and on the Bergamo (2026-10-16: SD upload of four GS16 patterns, Connect / first-command latency, a 26/26-step 2P run). Not exercised on hardware: the Qwiic Console panel beyond Michael's 12-18 bench. rc5 itself was not run as its own SHA on a rig.

@mbreiser
mbreiser marked this pull request as ready for review October 18, 2026 17:52
@mbreiser
mbreiser merged commit 1d9b2b7 into main Oct 18, 2026
11 checks passed
@mbreiser
mbreiser deleted the release/2026-10-06 branch October 18, 2026 17:52
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