Project C: guardian
The last project, and the hardest. guardian is a forward-collision
warning arbiter. It takes noisy object tracks from a simulated
perception stack, estimates time-to-collision, and every 50 ms cycle it
picks one of three answers: NoAction, Warn, or Brake.
Two things make this the hardest project of the course:
- The input is stochastic. The provided sensor simulator is noisy by design. The same scenario never plays out twice, so a test that asserts an exact outcome passes or fails by chance.
- Correctness is a distribution. The question isn’t “did it warn?” but “does it warn often enough, and false-alarm rarely enough, across many runs?” That’s also how the real systems in this domain are judged.
The next page places the project in its ISO 26262 context: the assumed ASIL, the decomposition our architecture follows, and where generated code may sit inside that structure.
Before the agent joins, your skeleton has to answer some questions in types. Same interview discipline as Projects A and B, pointed at this domain. These questions stay out of the starter on purpose: they’re for you to answer, not the agent.
- What state does the arbiter carry between cycles, if any, and why?
- What is the signature of one cycle’s decision?
- Which thresholds exist, what are their types and units, and who
decided their values? Using
f64everywhere is also a choice, and rarely the right one. - What can fail, and what counts as absence rather than failure? No tracks this cycle and one channel reporting nothing are both normal.
- The two channels report the same world. When they disagree, which one does your design believe, and what does it do while one channel reports nothing?
Three-hour workshop route
The starter now provides the mechanical multi-seed metrics runner. You review its metric semantics, but you do not spend the afternoon writing trial loops, CLI parsing, or output formatting. Your work is the arbiter, its policy, its tests, and the evidence connecting them.
The complete afternoon is three hours, including the break and debrief:
| Stage | Budget |
|---|---|
| Safety frame and acceptance claims | 10 minutes |
| Audit the prepared runner’s metric semantics | 10 minutes |
| Skeleton and agent-assisted first pass | 25 minutes |
| Deterministic test and 200-trial baseline | 20 minutes |
| Replay one bad seed and amend the policy | 15 minutes |
| Break | 10 minutes |
| Implement one deliberate stateful revision | 30 minutes |
| Add or review two properties | 18 minutes |
| Final metrics and compact safety case | 12 minutes |
| Debrief | 30 minutes |
Passing every acceptance row is still the product target, but it is not the workshop completion criterion. A measured failure, a replayed seed, a written policy amendment, and a defensible evidence gap are useful outcomes. Hiding a failure to finish more code is not.
In this project we practice:
- The whole course so far, under domain pressure: the state machine is an enum (or typestate), the thresholds are newtypes, and the arbiter’s signature is the spec.
- Testing a stochastic system: property-based tests for invariants that must always hold, measured behavior over replayable trials, and a clear distinction between a measured rate and a statistically supported claim.
- Recognizing when the agent’s tests are green but test nothing that matters.