Settles open questions 5 (the refusal code) and 6 (release ordering) of
0359
and builds its proposed decision 8 (rollback). Decisions 2 and 3 rest on 0359’s proposed
mechanics, so this page stays Proposed until the owner confirms them.
Context
Two codes meant the same thing: the action pipeline refused a structural action on live withlive_read_only, and
the settings resolver refused a write to a non-live setting with setting_live_read_only. ADR 0359 left rollback and a
change set’s minimum release as proposals, and SettingsReader read settings without the market floors that
SettingsResolver applies, so two read paths could disagree on a legal value. The settings pack commands of ADR 0213
had no CLI.
Decision
- One code. A write to read-only live configuration is
live_read_only, the coreLiveReadOnlyErrorof@stackra/errors. The settings resolver raises it with one field error per refused path (live_read_only); the settings-specificSettingLiveReadOnlyErroris retired. - Rollback is a new change set. A promotion diff carries the live snapshot it was computed against (
previous, which hashes to itsbase).Promotable.rollbackOf(live, applied)diffs live now againstapplied.previous; the result is reviewed and applied throughapplylike any promotion, at the same level, so live keeps every applied snapshot. - A minimum release.
diff(live, next, { release })records the platform release the sandbox runs.apply(live, diff, approver, { release })needs live’s release when the diff names one and refuses an older live withpromotion_release_too_old(failed precondition); releases compare as semantic versions. - One reader path honours floors.
SettingsReader#getlifts a value below its market floor exactly asSettingsResolver#getdoes (liftFloors); gen’s wiring binds the reader with theSettingFloorSourceand binds the resolver wherever either is injected. - CLI packs.
stackra settings:diffandsettings:applycallsettingsDiffandsettingsApplyin the member’s@stackra/settings/node: the pack against a scope node’s own values, applied as sandbox revisions with locks checked. That run cannot see the holder’s market, so it refuses any group whose keys carry a legal floor and any group not registered in the process; those go through the service or a promotion.
Consequences
- Clients map one code to one message; the settings form still shows which fields were refused.
- A promotion record stores the replaced snapshot, which makes rollback exact and the record larger.
- A sandbox on a newer release cannot promote configuration live does not understand.
- Runway’s deploy locks for a settings apply remain runway’s work.
Enforcement
packages/state/settings/src/core/services/__tests__/settings-resolver.service.test.ts(live_read_only).packages/state/settings/src/core/drivers/__tests__/settings-promotable.driver.test.ts(rollback, minimum release).packages/state/settings/src/core/services/__tests__/settings-reader.service.test.ts(floors lifted).packages/developer/gen/src/core/functions/__tests__/emit-wiring.function.test.ts(reader and resolver bindings).packages/developer/cli/src/node/constants/__tests__/settings-commands.constant.test.ts.- planned — the ADR 0137 amendment listing
live_read_onlyandapproval_requiredamong the declared refusal codes.
Supersedes and sources
Supersedes: none. Settles 0359 open questions 5 and 6 and builds its decision 8. Sources: STA-779; the wave 10 handover (notes/handover/build-wave10-2026-10-25.md, settings and actions rows); ADR 0213 decision 4.