Skip to content

FBD 2.1.0

Choose a tag to compare

@github-actions github-actions released this 20 Oct 12:22
· 23 commits to main since this release

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 carries null plus 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|codex writes an agent-ready SKILL.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; --print writes 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-display disconnect/reconnect action (with remember), a hidpi action
    (install, remove, status) and a gamma-floor action (enabled, optional threshold).
    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> reconnect and
    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-token no longer prints the API token to stdout. It now explains how to obtain
    it; --reveal prints 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 the fbd:// 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.md audits 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.sh is 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-test adds one
    set-and-read-back round trip per feature with the original value restored afterwards,
    --json prints the machine-readable evidence, and --ledger appends a timestamped
    evidence block to docs/PRIVATE_APIS.md. With no DDC display attached, every check is
    skipped and the script exits 0 (issue #26).