useAsyncControl (hook)

Molecule

State machine behind ControlTile: idle -> pending -> confirmed / mismatch / failed. `commit` returns a Promise (a rejection rolls the display back to the bound `value`); an optional `reported` value keeps the write pending until the other side agrees, else it ends as mismatch after `timeoutMs`; `confirm` parks the value until `accept()` / `dismiss()`. No transport knowledge. Lives in libs/hooks/useAsyncControl.ts.

Success: pending then confirmed

Preview
Heater: off

State: Idle

Code
const ctl = useAsyncControl({ value, commit: async (n) => { await api.write(n); setValue(n); } });

Failure: rolls back (with Retry)

Preview
Heater: off

State: Idle

Code
const ctl = useAsyncControl({ value, commit: () => Promise.reject(new Error('Device offline')) });
// ctl.state === 'failed', ctl.error === 'Device offline', ctl.retry()

Mismatch: the device reports a different value

Preview
Heater: off

State: Idle

Code
const ctl = useAsyncControl({ value, reported: deviceState, timeoutMs: 1500, commit: write });

Confirm before commit

Preview
Heater: off

State: Idle

Code
const ctl = useAsyncControl({ value, confirm: true, commit: write });
// ctl.set(next) -> ctl.awaiting -> ctl.accept() | ctl.dismiss()
Sourcelibs/hooks/useAsyncControl.ts