Fallbacks Are Product Decisions

Fallbacks are product decisions

A fallback in a mutation path is product policy. It decides what the system may do on the user's behalf when the intended target is missing.

For reads, a loose fallback can be acceptable: use cached data, show partial results, retry a secondary provider. For writes and real-world side effects, loose fallback is dangerous. "Use some available target" can mean play music on the wrong device, edit the wrong record, charge the wrong account, or message the wrong person.

The rule

Fail closed on mutation targets.

If the user intended a specific target, the system can use exact matches, explicitly configured aliases, or strongly owned local identity. It should not silently pick an unrelated available target because that target happens to be valid.

What to do instead

Failure is not evidence

An unavailable model, malformed response, timeout, or failed tool call is an operational failure. It is not evidence that a policy condition is false, unknown, or absent. Converting one into the other can make a deterministic policy produce a confident but invalid result.

Keep failure states explicit, then let product policy decide whether to retry, fail closed, ask for human review, or return an honest unavailable result. See Governed Agent Architecture.

Spotuify example

In Spotuify, pressing play in the TUI should target the daemon's embedded librespot device or a configured/active Spotify Connect device. If the daemon's device is not visible, falling through to another unrestricted device is surprising and wrong: it can start playback in some other room or on some other client.

The code now encodes that policy: device selection prefers the daemon-owned device id, active unrestricted devices, configured names, and spotuify/librespot name markers. If none match, it returns no target.

Where this generalizes

See also