Skip to content

Release 1.19.1 - #43

Merged
bethropolis merged 10 commits into
mainfrom
dev/next
Sep 21, 2026
Merged

bethropolis merged 10 commits into
mainfrom
dev/next

Conversation

@bethropolis

@bethropolis bethropolis commented Sep 21, 2026 •

Copy link
Copy Markdown
Owner

Seams, fixes, and features since v1.19.0, all green locally (vet, unit, integration+race, lint, static, goreleaser check):

Refactors (no behavior change):

Fixes:

Features/docs:

Single logging seam over zap (kept as backend): Logger value type,
Field alias, level ownership (New/SetLevel), Nop/NewDevelopment/NewTest
helpers. ~80 call-site files converted mechanically, no behavior change.
depguard forbids direct go.uber.org/zap imports outside internal/log.
AGENTS.md rule 10 + constructor table updated.
)

Collapse the decode -> plugin -> device preamble repeated across all
34 daemon IPC handlers into two generic helpers plus a jsonOK response
constructor. GetDeviceID accessors on ipc payloads (named types for the
two anonymous remotevolume payloads). Disabled-plugin errors derived
from the registry name; all error strings match docs/IPC_PROTOCOL.md
byte-for-byte. Table-driven helper tests lock the contract.
…where (#37)

Add protocol.DefaultTCPPort/DefaultSidechannelPortMin/Max; config
defaults reference them. Thread cfg.TCPPort into the UDP discovery
listener, broadcast destinations, pair-dial fallback, and doctor port
checks (previously hardcoded 1716, so a custom tcp_port left discovery
and doctor probing the wrong port). Share firewall hints now render the
configured side-channel range. Tests lock defaults, controller port
plumbing, and doctor check names; verified live with a tcp_port=1816
daemon (TCP+UDP listen, strace-confirmed broadcasts to :1816).
Add plugin.RunCommandOutput (stdout-only, ctx-bound) alongside Sync/Async
and migrate all sites the seam can express: mousepad, presenter
(move+probes), lockdevice (handle/lock/unlock/query), systemvolume
(getters+setters), notification help-probe, sftp fusermount cleanup,
findthisdevice alarm+unmute. Previously unbounded Background contexts
now carry 10s bounds (existing 5s/30s ctxs preserved). Hand-rolled exec
remains only where the seam is inexpressive (stdin piping, Start-detach,
custom Env/WaitDelay, injectable newExec, streaming supervisor) —
pinned in docs/ARCHITECTURE.md subprocess policy. Seam unit tests lock
stdout-purity, combined-on-error, and async non-blocking.
Replace bare duration literals with named constants (values unchanged):
discoveryDialMinInterval, reconnectBackoffBase, defaultIdleInterval
(shared by controller + broadcaster fallback), defaultPairListenTimeout,
defaultDispatchTimeout, defaultSetupTimeout, doctor probe budgets.
Collapse the duplicated TCP keepalive block (listener + dialer) into
transport.SetTCPKeepAlive so both ends stay symmetric. Already-named
device consts, config-driven network timeouts, per-plugin Timeout
methods, and test-only sleeps untouched.
vCard 2.1 contacts with ENCODING=QUOTED-PRINTABLE kept their =XX
escapes intact (issue #38). parseVCard now inspects field parameters
and RFC 2045-decodes QP values before display cleanup, fusing soft
breaks with line folding. Malformed QP keeps the raw value instead of
dropping the contact. Regression test uses the issue's example vector
(which decodes to 'Davíd Ireland', not 'David Íreland' as reported).
Delete a device's cached address book via new contacts_clear IPC command
(pluginRoute: offline-capable, reuses DevicePayload), Client.ContactsClear,
and kcd contacts clear <device-id> (reports the cleared count, then the
standard empty-list hint). Wraps the existing ForgetDevice used on unpair.
Docs: IPC_PROTOCOL, CLIENT_GUIDE, CLI command reference.
* fix(mpris): reconcile tracked players with the session bus

The D-Bus watcher enumerated players once at startup and thereafter relied
solely on NameOwnerChanged signals. Any missed signal, duplicate-instance
churn race (Firefox instance_N), or event gap left p.players permanently
out of sync - and the polling loop skips an empty map, so the phone ended
up with stale or no media state until the next daemon restart.

Run a 15s reconciliation tick inside the watcher loop: re-list bus names,
add untracked players through the signal-handler path (match rules plus
broadcast so the phone learns about them), and drop ghosts. Removal is
guarded on the tracked bus name so a same-named live player is never
evicted by its dead twin, and a failed listing never prunes. The diff is
a pure function covered by unit tests.

* fix(mpris): event-driven reconcile, no polling tick

Replace the 15s reconcile ticker with event-driven healing: the watcher
loop owns conn/uniqueToDisplay and re-lists on a coalescing nudge channel.
Triggers: incoming requestPlayerList (every phone query answered from fresh
truth), unknown-sender PropertiesChanged/Seeked (drift evidence), device
OnConnect, and CmdMprisRemote (kcd mpris list/status). Handle stays
non-blocking per the plugin contract; answers converge in two steps.
AddMatchSignal failures are logged instead of discarded.
Derived from the nix-verify failure output (got: sha256-6zwz...); go.mod
and go.sum are unchanged since that run, so the hash applies to the
current tree.
…script

- .goreleaser.yaml: install instructions move from header to footer so
  release notes lead with the changelog.
- README: contacts feature row; index the missing CLIENT_GUIDE and
  IPC_PROTOCOL docs in Further Reading.
- nautilus-kcd.py: proper file:// URI parsing, skip directories (share
  rejects them), name fallbacks, top-level time import.
@bethropolis
bethropolis merged commit 5eb7b26 into main Sep 21, 2026
9 checks passed
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