<feed xmlns='http://www.w3.org/2005/Atom'>
<title>archsetup/tests/gallery-probes, branch main</title>
<subtitle>Builds a full dev workstation from a bare Arch Linux install.
</subtitle>
<id>https://git.cjennings.net/archsetup/atom?h=main</id>
<link rel='self' href='https://git.cjennings.net/archsetup/atom?h=main'/>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/archsetup/'/>
<updated>2026-07-25T20:00:56+00:00</updated>
<entry>
<title>refactor(prototypes): merge casting widgets into Dupre kit</title>
<updated>2026-07-25T20:00:56+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-07-25T20:00:56+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/archsetup/commit/?id=ef00914a4dc5ef1347ca0bf9850157e659d0e654'/>
<id>urn:sha1:ef00914a4dc5ef1347ca0bf9850157e659d0e654</id>
<content type='text'>
</content>
</entry>
<entry>
<title>fix(probe): scroll instantly so the drag checks stop missing the widget</title>
<updated>2026-07-23T16:00:01+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-07-23T16:00:01+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/archsetup/commit/?id=8472977e74c588508b6583f19864b2f947da767f'/>
<id>urn:sha1:8472977e74c588508b6583f19864b2f947da767f</id>
<content type='text'>
The gallery sets `html{scroll-behavior:smooth}`, so `scrollIntoView` animates. The fader check slept a fixed 200ms and then read `getBoundingClientRect`, which sometimes caught the rect mid-scroll. The drag went out at stale coordinates. The press landed off the fader, and the check reported a dead widget about one run in six.

The probe has no reason to animate, so it now scrolls with `behavior:'instant'`. That removes the race rather than waiting it out. A `settledGeom` read still guards against zoom and column relayout. It requires the geometry to be stable twice over and on screen, because two matching samples taken before a relayout begins look identical to a settled one.

Both checks now assert the press landed on the widget before dispatching. That assertion earned itself during the fix. My first attempt polled for a stable rect and returned pre-scroll coordinates every time, and the press-landed check caught it by printing a point below the window.

The toggle check has the same fixed-sleep shape and failed that way while I was diagnosing, so it got the same fix.

Verified over 8 consecutive runs against the measured 1-in-6 rate. All three checks pass with the press point identical each time, so the result is deterministic rather than lucky.
</content>
</entry>
<entry>
<title>feat(gallery): bring the well-through-response ten to the extraction bar</title>
<updated>2026-07-19T00:00:14+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-07-19T00:00:14+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/archsetup/commit/?id=1dd929df9607bb1ff1d50e5afd535f4a3186c619'/>
<id>urn:sha1:1dd929df9607bb1ff1d50e5afd535f4a3186c619</id>
<content type='text'>
outputWell, toast, annunciator, tapeCounter, freqScale, patchBay, dataMatrix, warningFlag, seg14, and responseGraph each get the contract comment. The six DOM builders take dupre- prefixes across their markup and CSS blocks. patchBay's live jack and the annunciator's master caution adopt the kit-wide dupre-hot and dupre-on modifiers, and the annunciator board takes dupre-warn and dupre-fault. freqScale reuses the shared scoped dupre-tick and dupre-mk (as the tuner and dualknob do) and compounds its unit label to dupre-fs-band, since dupre-band is the EQ's. The four SVG-stage builders style through the shared .rsvg stage and inline attributes, so they get the SVG-built contract comment and no prefixes.

The annunciator documented a 0..2 state per cell but painted an undefined class on an out-of-range initial state or set(). It now clamps at build and at set. Two probe checks cover the batch: one fails red without that clamp, one drives each renamed DOM builder through its handle to catch a class-name mismatch the exception scan can't see.

Extraction audit: 104/111 contract comments.
</content>
</entry>
<entry>
<title>feat(gallery): bring the CRT-through-engraved ten to the extraction bar</title>
<updated>2026-07-18T23:05:55+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-07-18T23:05:55+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/archsetup/commit/?id=2f87baa926531d7c8f2a9bd149638ed1a79a3604'/>
<id>urn:sha1:2f87baa926531d7c8f2a9bd149638ed1a79a3604</id>
<content type='text'>
roundCrt, attitudeIndicator, headingBug, chartRecorder, verticalTape, twinNeedle, comfortMeter, badges, tabularReadout, and engravedLabel each get the contract comment. The three DOM builders take dupre- prefixes across their markup and CSS blocks: badges (dupre-badge with the kit-wide dupre-red plus a new dupre-ghost), tabularReadout (dupre-readout and dupre-unit), and engravedLabel (dupre-engrave and dupre-cnt).

The rename surfaced a dead rule: .readout .u selects a descendant, but the unit caption is a sibling, so its style never applied. The caption now styles through a standalone .dupre-unit rule.

The builders now enforce their documented domains at build, not only in set(): twinNeedle and comfortMeter clamp their initial opts through set(), headingBug normalizes opts.value to 0..360, and badges coerces junk variants through one norm() shared by build and set(). Two probe checks cover the gates and drive the renamed DOM.

Extraction audit: 94/111 contract comments.
</content>
</entry>
<entry>
<title>feat(gallery): bring the needle-through-edge ten to the extraction bar</title>
<updated>2026-07-18T22:21:24+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-07-18T22:21:24+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/archsetup/commit/?id=cf12fe73fc279914fd3f615851decc1b0449a8bb'/>
<id>urn:sha1:cf12fe73fc279914fd3f615851decc1b0449a8bb</id>
<content type='text'>
crossNeedle, thermometer, bourdon, stripChart, corrMeter, battCells, mcVu, chromeMinMax, aviationGauge, and edgeMeter each get the contract comment. The six DOM builders take dupre- prefixes across their markup and CSS blocks. Internals go compound where gauge, fader, and nixie already hold the plain names: bourdon's needle, hub, and cap, corrMeter's face, arc, needle, and label, crossNeedle's arc, and thermometer's tube and fill. crossNeedle's nA and nB become dupre-fwd and dupre-rfl, and battCells moves its cell modifiers to the shared dupre-on and dupre-warn.

The handles now enforce their documented domains: the needle meters clamp set() to 0-100, stripChart floors its history at two samples and survives a non-array set(), battCells floors its cell count at one, and mcVu clamps and paints opts.value at build instead of ignoring it for a hard-coded .35. Two probe checks cover the gates and drive the renamed DOM.

Extraction audit: 84/111 contract comments.
</content>
</entry>
<entry>
<title>feat(gallery): bring the decade-through-EQ ten to the extraction bar</title>
<updated>2026-07-18T21:33:31+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-07-18T21:33:31+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/archsetup/commit/?id=1bf9591e246fe531e3cdd8e414170fe186cad6fd'/>
<id>urn:sha1:1bf9591e246fe531e3cdd8e414170fe186cad6fd</id>
<content type='text'>
decadeBox, twoHandSafety, voiceLoop, miniSig, fuelBar, radialRing, sparkline, waveStrip, scope, and eqBars each get the contract comment. The eight DOM builders take dupre- prefixes across their markup and CSS blocks. voiceLoop's inner bar becomes dupre-vk-bar to stay clear of fuelBar's dupre-bar, and miniSig and eqBars move their cell modifiers to the shared dupre-on, dupre-hot, and dupre-clip.

Domain gates land where a handle could wedge: decadeBox coerces and clamps its digits, twoHandSafety ignores sides other than L and R, voiceLoop keeps the demo state to the stock loop set (a caller's shorter list used to crash on it), the meters clamp set() to their documented ranges, and sparkline and scope guard the one-sample case that drew NaN coordinates. Two probe checks cover the gates and drive voiceLoop's grammar through the prefixed DOM. probe-fams follows scope's rename.

Extraction audit: 74/111 contract comments.
</content>
</entry>
<entry>
<title>feat(gallery): bring the timer-through-knife ten to the extraction bar</title>
<updated>2026-07-18T20:45:33+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-07-18T20:45:33+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/archsetup/commit/?id=bdd2130e32cd8f86160e5fdf5a91b2a000ddae0f'/>
<id>urn:sha1:bdd2130e32cd8f86160e5fdf5a91b2a000ddae0f</id>
<content type='text'>
timerDial, rockerPad, fourWayToggle, pinMatrix, deadMan, telephoneDial, breakerPanel, dsky, camTimer, and knifeSwitch each get the contract comment. dsky, the one DOM builder, takes dupre- prefixes across its markup and CSS block. That resolves the batch-1 deferral on the shared .win name, and its lamp and window modifiers move to the shared dupre-on and dupre-hot.

Domain gates land where a handle could wedge: fourWayToggle ignores anything outside its four quadrants (prototype-inherited keys included) and falls back to C on a bad initial position, camTimer's set() clamps to the ring, and pinMatrix drops initial pins that name no intersection. Two probe checks cover the gates and drive dsky's grammar through the prefixed DOM.

Extraction audit: 64/111 contract comments.
</content>
</entry>
<entry>
<title>feat(gallery): bring the keypad-through-guarded ten to the extraction bar</title>
<updated>2026-07-18T20:26:13+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-07-18T20:26:13+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/archsetup/commit/?id=38e0dd7563d59ee01113972be5a0010cf8b91c3e'/>
<id>urn:sha1:38e0dd7563d59ee01113972be5a0010cf8b91c3e</id>
<content type='text'>
entryKeypad, thumbSlide, waveRegion, ledRow, pillSlide, spunKnob, stompSwitch, wingSelector, discSwitch, and guardedToggle each get the contract comment. All ten are SVG-stage builders, so there were no classes to prefix.

set() hardening lands where a handle could wedge: ledRow, pillSlide, and discSwitch clamp their index (discSwitch previously threw), waveRegion keeps E at least 4 above S from set() itself rather than only the drag path, and entryKeypad ignores keys outside its documented 0-9/confirm/clear set. ledRow's default selection is index 5 only for the default program list. A caller's own items start at 0.

Extraction audit: 54/111 contract comments.
</content>
</entry>
<entry>
<title>feat(gallery): bring the DIP-through-multiband ten to the extraction bar</title>
<updated>2026-07-18T20:06:52+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-07-18T20:06:52+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/archsetup/commit/?id=ee0826a1e475dba34aa84e548c24bca1023eed6d'/>
<id>urn:sha1:ee0826a1e475dba34aa84e548c24bca1023eed6d</id>
<content type='text'>
dipBank, jogWheel, vernierDial, batToggle, flutedKnob, filterBank, chickenHead, slotFader, spadeKnob, and multiBandDial each get the contract comment. The two DOM builders also get dupre- prefixes on their classes (dip/dipsw and the on modifier, jog/shuttle/inner/dimple). jogWheel caches its inner disc instead of querying it on every move.

set() hardening lands where a handle could wedge: vernierDial and flutedKnob clamp 0-100, filterBank clamps the band index and its initial values, and multiBandDial clamps the band and keeps the current one when set() omits it (a bare set(v) previously threw).

Extraction audit: 44/111 contract comments.
</content>
</entry>
<entry>
<title>feat(gallery): bring ten more controls to the extraction bar</title>
<updated>2026-07-18T19:09:35+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-07-18T19:09:35+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/archsetup/commit/?id=9fa438e990807e358b126f896b84d8b4d45a084b'/>
<id>urn:sha1:9fa438e990807e358b126f896b84d8b4d45a084b</id>
<content type='text'>
rotarySelector, slideRule, rocker, transport, presetBank, dualKnob, encoder, keySwitch, crossfader, and thumbwheel get contract comments, dupre- prefixed CSS, and cached element refs. presetBank and dualKnob set() now clamp out-of-range input, with a probe check covering both. rotarySelector and keySwitch cap their inputs at the five- and three-stop plates they draw. The audit's contract count moves to 34/111.
</content>
</entry>
</feed>
