The pass-2 secret-availability gate closed the stop-then-fail-at-respawn
class for the record-derivable tiers (instance, definition, harness) but
left two gaps:
1. Global tier: both post-install restart checks loaded the global config
with unwrap_or_default() while spawn_agent_child reloads it strictly, so
a restart authorized while the global ref was unavailable — even for an
unrelated secret — would stop a live process only to hit the spawn
refusal (FailedAfterStop). The global-config-save flow's under-lock
recheck reused phase-1 snapshots and never re-attested the committed
global ref before the stop.
2. The four production restart-gate call sites consulted
effective_secrets_unavailable at the call site, so mutating any single
call did not fail a test — only the pure predicate was bound.
Add refuse_restart_on_unavailable_global (mirrors
refuse_save_on_unavailable_current) and route the strict global load
through it at both post-install sites and the global-config under-lock
recheck. Consolidate each flow's secret consultation into AppHandle-free
composed seams (should_restart_after_install_for,
refuse_restart_on_unavailable_secrets,
should_restart_on_config_change_for) so the consultation lives in one
testable place, and bind each with record-driven regressions.
Global availability stays a separate strict Result gate rather than a
fourth arm of effective_secrets_unavailable — it is not derivable from a
record.
Co-authored-by: Will Pfleger <pfleger.will@gmail.com>
Signed-off-by: Will Pfleger <pfleger.will@gmail.com>