Skip to content

Commit 85e8ebc

Browse files
Sbussisoclaude
andcommitted
sentinel: narrow triggers to the 2 that match the night-guard role
User feedback on the v2 trigger list: - Motion detection: don't add a separate Sentinel threshold; reuse the existing per-camera notification threshold (single source of truth, no drift) - Camera-offline + CloudNode-offline: redundant in the common case (node down → all cameras down) and infrastructure, not security - CloudNode disk almost full: IT problem, not security - MCP API key audit: compliance/audit, not security - Same applies to member-added / role-changed (audit, not security) Right framing: Sentinel is a security role — a "night guard" — not an admin or IT role. Triggers should only fire for events a human guard would actually act on. Infrastructure events and admin events stay in the normal notification channels (in-app inbox, email, MCP log) where they belong. Final trigger list: 1. Motion detected — uses the existing per-camera motion threshold, no separate config. Sentinel-specific extra: per-camera cooldown (limits agent runs per camera, separate from email-digest cadence) 2. Incident opened by a human — agent auto-collects supporting evidence from the relevant cameras, like a guard helping document a report Also dropped: - The "Minimum severity" dropdown on the motion trigger. Motion events don't carry severity in the notification schema (severity is an incident concept), so the control was confused — its inclusion in v2 was a mistake on my part. Updated the cooldown helper text to call out that Sentinel cooldown is separate from email-digest cooldown and governs different concerns. - Section description rewritten to make the philosophy explicit: Sentinel is a guard role, infra/admin events are deliberately routed elsewhere. Future trigger candidates worth keeping in mind for when the notification schema grows: - Camera tampering (sudden blackout, lens covered, camera moved) - Sound / audio anomaly (glass breaking, alarm, raised voices) - Coordinated motion across cameras within seconds - Unknown face / unknown vehicle (when face/plate recognition lands) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent b742567 commit 85e8ebc

1 file changed

Lines changed: 16 additions & 57 deletions

File tree

frontend/src/pages/SentinelPage.jsx

Lines changed: 16 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -10,55 +10,26 @@ import { Link } from "react-router-dom"
1010
// clear so a curious user doesn't think they actually configured
1111
// something.
1212

13+
// Sentinel is intentionally narrow — it's a security role (a "night
14+
// guard"), not an admin or IT role. Triggers only fire for events a
15+
// human security guard would actually act on. Infrastructure events
16+
// (camera offline, node offline, disk low) and admin events (member
17+
// changes, MCP key audits) deliberately go to your normal notification
18+
// channels instead — they're not the agent's job.
1319
const NOTIFICATION_TRIGGERS = [
1420
{
1521
key: "motion",
1622
label: "Motion detected",
1723
description:
18-
"Wake Sentinel when a camera's scene-change scorer crosses its threshold. The most common trigger.",
24+
"Wake Sentinel when a camera reports motion. Uses your existing per-camera motion threshold — there's no separate Sentinel threshold to keep in sync.",
1925
defaultOn: true,
20-
extras: ["severity", "cooldown"],
21-
},
22-
{
23-
key: "camera_offline",
24-
label: "Camera offline / recovered",
25-
description:
26-
"When a camera stops or starts reporting segments — Sentinel can investigate whether it's a hardware issue or something tampered.",
27-
defaultOn: false,
28-
},
29-
{
30-
key: "node_offline",
31-
label: "CloudNode offline / recovered",
32-
description:
33-
"When a node loses or recovers its heartbeat. Useful for confirming whether a power outage explains the gap.",
34-
defaultOn: false,
26+
extras: ["cooldown"],
3527
},
3628
{
3729
key: "incident_opened",
3830
label: "Incident opened by a human",
3931
description:
40-
"When someone files an incident manually, Sentinel can collect supporting evidence from the relevant cameras automatically.",
41-
defaultOn: true,
42-
},
43-
{
44-
key: "cloudnode_disk_low",
45-
label: "CloudNode disk almost full",
46-
description:
47-
"When a node crosses 90% disk usage. Sentinel writes a short triage note so it's easy to act on.",
48-
defaultOn: false,
49-
},
50-
{
51-
key: "member_audit",
52-
label: "Member added / role changed",
53-
description:
54-
"Org membership changes. Useful as an audit-log enricher — Sentinel writes context about what changed and when.",
55-
defaultOn: false,
56-
},
57-
{
58-
key: "mcp_key_audit",
59-
label: "MCP API key created / revoked",
60-
description:
61-
"Security-audit signal. Sentinel notes the timing alongside other recent activity for the audit record.",
32+
"When someone files an incident manually, Sentinel auto-collects supporting evidence from the relevant cameras — like a guard helping document a report.",
6233
defaultOn: true,
6334
},
6435
]
@@ -127,7 +98,6 @@ function SentinelPage() {
12798
const [triggers, setTriggers] = useState(() =>
12899
Object.fromEntries(NOTIFICATION_TRIGGERS.map(t => [t.key, t.defaultOn])),
129100
)
130-
const [motionSeverity, setMotionSeverity] = useState("low")
131101
const [motionCooldownMin, setMotionCooldownMin] = useState(5)
132102

133103
// ── schedule ─────────────────────────────────────────────
@@ -266,10 +236,11 @@ function SentinelPage() {
266236
<div className="sentinel-section-header">
267237
<h2>Triggers</h2>
268238
<p className="section-description">
269-
Pick which Command Center notifications wake Sentinel up. Each event
270-
flows through your existing audience filter and email gate before
271-
reaching the agent — Sentinel sees only what your org is already
272-
configured to receive.
239+
Sentinel responds only to security-relevant events — it's a guard
240+
role, not an admin role. Infrastructure issues (camera offline,
241+
disk almost full) and admin events (member changes, MCP key audits)
242+
still flow through your normal notification channels; they're just
243+
not the agent's job.
273244
</p>
274245
</div>
275246
<div className="settings-toggles">
@@ -288,19 +259,6 @@ function SentinelPage() {
288259
</label>
289260
{t.key === "motion" && triggers.motion && enabled && (
290261
<div className="sentinel-trigger-extras">
291-
<div className="sentinel-trigger-extra">
292-
<label htmlFor="motion-severity">Minimum severity</label>
293-
<select
294-
id="motion-severity"
295-
className="settings-select"
296-
value={motionSeverity}
297-
onChange={e => setMotionSeverity(e.target.value)}
298-
>
299-
<option value="low">Low (every event)</option>
300-
<option value="medium">Medium and above</option>
301-
<option value="high">High and above</option>
302-
</select>
303-
</div>
304262
<div className="sentinel-trigger-extra">
305263
<label htmlFor="motion-cooldown">Per-camera cooldown</label>
306264
<div className="sentinel-trigger-cooldown">
@@ -318,7 +276,8 @@ function SentinelPage() {
318276
<p className="sentinel-trigger-extra-help">
319277
A noisy outdoor camera can fire many motion events per minute. Cooldown
320278
keeps Sentinel from running over and over for the same camera within
321-
the window.
279+
the window — separate from your email-digest cooldown, which governs
280+
notification volume rather than agent runs.
322281
</p>
323282
</div>
324283
)}

0 commit comments

Comments
 (0)