Files
kandev/docs/decisions/2026-08-12-built-in-utility-default-inheritance.md
T
2026-08-13 10:23:45 +01:00

50 lines
2.9 KiB
Markdown

# ADR-2026-08-12-built-in-utility-default-inheritance: Built-in Utility Actions Inherit the Global Profile by Default
**Status:** superseded by 2026-08-12-empty-utility-bindings-inherit-default
**Date:** 2026-08-12
**Area:** backend, frontend
## Context
Profile-backed utility agents can represent an action without a concrete profile override by using
the global default utility profile. The current migration and dependency cleanup paths can instead
mark a built-in action `unconfigured`, so the Utility Agents page shows an unavailable profile even
when a valid default is selected. The system needs to distinguish an empty built-in override from a
stale concrete profile binding so default inheritance remains convenient without weakening the
fail-closed behavior for deleted or disabled profiles.
## Decision
Built-in utility actions with a persisted `inherit` state and no concrete profile ID resolve the
saved global default utility profile. Legacy built-in rows still in the migration state's `explicit`
form with empty, unmatched, or ambiguous agent/model values are normalized to `inherit`; custom rows
with those migration results remain `unconfigured`. Existing `unconfigured` rows are preserved and
fail closed, including when their ID is empty, because an older release could have erased the ID of a
deleted explicit binding and its original intent cannot be recovered safely.
When an explicit profile binding is deleted, the binding keeps its stale profile ID and becomes
`unconfigured`. When the global default profile is deleted, inherited built-in rows remain inherited.
The UI displays the selected default for inherited actions, while concrete stale bindings remain
visible as unavailable and execution continues to fail closed until repaired.
## Consequences
- Legacy built-in actions still in the migration state recover automatically from ambiguous data, and
inherited actions recover automatically from replacement of the global default.
- Selecting a default profile is sufficient for the normal built-in action path; users do not need
to edit every action row.
- Explicit stale bindings remain diagnosable and do not silently change permissions, models, or
credentials.
- Ambiguous empty `unconfigured` rows from older releases remain unavailable until repaired instead
of risking a silent permission or model change.
- Migration and dependency tests must cover both empty inherited rows and stale concrete IDs.
## Alternatives Considered
1. **Keep every legacy migration row unconfigured.** Rejected because built-in rows in the migration
state have no recoverable concrete override when matching is ambiguous.
2. **Make every unconfigured row inherit the default.** Rejected because older releases erased
deleted profile IDs, so an empty unconfigured row could be an explicit stale binding.
3. **Select the first eligible profile during migration.** Rejected because matching profiles can
carry different models, permissions, flags, wrappers, or credentials.