Repository navigation
FBD 2.1.0
UNSIGNED BUILD — not notarised; right-click → Open on first launch.
Added
fbdcli report [<id>][file] [--json]is a paste-ready report for a bug report: the display's
identity (masked), its geometry and mode, the control paths, the EDID, the panel facts and the
sink's DPCD — revision, max link rate, lanes, capability bandwidth, DSC and HDCP. A fact is
either a value or absent with a reason, never a number standing in for a measurement: the
fields whose source cannot be read safely on this macOS (the active link bandwidth and rate,
the DSC-in-use flag, the tiling, the connection-mode keys) are reported as unavailable with
the reason, and the JSON carriesnullplus the reason next to it. Serials are masked and
home-directory paths are shortened, on the same precedent as the masked settings dump
(issue #19).fbdcli skill install claude|codexwrites an agent-readySKILL.md: the command grammar, the
token model (the token is never echoed), a read-back command for every state-changing command
and the write contract. The document is compiled in and version-stamped, so a re-install updates
it cleanly;--printwrites exactly the file's bytes to stdout (issue #31).- The capabilities the other issues added are now reachable from all three surfaces. The HTTP API
grew a per-displaydisconnect/reconnectaction (withremember), ahidpiaction
(install,remove,status) and agamma-flooraction (enabled, optionalthreshold).
Five new Shortcuts actions do the same through the controller seam the HTTP API drives: toggle
HDR mode, set the extra-brightness target, switch the input source, disconnect or reconnect a
display (remembering it if asked), and apply an image adjustment. The per-display page shows a
"Brightness blend" row and a "Connection" section — hidden rather than greyed where they do
not apply — and states what each of them needs. The CLI grew the matching commands:
fbdcli hidpi <id> install|remove|status [--preview],fbdcli gamma-floor <id> [on|off] [percent],fbdcli display <id> disconnect [--remember],fbdcli display <id> reconnectand
fbdcli display --list-remembered. Every one of them follows the write contract below: a lost
reply says the command may have applied and exits 75, a refused write names the read-back
command (issue #28). - A display can now be kept disconnected across reboots: FBD remembers the choice and
re-disconnects the display when it comes back, until the user re-enables it. The memory is
filed per display identity, so it survives a restart (issue #30). - The built-in display can be turned off while an external display is attached and the lid is
open. It is a setting, never a silent action, and the existing base-M3 guard still refuses
the whole path before any call is made: on those Macs the built-in display may not come
back without a reboot, so nothing is attempted (issue #30). - An external display can follow the built-in panel's auto-brightness: the ambient sensor's
value is mapped through the nits ceilings and written through the usual brightness path, so
it inherits the write cooldown and the coalescing instead of racing the slider (issue #30). - A monitor's brightness scale rarely reaches black, so the bottom of the brightness slider
was a dead zone: the knob moved, the screen did not. The new below-floor blend pins the
hardware at a threshold and lets the software layer carry the rest as a multiplicative dim,
so the screen reaches what was asked for instead of stopping at the panel's floor. The
curve is continuous at the handoff and monotonic across it, the read-back reports the
position that was asked for rather than the floor, and in HDR the whole range goes to the
software layer — the DDC scale says nothing about the panel's luminance there. Off by
default, per display, and it needs Screen Recording permission (issue #29). - A per-display HiDPI smooth scaling section: FBD generates a dense scaled-mode ladder
(the native size stepped down in 16-point increments, the aspect held, down to half the
native size) and installs it as a display override, so macOS offers scaled resolutions
between the panel's native size and half of it instead of a single HiDPI step. The ladder
is written to the display's own override folder and the display is re-enumerated
afterwards. The section is hidden on displays that cannot carry an override, and it says
plainly whether macOS will ask for an administrator password — it only says so when a
prompt is really coming (issue #27). - DDC/CI replies are validated before any of their numbers are used: a reply has to carry the
DDC/CI signature, echo the VCP code that was asked for, report no error, and pass its
checksum. A monitor that acknowledges an I2C read but answers with stale EDID bytes or a NULL
frame no longer poisons the brightness scale (issue #25). - A display whose DDC controller stops answering has its reads quarantined after six
consecutive failures — or after a single attempt that takes longer than three seconds, which
means the channel is not listening at all. Quarantined reads fail fast instead of hanging for
the full timeout; writes are unaffected (issue #25). - DDC/CI reads are cached for five seconds and paced like writes, so a display is not asked
more often than its controller can answer (issue #25).
Changed
- A write whose reply is lost now says so instead of inviting a blind retry: the CLI reports
"the command may have applied", names the command that reads the state back, and exits 75
(EX_TEMPFAIL). A refused write exits 2. Every state-changing command — routed and direct —
was audited for retry-inviting wording (issue #31). - The software boost no longer overwrites the display's own picture settings: the overlay
keeps the user's filter and composes the boost into it, so applying and removing a boost
leaves the screen as it was (issue #29). fbdcli auth-tokenno longer prints the API token to stdout. It now explains how to obtain
it;--revealprints the token explicitly. The token grants full control of the user's
displays, so it is treated as a secret (issue #32).- The local API token comparison now has a single implementation (
APIToken) shared by the
HTTP router and thefbd://URL handler, instead of two copies that had to be kept in
sync (issue #32). - Enabling or disabling a display and switching its mode now pause DDC traffic and wait for
the transactions already in flight to finish. The window server waits behind an in-flight
I2C transaction, and freezes the whole Mac with it (issue #25).
Fixed
- The HTTP server parsed every request's headers twice — once per received TCP segment. The
header block is now parsed exactly once per request (issue #32). - A DDC/CI write no longer leaves a stale cached read behind: the cache entry is dropped as
soon as the write is accepted, so the next read asks the display rather than the cache
(issue #25).
Documentation
- ADR 0005 records why the HiDPI override is a command model rather than a script: the
ladder, the path and the idempotency check are pure and unit-tested, and only the
executor knows about privilege escalation — so the privileged helper (issue #23) replaces
one type instead of the feature (issue #27). docs/ddc-equivalence.mdaudits FBD's DDC/CI transport against didriksg/Crisp v1.7.1,
component by component: the private symbol, the wire framing, the reply validation, the read
cache, the read quarantine, the write cadence, the bus contention and the display↔channel
matching. Each divergence is either aligned — with the commit that aligned it — or recorded
with the reason the equivalence still holds. The claim it supports is code-verified
equivalence, never hardware verification (issue #24).scripts/ddc-smoke.shis a non-destructive DDC/CI smoke harness: it enumerates the
displays through the app's own matching layer, then per display parses the EDID, parses the
capabilities string and reads brightness, contrast and volume.--write-testadds one
set-and-read-back round trip per feature with the original value restored afterwards,
--jsonprints the machine-readable evidence, and--ledgerappends a timestamped
evidence block todocs/PRIVATE_APIS.md. With no DDC display attached, every check is
skipped and the script exits 0 (issue #26).