pluginsdk/docs/adr/0002-keyed-load-once-hooks-have-durable-host-receipts.md
2026-08-10 23:04:47 +08:00

41 lines
2.1 KiB
Markdown

# Keyed load-once hooks have durable host receipts
Plugin `Load` callbacks are deliberately repeatable: startup, enable, update,
and provisioning-consent replay can all invoke them. Some initialization is
different. A plugin may add a suggested menu link on its first load, but must
not restore that link after an administrator later removes or renames it.
Decision: `PluginRegistration.LoadOnce` is an ordered slice of callbacks with
stable keys. DESCRIBE publishes those keys in `PluginManifest.load_once_keys`.
The host checks a durable `(plugin, key)` receipt before dispatching
`HOOK_LOAD_ONCE`; it records the receipt only after success. A completed key is
not removed when the plugin is disabled, updated, or uninstalled. A later
release that intentionally needs another one-time action declares a new key.
Load-once runs after the ordinary `Load` hook so repeatable provisioning can
create resources that a one-time callback references. Keys are lowercase,
MCP-style stable identifiers of at most 128 bytes and must be unique within a
registration. Failed callbacks may be retried because no completion receipt
exists. As with database migrations, callbacks should still make their own
external mutation idempotent to cover a process failure between the mutation
and receipt commit.
Encoding first-install booleans in plugin settings was rejected because it
mixes host lifecycle state with customer-visible configuration. Making all
provisioner operations one-shot was rejected because pages, settings defaults,
and other declarations intentionally reconcile on every load. Version-based
execution was rejected because an unrelated release must not repeat the side
effect.
Consequences:
- Native and WASM plugins share one keyed lifecycle abstraction.
- The host, not guest memory, owns durable completion state.
- Updating or re-enabling a plugin cannot recreate an administrator-removed
resource under an already completed key.
- Changing a key is an explicit request to run a new callback once.
Keywords: PluginRegistration.LoadOnce, LoadOnceHook, load_once_keys,
HOOK_LOAD_ONCE, durable receipt, first load, plugin update, idempotency,
one-time provisioning, lifecycle