# Public API surface audit (2026-09-30) A snapshot of what the SDK declares as public, what is documented, and where the gaps are. Produced by [`tools/api_audit.py`](../tools/api_audit.py), which is static and read-only — it never imports the package, so it costs no numpy/cv2 import and cannot be affected by the environment. Re-run it after any API change: ```powershell cd D:\orisys_ws\orisys-sdk python tools/api_audit.py # text report python tools/api_audit.py --json # machine-readable python tools/api_audit.py --quiet # headline numbers ``` ## 1. Headline | Measure | Value | |---|---| | Public classes / methods / functions | **393** (53 / 214 / 126) | | With a docstring | **256 (65 %)** | | Fully annotated signature (params + return) | **125 (32 %)** | | Docstring documents its return value | **38** | Docstring conventions actually in use: | Convention | Count | |---|---| | plain prose (no structured sections) | 243 | | none | 137 | | Google (`Args:` / `Returns:`) | 9 | | NumPy (`Parameters` + `---`) | 4 | **Reading:** the dominant convention is not a convention. Structured sections are absent from almost every docstring, and two thirds of signatures are missing type information. The hand-written reference compensates in the places it covers; a generated reference would not. ## 2. The declared public surface The root `__all__` (`src/orisys/__init__.py`) declares 18 names. Sub-surfaces declare a further 88. ### 2.1 Root exports — 9 of 18 are absent from `docs/api.md` | Documented | Not mentioned anywhere in `docs/api.md` | |---|---| | `Sensor`, `util`, `finger`, `signal_processing`, `capture`, `list_config`, `export_config`, `export_sensor_bundle`, `export_sensor_bundles` | **`StreamPipeline`**, **`FrameSnapshot`**, **`PipelineStats`**, **`StreamRecorder`**, **`mosaic_videos`**, **`FFCFrameProcessor`**, `CompoundEyeSensor`, `CameraSensor`, `calibration` | `StreamPipeline` is the engine behind the published "5 × 30 FPS on one desktop, 4.2× headroom" claim and is used by `examples/multi_stream.py`. `StreamRecorder` and `mosaic_videos` are the offline-recording path. None of them has a Markdown reference anywhere in the repository. ### 2.2 Sub-surfaces with no coverage in `api.md` at all | Module | Exports | Documented | Note | |---|---|---|---| | `orisys.unroll` | 18 | 0 | UV domain, remap, geometry — the finger pipeline's core maths | | `orisys.capture` | 17 | 0 | capture sources, workers, reconnect policy, camera discovery | | `orisys.hhd` + `hhd.solvers` | 7 | 0 | **no docstrings either** — see §3 | | `orisys.pipeline` | 3 | 0 | `StreamPipeline` etc. | | `orisys.export` | 2 | 0 | `StreamRecorder`, `mosaic_videos` | ### 2.3 Exports with no docstring — 20 of 88 Includes `CaptureWorker`, `pick_default_camera`, `available_blend_backends`, `compute_final_crop_rect`, `coverage_ratio`, `largest_fully_covered_rect`, `match_bgr_brightness`, `barycentric_grid`, `face_uvs_from_loop_data`, all four `orisys.hhd` exports, and named constants (`DEFAULT_LAPTOP_WEBCAM_PATTERNS`, `MAX_SIMULTANEOUS_CAPTURES`, `DEFAULT_FINGER_EXPORT_DIR`, `DEFAULT_FINGER_MAP_CACHE`, `BLEND_MODES`). ## 3. Coverage by module The extreme cases, which are where effort pays off: | Module | Symbols | Docstrings | Annotated | Comment | |---|---|---|---|---| | `orisys.finger.runtime` | 31 | **35 %** | **3 %** | `FingerRuntime` is the documented entry point for finger users, yet its implementation module is the thinnest in the package | | `orisys.hhd.timing` | 4 | **0 %** | 0 % | | | `orisys.stitch.feature` | 10 | 20 % | 0 % | | | `orisys.stitch.tiles` | 5 | 20 % | 0 % | | | `orisys.stitch.api` | 10 | 30 % | 10 % | | | `orisys.frame_processors` | 21 | 48 % | **0 %** | | | `orisys.capture.source` | 32 | 50 % | 91 % | annotations good, prose thin | | `orisys.sensor` | 21 | 90 % | **38 %** | the most-documented module, still missing annotations | | `orisys.configs` | 13 | 100 % | 69 % | | | `orisys.unroll.precompute`, `domain` | 6 / 6 | 100 % | 0 % | documented but untyped | Annotated and documented do not move together: `capture.source` is 91 % annotated but 50 % documented; `hhd.domain` is 100 % documented but 0 % annotated. ## 4. Used by examples and tests, absent from the reference — 74 names These are APIs users demonstrably reach for and the reference never explains. The highest-traffic group is the runtime/typing surface: `StreamPipeline`, `FrameSnapshot`, `PipelineStats`, `StreamRecorder`, `mosaic_videos`, `FFCFrameProcessor`, `UVDomain`, `UVRemap`, `UVSurfaceMap`, `UVSurfaceMesh`, `UVMeshViewer`, `Tracker`, `Contact3D`, `CalSample`, `CalibrationError`, `StitchStatus`, `CameraInfo`, `CameraFilter`, `CaptureSource`, `CaptureConfig`, `CaptureHealth`, `ReconnectPolicy`, `PoissonSolver`, `nHHD` Plus the finger/geometry helpers (`build_uv_surface_mesh`, `compute_uv_surface_frames`, `lift_uv_flow_to_3d`, `flow_magnitude_vertex_colors`, `scalar_map_vertex_colors`, `sample_field_at_mesh_vertices`, `mesh_uv_to_world_scale`, `resolve_export_paths`, `resolve_finger_geometry`, `load_finger_export_bundle`, `init_uv_mesh_viewer`, `update_uv_mesh_viewer`), the capture helpers (`open_capture`, `normalize_source`, `list_cameras`, `pick_default_camera`), the calibration helpers (`check`, `build`, `parse`, `load`, `calibrate_normal_force`, `calibrate_shear_force`, `calibrate_shear_components`), and the config resolvers (`load_config`, `list_sensor_bundles`, `resolve_sensor_config_path`, `resolve_sensor_resource`, `resolve_sensor_asset_dir`, `pipeline_from_sensor_json`). ## 5. Public classes exported nowhere — 21 Defined, carrying no name-mangling underscore, but in no `__all__` and not reachable as a declared API: `BlendBackend`, `CalSample`, `Calibration`, `CalibrationError`, `CausalMedianFilter`, `ChannelCurve`, `CheckResult`, `CompoundEyeFrameProcessor`, `Contact3D`, `ForceChannelCalibration`, `FrameUnwarper`, `LowpassFilter`, `MaskedDomain`, `MaskedPoissonConfig`, `NumbaBlendBackend`, `NumpyBlendBackend`, `SampleRateEstimator`, `SensorBundle`, `SingleCameraFrameProcessor`, `Tracker`, `VideoCaptureLike`. Two of these are the clearest signals of a boundary that was never decided: - **`LowpassFilter`** is documented in `docs/api.md` as `orisys.signal_processing.LowpassFilter` and is imported by examples — but it appears in neither the submodule's `__all__` nor the root's. It is public by documentation and private by declaration. - **`Calibration`** / `CalibrationError` / `CalSample` / `CheckResult` are the entire force calibration object model, and `calibration.check()` / `calibration.build()` are used directly by the test suite. The `orisys.calibration` package is exported from the root, but none of its public names are declared or documented. Each of the 21 needs one decision: promote into the relevant `__all__`, or rename with a leading underscore to mark it internal. ## 6. What this implies 1. **Fix the declaration boundary first.** Nine root exports have no reference and 21 classes sit in the gap between documented and declared. Publishing a reference on top of an undecided public surface multiplies the confusion rather than resolving it. 2. **Pick one docstring convention before generating anything.** With 243 prose docstrings, 137 absent, and 13 structured, a generator's output would be thin and inconsistent — the tool renders what is there. 3. **Annotations are the larger gap.** 32 % complete signatures means generated parameter tables would be mostly bare. This is mechanical work and it improves IDE help, not only docs. 4. **The omissions are not random.** `StreamPipeline`, `capture` and `unroll` are the *newest* subsystems, and they are the ones with no coverage. The reference drifted toward the parts that existed when it was written. 5. **`orisys.hhd` is documented nowhere and has no docstrings**, yet is exported from the root package. Either document it or stop exporting it — leaving it in `__all__` promises support that does not exist.