<feed xmlns='http://www.w3.org/2005/Atom'>
<title>luke/mattertimesync/package-lock.json, branch v0.1.0</title>
<subtitle>Unnamed repository; edit this file 'description' to name the repository.
</subtitle>
<id>https://src.nth.io/luke/mattertimesync/atom?h=v0.1.0</id>
<link rel='self' href='https://src.nth.io/luke/mattertimesync/atom?h=v0.1.0'/>
<link rel='alternate' type='text/html' href='https://src.nth.io/luke/mattertimesync/'/>
<updated>2026-07-26T16:44:49+00:00</updated>
<entry>
<title>Implement mattertimesync: one-shot Matter time synchronization CLI</title>
<updated>2026-07-26T16:44:49+00:00</updated>
<author>
<name>Luke Hoersten</name>
<email>luke@hoersten.org</email>
</author>
<published>2026-07-26T10:38:33+00:00</published>
<link rel='alternate' type='text/html' href='https://src.nth.io/luke/mattertimesync/commit/?id=0af1cf3b1e2b471f2bc06abb16520035efff252e'/>
<id>urn:sha1:0af1cf3b1e2b471f2bc06abb16520035efff252e</id>
<content type='text'>
A standalone CLI Matter controller that joins Matter devices' existing
setups as a secondary administrator (multi-admin) and sets their clocks
via the standard Time Synchronization cluster. Built on matter.js 0.17.6
using the CommissioningController API. One-shot runs from a systemd
timer, no daemon: being a secondary controller is fabric membership, not
a running process, so each invocation loads the persisted keys,
discovers the device via operational DNS-SD, opens a fresh CASE session,
does its work, and exits.

- TypeScript scaffold: strict tsc, oxlint, prettier, vitest (51 tests:
  Matter epoch conversion, config validation, IANA timezone offsets and
  exact DST transition search, atomic state writes, pairing-code
  parsing, clock-delta reporting)
- Validated JSON configuration with bigint-safe values; unknown fields
  rejected loudly
- Persistent controller fabric with the same identity across restarts.
  The fabric doubles as the device registry: every node commissioned
  onto it is kept in sync, and membership changes only through
  commission and decommission, so no separate device list can drift
- On-network multi-admin commissioning from a manual or QR pairing code;
  any number of devices, one per-device pairing code each. A device
  already on the fabric rejects re-commissioning via fabric conflict
- Commands: nodes, inspect (human/JSON), status, fabrics (reads the
  Operational Credentials fabric table, marks our own entry by fabric ID
  plus root public key, flags likely-stale orphans, and removes them
  with --remove), and decommission (device drops our fabric while
  staying paired to its primary ecosystem). --node selects a device
  where relevant; optional while only one is commissioned
- sync delta reporting: reads the device utcTime before writing and
  reports device time before, time written, and the delta with
  direction, e.g. "device clock was 1m 23s behind". Handles unset clocks
  after power loss and wrong-epoch garbage in exact bigint microseconds.
  The Time Synchronization write commands themselves still await
  real-device capability inspection
- systemd oneshot service (dedicated non-root user, hardening) plus
  hourly timer with randomized delay
- Deployment as a single esbuild bundle (mattertimesync.mjs, ~4.5 MB):
  all runtime deps are pure JavaScript, so the target needs only
  Node 20+, with no npm, registry access, or build toolchain. The Bun
  sqlite driver stays external behind its runtime guard so the bundle
  runs under plain Node. npm pack remains an alternative install path
</content>
</entry>
</feed>
