Inspiration

It's 6:59. You reach for the door. A camera on your front steps saw something a while ago, and an AI described it. Should that change what you do right now?

Most "smart camera" projects ask what did the camera see? We wanted to ask a harder question:

Has this evidence earned the right to influence the decision?

A description is not a decision. The picture might be 40 minutes old, come from a camera that isn't assigned to this entrance, or describe something the weather can't support. So we built a system that refuses to pretend when the evidence is missing, unusable, out of date or unsupported, and says why. FirstStep never says a surface is safe, and it never claims a camera detects ice.

What it does

FirstStep is a pre-departure entryway advisory built on one rule: AI describes. Physics decides. Policy advises.

  • Ring supplies the evidence: a real event and snapshot from the Ring Playground.
  • Amazon Bedrock (Nova Pro) returns observations only (wet, frost, snow, obstruction), under a strict schema. It never returns a verdict, and any extra key such as "ice", "risk" or "safe" makes the answer invalid.
  • A context check confirms the picture belongs to the camera configured for this entrance.
  • A deterministic Risk Engine alone decides the hazard level.
  • A separate Policy decides what to tell you, in fixed, non-reassuring wording, and marks results that have gone out of date.

The demo shows two moments from one recorded morning: in one, camera evidence earns a one-step raise; in the other it looks just as useful but is refused, because it is too old to count.

On the deployed AWS path, a real Ring snapshot and a real Bedrock call reported snow. FirstStep did not raise the risk, because the weather did not support it (NOT_SUPPORTED_BY_PHYSICS). The observation was accepted as an observation and rejected as decision-changing evidence.

How we built it

One authority per decision, enforced by an architecture checker that fails the build if a module reaches into another's job:

Decision Sole owner
Hazard level Risk Engine
Freshness, trend Temporal State
Does an interpretation apply to this media? Fusion
Observations Bedrock
What to tell the person Policy

Evidence may influence the level only if it is fresh (observed no more than 30 minutes before the assessment), the physics is already at least MODERATE, and the observation reports frost or snow. Even then it can raise the level by one step, never above ELEVATED, and it can never lower it.

the physics is already at least MODERATE, and the observation reports frost or snow. Even then it can raise the level by one step, never above ELEVATED, and it can never lower it.

On AWS (one CDK stack): EventBridge Scheduler runs a weather-only check; a separate Live function polls Ring, calls Bedrock, and runs the same Risk and Policy path. DynamoDB keeps the history, S3 keeps sealed run bundles, SNS carries advisories, Secrets Manager holds a short-lived Ring token, and CloudWatch collects logs.

Everything is replayable. Each run is sealed as a content-hashed bundle. Replaying it offline, with the network blocked and no model call, gives the identical result. Change one value and the bundle is refused with BUNDLE_HASH_MISMATCH.

Challenges we ran into

  • Ring Playground friction. The snapshot request body is undocumented and its error message misleading. Tokens stopped working after minutes. Event History took about 75 seconds to show a new event. Playground events are on_demand, so push-style triggers could not be tested. We logged all of it: 40 entries in docs/FRICTION_LOG.md.
  • Not overclaiming. A simulated Ring scene and recorded weather can prove the logic, not real-world accuracy. Every output carries a source label (HISTORICAL_REPLAY, RING_PLAYGROUND, BEDROCK, SYNTHETIC_*), so a replay can never read as live.
  • Real runs that ended in refusal. Our first cloud runs ended in RING_AUTH_FAILED, RING_AUTH_MISSING and EVENT_NOT_VISIBLE. We kept them all as honest results rather than hiding them.
  • Least privilege. Even a scoped CDK deployment hit an undocumented bootstrap permission.

Accomplishments that we're proud of

  • A refusal that is visible: the demo shows evidence being rejected, and why, as clearly as it shows evidence being accepted.
  • A real end-to-end cloud run: real Ring snapshot, real Bedrock call, sealed bundle, identical offline replay, and a tampered bundle refused.
  • 773 tests and 475 mutation probes, every probe killed. We deliberately break the rules (let the model lower risk, treat stale evidence as fresh, treat UNKNOWN as LOW) and the checks catch it.
  • A clean public repository with architecture, provenance and secret-hygiene checks, verified from a fresh clone.

What we learned

The valuable part of an AI system is often not the model but the boundary around it: who may decide what, what counts as admissible evidence, and what happens when the evidence isn't good enough. Making refusal a first-class, replayable outcome turned out to be more convincing than any detection claim.

We also learned to treat labels as part of the product: a number is only honest if you can see where its inputs came from.

What's next for FirstStep

  • A live, event-driven trigger once Ring events can be pushed from the Playground.
  • A real, unseen winter for measured evaluation. Today the rules are product-model assumptions and performance is not validated.
  • A verified end-to-end notification delivery path (the advisory topic exists, but we make no delivery claim yet).
  • A camera that is physically verified for the entrance, rather than declared in configuration.

Built With

Share this project:

Updates

Submission history