diff --git a/decisions/0016-warn-when-a-tier-resolves-to-no-model.md b/decisions/0016-warn-when-a-tier-resolves-to-no-model.md new file mode 100644 index 0000000..56c8127 --- /dev/null +++ b/decisions/0016-warn-when-a-tier-resolves-to-no-model.md @@ -0,0 +1,44 @@ +# 0016 — Warn when a tier resolves to no model + +Date: 2026-10-07 +Status: accepted + +## Context + +An agent's `tier` resolves per tool through the built-in defaults in +`engine/lib/common.sh` and any `models..` override in +`intelligence.yaml`. A tier that neither source defines — a misspelled `haevy`, +as a rule — rendered an empty `model` for every tool while sync exited 0 and +printed nothing, so the mistake surfaced only when a tool refused the agent or +quietly fell back to its own default (issue #39). Custom tier names are +legitimate: a project may define `models.claude.review-deep` for one tool and +no other. + +## Decision + +1. A tier that resolves to no model still renders, with an empty `model`, and + sync prints one `WARNING:` per tool and tier — naming both and the two ways + out: a standard tier, or a `models..` override. The warning is + deduplicated across every agent carrying the tier. +2. It is a `WARNING:` line, not an indented note, so `sync --compact` and an + unchanged compact run keep it. +3. A tier the manifest defines for a tool resolves quietly for that tool. + +## Consequences + +- A typo is visible on the first sync without blocking anyone's render. +- A project using a custom tier for one tool sees a warning for each other tool + until it defines the tier there too; that is the information it needs. +- Nothing refuses the render, so a project that ignores warnings can still ship + an agent without a model. + +## Rejected + +- **Refusing the sync.** A project that deliberately defines a custom tier for + one tool would fail on every other enabled tool until it added an override + for each. +- **Falling back to `heavy`.** It hides the typo and silently substitutes a + model the author did not choose — costlier than a misspelled `light` or + `standard` meant, weaker than a misspelled `frontier` — and is right only + when the misspelled tier was `heavy` itself. +- **Leaving it silent.** The issue this record closes. diff --git a/engine/lib/common.sh b/engine/lib/common.sh index 116df5a..7b89cb4 100644 --- a/engine/lib/common.sh +++ b/engine/lib/common.sh @@ -1132,7 +1132,7 @@ load_model_tiers() { # the tool has no default for and the manifest overrides nowhere — a typo, as a # rule — still renders an empty model, but never silently: the run warns once # per tool and tier, unindented on purpose because `sync --compact` keeps only -# `WARNING:` lines. +# `WARNING:` lines (decision 0016). # shellcheck disable=SC2034 # IS_MODEL is the return channel read by adapters resolve_model_var() { case "$1" in