Bootstrap-Wiring Trace (Ghost-Wired Settings Gate)¶
A registered setting whose consuming machinery exists but is never instantiated at boot is ghost-wired: the value resolves cleanly through the configuration precedence chain, but no code path that reads it ever runs in default config. Import-graph traces find the consumer code but miss that its owning service is never started, so a static "find references" walk cannot distinguish a live consumer from a ghost-wired one.
scripts/check_setting_to_startup_trace.py is the standing gate. Pre-push and CI; it mirrors the check_persistence_boundary.py shape.
What it catches¶
The lint detects two ghost-service patterns in lifecycle/app wiring, then matches settings to those ghosts via three matchers (first hit wins). Settings unrelated to a known ghost service pass silently; the lint never flags a setting in isolation.
Ghost-service patterns:
- Hardcoded-None ghost. A service variable
x: T | None = Nonepaired with a conditionalif x is not None: x.start(). The guard always evaluates False, so any setting consumed inside the would-be service is dead at runtime even though the consumer code exists. - Factory-gated ghost. A factory
build_x(config) -> T | NonewhoseNonebranch fires when a registered default-disabled flag is False: in default config the factory returnsNone, the start gate short-circuits, and every setting in the factory's gating namespace is dead.
Fixing a ghost-wired service means: drop the factory's early return (or the hardcoded None), construct the service unconditionally, gate the behaviour internally on the runtime flag, and wire a live SettingsSubscriber so operator changes take effect without restart. See BackupService (backup/factory.py + backup/service.py + BackupSettingsSubscriber) and ApprovalTimeoutScheduler (constructed in api/app.py, interval applied at boot via _apply_security_timeout_interval in lifecycle_helpers.py, live-tuned via SecurityTimeoutSettingsSubscriber) for end-to-end references.
Setting -> ghost matchers (run in order; first hit wins):
- Gating-namespace match (factory ghosts only). Every setting whose
namespaceequals the factory's gating namespace is ghost-wired when the gating flag's registered default is False. - Class-file containment match (hardcoded-None ghosts only). A setting is ghost-wired iff its
keyappears as a substring in the ghost class's source file AND itsnamespaceappears in that file's path. - Direct ConfigResolver consumer match (Pattern A; both ghost kinds). The lint scans the ghost class's source file for
ConfigResolver.get_*("<ns>", "<key>")calls (resolving both string literals ANDSettingNamespace.X.valuereferences); if any (ns, key) matches a registered setting, that setting flags as ghost-wired. Catches cross-namespace consumption: a ghost class inapi/foo.pythat readsengine.Xwould not match either gating-namespace or class-file containment, but the direct ConfigResolver call surfaces it.
When debugging a Pattern A flag, search the ghost class's source for ConfigResolver.get_*("<flagged_ns>", "<flagged_key>") calls and verify whether the consumer should migrate to a real unconditionally-started service or whether the gating service should be wired at boot.
read_only_post_init=True settings are skipped by design (registry entry exists for /settings UI introspection; mutation is rejected at runtime, no live consumer required).
Suppression marker¶
Per-setting opt-out: append a trailing comment on the _r.register(...) closing line:
_r.register(
SettingDefinition(
namespace=SettingNamespace.X,
key="discoverability_only_setting",
...,
)
) # lint-allow: bootstrap-wiring -- explanation here
The justification after -- is required and must be non-empty. It mirrors the # lint-allow: persistence-boundary contract.
Baseline file¶
scripts/setting_to_startup_trace_baseline.txt freezes the pre-existing violations so the lint can ship without forcing the wiring fix in the same PR. Format: one entry per line, <key>:<kind>:<owning_class>, sorted lexicographically.
Lint behaviour:
- Pass when current violations are a subset of baseline.
- Fail (exit 1) listing only the new violations when current is not a subset of baseline.
- Warn (stderr) but pass when baseline contains stale entries (a fix landed and the violation no longer exists). Regenerate the baseline via
--update-baselineonce the wiring is fixed.
uv run python scripts/check_setting_to_startup_trace.py
uv run python scripts/check_setting_to_startup_trace.py --update-baseline
--update-baseline requires explicit user approval to commit the diff. Do not run it casually: the baseline is the lint's frozen authority.