Risk register¶
What could make this project wrong, unreproducible, unsafe to share or unfinished, what is already done about it, and what is next. It is a working list. Entries marked Occurred happened during this project and link to the evidence.
How to read it. Likelihood and impact are my qualitative judgements (Low, Medium, High), not measurements. Status is one of: Occurred (it happened, with the fix noted), Open (not yet mitigated), Mitigated (a control exists and is checked), Accepted (a deliberate decision to live with it). A risk's status changes only with evidence.
| ID | Risk | Likelihood | Impact | Status |
|---|---|---|---|---|
| R1 | Results are read as field performance | High | High | Mitigated |
| R2 | Visual fusion is overconfident under GNSS denial | High | High | Accepted |
| R3 | Estimator and generator share a conceptual error | Medium | High | Open |
| R4 | A secret reaches the repository history | Low | High | Occurred |
| R5 | Numbers differ across platforms and break CI | Medium | Medium | Occurred |
| R6 | A snapshot or generated artefact goes stale | High | Medium | Occurred |
| R7 | Tooling drift changes a gate without a code change | Medium | Medium | Occurred |
| R8 | A third-party service fails a check for reasons unrelated to the code | Medium | Low | Occurred |
| R9 | Documentation claims drift from the code | High | Medium | Mitigated |
| R10 | Fault modes the simulator can inject are never measured | High | Medium | Open |
| R11 | Known model defects change published numbers when fixed | High | Medium | Open |
| R12 | Single maintainer | High | Medium | Accepted |
| R13 | Supply chain: unpinned or unattested artefacts | Low | High | Open |
| R14 | Defense-adjacent framing is misread | Medium | High | Mitigated |
| R15 | Scope creeps into SLAM, drivers or learned models | Medium | Medium | Mitigated |
| R16 | The published site is broken and nobody notices | Medium | Low | Open |
| R17 | Prioritisation inputs are wrong | High | Medium | Accepted |
Details¶
R1. Results are read as field performance¶
- Cause and effect. Every input is synthetic, so a reader quotes a number as if it were a measurement of a real system.
- In place. "Not field validated" is on the README, the social preview and Scope and responsible use. LIMITATIONS L1 and L5 state what the data cannot support. REAL_SYSTEMS lists the sim-to-real gap.
- Early warning. A quoted number in a doc or issue with no scenario name next to it.
- Next. P5-01 and P5-02 add the mismatch and fault evidence a real system would need first.
R2. Visual fusion is overconfident under GNSS denial¶
- Cause and effect. The single-anchor filter cannot represent correlated visual drift, so
it reports a small uncertainty while being wrong (headline case: the
outage_visualrow in Results, mean NEES in the hundreds against an expected 3). - In place.
vision_enabledships off (ADR-0003); the failing case is a benchmark row and a pinned test, not a hidden one. - Status reason. Accepted: it is the project's subject. A stochastic clone of the previous pose is calibrated on the fixture when the visual errors are independent, and is kept opt-in (ADR-0017): it is not calibrated when they are correlated over a couple of seconds, and no data here says which a real front end has. So the shipped configuration is unchanged and the risk stays accepted.
- Early warning. Any change that moves the NEES or coverage of
outage_visual.
R3. Estimator and generator share a conceptual error¶
- Cause and effect. One author wrote the filter, the generator and the metrics (LIMITATIONS L10), so a shared wrong assumption would pass.
- In place. The generator is analytic and its IMU output is checked against closed-form kinematics; Jacobians are checked against finite differences; the filter is told the true noise, which is itself a weakness (MODEL.md finding 5).
- Next. P5-01 breaks the "filter knows the true noise" assumption. P5-11 would add an independent estimator; it is not done. The stochastic clone is a live example: it is calibrated against a visual surrogate whose errors are independent, the assumption the filter makes, and it fails when the generator's errors are correlated. The stress cases in the benchmark push on that; a real front end would settle it.
R4. A secret reaches the repository history¶
- What happened. A provider API key was committed in an early commit. It was rotated by
the maintainer; the value is still readable in history (
SECURITY.md, section "Known incident"). - In place.
scripts/scan_secrets.pyruns in CI including history; the one known value is listed as accepted by commit and rule name, never printed. - Residual. History was not rewritten. The key is rotated, so the exposure is closed, but the string remains visible.
R5. Numbers differ across platforms and break CI¶
- What happened. The claimed-sigma series differed by 1.1e-8 between runners and turned test legs red (#33).
- In place. The IMU is analytic so it does not depend on platform trigonometry; the golden snapshot compares with stated tolerances (ADR-0009); CI runs Linux, macOS and Windows.
R6. A snapshot or generated artefact goes stale¶
- What happened. Two merged changes disagreed about the golden file and
mainwent red (#28). Documented test counts also fell behind (#38). - In place. Generated tables are checked against a fresh benchmark in CI and on every Pages
deploy; the golden file has a regeneration procedure in
CONTRIBUTING.md. - Residual. Hand-typed counts in prose still go stale until someone re-measures them.
R7. Tooling drift changes a gate without a code change¶
- What happened. An unpinned linter went from 14 to 131 findings with no change in this
repository, which is why CI installs the pinned extras (see the comment in
.github/workflows/ci.yml). MkDocs Material warns that MkDocs 2.0 removes plugins; the docs extra pinsmkdocs<2. - In place. Pinned extras, SHA-pinned actions, Dependabot for actions, pip and docker.
- Next. Review Dependabot #5 (P5-12).
R8. A third-party service fails a check for reasons unrelated to the code¶
- What happened. The
github-advanced-securitycheck failed on every pull request with a 402 monthly-quota error from GitHub's own code-scanning job. - In place. It is excluded from the recommended required checks in
CONTRIBUTING.md, section "Branch protection".
R9. Documentation claims drift from the code¶
- In place.
scripts/check_doc_tables.py,tests/test_model_doc.py,tests/test_scenarios_doc.py,tests/test_rice.pyand the link checker each turn a class of claim into a failing test. - Residual. Prose that quotes a number with no generator behind it. The early baseline records are excluded from the public site for this reason (P5-09).
R10. Fault modes the simulator can inject are never measured¶
- Cause and effect. The FMEA-lite table in MODEL.md shows spoofing, slow GNSS bias, IMU loss, timestamp offsets and vision outages as unit-tested only. One spoofing case (a modest offset after an outage) is an open problem with an expected-failure test. A slow-ramp spoof is followed in every measured run (slow ramp, ADR-0019).
- Next. P5-02 measures them and reports detection and false-alarm rates.
R11. Known model defects change published numbers when fixed¶
- Cause and effect. MODEL.md records six as-implemented findings (inert bias sigmas, mis-named drift keys, no velocity process noise and others). Fixing any moves the golden snapshot and so every published number.
- Next. P5-04 and P5-05, each with a deliberate regeneration and a review of the diff.
R12. Single maintainer¶
- Cause and effect. One person owns every path (
.github/CODEOWNERS). GitHub does not let an author approve their own pull request, so review is by CI only. - Status reason. Accepted for a portfolio project. The mitigation is that the gates, not a person, are the reviewer, and that decisions are written down as ADRs.
R13. Supply chain: unpinned or unattested artefacts¶
- In place. SHA-pinned actions, dependency review,
pip-audit, a CycloneDX SBOM, CodeQL. - Not done (ADR-0011): signed releases or build
provenance, a base image pinned by digest. There is no lock file;
uv.lockwas removed because nothing used it. - Next. P5-10 before a tagged release.
R14. Defense-adjacent framing is misread¶
- Cause and effect. The subject is navigation under contested GNSS. A reader could take the repository as operational or as controlled content.
- In place. Everything is synthetic, generic and unclassified; the README and Scope and responsible use say so; DUAL_USE_ANALYSIS records the reasoning.
- Residual. Wording is the control, so every new doc needs the same care.
R15. Scope creeps into SLAM, drivers or learned models¶
- In place. The roadmap lists these as deliberately not planned, because the question is whether a classical estimator is honest about itself.
R16. The published site is broken and nobody notices¶
- In place.
mkdocs build --strictruns on every pull request and on every deploy. - Not verified. Deploys succeed in Actions, but the live site has not been opened from the
development environment, which cannot reach
github.io. The maintainer should open it.
R17. Prioritisation inputs are wrong¶
- Cause and effect. The RICE inputs are judgements, so the order can be wrong.
- In place. Prioritisation states this, and shows how many single-input perturbations would change the top three.
- Status reason. Accepted: the score orders the argument, it does not settle it.
Review¶
Update this file in the same pull request as the change that creates or retires a risk. Re-read the whole list before tagging a release.