tools: add a static public-API audit and record its first run
Adds tools/api_audit.py, a read-only static audit of the public API surface, and docs/api-audit.md, its first run against this revision. The audit answers three questions the reference cannot answer about itself: 1. Does every declared export exist, have a docstring, and appear in docs/api.md? It reads the root __all__ plus each submodule's __all__. 2. How complete is each public definition? Docstring presence, detected docstring convention, parameter and return annotations. 3. Which public names do examples and tests actually use but the reference never explains? That set is the real documentation gap. It parses with ast and never imports the package, so it costs no numpy/cv2 import and cannot be affected by the environment. Findings on this revision (full detail in docs/api-audit.md): - 393 public classes/methods/functions; 65% have a docstring, 32% have a fully annotated signature, 38 document their return value. - 243 docstrings are unstructured prose, 137 are absent, 13 use Google or NumPy sections. There is effectively one convention: none. - 9 of the 18 root exports are absent from docs/api.md, including StreamPipeline, StreamRecorder, mosaic_videos and FFCFrameProcessor - the pipelined multi-stream and offline-recording paths. - Six sub-surfaces have zero coverage in the reference: unroll (18 exports), capture (17), hhd + solvers (7), pipeline (3), export (2). - 74 names are used by examples or tests but absent from the reference. - 21 public classes are exported nowhere; LowpassFilter is documented in docs/api.md and importable, but declared in no __all__. No behaviour change: a new tool and a new document, no source file touched.
This commit is contained in:
@@ -0,0 +1,147 @@
|
||||
# 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.
|
||||
Reference in New Issue
Block a user