<feed xmlns='http://www.w3.org/2005/Atom'>
<title>labUI.git/core, branch main</title>
<subtitle>Data acquisition program written in Python for use with serial communication devices.
</subtitle>
<id>https://git.kolset.xyz/labUI.git/atom?h=main</id>
<link rel='self' href='https://git.kolset.xyz/labUI.git/atom?h=main'/>
<link rel='alternate' type='text/html' href='https://git.kolset.xyz/labUI.git/'/>
<updated>2026-09-21T06:16:15Z</updated>
<entry>
<title>Fix Buffer size setting never being applied; add Safety Switch control type</title>
<updated>2026-09-21T06:16:15Z</updated>
<author>
<name>Christian Kolset</name>
<email>christian.kolset@gmail.com</email>
</author>
<published>2026-09-21T06:16:15Z</published>
<link rel='alternate' type='text/html' href='https://git.kolset.xyz/labUI.git/commit/?id=4ab2eea9af5338485303d421476fa874e5af6841'/>
<id>urn:sha1:4ab2eea9af5338485303d421476fa874e5af6841</id>
<content type='text'>
- Buffer size (samples) in Settings &gt; Acquisition was captured into the
  settings dict but never read anywhere — SignalBuffer always used the
  hardcoded MAX_BUFFER=20_000 constant (which happens to match the
  dialog's default, hence it looking like the value "reverts"). Add
  AcquisitionEngine.set_buffer_size(), wired in on startup and on Settings
  apply; existing buffers are rebuilt at the new size in place, keeping
  their most recent samples.

- New "Safety Switch" control type: an On/Off Switch that's disabled
  outright until acquisition is running, with a lock icon shown while
  disabled. AcquisitionEngine gains a run_state_changed(bool) signal
  (emitted from start()/stop()); ControlWidget gains a
  _check_safety_lock() hook (no-op by default, called uniformly by
  ControlPanel on every widget) that SafetySwitch overrides. engine is
  now threaded through to every ControlWidget for this. Persists via
  ControlSpec.control_type alone — no schema change needed.

Co-Authored-By: Claude Sonnet 5 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>Make Channel the single source of truth for a reading's name</title>
<updated>2026-09-21T04:30:13Z</updated>
<author>
<name>Christian Kolset</name>
<email>christian.kolset@gmail.com</email>
</author>
<published>2026-09-21T04:30:13Z</published>
<link rel='alternate' type='text/html' href='https://git.kolset.xyz/labUI.git/commit/?id=006366ef8099c8313ae596bf6267e9f98dfbeb5e'/>
<id>urn:sha1:006366ef8099c8313ae596bf6267e9f98dfbeb5e</id>
<content type='text'>
Device tab stays hardware-only (pins, wiring, may vary per workstation);
the Channels window owns the profile-facing identity. Concretely:

- Fix a real regression: SerialDevice generic-format Apply &amp; Reconnect
  nulled out custom channel_names/units every time (no fallback, unlike
  every other optional field in reconfigure()), silently reverting to
  sig0/sig1/... ids.
- Plot legend now live-tracks the current Signal/Channel name instead of
  freezing tr.label at add-time, so a rename shows up without re-adding
  the trace.
- Add an inline quick-reconnect (combo + button, pre-selects the actual
  current source) directly on each Channel block in the Channels window,
  for the common single-source case — rewiring hardware no longer means
  touching every Plot/pipeline that referenced it.
- Collapse the Channel ID field behind an "ID ▸" advanced toggle;
  channel_id is already auto-derived from the name (_slug_id) and rarely
  needs to be seen.
- Devices tab's Signal "Name" column relabeled "Label" with a tooltip —
  de-emphasized now that Channel name is the real identity.
- Move "create a Channel from this Signal" from a column on the Devices
  tab's signal table to a ⊕ button on each Signal row in the Channels
  tab's Namespace panel — the action now lives where the identity is
  created, not on the hardware tab. Only that instance opts in
  (on_create_channel); the read-only Namespace dock on the main window
  is unaffected.
- Floor the Namespace panel's width at its columns' natural size so
  dragging the Channels-tab splitter narrower can't push the ⊕ column
  behind the horizontal scrollbar.
- Breadcrumb log when a profile-saved Signal override can't be applied
  because the signal_id no longer exists.

Co-Authored-By: Claude Sonnet 5 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>Fix Signal name reset and orphaned references on device reconfigure</title>
<updated>2026-09-20T17:31:07Z</updated>
<author>
<name>Christian Kolset</name>
<email>christian.kolset@gmail.com</email>
</author>
<published>2026-09-20T17:31:07Z</published>
<link rel='alternate' type='text/html' href='https://git.kolset.xyz/labUI.git/commit/?id=bb8be051ffffa56a01093c9f3aaa80e84748568f'/>
<id>urn:sha1:bb8be051ffffa56a01093c9f3aaa80e84748568f</id>
<content type='text'>
Apply &amp; Reconnect rebuilt a device's whole Signal list from hardware
defaults on every call, silently discarding user/profile-set names,
units, and colors even when pins hadn't changed. Add
merge_signal_metadata() and call it from ArduinoDevice.remap_pins()
and SerialDevice.reconfigure() to reapply the same fields
ProfileManager already treats as user overrides, keyed by signal_id.

Also close a related gap: removing a pin that a Channel/Plot/Control
still referenced left it silently dangling, and SignalProcessor never
pruned its latest-value cache, so a derived Channel kept computing off
a permanently frozen stale reading. Add SignalProcessor.
on_device_reconfigured() to purge that cache, reference_registry.
find_references() for a console breadcrumb, and live "missing source"
indicators on Plot traces and Channel blocks reusing ControlWidget's
existing stale/QSS pattern. Also fixes ControlWidget._write() still
enqueuing writes to a channel that no longer exists.

Co-Authored-By: Claude Sonnet 5 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>Redesign Signal/Channel naming and fix pin-remap breaking references</title>
<updated>2026-09-19T23:38:07Z</updated>
<author>
<name>Christian Kolset</name>
<email>christian.kolset@gmail.com</email>
</author>
<published>2026-09-19T23:38:07Z</published>
<link rel='alternate' type='text/html' href='https://git.kolset.xyz/labUI.git/commit/?id=f3327d56d48d63b21ffc03a55fa5e7db753d1707'/>
<id>urn:sha1:f3327d56d48d63b21ffc03a55fa5e7db753d1707</id>
<content type='text'>
Arduino analog Signal ids used to be the pin name itself, so fixing a
wrong pin silently changed the id and orphaned any plot trace, control,
or filter pipeline pointing at it. Analog Signal ids are now positional
(ai0, ai1, ...) and decoupled from the underlying pin, matching how
digital I/O already worked.

More broadly, formalizes a Device -&gt; Signal -&gt; Channel -&gt; Plot naming
model (SignalConfig for physical device channels, Channel for derived/
computed ones) and adds core/reference_registry.py to propagate any
Signal or Channel id rename through plot traces, controls, and filter
pipelines instead of leaving them dangling. Signal ids are now editable
in the Signals tab with the same propagation.

.labui profile schema bumped to v2.0 with a transparent migration for
old files, including remapping old pin-name Signal ids to the new
positional ones. Removed six confirmed-dead files (two legacy device
classes, four superseded top-level ui/ duplicates).
</content>
</entry>
<entry>
<title>Add .labui file association — open by double-click, cross-platform</title>
<updated>2026-08-17T16:01:59Z</updated>
<author>
<name>Christian Kolset</name>
<email>ckolset@colostate.edu</email>
</author>
<published>2026-08-17T16:01:59Z</published>
<link rel='alternate' type='text/html' href='https://git.kolset.xyz/labUI.git/commit/?id=e749cca30da2d02839aca736873e7e5ad45e191c'/>
<id>urn:sha1:e749cca30da2d02839aca736873e7e5ad45e191c</id>
<content type='text'>
Windows/Linux self-register via core/file_association.py (winreg /
XDG .desktop+mime), triggered from a new Settings button since there's
no installer to do it at install time. macOS gets it at build time via
labui.spec's new BUNDLE() step (CFBundleDocumentTypes in Info.plist) —
that step also makes mac builds a real .app bundle for the first time,
not just a bare onedir folder. main.py gains a LabUIApplication
subclass to catch the macOS QFileOpenEvent (buffered if it arrives
before MainWindow exists) plus argv[1] handling for Windows/Linux.
ProfileButton.load_path() extracted so both paths share the same
load-and-apply logic as the existing file-dialog flow.

Co-Authored-By: Claude Sonnet 5 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>Channels tab drag-to-reorder, Namespace absolute references, fix stale Channel ID renames</title>
<updated>2026-08-13T19:39:25Z</updated>
<author>
<name>Christian Kolset</name>
<email>ckolset@colostate.edu</email>
</author>
<published>2026-08-13T19:39:25Z</published>
<link rel='alternate' type='text/html' href='https://git.kolset.xyz/labUI.git/commit/?id=34c12b2b5b280206890cd03153b1c95116acc85e'/>
<id>urn:sha1:34c12b2b5b280206890cd03153b1c95116acc85e</id>
<content type='text'>
Generalized the Plot pane drag-to-reorder (_PaneDragHandle/_PlotDropContainer
-&gt; _DragHandle/_DragReorderContainer) and reused it for the Channels tab's
derived-channel list; reordering also updates SignalProcessor's evaluation
order (list order matters for chained Channels) via new reorder_derived().

Namespace panel: added an ID column (bare channel_id, matching the actual
channels.get(...) script convention) and fixed the Source column for
Channels to show resolved absolute references (dev_id/ch_id for a Signal,
bare id for a chained Channel) instead of the operation kind, so a chain
is traceable by eye.

Fixed a real bug this surfaced: renaming a Channel's ID never propagated
to other Channels' sources, leaving dangling ("derived", old_id)
references that silently stopped updating. Added
SignalProcessor.rename_derived() to fix up sources plus carry the ring
buffer/latest-value cache to the new key, wired to DerivedBlock's Apply.

Co-Authored-By: Claude Sonnet 5 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>Re-detect serial device ports by identity when a profile loads on another machine</title>
<updated>2026-08-13T17:09:03Z</updated>
<author>
<name>Christian Kolset</name>
<email>ckolset@colostate.edu</email>
</author>
<published>2026-08-13T17:09:03Z</published>
<link rel='alternate' type='text/html' href='https://git.kolset.xyz/labUI.git/commit/?id=4d08be2656d5599caf60ab5163a9d2305b397daf'/>
<id>urn:sha1:4d08be2656d5599caf60ab5163a9d2305b397daf</id>
<content type='text'>
COM/tty numbers aren't stable across machines or replugs. Devices now save
their USB serial number and OS description alongside the port; on profile
load, if the saved port isn't present, ArduinoLayer.find_port_by_identity()
looks for a match and remaps it. Falls back to the saved port (device shows
ERROR) if nothing matches.

Co-Authored-By: Claude Sonnet 5 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>Fixed loading profiles data retention and display.</title>
<updated>2026-08-13T17:04:34Z</updated>
<author>
<name>Christian Kolset</name>
<email>ckolset@colostate.edu</email>
</author>
<published>2026-08-13T16:59:25Z</published>
<link rel='alternate' type='text/html' href='https://git.kolset.xyz/labUI.git/commit/?id=012a1093e3cb9a1b376fc3beee4df859ccfb8da5'/>
<id>urn:sha1:012a1093e3cb9a1b376fc3beee4df859ccfb8da5</id>
<content type='text'>
</content>
</entry>
<entry>
<title>Finish multi-platform release restructuring (previous commit was incomplete)</title>
<updated>2026-08-11T17:36:10Z</updated>
<author>
<name>Christian Kolset</name>
<email>ckolset@colostate.edu</email>
</author>
<published>2026-08-11T17:36:10Z</published>
<link rel='alternate' type='text/html' href='https://git.kolset.xyz/labUI.git/commit/?id=d734011601ae1eecc0e3ae334b58d07e5b4d80d3'/>
<id>urn:sha1:d734011601ae1eecc0e3ae334b58d07e5b4d80d3</id>
<content type='text'>
git add silently staged nothing from the previous attempt because one
pathspec in that batch (scripts/release/repository, already moved) no
longer existed — only the .gitignore-adjacent renames landed. This
commit adds what was actually meant to go in:

- core/updater.py: releases/download/updates-&lt;platform&gt;/ instead of a
  single shared updates/ tag.
- labui.spec: bundles root.json from this platform's own tree.
- scripts/release/repo_init.py, repo_release.py: auto-detect platform,
  operate inside scripts/release/&lt;platform&gt;/.
- .gitignore: per-platform ignore rules (previous commit only carried
  the file renames, not this).
- docs/building.md, scripts/release/README.md: rewritten for the
  per-platform flow.
- Also picks up pre-existing local TUF re-signing (new snapshot/
  timestamp signatures, bumped expiry/version) that was sitting
  uncommitted before this restructuring started.

Co-Authored-By: Claude Sonnet 5 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>Add dockable Namespace panel — live Python-namespace browser</title>
<updated>2026-08-10T22:45:37Z</updated>
<author>
<name>Christian Kolset</name>
<email>ckolset@colostate.edu</email>
</author>
<published>2026-08-10T22:45:37Z</published>
<link rel='alternate' type='text/html' href='https://git.kolset.xyz/labUI.git/commit/?id=8d546990c86df61174b2f3f2036771757aa69913'/>
<id>urn:sha1:8d546990c86df61174b2f3f2036771757aa69913</id>
<content type='text'>
New right-docked panel (mirrors Control Panel's dock, opposite side)
listing every Signal, Channel, and shared `vars` key currently in the
profile, with live values and a double-click-to-copy reference snippet
(vars.get(...) / channels.get(...)) for use in scripts. Closed by
default — opt-in config tool, no collapse-strip nag like Control Panel
gets since it's not needed mid-run.

Also moves Configuration out of the View menu into its own toolbar
button, and makes table row hover match the selection highlight color.

Co-Authored-By: Claude Sonnet 5 &lt;noreply@anthropic.com&gt;
</content>
</entry>
</feed>
