v0.89.0: pbsdr self-grant (R-22) + escrow config live-reload + agent-plane poke listener (Direction-2a)

- pbsdr: on a 403 pre-check (non-default storage id, no ACL yet) self-grant via the root wrapper then re-read, instead of aborting before the grant — closes F4/R-22. Red-proof TestSelfGrant_PreCheck403DoesNotAbortBeforeGrant.
- escrow preflight: late-bound CurrentPBSStorageID re-reads agent.json so a pbsdr-seeded pbs_storage_id flips the row green in-process (no restart). Red-proof TestEscrowPreflight_PBSStorageIDLiveReload.
- internal/poke: contentless UDP poke listener bound exclusively to the box WG /32 (port 51822), leading-edge debounced, fires the hub-loop out-of-band trigger for an immediate desired-state cycle. First slice of R-13. Red-proofs TestBindConfinement + TestDebounceCoalescesBurst.
This commit is contained in:
2026-07-16 22:47:22 +02:00
parent c040c180e9
commit a659e5dc09
11 changed files with 643 additions and 15 deletions
+7 -6
View File
@@ -81,9 +81,10 @@ func NewLoop(collector collectorIface, client reporter, interval time.Duration,
}
// SetTrigger wires an out-of-band report channel. A receive on it runs one extra
// collect→report cycle immediately WITHOUT disturbing the regular ticker cadence — used by
// the storage watchdog to push a disconnect to the hub in seconds. The watchdog debounces,
// so this fires at most once per debounce window.
// collect→report cycle immediately WITHOUT disturbing the regular ticker cadence. Two producers
// fan into this one channel: the storage watchdog (push a disconnect in seconds) and the
// agent-plane poke listener (v0.89.0 immediate-sync). Both debounce, and the channel is cap-1
// non-blocking, so a burst coalesces to at most one pending extra cycle.
func (l *Loop) SetTrigger(ch <-chan struct{}) { l.trigger = ch }
// SetEnvelopeObserver wires the slice-10A desired-state sync hook. It is called once per cycle
@@ -115,10 +116,10 @@ func (l *Loop) Run(ctx context.Context) error {
ticker.Reset(interval)
}
case <-l.trigger:
// Out-of-band report (storage watchdog). Run a cycle now; keep the regular
// cadence (do not reset the ticker). The envelope's interval is still adopted
// Out-of-band report (storage watchdog OR agent-plane poke). Run a cycle now; keep the
// regular cadence (do not reset the ticker). The envelope's interval is still adopted
// if it changed, mirroring the normal path.
l.logger.Info("hub: out-of-band report triggered (storage watchdog)")
l.logger.Info("hub: out-of-band report triggered (watchdog/poke)")
next := l.cycle(ctx, interval)
if next != interval {
l.logger.Info("hub: poll interval changed", "from", interval, "to", next)