112. Harness overlays may set any harness field
Date: 2026-10-01
Status
Accepted
Context
Tasks differ: a typo fix can run cheaper, a security-sensitive change deserves a deeper review (#5777, #2842, agents#497, agents#535) and a listed model is sometimes not served (#6964), yet a repo picks one model and effort per agent (ADR 0091).
Harness overlays: (ADR 0088) already vary a harness per event, but only its forge-oriented fields (field reference), not model or effort. They can already set policy, providers and env from any event field, and the normalized event is gaining change facts the author shapes.
Options
- A separate
routing:policy in.fullsend/config.yaml(#7808): it also routes the runtime, but adds a second conditional mechanism. - Per-prompt routing in the sandbox (#6361), rejected: it reads author-controlled prompts and loses the prompt cache mid-loop.
- Overlays set any field, chosen: routing and every other conditional setting reuse one mechanism.
Decision
- Any field. An overlay may set any harness field except
base,trigger,overlays,slug,roleand the deprecatedforge, which decide how a harness is found, composed or dispatched and stay top level. Field merge rules and ADR 0091's precedence are unchanged, so an overlay can set a field only to a non-empty, non-zero value. - Guarded fields. Guarding stops a change's author from picking which of the harness's branches sets a guarded field. If an overlay keys on something the author controls, like which files changed, they can shape the change to win a looser
policy, a broader token or a skipped scan. So a guarded field can only be set from trusted facts, which neither the author nor the event's actor can choose beyond what their permission allows:runtime.forge,config(from the same trusted ref as OWNERS and the harness) and the event and entity fields (ADR 0098) the normalized event spec lists as trusted. Every field, including any added later, is guarded exceptmodel,effort,descriptionanddoc, which change how well or how cheaply an agent works, not what it may do. Validation fails an overlay that sets a guarded field when itswhen:reads anything else, such as a parent object of an untrusted field or an unresolvable path (event != nullandhas()on an object the schema always requires are allowed); on such an overlay a missing event or key is no match, as today, and any other evaluation error fails the run. - Resolution trace. The plan output and a dedicated span (for example
config.overlay_resolution) record which overlays matched, the names of the fields each set (values only formodelandeffort), and for each of those fields whether it applied, which higher-precedence source overrode it, or, formodelandeffort, that a fallback replaced it (Decision 4). - Routed-model fallback. When the runtime reports that a model an overlay set isn't served, the runner retries the run once with the model and effort it would use without overlays;
FULLSEND_FALLBACK_MODELSapplies as each runtime allows.
Consequences
- Per-task routing needs no mechanism of its own: a harness sets
modelandeffortin overlays keyed on change facts. - A repo routes a built-in agent by composing a custom harness on it through
base:; overriding harness settings without a custom harness is separate work. - An overlay that sets a guarded field from anything but trusted facts fails validation instead of relying on review, while today's built-in,
config-keyed and no-event fall-through overlays keep working. - A change's author can still steer which routing branch applies, so
modelandeffortoverlays can't enforce a floor: security-relevant harnesses should keep their strongest model and effort and any restrictive values at top level, and loosen them only in overlays whosewhen:positively proves a trusted fact; a restriction whose loosened value is false, zero or empty needs a separate harness composed throughbase:. - The runtime and persona models are not harness fields (ADR 0091, ADR 0104, ADR 0126), so overlays cannot route them.
Deferred
- Persona-model routing, with the configuration standardization work in flight rather than a new harness field.
- LLM-based routing isn't decided here (see AISDLC-95) and would need its own ADR.
