BOB Sentinel, Agent Worker, and the webhook → dispatcher → worker → review-gate pipeline on Node1. An independent review of authorization, tenant isolation, approval handling, and emergency controls — followed by same-night remediation and live verification.
This review covers one agent family: Scout — the shared identity behind Repository-Monitor-Agent, GitHub-Issue-Agent, and PR-Review-Status-Agent (see agentAliases in sentinel-runtime.json). The other four are shown for ecosystem context; none of them were part of tonight's review.





The review examined the Sentinel authorization gate, the evidence-validated approval flow in Agent Worker, and the read-only webhook pipeline feeding both. Four issues were severe enough to fix immediately: a corrupted route table that had silently disabled two of three monitoring agents, an authorization gate that defaulted to off unless a specific environment variable happened to be set, a tenant-isolation check that could be skipped entirely, and an emergency “safe mode” that, as designed, would not have stopped anything.
All four were fixed the same night, applied to the live services, and verified against the running system — not just against unit tests. A second pass closed five smaller gaps: reviewer-independence, approval replay, a prompt/validator mismatch, injected-language detection, and a hard-coded path that had already caused one of the four critical bugs once.
Three findings remain open by design, not oversight — each is blocked on a decision already made to defer it (see Still open).
All four fixed, applied to the live services, and confirmed via /health and a full three-service safe-mode drill — twice.
BOB_SENTINEL_ENFORCEMENT=1 was set in its environment. Agent Worker already forced this in code; the dispatcher relied entirely on its launch script setting it — with no fail-closed fallback if it didn't.sentinel.enabled: true independent of launch method. 14/14 dispatcher tests pass.issues.* and pull_request.* rules were nested inside wrapper objects the router never inspected. Verified by executing the real router against the real file: only push events routed correctly. GitHub-Issue-Agent and PR-Review-Status-Agent had been silently dark, while the one working canary (a push event) made the whole pipeline look healthy.issues.opened, pull_request.opened, and push all resolve to the correct agent.result.tenant_id was truthy — a missing tenant_id bypassed the check entirely, regardless of the reviewer's own tenant.tenant_unresolved), never a bypass.read. And nothing in the pipeline ever set safeMode: true in the first place — there was no switch to flip.DISABLED file, just shared across all three.enabled: true → file created, all three flip to false within 8 seconds → file removed, all three resume automatically.Second remediation wave — five self-contained fixes, none dependent on undecided architecture. All applied live and covered by new regression tests (31/31 passing).
triggered_by; the gate rejects a reviewer who matches either the agent name or the trigger.approval_already_consumed.Summary:, but the prompt never told the model to use that exact, colon-suffixed format — a latent source of false missing_section findings.reviewer_directed_language_detected to the result's findings, independent of any UI.E:\BOB was duplicated identically across all three services' entry points — exactly the kind of drift that had already caused REV‑02.ROOT and the safe-mode file path; all three services import it.Every fix was applied to the running services — not just tested in isolation — and the emergency switch was drilled end to end, twice.
| Stage | webhook-runtime | agent-dispatcher | agent-worker |
|---|---|---|---|
| Baseline | enabled | enabled | enabled |
| SAFE-MODE engaged (+8s) | disabled | disabled | disabled |
| SAFE-MODE cleared (+8s) | enabled | enabled | enabled |
agent-worker 31/31 · agent-dispatcher 14/14 · webhook-runtime 15/15 · shared-config 2/2
All three services' logs since Sept 17 (2,662 combined entries), plus every quarantine directory.
Clean: every event traces to the two allowlisted repositories. No unexpected agents or targets. Zero quarantine events in the entire history of any of the three services. No duplicate or replayed event IDs. No crash loops. No secrets in any current-format log line.
The two oldest webhook-runtime log lines (Sept 17, from initial webhook setup) contain the full raw GitHub payload instead of the sanitized summary the current code writes — a leftover from before that day's hardening pass. They expose the webhook's public hostname, hooks.loper.family, and repo/owner metadata. GitHub's own redaction meant the actual signing secret was not exposed. Verified all 249 later entries, including today's, are properly sanitized — this affects two lines at rest, not current behavior.
Not fixed tonight because each is blocked on a decision already made to defer it — not because they were missed.