MICROBOTICA (MICROROBOTics Iterative simulation for Clinical Adoption) is a C++17/Qt 6.6 open-source research simulator for microrobot-assisted drug delivery in cerebrospinal fluid and other confined biological geometries. It occupies Layer 3 of a four-layer open-source stack:
Layer 1 — MADDENING (Python, JAX, LGPL-3.0)
JAX-based differentiable multiphysics graph framework.
Near-complete. JOSS/arXiv target.
Has its own DOCUMENTATION_ARCHITECTURE.md.
Layer 2 — MIME (Python, LGPL-3.0)
MIcrorobotics Multiphysics Engine. Built on MADDENING.
Not yet started. IEC 62304 Class C SaMD compliance target.
Layer 3 — MICROBOTICA (C++17 / Qt 6.6, AGPL-3.0) ← THIS PROJECT
Open-source research simulator.
Inspired by NVIDIA Omniverse; OpenUSD as primary scene format.
Not a medical device. Research platform only.
Layer 4 — Commercial Product (future, by a spin-out or licensee)
CE-marked SaMD built on top of the open-source stack.
Bears all EU MDR obligations.
Not our responsibility, but everything we write must support it.
MICROBOTICA serves three audiences simultaneously: researchers building and running microrobotics simulations; developers extending the platform with new physics backends, render backends, or compute backends; and downstream commercial manufacturers who need to cite MICROBOTICA's verification record in regulatory submissions — without MICROBOTICA itself making any clinical claims.
Regulatory context: The developer is EU-based (Netherlands). EU MDR (EU 2017/745) is the primary regulatory framework. A commercial product built on top of MICROBOTICA would face EU MDR Class III classification for the most demanding plausible use case: intraoperative digital twin or RL policy validation for a device operating in the central nervous system, where erroneous output could cause irreversible neurological harm or death. The documentation architecture must be designed to support this most demanding plausible classification so that less demanding use cases are automatically covered.
Under IEC 62304, when any downstream commercial manufacturer incorporates MICROBOTICA into a regulated product, MICROBOTICA is classified as SOUP (Software of Unknown Provenance). For a Class III device, MICROBOTICA will almost certainly be classified as IEC 62304 Class C SOUP, carrying the most stringent lifecycle documentation requirements. MICROBOTICA's documentation must therefore be structured to satisfy Class C SOUP assessment requirements for any downstream commercial manufacturer.
Relationship to MADDENING's documentation architecture: This document inherits structural patterns, regulatory boundary language, and compliance schema conventions from MADDENING's DOCUMENTATION_ARCHITECTURE.md. Where a section is directly inherited, this is stated explicitly. Where a section is adapted for the C++/Qt application domain, the adaptation rationale is documented. Where a section is new (no MADDENING equivalent), the design rationale is provided from first principles. This document is self-contained — it can be read without MADDENING's document, though references are provided for deeper context.
This plan is informed by the same regulatory standards as MADDENING: ASME V&V 40, FDA computational modeling guidance (2016, 2023), IEC 62304:2006+AMD1:2015, EU MDR (EU 2017/745), MDCG 2019-11, MDCG 2019-16, IMDRF SaMD N10/N12/N23, EN ISO 13485:2016, IEC 62366-1:2015 (usability engineering, new for MICROBOTICA), and ISO 14971:2019.
- Documentation Structure
- Regulatory Boundary Language
- Component Documentation Standards
- V&V Documentation Hooks
- Versioning and API Stability
- Contributor and Extensibility Documentation
- README and Repository-Level Documentation
- Code-Embedded Documentation and Structural Hooks
- Rendering Pipeline Correctness Documentation
- Python Scripting API Contract
- Cloud Provenance Documentation
- IEC 62304 SOUP Compliance Package
- IEC 62304 Software Lifecycle Documentation Mapping
- EU MDR Annex I and Annex II Alignment
- MDCG 2019-11: Qualification and Classification
- Configuration Management
- QMS Compatibility
- Downstream Integration Guide
Appendices:
- A: Inheritance from MADDENING Summary Table
- B: Implementation Priority
- C: Architectural Concern Resolutions
- D: Project Setup Checklist
This section adapts MADDENING Section 1 for a C++/Qt application. The three-tier documentation model (API reference, component guide, executable examples) is preserved; the tooling changes from Python/Sphinx-autodoc to C++/Doxygen/Breathe.
MICROBOTICA adopts the same three-tier documentation model as MADDENING, adapted for C++17 and Qt 6.6:
MICROBOTICA/
├── README.md # Project overview + disclaimers
├── DESIGN.md # Architecture decisions
├── ROADMAP.md # Feature roadmap
├── CHANGELOG.md # Structured changelog
├── CITATION.cff # Academic citation metadata
├── GOVERNANCE.md # Decision-making process
├── CONTRIBUTING.md # Contributor guide
├── SECURITY.md # Security reporting
├── LICENSE # AGPL-3.0-or-later
├── CMakeLists.txt # Root build file
├── Doxyfile # Doxygen configuration
│
├── docs/ # Tier 2: Comprehensive documentation
│ ├── conf.py # Sphinx configuration (Breathe bridge)
│ ├── index.rst # Documentation root
│ │
│ ├── user_guide/ # For simulator users
│ │ ├── installation.md
│ │ ├── quickstart.md
│ │ ├── concepts.md # USD scenes, viewports, backends
│ │ ├── scripting.md # Python scripting via microrobotica module
│ │ ├── tutorials/ # Step-by-step tutorials
│ │ └── faq.md
│ │
│ ├── developer_guide/ # For platform contributors
│ │ ├── architecture.md # System architecture overview
│ │ ├── component_authoring.md # How to add a new component
│ │ ├── interface_contracts.md # PhysicsProcess, RenderBackend, etc.
│ │ ├── testing_standards.md # Test requirements
│ │ ├── documentation_standards.md # Doc requirements for contributions
│ │ └── code_style.md
│ │
│ ├── component_guide/ # Architectural component docs (Tier 2)
│ │ ├── index.md # Component documentation overview
│ │ ├── interfaces/ # One document per abstract interface
│ │ │ ├── physics_process.md
│ │ │ ├── render_backend.md
│ │ │ ├── render_session.md
│ │ │ ├── compute_backend.md
│ │ │ ├── result_frame.md
│ │ │ ├── physics_config.md
│ │ │ └── _template.md # Template for new interface docs
│ │ ├── implementations/ # One document per concrete impl
│ │ │ ├── stub_physics_process.md
│ │ │ ├── stub_render_session.md
│ │ │ ├── local_compute_backend.md
│ │ │ ├── scene_manager.md
│ │ │ ├── results_applicator.md
│ │ │ ├── simulation_controller.md
│ │ │ ├── viewport_widget.md
│ │ │ ├── console_widget.md
│ │ │ └── _template.md
│ │ ├── scripting_api.md # microrobotica Python module contract
│ │ └── cloud_compute.md # SkyPilot/ZeroMQ/Selkies architecture
│ │
│ ├── validation/ # V&V documentation
│ │ ├── index.md # V&V philosophy and scope
│ │ ├── framework_verification.md # Framework-level verification evidence
│ │ ├── component_verification/ # Per-component verification reports
│ │ │ ├── layer_stack.md # USD layer separation tests
│ │ │ ├── results_applicator.md # ResultFrame → USD mapping tests
│ │ │ ├── ipc_protocol.md # ZeroMQ parameter/result fidelity
│ │ │ ├── scripting_api.md # microrobotica module contract tests
│ │ │ └── _template.md
│ │ ├── known_anomalies.yaml # Machine-readable anomaly registry
│ │ ├── soup_package.md # IEC 62304 SOUP package document
│ │ └── cou_template.md # Context-of-use template
│ │
│ ├── regulatory/ # Regulatory context documentation
│ │ ├── intended_use.md # Platform positioning statement
│ │ ├── eu_mdr_guidelines.md # EU MDR alignment guide
│ │ ├── fda_guidelines.md # FDA alignment guide (secondary)
│ │ ├── iec62304_mapping.md # IEC 62304 lifecycle mapping
│ │ ├── mdcg_2019_11.md # Software qualification guidance
│ │ ├── downstream_integration.md # Three-layer SOUP chain (from MBCA's view)
│ │ └── usability_engineering.md # IEC 62366 UI/UX compliance (NEW)
│ │
│ ├── api_reference/ # Tier 1: Auto-generated API docs
│ │ └── (Doxygen + Breathe output)
│ │
│ ├── releases/ # Per-version release notes
│ │ ├── v0.1.0.md
│ │ └── _template.md
│ │
│ └── bibliography.bib # Centralized academic references
│
├── examples/ # Tier 3: Executable examples
│ ├── scripts/ # Python scripting examples
│ └── scenes/ # Example USD scenes
│
├── src/ # Source tree
│ ├── core/ # Abstract interfaces (no Qt/USD/Python)
│ ├── stubs/ # Stub implementations
│ ├── scene/ # USD scene management
│ ├── viewport/ # Viewport widgets
│ ├── simulation/ # SimulationController
│ └── scripting/ # pybind11 embedded interpreter
│
└── tests/ # Test suite
├── verification/ # Verification tests (Catch2)
│ ├── test_layer_stack.cpp
│ ├── test_results_applicator.cpp
│ ├── test_ipc_protocol.cpp
│ └── ...
└── (other test files)
Rationale: The structure mirrors MADDENING's three-tier model (API reference + component guide + examples) with two key differences: (1) docs/component_guide/ replaces docs/algorithm_guide/ because MICROBOTICA documents architectural components and interface contracts rather than physics algorithms; (2) docs/regulatory/usability_engineering.md is new because MICROBOTICA has a UI while MADDENING does not.
Tooling: Sphinx with MyST-Parser, Doxygen for C++ API extraction, Breathe for Sphinx↔Doxygen bridge. MICROBOTICA-specific academic references in docs/bibliography.bib with Pandoc [@Key] citation syntax. The Sphinx documentation site is a subproject of microbotica-web (the umbrella documentation site for the ecosystem).
This section is directly inherited from MADDENING Section 2, with surface substitutions (project name, licence, layer position). The "platform, not product" framing, layered responsibility model, and commercial boundary language are taken verbatim in structure. The key difference is that MICROBOTICA sits at Layer 3 — the layer most likely to be the direct dependency of a commercial product — which makes the boundary language even more critical.
Platform Positioning Statement:
MICROBOTICA is an open-source research simulator for microrobot-assisted drug delivery in cerebrospinal fluid and other confined biological geometries. It is research software distributed under the AGPL-3.0-or-later licence.
MICROBOTICA is NOT a medical device as defined by EU MDR (EU 2017/745) Article 2(1), nor is it a medical device under US FDA regulations. It does not have a medical purpose. It is not intended for direct clinical use, clinical decision-making, or patient diagnosis. It has not been CE-marked, cleared, or approved by any regulatory body.
MICROBOTICA is a research platform — analogous to 3D Slicer, ParaView, or NVIDIA Omniverse for research. Under the qualification criteria of MDCG 2019-11, software without a medical purpose is not a medical device regardless of whether it is subsequently used within a medical device. MICROBOTICA performs no clinical interpretation, provides no diagnostic output, and makes no therapeutic recommendations.
MICROBOTICA is designed to be a credible, auditable research platform that downstream commercial manufacturers may build upon. When incorporated into a regulated medical device by any commercial entity, MICROBOTICA is classified as SOUP (Software of Unknown Provenance) under IEC 62304:2006+AMD1:2015. The device manufacturer bears full responsibility for assessing MICROBOTICA's suitability for their specific context of use and for performing all required verification and validation activities.
Cybersecurity Boundary Statement (MDCG 2019-16):
MICROBOTICA exposes a network surface through two channels: (1) ZeroMQ IPC to remote MADDENING/MIME physics backends running on SkyPilot cloud infrastructure, and (2) WebRTC streaming from remote Selkies rendering containers. In the open-source research configuration, both channels assume a trusted network environment. No authentication, authorisation, or encryption is provided by MICROBOTICA itself.
When MICROBOTICA is incorporated into a regulated product, the commercial integration layer is solely responsible for: securing ZeroMQ channels (CurveZMQ or TLS), authenticating Selkies streams, validating and sanitizing all simulation parameters before they reach MADDENING/MIME via IPC, protecting the Python scripting console from injection attacks, and ensuring the cloud compute infrastructure meets the security requirements of the clinical context.
The embedded Python scripting console (
microroboticamodule) accepts arbitrary user input and can modify scene state and simulation parameters. In a clinical context, the manufacturer must implement appropriate access controls and parameter validation at the scripting boundary.MICROBOTICA does not implement security controls because it is designed for trusted research environments. The vulnerability reporting process and the threat model for the open-source configuration are documented in
SECURITY.md. When MICROBOTICA is incorporated into a regulated product, the manufacturer's cybersecurity documentation (per MDCG 2019-16) must address all network surfaces listed above.
AGPL Licence Statement:
MICROBOTICA is licensed under AGPL-3.0-or-later. The AGPL requires that any user who interacts with the software over a network receives the complete corresponding source code. For a commercial product that exposes MICROBOTICA's functionality over a network (e.g., a cloud-based SaaS offering), this means the AGPL-3.0 source disclosure obligation applies to the network-accessible portions of the software. Commercial entities building on MICROBOTICA should consult legal counsel regarding AGPL compliance for their specific deployment model. MICROBOTICA's upstream dependencies (MADDENING, MIME) are LGPL-3.0, which has weaker copyleft requirements — the AGPL obligation arises only from MICROBOTICA's own code.
Layered Responsibility Model:
| Responsibility | Owner | Applicable Standard | Evidence |
|---|---|---|---|
| Application-layer correctness (USD management, IPC protocol, UI behaviour) | MICROBOTICA project | IEC 62304 Clause 5.6 (via SOUP assessment) | Test suite, Catch2 verification tests |
| Physics correctness | MIME/MADDENING projects | IEC 62304 Clause 5.6 | MIME/MADDENING verification suites |
| SOUP assessment (MICROBOTICA) | Downstream manufacturer | IEC 62304 Clause 5.3.3, 5.3.4 | Using MICROBOTICA's SOUP package |
| SOUP assessment (MIME, MADDENING) | Downstream manufacturer | IEC 62304 Clause 5.3.3, 5.3.4 | Using MIME/MADDENING SOUP packages (SOUP-of-SOUP chain) |
| Known anomaly evaluation | Downstream manufacturer | IEC 62304 Clause 7.1.3 | Using MICROBOTICA's known anomalies registry |
| Validation for specific COU | Device manufacturer | EU MDR Annex I Section 17.2 | Experimental comparisons for their COU |
| Risk management | Device manufacturer | ISO 14971, EU MDR Annex I Chapter I | Risk management file for their device |
| Usability engineering | Device manufacturer | IEC 62366-1:2015 | Usability engineering file |
| Clinical evidence | Device manufacturer | EU MDR Annex XIV, MEDDEV 2.7/1 rev. 4 | Clinical evaluation report; PMCF plan (Class III) |
| Regulatory submission | Device manufacturer | EU MDR Article 52+ | CE marking, Notified Body review |
This section is taken verbatim in structure from MADDENING Section 2. The same strategic decision applies: MADDENING, MIME, and MICROBOTICA are open-source research tools. None of them will seek CE marking. None of them are medical devices. None of them carry manufacturer liability under EU MDR.
The regulated clinical product is built by a downstream commercial entity on top of these open-source tools. That entity takes on the QMS, the Notified Body relationship, post-market surveillance obligations, and EU MDR manufacturer liability.
MICROBOTICA's position at Layer 3 — the topmost open-source layer and the most likely direct dependency of a commercial product — means its documentation boundary language is the first thing a commercial manufacturer's regulatory team will encounter. The boundary must be unambiguous.
MICROBOTICA is licensed under AGPL-3.0-or-later. The AGPL differs from MADDENING's LGPL-3.0 in one significant respect: it extends the source disclosure obligation to network interaction. A commercial product that deploys MICROBOTICA as a network service must provide the complete source to users who interact with it over the network.
This does not prevent commercial use. It does impose a stronger copyleft requirement that commercial entities must evaluate:
- Commercial use is permitted: The AGPL explicitly permits commercial use.
- Strong copyleft: Unlike the LGPL, the AGPL's "network use" clause means that if a commercial product serves MICROBOTICA's functionality over a network, the AGPL-licensed source must be made available to network users.
- Dual-licensing option: The developer retains the option to offer commercial licences that waive the AGPL network disclosure requirement, enabling proprietary SaaS deployments without source disclosure.
- Upstream compatibility: MADDENING and MIME (LGPL-3.0) can be incorporated into AGPL-3.0 code. The AGPL is a "stronger" licence compatible with the LGPL for combination purposes.
Commercial entities should assess AGPL compatibility with their deployment model. For on-premises deployment (no network interaction), the AGPL source disclosure obligation may not be triggered. For cloud/SaaS deployment, it will be.
This section adapts MADDENING Section 3 (Algorithm and Model Documentation Standards) to the application-layer domain. MADDENING documents physics nodes with governing equations, discretization, and analytical benchmarks. MICROBOTICA documents architectural components — abstract interfaces, concrete implementations, and the microrobotica scripting API — with design rationale, interface contracts, failure modes, and verification evidence. The template structure is preserved; the content domain changes.
Every abstract interface in src/core/ and every significant implementation class must have a corresponding document in docs/component_guide/. The template below draws from MADDENING's algorithm guide template, adapted for architectural components.
---
bibliography: ../../bibliography.bib
---
# [Interface Name]
**Header**: `src/core/[header].h`
**Stability**: [experimental | provisional | stable | deprecated]
**Component ID**: `MBCA-COMP-[XXX]`
**Version**: [semantic version of this interface]
## Summary
[1-2 sentence description of what this interface abstracts.]
## Design Rationale
[Why this interface exists. What architectural decision it enables.
What would break if it were removed or redesigned.]
## Interface Contract
[The formal contract that all implementations must satisfy.
Include pre-conditions, post-conditions, invariants, and
thread-safety guarantees.]
```cpp
// Key interface methods with Doxygen-style documentation
class PhysicsProcess {
public:
/// @pre Configuration has been validated by the caller.
/// @post Launches the physics backend. Subsequent calls to
/// receiveResult() will return ResultFrame objects.
/// @throws std::runtime_error if launch fails.
virtual void launch(const PhysicsConfig& config) = 0;
/// @pre launch() has been called successfully.
/// @post Returns the next ResultFrame from the physics backend.
/// @note Blocking call. Returns std::nullopt on backend shutdown.
virtual std::optional<ResultFrame> receiveResult() = 0;
/// @pre launch() has been called successfully.
/// @post Parameters are transmitted to the physics backend.
/// Effect is visible on the next receiveResult() call.
virtual void sendParameters(const nlohmann::json& params) = 0;
virtual ~PhysicsProcess() = default;
};[Trace each interface method to its concrete implementations. This is the C++ equivalent of MADDENING's equation-to-code Implementation Mapping, adapted for interface-to-implementation traceability. Mandatory for IEC 62304 Class C detailed design traceability (Clause 5.4).]
| Interface Method | Implementation | Notes |
|---|---|---|
PhysicsProcess::launch() |
StubPhysicsProcess::launch() |
Starts synthetic data generation thread |
PhysicsProcess::launch() |
ZmqPhysicsProcess::launch() (Phase 2) |
Opens ZeroMQ REQ socket to MIME |
PhysicsProcess::receiveResult() |
StubPhysicsProcess::receiveResult() |
Returns synthetic ResultFrame |
[Numbered list of architectural assumptions.]
- [e.g., "All implementations are single-threaded per instance"]
- [e.g., "PhysicsConfig is immutable after launch()"]
- [e.g., "ResultFrame values are in SI units"]
[Specific conditions where this interface or its implementations fail or behave unexpectedly. Feeds into IEC 62304 SOUP anomaly assessment.]
- [e.g., "No timeout on receiveResult() — blocks indefinitely if the physics backend hangs"]
- [e.g., "sendParameters() does not validate parameter names or ranges — invalid parameters are forwarded silently"]
[Technical conditions that a downstream ISO 14971 risk manager should evaluate. See Section 8.7 for the technical-vs-clinical boundary principle — these are technical conditions only, NOT clinical risk assessments.]
- [e.g., "Undefined behaviour if receiveResult() is called before launch() — no runtime check enforced"]
- [e.g., "If the remote physics backend is killed mid-step, the ZeroMQ transport may silently drop the in-flight ResultFrame"]
[What SOUP components does this interface interact with?]
| SOUP Component | Interface Point | Data Flow |
|---|---|---|
| MIME (via ZeroMQ) | sendParameters() / receiveResult() |
Bidirectional: config out, ResultFrame in |
[Link to verification report and test files.]
[Cite using Pandoc-style [@Key] syntax.]
- [@Key] Author (Year). Title. — Relevance note.
| Version | Date | Change |
|---|---|---|
| 1.0.0 | 2026-XX-XX | Initial interface definition |
#### Implementation Documentation Template (`docs/component_guide/implementations/_template.md`)
Uses the same structure as the interface template but adds:
- **Implements**: which interface(s) this class implements
- **Dependencies**: Qt, USD, pybind11, or other concrete dependencies
- **Threading model**: which thread(s) the implementation runs on
- **Resource lifecycle**: what resources are acquired/released and when
### Bibliography and Citation System
**Taken verbatim from MADDENING Section 3**. MICROBOTICA maintains its own `docs/bibliography.bib` for application-layer references: CSF dynamics, microrobotics navigation, clinical microrobotics literature, OpenUSD architecture, Selkies/WebRTC architecture. Same `[@Key]` syntax, same `check_citations.py` CI script (adapted for MICROBOTICA's directory structure).
> **Planned extension — BiocompatibilityMeta**: When MIME introduces `BiocompatibilityMeta` on physics nodes (biological environment, protein mixture, temperature, pH, ISO 10993 regulatory context, ChEBI/UBERON/NCBI external identifiers), the `ResultFrame` will carry biocompatibility output fields alongside kinematic data. The component guide template will be extended to include a `BiocompatibilityContext` section for components that consume or display these fields. This extension is deferred to Phase 2 (MIME integration). The `ComponentMeta` struct's `validated_regimes` field is already capable of expressing biocompatibility parameter bounds (e.g., validated pH range, temperature envelope) — no schema change is needed for that layer.
---
## 4. V&V Documentation Hooks
### Inheritance Statement
This section **adapts** MADDENING Section 4 for application-layer V&V. MADDENING's V&V scope is physics correctness (analytical benchmarks, convergence studies). MICROBOTICA's V&V scope is application-layer correctness: interface fidelity, data integrity, and UI behaviour. The V&V boundary principle — "we verify our layer, not upstream layers" — is preserved identically.
### MICROBOTICA V&V Scope
**What MICROBOTICA's V&V provides**:
- **USD layer separation enforcement**: the base layer is never written by simulation code; the results layer is never persisted to disk; the override layer is the only layer the scripting API can write to.
- **ResultsApplicator correctness**: given a `ResultFrame`, the values that appear on USD prims match the input values exactly (no truncation, no unit conversion error, no wrong prim path).
- **IPC protocol fidelity**: parameters sent via `sendParameters()` arrive at the physics backend without corruption; `ResultFrame` values received are identical to what was sent.
- **Scripting API contract**: `microrobotica.scene().set_attribute()` writes to the override layer only; `microrobotica.sim().send_parameters()` validates parameter types before forwarding; `microrobotica.sim().current_frame()` returns a dict that faithfully mirrors the current `ResultFrame`.
- **Viewport correctness**: the viewport switches correctly between local (Hydra/Storm) and stream (Selkies/WebRTC) modes; the rendered frame corresponds to the current `ResultFrame` state.
**What MICROBOTICA's V&V does NOT provide**:
- **Physics accuracy**: whether the `ResultFrame` values are physically correct is MIME/MADDENING's domain, not MICROBOTICA's. MICROBOTICA faithfully renders and presents whatever it receives — it does not assess whether the received values are physically meaningful.
- **Clinical validation**: MICROBOTICA does not validate that any simulation output matches patient physiology. That is the commercial manufacturer's responsibility.
**The "faithful rendering" boundary**: MICROBOTICA's correctness obligation is that it faithfully renders and presents the data it receives from the physics backend. This is analogous to a medical display's obligation: the display must faithfully reproduce the image it receives, but it is not responsible for whether the image is diagnostically correct. This boundary is important for the downstream manufacturer's risk management file: they must assess MICROBOTICA's rendering fidelity separately from MIME/MADDENING's physics accuracy.
**The dependency acknowledgement**: MICROBOTICA's `ResultsApplicator` correctness test — "does the position in `ResultFrame` correctly map to a USD prim transform?" — implicitly assumes the `ResultFrame` values have semantic meaning. MICROBOTICA's V&V documentation acknowledges this dependency explicitly:
> MICROBOTICA's verification tests confirm that data received from the physics backend is correctly mapped to the USD scene. These tests use synthetic `ResultFrame` data with known values. Correctness is defined as: the value written to the USD prim attribute matches the value in the `ResultFrame` within floating-point equality. This verification does not assert that the `ResultFrame` values are physically meaningful — that assertion belongs to MIME/MADDENING's verification suite. The conjunction of MICROBOTICA's rendering fidelity verification and MIME/MADDENING's physics accuracy verification together establish that the displayed result is both faithfully rendered and physically correct. Neither verification alone is sufficient.
### Verification Boundary: Where MICROBOTICA Ends and Physics Begins
This boundary is critical and must be documented in `docs/validation/index.md`:
| Verification Domain | Owner | Evidence |
|---|---|---|
| Physics equations solve the right math | MADDENING | Analytical benchmarks, convergence studies |
| Physics engine applies correct CSF parameters | MIME | Domain-specific verification |
| Application displays physics output faithfully | MICROBOTICA | `ResultsApplicator` tests, layer separation tests |
| IPC transmits data without corruption | MICROBOTICA + MIME | End-to-end IPC fidelity tests |
| Scripting API behaves as documented | MICROBOTICA | Scripting contract tests |
| UI prevents unsafe user actions | MICROBOTICA | Usability engineering tests |
| Complete chain produces clinically valid output | Commercial manufacturer | Clinical evaluation |
---
## 5. Versioning and API Stability
### Inheritance Statement
**Taken verbatim** from MADDENING Section 5, with surface substitutions only.
### Semantic Versioning
MICROBOTICA follows strict semantic versioning (SemVer 2.0):
- **MAJOR** (X.0.0): Breaking changes to `src/core/` interfaces, `microrobotica` scripting API, or USD scene contract
- **MINOR** (0.X.0): New components, new backends, new scripting API methods (backward-compatible)
- **PATCH** (0.0.X): Bug fixes, documentation updates, performance improvements
Pre-release versions: `X.Y.Z-alpha.N`, `X.Y.Z-beta.N`, `X.Y.Z-rc.N`
### `CHANGELOG.md`
Following [Keep a Changelog](https://keepachangelog.com/) with regulatory-specific sections:
```markdown
# Changelog
All notable changes to MICROBOTICA are documented in this file.
## [Unreleased]
### Added
### Changed
### Deprecated
### Removed
### Fixed
### Verification
- [Tracks changes to V&V status]
### Security
- [Required by MDCG 2019-16 cybersecurity guidance]
### Known Anomalies
- [Changes to known_anomalies.yaml — required for IEC 62304 SOUP]
| Prefix | Meaning |
|---|---|
feat: |
New feature |
fix: |
Bug fix |
refactor: |
Code restructuring (no behaviour change) |
docs: |
Documentation only |
test: |
Test additions or changes |
perf: |
Performance improvement |
verify: |
Verification/validation evidence |
break: |
Breaking change |
deprecate: |
Deprecation notice |
security: |
Security-relevant change |
ui: |
UI/UX change (new — MICROBOTICA-specific) |
Each public API surface carries a stability level (see Section 8.4 for code-level machinery):
| Level | Meaning | SemVer Guarantee |
|---|---|---|
| stable | Covered by SemVer; breaking changes only in major versions | Full |
| provisional | API may change in minor versions with deprecation warnings | One minor version notice |
| experimental | API may change without notice | None |
| deprecated | Scheduled for removal; use alternative | Removed in next major |
This section adapts MADDENING Section 7 for a C++/Qt project. The contributor checklist structure is preserved; the checklist items change to reflect C++ artifacts.
Top-level contributor guide covering: development environment setup (Qt 6.6, OpenUSD build, pybind11), CMake build instructions, branching model, commit convention, code style, and links to detailed guides.
Guide for adding a new component to MICROBOTICA:
- The interface contract: pure virtual classes in
src/core/, no Qt/USD/Python dependencies - Directory structure: where the files live, naming conventions
- Required documentation: Doxygen comments + component guide document
- Required tests: Catch2 unit tests + at least one verification test
- Required metadata:
ComponentMetastruct (Section 8.1) - Checklist:
### New Component Checklist
- [ ] Abstract interface in `src/core/` (if new interface)
- [ ] Concrete implementation in appropriate `src/` subdirectory
- [ ] `ComponentMeta` attached to the implementation (component ID, stability, hazard hints)
- [ ] Doxygen documentation on all public methods
- [ ] Component guide document in `docs/component_guide/`
- [ ] Design rationale documented
- [ ] Interface contract (pre/post conditions) documented
- [ ] Assumptions and constraints listed
- [ ] Known limitations and failure modes documented
- [ ] Hazard hints for ISO 14971 hazard identification
- [ ] At least one Catch2 verification test
- [ ] Entry in `docs/bibliography.bib` for primary reference (if applicable)
- [ ] Known limitations entered in `docs/validation/known_anomalies.yaml`
- [ ] CI passes on all platformsTest requirements:
- Unit tests (mandatory): test each public method using Catch2
- Integration tests (mandatory for implementations): test the implementation through its abstract interface
- Verification tests (mandatory for
src/core/interfaces and safety-relevant implementations): registered via the verification test pattern (Section 8.3); test data integrity, interface contract enforcement, and failure mode behaviour
4. Memory Safety Analysis (mandatory for all src/ code)
MICROBOTICA requires memory safety analysis as part of CI. The following tools are used:
AddressSanitizer + UndefinedBehaviorSanitizer (ASan/UBSan)
Enabled via a dedicated CMake preset. This is the primary memory safety CI job and must pass on every pull request.
# CMakePresets.json — add alongside linux-debug and linux-release
{
"name": "linux-asan",
"inherits": "linux-debug",
"binaryDir": "${sourceDir}/build/asan",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug",
"CMAKE_CXX_FLAGS": "-fsanitize=address,undefined -fno-omit-frame-pointer -g",
"CMAKE_EXE_LINKER_FLAGS": "-fsanitize=address,undefined"
}
}Catches: heap use-after-free, stack buffer overflow, uninitialised memory reads, null pointer dereference, signed integer overflow, invalid enum values, out-of-bounds array access. LeakSanitizer (LSan) is enabled automatically with ASan on Linux and catches memory leaks at process exit.
Known false-positive scope: pybind11 intentionally retains some Python interpreter state at shutdown (CPython limitation — not all extension modules can fully unload). LSan will report these as leaks. Suppress them with a lsan.suppressions file:
# lsan.suppressions — suppress known pybind11/CPython shutdown leaks
leak:libpython
leak:pybind11
leak:Py_Finalize
Pass to the test runner with LSAN_OPTIONS=suppressions=lsan.suppressions.
ThreadSanitizer (TSan)
Enabled via a separate CMake preset. Run as a nightly CI job or on branches that touch src/scripting/ or any code that crosses the Qt main thread / Python thread boundary.
{
"name": "linux-tsan",
"inherits": "linux-debug",
"binaryDir": "${sourceDir}/build/tsan",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug",
"CMAKE_CXX_FLAGS": "-fsanitize=thread -fno-omit-frame-pointer -g",
"CMAKE_EXE_LINKER_FLAGS": "-fsanitize=thread"
}
}Important: ASan and TSan are mutually exclusive — they cannot run in the same binary. CI uses two separate jobs: asan-ubsan (PRs) and tsan (nightly or scripting-related PRs).
Catches: data races between threads. The primary concern in MICROBOTICA is the microrobotica scripting module: Python scripts execute on a Python thread, but all microrobotica API calls dispatch to the Qt main thread via QMetaObject::invokeMethod(..., Qt::BlockingQueuedConnection). This pattern is correct and race-free by design, but TSan may flag Qt internal dispatch without a suppression. Add:
# tsan.suppressions — suppress known Qt/Python thread dispatch patterns
race:QMetaObject::invokeMethod
race:QCoreApplication::postEvent
Valgrind/Memcheck
Run manually or as a weekly CI job on the Catch2 verification test suite. Slower than ASan but catches different classes of errors (particularly conditional jumps on uninitialised values that ASan misses). Not required to pass on every PR due to runtime cost, but any Valgrind error in tests/verification/ is treated as a blocking issue.
valgrind --tool=memcheck \
--leak-check=full \
--show-leak-kinds=definite,indirect \
--track-origins=yes \
--suppressions=valgrind.suppressions \
./build/debug/tests/microbotica_tests \
"[verification]"Maintain a valgrind.suppressions file for known false positives (Qt internals, OpenUSD static initialisation). Only suppress with a comment explaining why the suppression is safe.
CI scope — test binary, not the full application:
The ASan/UBSan and TSan jobs compile and run the Catch2 test binary only — not the full Qt application. The test binary links src/core/, src/scene/, src/simulation/, and src/scripting/ directly, without instantiating a QApplication or invoking OpenUSD's rendering stack. This is deliberate: the code paths where memory errors are safety-relevant (ResultsApplicator, SceneManager, SimulationController, ScriptingEngine) are fully exercised by the headless test suite. The sanitizer-instrumented test binary builds and runs in 2-3 minutes on a standard GitHub Actions runner.
The full application binary (Qt + OpenUSD + Hydra/Storm) is not rebuilt on every PR. OpenUSD alone takes 20-40 minutes to build from source. The correct approach is to keep the USD and Qt builds in a cached Docker image that is rebuilt manually only when the version pin changes, and pulled in CI as a layer. NVIDIA publishes prebuilt OpenUSD binaries for Ubuntu that are suitable for this purpose. MICROBOTICA's own src/ compiles against the cached USD headers in under a minute.
Consequence: the asan-ubsan CI job must be structured as:
- Pull the cached USD/Qt Docker image (or restore from GitHub Actions cache using the USD version as the cache key)
- Build only
microbotica_teststarget with ASan flags — do not build themicroboticaapplication target - Run
./microbotica_tests "[verification]"and./microbotica_tests "[unit]"withLSAN_OPTIONS=suppressions=lsan.suppressions
If the USD version pin changes, update the Docker image or cache key — do not attempt to build USD from source in the sanitizer job.
CI job structure:
| Job | Trigger | Target built | Tools | Duration |
|---|---|---|---|---|
build-test |
Every PR | microbotica_tests |
GCC, no sanitizers | ~2 min |
asan-ubsan |
Every PR | microbotica_tests |
ASan + UBSan + LSan | ~3 min |
tsan |
Nightly + scripting PRs | microbotica_tests |
TSan | ~3 min |
valgrind |
Weekly | microbotica_tests |
Valgrind/Memcheck | ~15 min |
full-build |
Nightly | microbotica (full app) |
GCC, no sanitizers | ~5 min with cache |
All jobs assume the USD/Qt Docker image is pre-cached. The full-build job is a smoke test only — it verifies the application links correctly but does not run the GUI.
Regulatory note: Memory safety analysis results are part of the IEC 62304 Clause 5.6 verification evidence. Any memory error found by these tools that is not immediately fixed must be entered into docs/validation/known_anomalies.yaml as an MBCA-ANO-* entry with safety_relevance assessed. A memory error that affects ResultsApplicator, SceneManager, or SimulationController is presumptively safety_relevant: "context_dependent" until assessed otherwise.
Taken verbatim in structure from MADDENING Section 8, adapted for MICROBOTICA.
# MICROBOTICA
MICROROBOTics Iterative simulation for Clinical Adoption.
[Badges: CI status, test count, license]
## What is MICROBOTICA?
MICROBOTICA is an open-source research simulator for microrobot-assisted
drug delivery in cerebrospinal fluid and other confined biological
geometries. Built on C++17/Qt 6.6 with OpenUSD as the primary scene
format, MICROBOTICA provides a desktop application for interactive
visualisation, scripting, and analysis of microrobotics simulations.
MICROBOTICA sits at Layer 3 of an open-source stack: MADDENING (physics
framework) → MIME (microrobotics engine) → MICROBOTICA (simulator UI).
## Intended Use and Disclaimers
> **MICROBOTICA is research software.** It is not a medical device as
> defined by EU MDR (EU 2017/745) or US FDA regulations. It has no
> medical purpose. It is not intended for clinical use, clinical
> decision-making, or patient diagnosis. It has not been CE-marked,
> cleared, or approved by any regulatory body.
>
> When used as a component within regulated medical software,
> MICROBOTICA is classified as SOUP (Software of Unknown Provenance)
> under IEC 62304. The device manufacturer is responsible for
> assessing MICROBOTICA's suitability and performing all required
> verification and validation. See
> [Regulatory Documentation](docs/regulatory/) for details.
## Quick Start
[Installation, minimal example]
## Documentation
| Document | Description |
|----------|-------------|
| [User Guide](docs/user_guide/) | Installation, tutorials, concepts |
| [Component Guide](docs/component_guide/) | Architectural component docs |
| [Developer Guide](docs/developer_guide/) | Contributing, testing, code style |
| [Validation](docs/validation/) | V&V evidence, SOUP package |
| [Regulatory](docs/regulatory/) | Intended use, EU MDR/FDA guidance |
| [API Reference](docs/api_reference/) | Auto-generated C++ API docs |
| [DESIGN.md](DESIGN.md) | Architecture decisions |
| [ROADMAP.md](ROADMAP.md) | Feature roadmap |
| [CHANGELOG.md](CHANGELOG.md) | Version history |
## Citation
If you use MICROBOTICA in academic work, please cite:
[BibTeX entry]
## License
AGPL-3.0-or-later. See [LICENSE](LICENSE).| File | Purpose |
|---|---|
CITATION.cff |
Machine-readable citation metadata + configuration management artifact |
GOVERNANCE.md |
Decision-making process, maintainer roles |
CONTRIBUTING.md |
Quick-start for contributors |
SECURITY.md |
Vulnerability reporting (supports MDCG 2019-16 cybersecurity) |
CODE_OF_CONDUCT.md |
Community standards |
This section proposes concrete code-level mechanisms for MICROBOTICA. It adapts MADDENING Section 9 for a C++17 codebase.
This section adapts MADDENING Section 9.1 (NodeMeta) for C++17. The key architectural decision is how to attach structured metadata to C++ abstract interfaces without pulling in heavy dependencies.
Resolution of Concern 1 (ComponentMeta scope in C++):
ComponentMeta is a plain C++ struct defined in src/core/component_meta.h. This location ensures:
- Dependency-free:
src/core/has no Qt, USD, or Python dependencies.ComponentMetauses only standard library types (std::string,std::vector,std::optional), nlohmann_json for serialization, and nothing else. - Embeddable in headers: Any
src/core/interface header can#include "component_meta.h"without pulling in transitive dependencies. - Machine-readable: The struct serializes to JSON via nlohmann_json, enabling automated harvesting for SOUP package generation, capability matrices, and CI validation scripts.
Granularity: One ComponentMeta instance per abstract interface AND per concrete implementation that adds new failure modes or hazard hints. The abstract interface's ComponentMeta documents the contract-level properties (what all implementations must satisfy). Each concrete implementation's ComponentMeta documents implementation-specific properties (transport-specific failure modes, platform-specific limitations). See Section 8.7 for how this granularity interacts with hazard hint scoping.
// src/core/component_meta.h
#pragma once
#include <string>
#include <vector>
#include <optional>
#include <nlohmann/json.hpp>
namespace microbotica::core {
/// Stability level for API surfaces and components.
enum class StabilityLevel {
Experimental,
Provisional,
Stable,
Deprecated
};
NLOHMANN_JSON_SERIALIZE_ENUM(StabilityLevel, {
{StabilityLevel::Experimental, "experimental"},
{StabilityLevel::Provisional, "provisional"},
{StabilityLevel::Stable, "stable"},
{StabilityLevel::Deprecated, "deprecated"},
})
/// A quantitative bound on a validated parameter range.
struct ValidatedRegime {
std::string parameter;
double min_value;
double max_value;
std::string units;
std::string evidence;
NLOHMANN_DEFINE_TYPE_INTRUSIVE(ValidatedRegime,
parameter, min_value, max_value, units, evidence)
};
/// A citable academic or technical reference.
struct Reference {
std::string key; ///< BibTeX key in bibliography.bib
std::string description;
NLOHMANN_DEFINE_TYPE_INTRUSIVE(Reference, key, description)
};
/// Structured metadata for a MICROBOTICA component.
///
/// Machine-readable and automatically harvestable for V&V reports,
/// SOUP package documents, and IEC 62304 SOUP assessment.
///
/// The ComponentMeta struct is the C++ equivalent of MADDENING's
/// NodeMeta Python dataclass. It lives in src/core/ to ensure
/// zero Qt/USD/Python dependency. Serializes to JSON via
/// nlohmann_json for CI script consumption.
struct ComponentMeta {
std::string component_id; ///< e.g., "MBCA-COMP-001"
std::string component_version; ///< e.g., "1.0.0"
StabilityLevel stability = StabilityLevel::Experimental;
std::string description;
// Interface contract
std::vector<std::string> preconditions;
std::vector<std::string> postconditions;
std::vector<std::string> invariants;
// Design rationale
std::string design_rationale;
// Assumptions and constraints
std::vector<std::string> assumptions;
std::vector<std::string> limitations;
// Validated regimes (quantitative, parameter-bound)
std::vector<ValidatedRegime> validated_regimes;
// Hazard hints (qualitative, non-parameter-bound)
// See Section 8.7 for scope distinction.
std::vector<std::string> hazard_hints;
// References
std::vector<Reference> references;
// Deprecation
std::optional<std::string> deprecation_notice;
NLOHMANN_DEFINE_TYPE_INTRUSIVE(ComponentMeta,
component_id, component_version, stability, description,
preconditions, postconditions, invariants,
design_rationale, assumptions, limitations,
validated_regimes, hazard_hints, references,
deprecation_notice)
};
// std::optional serialization requires nlohmann_json >= 3.11.0
// Ensure vcpkg.json pins: "nlohmann-json": ">=3.11.0"
// If building without vcpkg, verify: nlohmann/json.hpp version >= 3.11.0
static_assert(NLOHMANN_JSON_VERSION_MAJOR > 3 ||
(NLOHMANN_JSON_VERSION_MAJOR == 3 && NLOHMANN_JSON_VERSION_MINOR >= 11),
"ComponentMeta requires nlohmann_json >= 3.11.0 for std::optional support");
} // namespace microbotica::coreDependency note:
component_meta.hdepends on<nlohmann/json.hpp>. This is the only third-party dependency insrc/core/. The tradeoff is deliberate: machine-readable JSON serialization is essential for CI harvest scripts (scripts/collect_component_meta.py), SOUP package generation, and capability matrix generation. nlohmann_json is header-only, adds no link-time dependency, and is already a vcpkg dependency of the main executable. If a future embedded or constrained context requires a truly dependency-freesrc/core/, the serialization methods can be removed or conditionally compiled via#ifdef MBCA_ENABLE_JSON_SERIALIZATION.Version requirement: nlohmann_json >= 3.11.0 is required for
std::optionalserialization. Pin this invcpkg.jsonwith"nlohmann-json": ">=3.11.0". Earlier versions will compile but silently omitdeprecation_noticefrom JSON output.
Each abstract interface in src/core/ exposes metadata via a static method:
// src/core/physics_process.h
#include "component_meta.h"
class PhysicsProcess {
public:
/// Return structured metadata for this interface.
/// Concrete implementations override with their own metadata.
static const ComponentMeta& interfaceMeta() {
static const ComponentMeta meta{
.component_id = "MBCA-COMP-001",
.component_version = "1.0.0",
.stability = StabilityLevel::Experimental,
.description = "Abstract interface for physics computation backends",
.preconditions = {"PhysicsConfig validated by caller before launch()"},
.postconditions = {"After launch(), receiveResult() returns valid frames"},
.assumptions = {
"Single PhysicsProcess instance per SimulationController",
"ResultFrame values are in SI units",
"PhysicsConfig is immutable after launch()",
},
.limitations = {
"No timeout on receiveResult() — blocks indefinitely if backend hangs",
"sendParameters() does not validate parameter names or ranges",
},
.hazard_hints = {
"Undefined behaviour if receiveResult() is called before launch()",
"No mechanism to detect if the physics backend has entered a "
"numerically unstable state — MICROBOTICA will faithfully render "
"divergent results without warning unless the upstream physics "
"engine provides health status in the ResultFrame",
},
};
return meta;
}
// ... interface methods ...
};Concrete implementations provide their own meta():
// src/stubs/stub_physics_process.h
class StubPhysicsProcess : public PhysicsProcess {
public:
static const ComponentMeta& meta() {
static const ComponentMeta meta{
.component_id = "MBCA-IMPL-001",
.component_version = "1.0.0",
.stability = StabilityLevel::Experimental,
.description = "Stub physics backend generating synthetic data for architecture proving",
.assumptions = {
"Synthetic data uses hardcoded sinusoidal trajectories",
"No physical meaning — for architecture proving only",
"simTime increases monotonically at 60 Hz regardless of wall time",
},
.limitations = {
"Fixed output format — does not respond to sendParameters()",
"Produces only position and simTime fields in ResultFrame",
"Does not simulate any physical phenomenon",
},
.hazard_hints = {
"Output is synthetic, not physical — must never be used for "
"any validation or clinical purpose",
"Does not exercise the ZeroMQ transport path — IPC-related "
"failure modes (frame drops, reordering, latency) are not "
"testable with this stub",
},
};
return meta;
}
// ...
};A CI script (scripts/harvest_component_meta.py) discovers all ComponentMeta instances by parsing C++ headers for the ComponentMeta struct initializations, validates that all required fields are populated, and generates a JSON capability matrix. This is the C++ equivalent of MADDENING's collect_node_metadata().
Identical to MADDENING Section 9.1:
| Field | Nature | Scope | Example | Consumer |
|---|---|---|---|---|
validated_regimes |
Quantitative, parameter-bound | Defines the envelope within which the component has been verified | ValidatedRegime("max_prims_in_scene", 1, 10000, "", "Performance test") |
Runtime validators, component guide tables |
hazard_hints |
Qualitative, non-parameter-bound | Technical conditions that cannot be reduced to a single parameter range | "If the physics backend is killed mid-step, in-flight ResultFrame is silently dropped" |
ISO 14971 hazard identification, SOUP package |
Adapts MADDENING Section 9.2 for a desktop application with cloud compute backends.
// src/core/session_provenance.h
#pragma once
#include <string>
#include <optional>
#include <nlohmann/json.hpp>
namespace microbotica::core {
/// Complete, serializable record of a MICROBOTICA session.
///
/// Captures everything needed to reproduce the session and to serve
/// as an audit trail in a regulatory context. Extends MADDENING's
/// SimulationProvenance with application-layer and cloud provenance.
struct SessionProvenance {
// Software identity
std::string microbotica_version; ///< IEC 62304 Clause 8: SOUP identification
std::string qt_version;
std::string usd_version;
std::string compiler_version;
std::string platform;
// Upstream SOUP versions (captured from IPC handshake)
std::optional<std::string> mime_version;
std::optional<std::string> maddening_version;
// Scene identity
std::string scene_file_path;
std::string scene_file_hash; ///< SHA-256 of the loaded USD file
// Compute backend
std::string compute_backend_type; ///< "local" | "skypilot"
std::optional<std::string> skypilot_job_id;
std::optional<std::string> cloud_provider;
std::optional<std::string> container_image_hash;
// Render backend
std::string render_backend_type; ///< "local_hydra" | "selkies_stream"
std::optional<std::string> selkies_session_id;
// Simulation parameters
nlohmann::json initial_parameters;
std::vector<nlohmann::json> parameter_changes; ///< Timestamped changes
// Timestamps
std::string session_started;
std::string session_ended;
// Results summary
int total_frames_received = 0;
int frames_dropped = 0;
int out_of_range_warnings = 0;
NLOHMANN_DEFINE_TYPE_INTRUSIVE(SessionProvenance,
microbotica_version, qt_version, usd_version,
compiler_version, platform,
mime_version, maddening_version,
scene_file_path, scene_file_hash,
compute_backend_type, skypilot_job_id, cloud_provider,
container_image_hash,
render_backend_type, selkies_session_id,
initial_parameters, parameter_changes,
session_started, session_ended,
total_frames_received, frames_dropped, out_of_range_warnings)
};
// std::optional serialization requires nlohmann_json >= 3.11.0
// Ensure vcpkg.json pins: "nlohmann-json": ">=3.11.0"
static_assert(NLOHMANN_JSON_VERSION_MAJOR > 3 ||
(NLOHMANN_JSON_VERSION_MAJOR == 3 && NLOHMANN_JSON_VERSION_MINOR >= 11),
"SessionProvenance requires nlohmann_json >= 3.11.0 for std::optional support");
} // namespace microbotica::coreVersion requirement: Same nlohmann_json >= 3.11.0 requirement as
component_meta.h— required forstd::optionalserialization ofmime_version,maddening_version, and cloud provenance fields. Thestatic_assertabove will produce a clear compile-time error if an older version is used.audit_logger.h(Section 8.5) carries the same requirement when implemented in Phase 2.
Adapts MADDENING Section 9.3 for Catch2 tests. The decorator pattern becomes a Catch2 tag + a registry header.
// src/core/verification_registry.h
#pragma once
#include <string>
#include <vector>
#include <nlohmann/json.hpp>
namespace microbotica::core {
enum class BenchmarkType {
DataIntegrity, ///< Data passes through without corruption
ContractEnforcement,///< Interface pre/post conditions hold
LayerSeparation, ///< USD layer invariants maintained
ProtocolFidelity, ///< IPC data fidelity
UIBehavior, ///< UI responds correctly to state changes
Regression ///< Regression test against known output
};
struct VerificationBenchmark {
std::string benchmark_id; ///< e.g., "MBCA-VER-001"
std::string component_id; ///< e.g., "MBCA-COMP-003"
BenchmarkType type;
std::string description;
std::string test_file; ///< e.g., "tests/verification/test_layer_stack.cpp"
std::string test_case; ///< Catch2 test case name
};
/// Global verification benchmark registry.
/// Populated at static init time via REGISTER_VERIFICATION_BENCHMARK.
std::vector<VerificationBenchmark>& benchmarkRegistry();
} // namespace microbotica::core
/// Register a Catch2 test as a verification benchmark.
///
/// Parameters:
/// token — a valid C++ identifier token (no quotes, no dashes),
/// e.g. MBCA_VER_001. Used only for ODR-safe static init.
/// id_str — the human-readable benchmark ID string, e.g. "MBCA-VER-001"
/// comp_id — the component ID string, e.g. "MBCA-COMP-010"
/// type — BenchmarkType enum value
/// desc — description string
/// file — source file path (use __FILE__)
/// test_name — Catch2 TEST_CASE name string
///
/// Usage: place in a .cpp file alongside the Catch2 TEST_CASE.
#define REGISTER_VERIFICATION_BENCHMARK(token, id_str, comp_id, type, desc, file, test_name) \
namespace { \
static const bool _reg_##token = []() { \
microbotica::core::benchmarkRegistry().push_back({ \
id_str, comp_id, type, desc, file, test_name}); \
return true; \
}(); \
}// tests/verification/test_layer_stack.cpp
#include <catch2/catch_test_macros.hpp>
#include "core/verification_registry.h"
REGISTER_VERIFICATION_BENCHMARK(
MBCA_VER_001, // token: valid C++ identifier
"MBCA-VER-001", // id_str: human-readable ID
"MBCA-COMP-010", // component ID
microbotica::core::BenchmarkType::LayerSeparation,
"Base layer is never written by ResultsApplicator",
__FILE__,
"ResultsApplicator never writes to base layer"
)
TEST_CASE("ResultsApplicator never writes to base layer",
"[verification][layer-separation]") {
// ... test implementation ...
}Token convention: The
tokenparameter must be a valid C++ identifier — use underscores instead of dashes, no quotes. The conventional mapping is:MBCA-VER-001→MBCA_VER_001,MBCA-VER-002→MBCA_VER_002, etc. Theid_strstring is what appears in generated JSON reports and the verification traceability table; thetokenis only used to guarantee ODR-safe static initialization.
CI runs all [verification]-tagged Catch2 tests and generates structured JSON reports for docs/validation/.
The following verification benchmarks are defined for Phase 0. These are architectural decisions — the test implementations will be written as part of Phase 0/1 development.
| Benchmark ID | Component ID | Type | Description |
|---|---|---|---|
MBCA-VER-001 |
MBCA-COMP-010 |
LayerSeparation | Base layer is never written by ResultsApplicator |
MBCA-VER-002 |
MBCA-COMP-010 |
LayerSeparation | Results layer is never persisted to disk |
MBCA-VER-003 |
MBCA-COMP-011 |
DataIntegrity | ResultFrame position values map exactly to USD xformOp:translate |
MBCA-VER-004 |
MBCA-COMP-011 |
DataIntegrity | ResultsApplicator logs a warning for unknown prim paths (not silent) |
MBCA-VER-005 |
MBCA-COMP-040 |
UIBehavior | microrobotica.scene().set_attribute() writes to override layer only |
MBCA-VER-006 |
MBCA-COMP-001 |
Regression | StubPhysicsProcess produces monotonically increasing simTime |
MBCA-VER-007 |
MBCA-COMP-011 |
DataIntegrity | Orientation values map exactly to USD xformOp:orient |
MBCA-VER-008 |
MBCA-COMP-011 |
DataIntegrity | MeshData vertexColors map exactly to primvars:displayColor |
MBCA-VER-009 |
MBCA-IMPL-010 |
ProtocolFidelity | ResultFrame JSON survives ZMQ PUB/SUB transport without corruption |
MBCA-VER-010 |
MBCA-IMPL-012 |
DataIntegrity | MimeStubPhysicsProcess data arrives at USD prims via demo scene pipeline |
Note on MBCA-VER-004: This benchmark documents the desired behaviour that fixes MBCA-ANO-001 — the verification test should currently fail until the fix is implemented. This is intentional: verification tests are written against the correct behaviour, not the current behaviour. A failing MBCA-VER-004 in CI is expected until the ResultsApplicator logging fix lands. This benchmark is the resolution_verification target for MBCA-ANO-001. When MBCA-VER-004 passes in CI, MBCA-ANO-001 may be updated to resolution_status: "fixed" with resolution_verification: "MBCA-VER-004".
Adapts MADDENING Section 9.5 for C++17. Uses [[deprecated]] attribute and a compile-time registry.
// src/core/stability.h
#pragma once
#include <spdlog/spdlog.h>
/// Mark a class or function as deprecated with a compiler warning.
#define MBCA_DEPRECATED(msg) [[deprecated(msg)]]
/// Mark a class as experimental.
/// Emits a runtime spdlog::warn on the first instantiation of the class,
/// not at program startup. Place in the class constructor body.
///
/// Usage:
/// MyExperimentalClass::MyExperimentalClass() {
/// MBCA_EXPERIMENTAL_WARN("MyExperimentalClass");
/// // ... rest of constructor
/// }
#define MBCA_EXPERIMENTAL_WARN(class_name) \
do { \
static bool _warned = false; \
if (!_warned) { \
spdlog::warn("{} is experimental — API may change without notice. " \
"Do not rely on this interface in production.", class_name); \
_warned = true; \
} \
} while(0)Thread-safety note: The static bool _warned inside MBCA_EXPERIMENTAL_WARN is not thread-safe. For Phase 0 (single-threaded construction) this is acceptable. If construction is ever moved to worker threads, replace with std::atomic<bool>.
Adapts MADDENING Section 9.6 for C++17. Uses spdlog as the logging backend with a dedicated audit log sink.
// src/core/audit_logger.h
#pragma once
#include <string>
#include <nlohmann/json.hpp>
#include <spdlog/spdlog.h>
#include <spdlog/sinks/basic_file_sink.h>
namespace microbotica::core {
/// Lightweight audit logger for regulatory audit trails.
///
/// Writes structured JSON events to a session-specific audit log.
/// Activated when audit_enabled=true in application config.
/// Uses NullSink by default (zero overhead).
///
/// Captured events:
/// - Session start/end (with SessionProvenance)
/// - Scene load (path, hash)
/// - Compute backend selection (local/cloud)
/// - Parameter changes (with timestamp, old/new values)
/// - ResultFrame receipt (frame number, timestamp)
/// - Out-of-range warnings (which values, what thresholds)
/// - Scripting console commands (input, success/failure)
/// - Cloud provenance (SkyPilot job ID, container hash, RTT)
class AuditLogger {
public:
/// Start with no-op sink. Call enable() to activate.
AuditLogger() = default;
/// Enable audit logging to a file.
void enable(const std::string& log_path);
/// Log a structured event.
void logEvent(const std::string& event_type,
const nlohmann::json& data);
/// Log a session start with full provenance.
void logSessionStart(const SessionProvenance& provenance);
/// Log a parameter change with old and new values.
void logParameterChange(const std::string& param_name,
const nlohmann::json& old_value,
const nlohmann::json& new_value);
/// Log receipt of a ResultFrame.
void logResultFrame(int frame_number, double sim_time,
bool any_out_of_range);
/// Log a scripting console command.
void logScriptCommand(const std::string& command,
bool success,
const std::string& error_msg = "");
private:
std::shared_ptr<spdlog::logger> logger_;
bool enabled_ = false;
};
} // namespace microbotica::coreTaken verbatim from MADDENING Section 9.7 with surface substitutions (prefix MBCA-ANO-*, project name, version field name). The three-tier release gate, YAML schema, GitHub Issues label taxonomy, and check_anomalies.py CI validation script are identical in structure.
Same schema as MADDENING, with prefix MBCA-ANO-*:
# MICROBOTICA Known Anomalies Registry
# Updated with each release per IEC 62304 SOUP anomaly assessment requirements
# Schema version: 1.0
schema_version: "1.0"
microbotica_version: "0.1.0"
generated_date: "2026-XX-XX"
anomalies:
- anomaly_id: "MBCA-ANO-001"
title: "ResultsApplicator silently drops ResultFrame fields with unknown prim paths"
description: >
When a ResultFrame contains a prim path that does not exist in the
current USD stage, ResultsApplicator silently ignores it. No warning
is logged and no error is raised. This means if the physics backend
adds a new output field that the scene does not expect, the data is
silently lost.
affected_components: ["ResultsApplicator"]
affected_versions: "0.1.0 – current"
severity: "major"
safety_relevance: "context_dependent"
safety_relevance_rationale: >
In a research context, silently dropped fields are a minor annoyance.
In a clinical context, a dropped field could mean that a critical
simulation output (e.g., drug concentration at a target site) is not
displayed to the operator, who may make decisions based on incomplete
information. The downstream manufacturer must assess whether any
ResultFrame fields in their context of use are safety-critical.
workaround: "Ensure scene prims match expected ResultFrame fields before simulation"
resolution_status: "open"
resolution_verification: "MBCA-VER-004" # warning test that fixes the silent drop
detected_by: "manual_review"
memory_safety_relevant: false
github_issue: null
date_reported: "2026-XX-XX"
- anomaly_id: "MBCA-ANO-002"
title: "ScriptingEngine::execute() blocks the Qt main thread for script duration"
description: >
When a Python script is executed via the scripting console, the
ScriptingEngine::execute() call runs on the Qt main thread and
blocks the event loop for the entire duration of the script. The
UI is completely unresponsive during execution — no viewport
updates, no button clicks, no menu interactions are processed.
affected_components: ["ConsoleWidget", "MicrobotaModule"]
affected_versions: "0.1.0 – current"
severity: "minor"
safety_relevance: "context_dependent"
safety_relevance_rationale: >
In a research context, brief UI freezes during script execution
are a minor inconvenience. In a clinical context where an operator
needs to interrupt a running simulation or respond to an emergency,
a blocking script could delay a safety-critical user action (e.g.,
halting a simulation that has entered a dangerous regime). The
downstream manufacturer must assess whether uninterruptible script
execution is acceptable in their context of use.
workaround: "Keep scripts short; avoid long-running computations in the console"
resolution_status: "open"
resolution_verification: null # async scripting is a future architectural change
detected_by: "manual_review"
memory_safety_relevant: false
github_issue: null
date_reported: "2026-XX-XX"
- anomaly_id: "MBCA-ANO-003"
title: "USD results layer left in partially-written state on physics process crash"
description: >
If the PhysicsProcess backend terminates unexpectedly (crash, OOM,
network loss in cloud mode) while ResultsApplicator::apply() is
mid-write, the USD results layer may contain a mix of current-frame
and previous-frame values. The partially-written results layer
remains visible in the viewport until the user manually reloads the
scene or clears the results layer.
affected_components: ["ResultsApplicator", "SceneManager", "SimulationController"]
affected_versions: "0.1.0 – current"
severity: "major"
safety_relevance: "context_dependent"
safety_relevance_rationale: >
Stale position data from a prior frame may be displayed as current,
potentially misrepresenting a microrobot's last known state to the
operator. In a clinical context, an operator relying on the displayed
position to make a treatment decision could be misled by stale data.
The downstream manufacturer must implement crash detection and
automatic results layer clearing.
workaround: "Reload the scene to clear the results layer after a backend crash"
resolution_status: "open"
resolution_verification: null # crash recovery requires SimulationController changes
detected_by: "manual_review"
memory_safety_relevant: true # mid-write crash may leave SdfLayer inconsistent
github_issue: null
date_reported: "2026-XX-XX"
- anomaly_id: "MBCA-ANO-004"
title: "PhysicsProcess::receiveResult() blocks indefinitely on backend hang"
description: >
PhysicsProcess::receiveResult() is a blocking call with no timeout.
If the physics backend (MADDENING/MIME) enters an infinite loop,
deadlocks, or becomes unresponsive without closing the connection,
receiveResult() will block indefinitely. Because this call executes
on the simulation thread which holds resources needed by the Qt
event loop, the entire application may become unresponsive with no
recovery path other than process termination (kill -9).
affected_components: ["PhysicsProcess", "SimulationController"]
affected_versions: "0.1.0 – current"
severity: "major"
safety_relevance: "context_dependent"
safety_relevance_rationale: >
In a clinical context, an unrecoverable application hang during a
live procedure would prevent the operator from accessing simulation
output or controlling the simulation. The downstream manufacturer
must implement a timeout mechanism (e.g., ZeroMQ RCVTIMEO socket
option) and a watchdog that detects backend unresponsiveness and
triggers a controlled shutdown of the simulation session.
workaround: "Terminate the application process if it becomes unresponsive"
resolution_status: "open"
resolution_verification: null # timeout requires ZmqPhysicsProcess implementation
detected_by: "manual_review"
memory_safety_relevant: false
github_issue: null
date_reported: "2026-XX-XX"Schema fields added beyond MADDENING's base schema:
-
resolution_verification(optional, string): TheMBCA-VER-*benchmark ID that must pass before this anomaly can be marked"fixed". Null if no verification benchmark exists yet. The validator (check_anomalies.py) checks that whenresolution_statusis"fixed", theresolution_verificationfield is non-null and references a validMBCA-VER-*ID that exists in the verification benchmark registry. An anomaly marked"fixed"without a passing verification benchmark fails the release gate. -
detected_by(optional, string): Tool or process that found the anomaly. Values:"asan"|"ubsan"|"tsan"|"valgrind"|"manual_review"|"ci_test"|"user_report". Allows the SOUP package summary to count anomalies by detection method. -
memory_safety_relevant(optional, boolean, defaultfalse):trueif this anomaly involves undefined behaviour, memory corruption, or a data race. Whenmemory_safety_relevant: true, the anomaly'ssafety_relevancemust be explicitly set (not omitted) — memory safety anomalies may not default to"not_safety_relevant"without a documented rationale. This field enables separate counting of memory-safety-relevant anomalies in the SOUP package summary — a metric a Notified Body reviewer is likely to ask about specifically.
Identical to MADDENING:
| Label | Colour | Meaning |
|---|---|---|
anomaly:critical |
Red | Incorrect behaviour, no workaround |
anomaly:major |
Orange | Incorrect behaviour, workaround available |
anomaly:minor |
Yellow | Cosmetic or minor issue |
safety-relevant |
Purple | Could affect safety-critical downstream use |
soup-assessment |
Blue | Relevant to IEC 62304 SOUP evaluation |
known-anomaly |
Grey | Tracked in known_anomalies.yaml |
Identical to MADDENING Section 9.7:
- Tier 1 —
safety-relevant: Hard gate, no grace period - Tier 2 —
anomaly:criticaloranomaly:major: No grace period - Tier 3 —
anomaly:minor: Two-cycle grace period
CI validation via scripts/check_anomalies.py (adapted from MADDENING's maddening.compliance.validate_anomaly_registry() — MICROBOTICA calls it with --prefix MBCA-ANO-).
This section adapts MADDENING Section 9.8 for interface boundaries rather than physics nodes. The technical-vs-clinical boundary principle is preserved identically.
Hazard hints live on both the abstract interface and concrete implementations, with clearly delineated scope:
Abstract interface hazard hints document failure modes inherent to the interface contract itself — conditions that any implementation must contend with. Example: "Undefined behaviour if receiveResult() is called before launch()" is a PhysicsProcess interface-level hazard because it applies to all implementations regardless of transport mechanism.
Concrete implementation hazard hints document failure modes specific to that implementation's technology choices. Example: "ZeroMQ transport drops frames if the remote process is killed mid-step" is a ZmqPhysicsProcess implementation-level hazard that does not apply to StubPhysicsProcess.
How this interacts with the downstream manufacturer's ISO 14971 assessment: When the manufacturer assesses MICROBOTICA as SOUP, they must evaluate hazard hints at both levels. The interface-level hints apply regardless of which implementation the manufacturer uses. The implementation-level hints apply only to the specific implementations they deploy. When the concrete implementation wraps an upstream SOUP component (e.g., ZmqPhysicsProcess communicates with MIME, which uses MADDENING), the implementation-level hazard hints should cross-reference upstream anomalies where relevant (e.g., "See MIME-ANO-003 for upstream anomaly affecting this transport path"). The manufacturer must assess the upstream anomaly through both MICROBOTICA's and MIME's SOUP packages.
Taken verbatim in principle from MADDENING Section 9.8. The boundary is:
- MICROBOTICA provides technical conditions only — interface contract violations, transport failures, rendering pipeline limitations, scripting API boundary conditions
- MICROBOTICA does NOT provide clinical risk assessments — "could cause patient harm", "risk of neurological damage"
- The transition from technical hint to clinical hazard requires the manufacturer to supply clinical context, device-specific scenario, patient population, and ISO 14971 probability/severity estimation
This section is new — it has no MADDENING equivalent. MICROBOTICA is all UI; MADDENING has no UI. This section addresses IEC 62366-1:2015 considerations.
IEC 62366-1:2015 applies to the commercial manufacturer's product, not to MICROBOTICA itself. MICROBOTICA is not a medical device and is not subject to usability engineering requirements. However, MICROBOTICA's UI design directly affects the use error risks that the downstream manufacturer must assess.
This document must identify:
1. UI Actions with Safety-Relevant Consequences
| UI Action | Safety Consequence | Current Mitigation | Recommended Manufacturer Control |
|---|---|---|---|
| Switching physics backend (validated → unvalidated) | Simulation output no longer verified | Warning dialog | Disable in production mode or require authentication |
| Modifying parameters during live simulation | Physics backend receives unvalidated values | None (Phase 0) | Parameter whitelist + range validation in SimulationController |
| Executing arbitrary Python in scripting console | Can modify scene state and inject parameters | None | Sandboxed scripting mode in clinical deployment |
| Loading an untrusted USD scene file | Malicious scene could exploit USD parser | None | Scene validation and signing |
| Switching from local to cloud compute during simulation | Results may differ due to platform differences | None | Require simulation restart on backend switch |
2. Out-of-Range Warning System
When simulation output values exceed validated parameter regimes (as defined by MIME/MADDENING's validated_regimes metadata), MICROBOTICA should display a visual warning in the viewport. The specifics:
- Warning appears as a non-dismissible banner in the viewport widget
- Warning states which values are out of range and what the validated range is
- Warning is logged to the audit log
- Warning does NOT halt the simulation — that is an application-layer control decision for the manufacturer
3. Scripting Console Boundaries During Live Simulation
The microrobotica scripting module must define which operations are safe during active simulation:
| Operation | Safe During Simulation? | Rationale |
|---|---|---|
microrobotica.scene().prim_paths() |
Yes | Read-only |
microrobotica.scene().get_attribute(...) |
Yes | Read-only |
microrobotica.scene().set_attribute(...) |
No — writes to override layer | Could modify scene geometry while physics is running on stale geometry |
microrobotica.sim().current_time() |
Yes | Read-only |
microrobotica.sim().current_frame() |
Yes | Read-only |
microrobotica.sim().send_parameters(...) |
Conditional | Safe if parameters are within validated ranges; unsafe otherwise |
Resolution of Concern 4 (Scripting console safety boundary): Parameter validation should be implemented at two layers:
-
SimulationController(primary): A parameter whitelist and range check before forwarding toPhysicsProcess. This is the architectural enforcement point — it exists regardless of how parameters arrive (scripting console, UI widget, programmatic API). The whitelist is populated from MIME/MADDENING'svalidated_regimesmetadata at simulation launch time. -
MicrobotaModule.cpp(secondary): Type validation (correct Python types for each parameter) and a runtime check thatsend_parameters()is not called when the simulation is in an unsafe state. This catches errors at the scripting API boundary before they reachSimulationController. -
Documented limitation for downstream manufacturer: Even with both layers, the parameter validation is a best-effort safeguard, not a safety barrier. The validated ranges come from MIME/MADDENING and may not cover all possible dangerous parameter combinations. The downstream manufacturer must implement their own parameter governance (potentially hardware-in-the-loop validation or formal parameter approval workflows) for clinical deployment. This limitation is documented in the component guide for
SimulationControllerand in the SOUP package.
This section is new — it has no MADDENING equivalent. The USD layer separation architecture is a safety-relevant design decision unique to MICROBOTICA.
MICROBOTICA enforces a three-layer USD composition stack:
Layer 3 (strongest): Results Layer (session sublayer)
Written by: ResultsApplicator ONLY
Contains: simulation output (prim transforms, scalar fields)
Persisted: NEVER — destroyed when session ends
Mutability: overwritten every frame
Layer 2 (middle): Override Layer (user sublayer)
Written by: microrobotica.scene().set_attribute() ONLY
Contains: user parameter overrides, annotation prims
Persisted: optionally, as a .usd sidecar file
Mutability: modified by user scripting commands
Layer 1 (weakest): Base Layer (scene file)
Written by: scene file loader ONLY
Contains: original scene geometry, materials, initial state
Persisted: always — this IS the scene file
Mutability: NEVER modified after load
USD composition semantics mean that a stronger layer's opinion overrides a weaker layer's. This architecture ensures:
-
Simulation output never contaminates the base scene: If the simulation writes a wildly incorrect position, the base geometry is unaffected. Restarting the simulation (clearing the results layer) restores the base state exactly.
-
User overrides are separable from simulation results: A user script that modifies a parameter can be undone by removing the override layer, without affecting either the base scene or current simulation results.
-
The base scene is immutable after load: This provides a clean "known-good state" that can always be restored. In a clinical context, this means the anatomical geometry (e.g., CSF ventricle mesh from imaging data) is never modified by simulation output or user scripting.
The test_layer_stack.cpp verification test suite (seed exists in Phase 0) must verify:
| Test | What It Proves | Benchmark ID |
|---|---|---|
| Base layer is never written by ResultsApplicator | Simulation output cannot contaminate base scene | MBCA-VER-001 |
| Results layer is not persisted on scene save | Results are session-only | MBCA-VER-002 |
| ResultFrame position maps exactly to USD xformOp:translate | Data integrity through the rendering pipeline | MBCA-VER-003 |
| ResultsApplicator logs warning for unknown prim paths | No silent data loss (fixes MBCA-ANO-001) | MBCA-VER-004 |
set_attribute() writes only to override layer |
Scripting cannot contaminate base or results | MBCA-VER-005 |
| Orientation values map exactly to USD xformOp:orient | Orientation data integrity through the rendering pipeline | MBCA-VER-007 |
| MeshData vertexColors map exactly to primvars:displayColor | Vertex-color data integrity through the rendering pipeline | MBCA-VER-008 |
| ResultFrame JSON survives ZMQ PUB/SUB transport | IPC protocol fidelity through the ZMQ transport | MBCA-VER-009 |
| MimeStubPhysicsProcess data arrives at USD prims via demo scene | End-to-end data integrity through the full pipeline | MBCA-VER-010 |
docs/component_guide/implementations/scene_manager.md and docs/component_guide/implementations/results_applicator.md must document the three-layer architecture, the invariants it enforces, and the verification evidence that supports each invariant.
If the PhysicsProcess backend terminates unexpectedly (crash, OOM, network loss in cloud mode), the USD results layer may be left in a partially-written state. The results layer is an in-memory SdfLayer with the most recently applied ResultFrame values — these may be mid-write if the crash occurs during ResultsApplicator::apply(). Recovery requires: (1) stopping the simulation loop, (2) clearing the results layer via resultsLayer->Clear(), (3) reloading the base layer. MICROBOTICA does not implement automatic crash recovery in Phase 0. The SimulationController should catch the exception from PhysicsProcess::receiveResult() (which will throw or return std::nullopt when the backend dies) and emit a Qt signal that triggers the crash recovery UI flow. This recovery path must be implemented before MIME integration — it is a Phase 1 requirement, not Phase 2.
This section is new — it has no MADDENING equivalent. The microrobotica Python module is the surface most likely to be misused and requires explicit contract documentation.
import microrobotica
# Scene access (read-only during simulation)
microrobotica.scene().prim_paths() # → list[str]
microrobotica.scene().get_attribute(prim, attr) # → value
microrobotica.scene().set_attribute(prim, attr, value) # → None (override layer)
# Simulation access
microrobotica.sim().current_time() # → float
microrobotica.sim().current_frame() # → dict (mirrors ResultFrame)
microrobotica.sim().send_parameters(params_dict) # → None
microrobotica.sim().status() # → str ("idle"|"running"|"paused"|"error")This is the authoritative table for which operations are safe during active simulation. The summary table in Section 8.8 is a subset — this table is canonical.
| Operation | Safe During Simulation? | Phase 0 Enforcement | Required Manufacturer Control |
|---|---|---|---|
microrobotica.scene().prim_paths() |
Yes — read-only | None needed | None |
microrobotica.scene().get_attribute(path, attr) |
Yes — read-only | None needed | None |
microrobotica.scene().set_attribute(path, attr, val) |
No — writes override layer | Documented limitation only | Disable scripting console during active simulation, or implement scene locking |
microrobotica.sim().current_time() |
Yes — read-only | None needed | None |
microrobotica.sim().current_frame() |
Yes — read-only | None needed | None |
microrobotica.sim().send_parameters(params) |
Conditional — type-checked only | Type validation in MicrobotaModule.cpp; range validation deferred | Parameter whitelist + validated range enforcement |
microrobotica.sim().status() |
Yes — read-only | None needed | None |
-
Layer isolation:
set_attribute()writes to the override layer ONLY. Attempting to write to a prim path that is managed by the results layer raisesRuntimeError. -
Simulation state safety:
set_attribute()raisesRuntimeErrorwhen called during an active simulation (state ==Running). The simulation must be paused or stopped before scene modifications. -
Parameter validation:
send_parameters()validates:- All keys are
str - All values are JSON-serializable
- If a parameter whitelist is active (populated from MIME/MADDENING
validated_regimes), out-of-range values raiseValueErrorwith a descriptive message including the validated range
- All keys are
-
Thread safety: All
microroboticamodule calls are dispatched to the Qt main thread viaQMetaObject::invokeMethod()withQt::BlockingQueuedConnection. The scripting console runs on a separate Python thread; all mutations are serialized through Qt's event loop. -
Error handling: Invalid arguments during an active session produce Python exceptions (
RuntimeError,ValueError,TypeError), never C++ crashes. The scripting engine catches all exceptions and displays them inConsoleWidget. No exception causes the simulation to enter an undefined state.
The microrobotica module executes on the Qt main thread, holding the Python GIL for the duration of each call. This means:
- Scripts that run long computations block the Qt event loop (see
MBCA-ANO-002) - Qt signals are not processed during script execution
- The module must never be called from a worker thread — doing so without explicit GIL management will cause undefined behaviour
This is a known architectural constraint in Phase 0, acceptable for a research tool. A future async scripting mode (executing scripts in a sub-interpreter on a worker thread with proper GIL release) is the long-term solution, deferred until Phase 2 or later.
The microrobotica embedded module is compiled from src/scripting/MicrobotaModule.cpp using PYBIND11_EMBEDDED_MODULE. The same source file will be compiled as a standalone pybind11 extension module when -DBUILD_PYTHON_MODULE=ON is passed to CMake. The CMake target is:
if(BUILD_PYTHON_MODULE)
pybind11_add_module(microrobotica src/scripting/MicrobotaModule.cpp)
target_include_directories(microrobotica PRIVATE src)
endif()This proves the future library is buildable from day one. The standalone library will be published to PyPI as microrobotica and will allow external Python scripts and Jupyter notebooks to drive MICROBOTICA sessions programmatically (connecting to a running MICROBOTICA instance via a local socket). The API contract defined in this section is the same API contract the standalone library will expose.
The single-source-file design (MicrobotaModule.cpp used for both embedded and standalone) means the API cannot diverge between the two deployment modes. Any change to the embedded API is automatically reflected in the standalone library at the next build.
This section is new — it has no MADDENING equivalent. When MADDENING/MIME runs on SkyPilot cloud infrastructure and results stream back to MICROBOTICA, the provenance chain is longer and must be captured.
When MICROBOTICA connects to a remote compute backend (via SkyPilotComputeBackend), the audit logger must capture:
| Field | Source | Why It Matters |
|---|---|---|
| Cloud provider (AWS/GCP/Azure) | SkyPilot job metadata | Reproducibility: different providers may have different GPU hardware |
| SkyPilot job ID | SkyPilot API | Traceability: maps MICROBOTICA session to cloud job |
| Container image hash | Docker inspect on remote | Ensures the exact MIME/MADDENING versions are known |
| MIME version | IPC handshake response | SOUP-of-SOUP identification |
| MADDENING version | IPC handshake response | SOUP-of-SOUP identification |
| GPU hardware model | Remote system info | Platform-dependent numerical behaviour |
| Network round-trip time (RTT) | ZeroMQ heartbeat | Detects latency that could affect real-time use |
| Frames dropped | Sequence number gaps | Data integrity — any dropped frame is a provenance gap |
| Frames reordered | Sequence number ordering | Data integrity — reordered frames indicate network issues |
If any frames are dropped or reordered during a cloud compute session, the session provenance record must flag this. The audit log records the gap; the session summary includes frames_dropped and frames_reordered counts. MICROBOTICA does not attempt to interpolate or reconstruct missing frames — it renders what it receives and logs what it doesn't.
In a clinical context, the downstream manufacturer must decide whether dropped frames are acceptable in their context of use (they likely are for offline pre-operative planning; they are not for real-time intraoperative use).
Taken verbatim in structure from MADDENING Section 10. The SOUP package template is identical, with MICROBOTICA-specific content.
docs/validation/soup_package.md:
# MICROBOTICA SOUP Package — v[X.Y.Z]
## 1. Software Identification (IEC 62304 Clause 5.3.3)
| Field | Value |
|-------|-------|
| Name | MICROBOTICA |
| Full name | MICROROBOTics Iterative simulation for Clinical Adoption |
| Version | [X.Y.Z] |
| Release date | [YYYY-MM-DD] |
| Licence | AGPL-3.0-or-later |
| Source repository | https://github.com/[org]/MICROBOTICA |
| SHA-256 (source tarball) | [hash] |
| Build system | CMake 3.25+, GCC 13, Ubuntu 24.04 |
| Runtime dependencies | Qt 6.6, OpenUSD 24.08, pybind11 2.12 |
## 2. Functional Description (IEC 62304 Clause 5.3.4 support)
MICROBOTICA provides:
### Core Application
- USD-based 3D scene management with three-layer composition
- Dual viewport: local Hydra/Storm rendering and Selkies WebRTC streaming
- Simulation timeline control via SimulationController
- Embedded Python scripting console (`microrobotica` module)
### Integration Interfaces (src/core/)
- PhysicsProcess: abstract physics computation backend
- RenderBackend / RenderSession: abstract rendering backend
- ComputeBackend: abstract compute resource management
- ResultFrame: structured simulation output
- PhysicsConfig: validated simulation configuration
### Capabilities NOT provided
- MICROBOTICA does not perform physics simulation
- MICROBOTICA does not interpret simulation results clinically
- MICROBOTICA does not provide diagnostic or therapeutic output
- MICROBOTICA does not validate that simulation parameters match
any real physical system
- MICROBOTICA does not enforce safety limits on user-provided
parameters (see Section 8.8 for the scripting safety boundary)
- MICROBOTICA does not currently surface biocompatibility simulation
output (protein adsorption, coating degradation) — this is planned
for Phase 2 when MIME's biocompatibility nodes are integrated
## 3. Known Anomalies (IEC 62304 Clauses 7.1.2, 7.1.3)
See `docs/validation/known_anomalies.yaml` for the complete,
machine-readable known anomalies registry for this release.
Summary of [N] known anomalies:
- Critical: [N] (of which safety-relevant: [N])
- Major: [N] (of which safety-relevant: [N])
- Minor: [N]
- Context-dependent safety relevance: [N]
## 4. Verification Evidence (IEC 62304 Clause 5.5/5.6 support)
### Test Suite Summary
- Total tests: [N]
- Verification tests: [N]
- Integration tests: [N]
- Pass rate: [N]% (release CI)
- Platforms tested: [list]
- CI system: [description, link]
### Verification Traceability (Class C)
| Component | Verification Test | Acceptance Criterion | Result |
|---|---|---|---|
| SceneManager | MBCA-VER-001 | Base layer never written by ResultsApplicator | PASS |
| SceneManager | MBCA-VER-002 | Results layer never persisted to disk | PASS |
| ResultsApplicator | MBCA-VER-003 | Position values map exactly to xformOp:translate | PASS |
| ResultsApplicator | MBCA-VER-004 | Warning logged for unknown prim paths | FAIL (expected — see MBCA-ANO-001) |
| MicrobotaModule | MBCA-VER-005 | set_attribute() writes to override layer only | PASS |
| StubPhysicsProcess | MBCA-VER-006 | simTime monotonically increasing | PASS |
| ResultsApplicator | MBCA-VER-007 | Orientation values map exactly to xformOp:orient | PASS |
| ResultsApplicator | MBCA-VER-008 | MeshData vertexColors map exactly to primvars:displayColor | PASS |
| MimePhysicsProcess | MBCA-VER-009 | ResultFrame JSON survives ZMQ PUB/SUB transport | PASS |
| MimeStubPhysicsProcess | MBCA-VER-010 | Data arrives at USD prims via demo scene pipeline | PASS |
## 5. IEC 62304 Lifecycle Activities Performed
[See Section 13 for the full mapping.]
## 6. Configuration Management
- All source code in Git with complete history
- Tagged releases on GitHub
- SHA-256 hashes for source tarballs
- CITATION.cff for citation and version identification
- SBOM available at [path]
## 7. Anomaly Management Policy
[Same structure as MADDENING Section 10, §7]
## 8. Dependencies (SOUP of SOUP)
### 8.1 MIME
| Field | Value |
|-------|-------|
| Name | MIME |
| Version | [X.Y.Z] (pinned) |
| Licence | LGPL-3.0-or-later |
| SOUP package | [URL to MIME's soup_package.md, version-tagged] |
| Known anomalies | [URL to MIME's known_anomalies.yaml, version-tagged] |
MIME in turn depends on MADDENING. See MIME's SOUP package
Section 8 for the MADDENING dependency chain.
### 8.2 Direct Dependencies
| Dependency | Version | Licence | Purpose |
|---|---|---|---|
| Qt | 6.6.x | LGPL-3.0 | UI framework, OpenGL, WebEngine |
| OpenUSD | 24.08 | Modified Apache-2.0 | Scene format, Hydra/Storm renderer |
| pybind11 | 2.12.x | BSD-3-Clause | Embedded Python interpreter |
| ZeroMQ/cppzmq | 4.x | MPL-2.0 / MIT | IPC to physics backends |
| spdlog | 1.x | MIT | Logging |
| nlohmann_json | 3.x | MIT | JSON serialization |
| Catch2 | 3.x | BSL-1.0 | Testing framework |The MICROBOTICA SOUP chain is the longest in the ecosystem:
Commercial Product
└── MICROBOTICA (SOUP) ← assessed directly
├── Qt 6.6 (SOUP of SOUP)
├── OpenUSD 24.08 (SOUP of SOUP)
├── pybind11 (SOUP of SOUP)
├── ZeroMQ (SOUP of SOUP)
└── MIME (SOUP of SOUP)
└── MADDENING (SOUP of SOUP of SOUP)
├── JAX (SOUP³)
└── NumPy (SOUP³)
The manufacturer must assess the entire chain. MICROBOTICA's SOUP package Section 8 provides the first level of chain documentation; MIME's SOUP package Section 8 provides the second level (MADDENING); and MADDENING's SOUP package Section 8 provides the third level (JAX, NumPy).
Adapts MADDENING Section 11 for C++/Qt artifacts. The IEC 62304 clause structure is identical; the evidence artifacts change.
MICROBOTICA is not subject to IEC 62304. This mapping is provided voluntarily to support downstream SOUP assessment.
| IEC 62304 Phase | Clause | What the Standard Requires | What MICROBOTICA Provides | Gaps |
|---|---|---|---|---|
| Software development planning | 5.1 | Development plan, standards, tools | DESIGN.md, ROADMAP.md, CONTRIBUTING.md, CMakeLists.txt, CI YAML |
No formal development plan in IEC 62304 format |
| Software requirements analysis | 5.2 | Documented requirements | DESIGN.md, interface contracts in src/core/, test suite |
Requirements implicit in tests, not formal spec with IDs |
| Software architectural design | 5.3 | Architecture document, SOUP identification | DESIGN.md, src/core/ interfaces, ComponentMeta on all interfaces |
Well-documented architecture |
| ↳ Segregation analysis (Class C) | 5.3.5 | Failure isolation evidence | Three-layer USD architecture (Section 9), src/core/ interfaces are pure virtual with no shared mutable state, Qt signal/slot for loose coupling |
USD layer separation is an architecturally enforced segregation boundary |
| Software detailed design | 5.4 | Detailed design per unit | Component guide documents, Doxygen comments, ComponentMeta |
Coverage grows as component guide is populated |
| Software unit implementation | 5.5 | Implementation per design | Source code in src/, Doxygen-documented |
Code is structured by architectural layer |
| Software unit verification | 5.6 | Unit verification evidence | tests/ with Catch2, tests/verification/ for formal benchmarks; ASan/UBSan on every PR; TSan nightly; Valgrind weekly on verification suite |
Memory safety analysis is CI-enforced; errors enter the anomaly registry |
| Software integration testing | 5.7 | Integration test evidence | Integration tests exercising interface → implementation paths | Present |
| Software system testing | 5.8 | System-level testing | End-to-end session tests (load scene → run sim → verify output) | Examples serve as system tests |
| Software release | 5.9 | Release documentation | CHANGELOG.md, tagged releases, known_anomalies.yaml, SOUP package |
Once SOUP package is populated, well-covered |
For IEC 62304 Clause 5.3, the unit decomposition of MICROBOTICA is:
| Software Unit | Header(s) | Responsibility | Component ID |
|---|---|---|---|
PhysicsProcess |
src/core/physics_process.h |
Abstract physics backend interface | MBCA-COMP-001 |
RenderBackend |
src/core/render_backend.h |
Abstract interface for local rendering backends | MBCA-COMP-002 |
RenderSession |
src/core/render_session.h |
Abstract interface for cloud streaming render sessions | MBCA-COMP-003 |
ComputeBackend |
src/core/compute_backend.h |
Abstract interface for compute resource management | MBCA-COMP-004 |
ResultFrame |
src/core/result_frame.h |
Structured simulation output data type | MBCA-COMP-005 |
PhysicsConfig |
src/core/physics_config.h |
Validated simulation configuration data type | MBCA-COMP-006 |
SceneManager |
src/scene/scene_manager.h |
USD stage ownership and three-layer composition enforcement | MBCA-COMP-010 |
ResultsApplicator |
src/scene/results_applicator.h |
ResultFrame to USD prim attribute mapping | MBCA-COMP-011 |
SimulationController |
src/simulation/simulation_controller.h |
Timeline control and PhysicsProcess orchestration | MBCA-COMP-020 |
ViewportWidget |
src/viewport/viewport_widget.h |
Local/stream viewport switching | MBCA-COMP-030 |
MicrobotaModule |
src/scripting/MicrobotaModule.cpp |
microrobotica Python scripting API (embedded + future standalone) |
MBCA-COMP-040 |
ConsoleWidget |
src/scripting/console_widget.h |
In-app Python REPL panel | MBCA-COMP-041 |
The src/core/ interfaces are the primary unit decomposition artifact. Each interface defines an architectural boundary; each concrete implementation is a sub-unit.
Taken verbatim in structure from MADDENING Section 12. The same Annex I GSPRs and Annex II sections apply; the evidence artifacts change.
| Annex II Section | What MICROBOTICA Provides |
|---|---|
| §2 — Information supplied by manufacturer | intended_use.md, downstream_integration.md, README disclaimer |
| §4 — Design and manufacturing information | DESIGN.md, docs/component_guide/, docs/validation/, soup_package.md, IEC 62304 mapping |
| §6 — Benefit-risk analysis | Component hazard hints, known_anomalies.yaml, validated regimes |
17.1: MICROBOTICA's state-of-the-art evidence: published verification tests, systematic architecture (abstract interfaces in src/core/), established rendering technology (OpenUSD, Hydra/Storm), peer-reviewed scripting interface pattern (pybind11).
17.3: SOUP package Section 1 includes hardware/OS requirements. SECURITY.md documents vulnerability reporting. SBOM artifacts support cybersecurity assessment per MDCG 2019-16.
Taken verbatim in structure from MADDENING Section 13, with MICROBOTICA-specific analysis.
MICROBOTICA is NOT a medical device because:
-
No medical purpose: MICROBOTICA is a research simulator. It displays physics simulation output in a 3D viewport and provides scripting access to scene and simulation state. It does not perform any function listed in EU MDR Article 2(1).
-
Research platform: MDCG 2019-11 Section 3.2 explicitly states that "generic tools or general purpose software [...] are not in themselves medical devices." MICROBOTICA is analogous to 3D Slicer, ParaView, or NVIDIA Omniverse for research.
-
No clinical interpretation: MICROBOTICA renders numerical simulation output. It does not interpret results in a clinical context, provide diagnostic conclusions, or make therapeutic recommendations.
A commercial product built on MICROBOTICA with a medical purpose would be classified identically to the analysis in MADDENING Section 13: Class IIb minimum for intraoperative digital twin use; Class III for RL policy generation for active microrobot control.
MICROBOTICA's position at Layer 3 makes it the most proximate open-source component to the commercial product. The manufacturer's classification dossier will reference MICROBOTICA's SOUP package as the primary SOUP assessment, with MIME and MADDENING as SOUP-of-SOUP dependencies assessed through MICROBOTICA's SOUP package chain documentation.
Adapts MADDENING Section 14 for C++ distribution. No PyPI; uses source tarballs and CMake.
- GitHub release tags: Each version tagged in Git with SHA-256 hashes for source tarballs
- CITATION.cff: Academic citation and configuration management artifact
- SessionProvenance: Captures
microbotica_versionat runtime (Section 8.2) - SBOM: CycloneDX format, generated from
CMakeLists.txtdependency declarations andvcpkg.json/conanfile.txt(whichever package manager is used)
cff-version: 1.2.0
message: "If you use MICROBOTICA, please cite it as below."
title: "MICROBOTICA"
type: software
version: "0.1.0"
date-released: "2026-XX-XX"
license: "AGPL-3.0-or-later"
repository-code: "https://github.com/[org]/MICROBOTICA"
authors:
- family-names: "[Author]"
given-names: "[Author]"
orcid: "https://orcid.org/XXXX-XXXX-XXXX-XXXX"Taken verbatim from MADDENING Section 15 — same model, same rationale. MICROBOTICA is a solo research project that does not operate under an ISO 13485 QMS. The same substitution table applies (Git for version control, CI for verification, GitHub Issues for corrective action, etc.).
This section is new from MICROBOTICA's perspective — it is the counterpart to MADDENING's downstream_integration.md, but written from Layer 3's viewpoint (the layer most likely to be the direct dependency of a commercial product).
This document describes how a commercial manufacturer building on MICROBOTICA inherits from all three upstream layers:
Commercial Product (CE-marked SaMD)
├── MICROBOTICA (Layer 3, AGPL-3.0, SOUP)
│ ├── Qt, OpenUSD, pybind11, ZeroMQ (SOUP of SOUP)
│ └── MIME (Layer 2, LGPL-3.0, SOUP of SOUP)
│ └── MADDENING (Layer 1, LGPL-3.0, SOUP of SOUP of SOUP)
│ └── JAX, NumPy (SOUP³)
└── Manufacturer's own code (clinical interpretation, UI customization,
safety controls, regulatory compliance layer)
| Manufacturer's Need | MICROBOTICA Provides |
|---|---|
| Software identification (IEC 62304 §5.3.3) | SOUP package §1 with version, hash, dependencies |
| Functional specification (IEC 62304 §5.3.4) | SOUP package §2 with capability list and "NOT provided" list |
| Known anomalies (IEC 62304 §7.1.2) | known_anomalies.yaml with MBCA-ANO-* entries |
| Architecture for SOUP assessment (IEC 62304 §5.3) | DESIGN.md, component guide, src/core/ interfaces |
| Segregation evidence (IEC 62304 §5.3.5) | Three-layer USD architecture, src/core/ pure virtual interfaces |
| V&V evidence (IEC 62304 §5.5/5.6) | Catch2 verification tests, verification traceability table |
| SOUP chain (MIME + MADDENING) | SOUP package §8 with pinned versions and cross-references |
| Usability engineering input (IEC 62366) | usability_engineering.md with safety-relevant UI actions |
| Configuration management (IEC 62304 §8) | CITATION.cff, Git tags, SHA-256 hashes, SBOM |
| Requirement | Why MICROBOTICA Cannot Provide It |
|---|---|
| ISO 14971 risk management file | Risk assessment requires clinical context MICROBOTICA does not have |
| Clinical evaluation report (CER) | Clinical evidence requires clinical studies |
| IEC 62366-1 usability engineering file | Usability evaluation requires the manufacturer's own clinical UI |
| ISO 13485 QMS | QMS requires organisational structure |
| Notified Body relationship | Legal/financial obligation |
| Post-market surveillance (PMS, PSUR, PMCF) | Legal obligation requiring ongoing clinical monitoring |
| Parameter governance for clinical deployment | Clinical parameter ranges specific to the manufacturer's COU |
| Scripting console access controls | Authentication/authorisation for clinical contexts |
| Network security for cloud compute | TLS/CurveZMQ configuration for clinical deployment |
| Biocompatibility assessment for specific materials | Requires ISO 10993 testing; MIME provides simulation predictions only, not regulatory evidence |
The AGPL-3.0 licence has specific implications for commercial deployment:
- On-premises deployment (MICROBOTICA runs on the manufacturer's hardware, no network interaction with external users): AGPL source disclosure obligation may not be triggered, subject to legal interpretation of "network interaction."
- Cloud/SaaS deployment (MICROBOTICA's functionality served over a network): AGPL requires complete source disclosure to network users.
- Dual licensing: The developer retains the option to offer commercial licences that waive the AGPL network disclosure requirement.
Commercial manufacturers should obtain legal counsel on AGPL compliance for their specific deployment model before incorporating MICROBOTICA.
| Section | Relationship to MADDENING | What Changed |
|---|---|---|
| §1 Documentation Structure | Adapted | Doxygen/Breathe instead of autodoc; component_guide instead of algorithm_guide; usability_engineering.md added |
| §2 Regulatory Boundary Language | Near-verbatim | AGPL instead of LGPL; Layer 3 framing; scripting console cybersecurity |
| §3 Component Documentation Standards | Adapted | Interface/implementation templates instead of algorithm templates; implementation map traces interface→impl not equation→code |
| §4 V&V Documentation Hooks | Adapted | Application-layer V&V scope; "faithful rendering" boundary; dependency acknowledgement language |
| §5 Versioning and API Stability | Verbatim | ui: commit prefix added |
| §6 Contributor Standards | Adapted | C++/CMake/Catch2 checklist instead of Python/pytest |
| §6 Memory Safety (addition) | New | No MADDENING equivalent (Python GC; different safety profile); ASan/UBSan/TSan/Valgrind suite for C++17; anomaly schema extended with detected_by and memory_safety_relevant fields |
| §7 README and Root Files | Near-verbatim | AGPL licence; C++ build instructions |
| §8.1 ComponentMeta | Adapted | C++ struct instead of Python dataclass; interface + implementation granularity |
| §8.2 Session Provenance | Adapted | Cloud provenance fields added; desktop session model |
| §8.3 Verification Test Registration | Adapted | Catch2 tags + C++ macro instead of Python decorator |
| §8.4 Deprecation/Stability | Adapted | C++ [[deprecated]] + spdlog instead of Python warnings |
| §8.5 Audit Logging | Adapted | spdlog backend; cloud provenance events; scripting events |
| §8.6 Anomaly Management | Verbatim | Prefix MBCA-ANO-* instead of MADD-ANO-* |
| §8.7 ISO 14971 Hazard Hints | Adapted | Interface + implementation dual-level scoping |
| §8.8 Usability Engineering | New | IEC 62366; UI safety actions; scripting boundaries |
| §9 Rendering Pipeline | New | Three-layer USD architecture; layer separation verification |
| §10 Scripting API Contract | New | microrobotica module safety boundaries; GIL/main-thread constraint; future standalone library boundary; complete operation safety table |
| §11 Cloud Provenance | New | SkyPilot/Selkies provenance; frame drop tracking |
| §12 SOUP Package | Near-verbatim | C++ dependencies; SOUP-of-SOUP-of-SOUP chain |
| §13 IEC 62304 Mapping | Adapted | CMake/Catch2 artifacts; three-layer USD segregation |
| §14 EU MDR Alignment | Near-verbatim | Same Annex I/II mapping |
| §15 MDCG 2019-11 | Near-verbatim | Layer 3 specifics |
| §16 Configuration Management | Adapted | Source tarballs instead of PyPI |
| §17 QMS Compatibility | Verbatim | Same model |
| §18 Downstream Integration | New from MBCA perspective | Three-layer SOUP chain; AGPL considerations |
Phase 0 establishes the proving shell and documentation foundation. Phases 1–2 build verification infrastructure and regulatory documents. Phase 3 adds cloud integration and community features. Phase 4 adds full documentation site and commercial-readiness artifacts.
Resolution of Concern 6 (Phase-gated documentation): Phase 0 documentation must exist before any code is written beyond the proving shell. This is the minimum set needed to establish the documentation discipline from day one.
0a. ComponentMeta struct in src/core/component_meta.h (Section 8.1) — define the struct and attach to all Phase 0 src/core/ interfaces
0b. docs/validation/known_anomalies.yaml (Section 8.6) — start the anomaly registry immediately, even if empty
0c. CHANGELOG.md (Section 5) — start structured changelog
0d. CITATION.cff (Section 16) — citation and CM artifact
0e. README disclaimer (Section 7) — EU MDR-aware intended use statement
0f. docs/regulatory/intended_use.md (Section 2) — platform positioning statement
0g. Skeleton docs/regulatory/downstream_integration.md (Section 18) — four-layer chain + commercial boundary statement
0h. GitHub Issues label taxonomy (Section 8.6) — anomaly labels
0i. .github/ISSUE_TEMPLATE/anomaly.md (Section 8.6) — structured anomaly issue template
0j. scripts/check_anomalies.py (Section 8.6) — YAML validation (calls with --prefix MBCA-ANO-)
0k. Skeleton docs/validation/soup_package.md (Section 12) — Sections 1-3 at minimum
MIME Integration Gate: All Phase 1 items in this checklist must be complete before the first real MIME/MADDENING physics process is wired into MICROBOTICA. This gate is non-negotiable. When real physics data flows through MICROBOTICA for the first time, the verification infrastructure must already be in place. Integration errors that go undetected at first wiring become architectural debt. The integration gate is enforced by a CI check: a GitHub Actions workflow step that verifies the existence of all required Phase 1 files before any branch named
feat/mime-*orfeat/maddening-*can merge to main.
Resolution of Concern 6 (minimum before MIME integration): Before the first real MIME integration, ALL Phase 0 items plus the following must exist.
tests/verification/directory with Catch2 verification tests — seed withtest_layer_stack.cpp- Component guide template (
docs/component_guide/interfaces/_template.md) - Component guide for
PhysicsProcess— the first real interface documentation - Component guide for
ResultsApplicator— the data integrity boundary - Component guide for
SceneManager— the USD layer separation documentation - Verification benchmark registration (Section 8.3) —
REGISTER_VERIFICATION_BENCHMARKmacro docs/validation/framework_verification.md— aggregate verification evidence- Centralized
bibliography.bibandcheck_citations.pyCI script docs/regulatory/iec62304_mapping.md— IEC 62304 lifecycle mappingdocs/regulatory/usability_engineering.md(Section 8.8) — UI safety documentationdocs/component_guide/scripting_api.md(Section 10) —microroboticamodule contractSECURITY.md— vulnerability reporting- Crash recovery path —
SimulationControllerhandlesPhysicsProcesscrash by clearing the results layer and notifying the UI (see MBCA-ANO-003)
- Session provenance (Section 8.2) —
SessionProvenancestruct and audit logger integration - Cloud provenance documentation (Section 11) — SkyPilot/Selkies provenance fields
docs/component_guide/cloud_compute.md— SkyPilot/ZeroMQ/Selkies architecture- IPC protocol verification tests —
test_ipc_protocol.cpp - Audit logger implementation (Section 8.5) — spdlog-based audit logger
- Complete
docs/regulatory/downstream_integration.md(Section 18) — full three-layer SOUP chain documentation docs/regulatory/eu_mdr_guidelines.md(Section 14) — EU MDR alignmentdocs/regulatory/mdcg_2019_11.md(Section 15) — qualification and classificationdocs/validation/cou_template.md— Context of Use template- SBOM generation — CycloneDX from CMake/vcpkg
- Complete SOUP package — all 8 sections fully populated
- Ontology integration forward reference — when the MICROBOTICA registry adds SPARQL-based search (via MCO/Fuseki) and
BiocompatibilityMetadisplay in the asset browser, a documentation architecture update will be required covering: thedocs/component_guide/entries for registry browser components, the SOUP chain extension (Fuseki as a new SOUP dependency), and theknown_anomalies.yamlscope for ontology query failures. This is deferred until the ontology layer design is finalised in the MIME and MICROBOTICA registry documentation architectures.
- Sphinx documentation build — full docs site with Doxygen/Breathe API reference
- Per-component verification reports — auto-generated from CI
GOVERNANCE.md— decision-making processdocs/regulatory/fda_guidelines.md— FDA alignment (secondary market)- Stability machinery (Section 8.4) —
[[deprecated]]+ registry - Complete component guide coverage — every
src/core/interface andsrc/implementation documented
This appendix collects the resolutions to the six concerns raised in the project brief, with cross-references to where each resolution is implemented in the document.
Resolution: ComponentMeta is a plain C++ struct in src/core/component_meta.h, using only standard library types and nlohmann_json. No Qt, USD, or Python dependencies. Granularity: one instance per abstract interface (contract-level) AND per concrete implementation (implementation-specific). See Section 8.1.
Rationale: A header-only struct is the simplest solution that achieves dependency-freedom. JSON sidecar files were considered but rejected because they would separate metadata from the code it describes, creating a documentation-rot risk that the C++ compiler cannot catch. A constexpr approach was considered but rejected because std::string is not constexpr in C++17.
Resolution: Both. Interface-level hazard hints document contract-inherent failure modes (apply to all implementations). Implementation-level hazard hints document technology-specific failure modes (apply to that implementation only). Cross-references to upstream SOUP anomalies via anomaly ID strings (e.g., "See MIME-ANO-003"). See Section 8.7.
Rationale: The downstream manufacturer's ISO 14971 assessment must evaluate both levels. Interface-level hints are evaluated once regardless of implementation choice; implementation-level hints are evaluated per deployment configuration. This matches how a manufacturer would naturally perform hazard identification: first assess the architectural design (interfaces), then assess the detailed design (implementations).
Resolution: MICROBOTICA's V&V explicitly acknowledges the dependency with the "faithful rendering" boundary language. MICROBOTICA verifies that data received is correctly rendered; MIME/MADDENING verify that data produced is physically correct. The conjunction of both is needed for end-to-end correctness. See Section 4.
Rationale: Over-claiming ("MICROBOTICA verifies physics") would misrepresent our V&V scope and could be challenged by a Notified Body. Under-claiming ("the rendering layer has no correctness obligation") would ignore that incorrect rendering of correct physics data is itself a hazard. The "faithful rendering" boundary — analogous to a medical display's fidelity obligation — is both technically accurate and regulatorily defensible.
Resolution: Two-layer validation. Primary: SimulationController parameter whitelist + range check (architectural enforcement point). Secondary: MicrobotaModule.cpp type validation + state check (API boundary). Documented limitation: not a safety barrier; manufacturer must implement clinical parameter governance. See Section 8.8.
Rationale: Single-layer validation at the scripting API is insufficient because parameters can arrive via other paths (UI widgets, programmatic API). Single-layer validation at SimulationController is insufficient because type errors should be caught before they propagate. The "not a safety barrier" documentation is essential because validated ranges come from upstream SOUP and may not cover all dangerous parameter combinations.
Resolution: MICROBOTICA anomaly entries (MBCA-ANO-*) document only defects in MICROBOTICA's own C++ code and the downstream impact of upstream anomalies. An upstream MADDENING anomaly (e.g., LBM numerical instability) does NOT get a separate MBCA-ANO-* entry unless it manifests as a MICROBOTICA-specific failure mode (e.g., "viewport displays divergent results with no warning because the ResultFrame contains NaN values from upstream LBM instability"). See Section 8.6.
Rationale: Duplicating upstream anomalies would create a maintenance burden and risk inconsistency between registries. The correct scoping is: MBCA-ANO-* entries document what MICROBOTICA itself does wrong (or fails to detect) when upstream anomalies surface. The upstream anomaly itself is documented in MADDENING/MIME's registry and cross-referenced by ID string.
Cross-references to upstream anomalies appear in two places:
- MICROBOTICA's SOUP package Section 8 — "MIME/MADDENING Anomalies Relevant to MICROBOTICA" table
- Individual
MBCA-ANO-*entries that describe MICROBOTICA-specific manifestations — thesafety_relevance_rationalefield references the upstream anomaly ID
Resolution: Four-phase model aligned with MICROBOTICA's development phases. Phase 0 (proving shell): ComponentMeta, anomaly registry, intended use, SOUP package skeleton. Phase 1 (before MIME integration): verification tests, component guides for core interfaces, usability engineering, scripting contract. Phase 2 (cloud integration): session provenance, cloud provenance, IPC tests. Phase 3 (commercial interest): full regulatory documentation, complete SOUP package. Phase 4 (user base): documentation site, complete coverage. See Appendix B.
Critical gate: All Phase 0 + Phase 1 items must exist before the first real MIME integration. This ensures that when real physics data flows through MICROBOTICA for the first time, the verification infrastructure (layer separation tests, ResultsApplicator tests, IPC fidelity tests) is already in place. Without this gate, integration errors could go undetected and become entrenched in the codebase.
Repository root files:
-
CHANGELOG.mdexists withVerification,Security, andKnown Anomaliessections (Section 5) -
CITATION.cffexists withcff-version,title,type: software,version,date-released,license,repository-code,authors(Section 16) -
README.mdcontains EU MDR-aware disclaimer (Section 7)
docs/ directory structure:
-
docs/regulatory/directory exists -
docs/validation/directory exists -
docs/component_guide/directory exists
docs/regulatory/intended_use.md:
- File exists (Section 2)
- Contains Platform Positioning Statement identifying MICROBOTICA as research software, not a medical device under EU MDR Article 2(1) (Section 2)
- Contains Layered Responsibility Model table (Section 2)
- Contains Commercial Boundary Statement (Section 2)
- Contains Cybersecurity Boundary Statement (MDCG 2019-16) (Section 2)
- Contains AGPL Licence Statement (Section 2)
docs/regulatory/downstream_integration.md (skeleton):
- File exists (Section 18)
- Contains four-layer dependency chain (Section 18)
- Contains commercial responsibility statement (Section 18)
- Contains forward reference to full content in Phase 3 (Section 18)
docs/validation/known_anomalies.yaml:
- File exists and is valid YAML (Section 8.6)
- Contains
schema_version,microbotica_version,generated_date,anomalieskey (Section 8.6)
docs/validation/soup_package.md (skeleton):
- File exists with Sections 1-3 at minimum (Section 12)
ComponentMeta:
-
src/core/component_meta.hexists withComponentMetastruct (Section 8.1) -
StabilityLevelenum defined (Section 8.1) - All Phase 0
src/core/interfaces haveComponentMetaattached viainterfaceMeta()/meta()(Section 8.1)
GitHub repository settings:
- Labels:
anomaly:critical,anomaly:major,anomaly:minor,safety-relevant,soup-assessment,known-anomaly(Section 8.6) -
.github/ISSUE_TEMPLATE/anomaly.mdexists with mandatory fields (Section 8.6)
CI:
-
scripts/check_anomalies.pyexists and validatesknown_anomalies.yamlwith--prefix MBCA-ANO-(Section 8.6) - CI runs
scripts/check_anomalies.pyon every push (Section 8.6)
Memory safety (Phase 0):
-
CMakePresets.jsoncontainslinux-asanpreset with-fsanitize=address,undefined(Section 6) -
lsan.suppressionsfile exists suppressing known pybind11/CPython shutdown leaks (Section 6) - CI runs
linux-asanbuild on every pull request (Section 6)
MIME Integration Gate: All Phase 1 items must be complete before the first real MIME/MADDENING physics process is wired into MICROBOTICA. This gate is enforced by a CI check that verifies required Phase 1 files exist before any
feat/mime-*orfeat/maddening-*branch can merge to main.
-
tests/verification/directory exists with at least one Catch2 test (Section 8.3) -
docs/component_guide/interfaces/_template.mdexists (Section 3) - Component guides exist for:
PhysicsProcess,ResultsApplicator,SceneManager(Sections 3, 9) -
docs/component_guide/scripting_api.mdexists (Section 10) -
docs/regulatory/usability_engineering.mdexists (Section 8.8) -
docs/regulatory/iec62304_mapping.mdexists (Section 13) -
docs/bibliography.bibexists (Section 3) -
scripts/check_citations.pyexists and runs in CI (Section 3) -
docs/validation/framework_verification.mdexists (Section 4) -
SECURITY.mdexists (Section 7) - Verification benchmark registration macro exists in
src/core/verification_registry.h(Section 8.3) - At least one test registered via
REGISTER_VERIFICATION_BENCHMARK(Section 8.3) -
SimulationControllerhandlesPhysicsProcesscrash by clearing the results layer and notifying the UI (MBCA-ANO-003, Section 9)
Memory safety (Phase 1):
-
CMakePresets.jsoncontainslinux-tsanpreset with-fsanitize=thread(Section 6) -
tsan.suppressionsfile exists suppressing known Qt/Python dispatch patterns (Section 6) -
valgrind.suppressionsfile exists (Section 6) - CI nightly job runs
linux-tsanbuild (Section 6)
-
src/core/session_provenance.hexists withSessionProvenancestruct (Section 8.2) -
src/core/audit_logger.hexists withAuditLoggerclass (Section 8.5) -
docs/component_guide/cloud_compute.mdexists (Section 11) -
tests/verification/test_ipc_protocol.cppexists (Section 4)
-
docs/regulatory/downstream_integration.mdis complete (not skeleton) (Section 18) -
docs/regulatory/eu_mdr_guidelines.mdexists (Section 14) -
docs/regulatory/mdcg_2019_11.mdexists (Section 15) -
docs/validation/cou_template.mdexists (Section 4) -
docs/validation/soup_package.mdfully populated (Section 12) - SBOM generation in release process (Section 16)
-
docs/conf.pyexists (Sphinx) (Section 1) -
Doxyfileexists and generates API reference (Section 1) - Every
src/core/interface has a component guide document (Section 3) - Every
src/implementation has a component guide document (Section 3) -
GOVERNANCE.mdexists (Section 7)