did-btcr2-js

ADR 073: CAS Publication Is Opt-In - Default publishToCas to ‘never’ and Make ‘auto’ Non-Blocking

Status: Accepted

Date: 2026-07-07

Branch / PR: feat/cli-cas-rpc-url

References: ADR 070, ADR 071

Context

ADR 071 introduced the api’s publishToCas policy with a default of 'auto', where 'auto' publishes when a writable CAS is configured and, for CAS beacons only, throws up-front when no writable CAS is available. The stated reasoning was that a CAS beacon signal points at an announcement that “must be retrievable somewhere,” so refusing to broadcast prevents a resolution failure.

That reasoning was wrong on the method’s own principle: CAS publication is optional and never required. Every update, for every beacon type including a CAS beacon, can be completed and distributed entirely via sidecar. A CAS beacon’s announcement is returned in DidUpdateResult.announcement precisely so the caller can distribute it out-of-band; sidecar-only distribution is a first-class, always-available path, not a footgun to be guarded against.

Under ADR 071’s default, two behaviors violated that principle:

  1. Publishing happened without being asked. With the default 'auto' and any writable CAS configured (including one set up only for reads), every canonical signed update was published to a possibly-public store as a side effect of configuration. That is opt-out.
  2. Sidecar-only was blocked for CAS beacons. With the default 'auto', a CAS beacon update with no writable CAS threw up-front. Completing it sidecar-only required explicitly passing 'never'. That makes CAS publication effectively required for CAS beacons, contradicting “never required.”

In short, ADR 071 made CAS publication opt-out (and mandatory for one beacon type), when it must be opt-in.

Decision

  1. The default is 'never'. Out of the box, DidMethodApi.update, DidBtcr2Api.updateDid, and UpdateBuilder publish nothing. A configured CAS never causes publication on its own; the caller opts in explicitly.

  2. 'auto' is best-effort and never blocks. It publishes the signed update (all beacon types) and the CAS Announcement (CAS beacons) when a writable CAS is configured; otherwise it skips publication silently for every beacon type (CAS beacons included) and returns the artifacts for sidecar distribution. The CAS-beacon up-front throw from ADR 071 is removed.

  3. 'always' is unchanged. It requires a writable CAS and throws up-front for every beacon type when none is available. This is the explicit opt-in for a hard guarantee that the artifacts reached the CAS; the caller asked for a promise that cannot be met, so failing is correct.

Resulting policy:

Policy Writable CAS Read-only / no CAS
'never' (default) publish nothing publish nothing
'auto' publish update (+ announcement for CAS) skip silently, all beacon types
'always' publish update (+ announcement for CAS) throw up-front, all beacon types

This supersedes ADR 071’s decision 2 (the 'auto' default and its CAS-beacon asymmetry). ADR 071’s other decisions (the canPublish/writable capability detection, the update-then-announcement-then-broadcast ordering, the enriched DidUpdateResult, broadcastOptions passthrough, and the resolve() NeedSMTProof fail-fast) stand unchanged.

Consequences

Rejected alternatives