examples/gui/ is a full Qt + open3d application (30 modules, 4,815 lines) rather
than an example, and its proper home is the orisys-studio application. The move
is planned but not started, so this records the plan rather than performing any
of it.
What the plan establishes, so the work does not have to be re-derived:
- src/orisys/ imports no gui/viz/examples module, verified by AST rather than
grep. The dependency is one-way, so the GUI can leave without a library
change. The single apparent hit is `from .pipeline import ...` in
src/orisys/__init__.py, which is the SDK's own module.
- examples/viz/ is shared and cannot follow the GUI wholesale: it mixes open3d
renderers with toolkit-independent helpers that examples/pipeline/service.py
and tests/test_contact_arrow_scale.py depend on. It has to be split.
- The real coupling is inverted and lives in the tests: tests/test_qt_viewer_backend.py
imports examples/gui, and tests/conftest.py deliberately puts examples/ ahead
of build/ because both define a package named `gui`. Removing the GUI means
re-deriving that guard, not deleting it blindly.
- UVMeshViewer and friends are in src/orisys/finger/__init__.__all__, so removing
them is a breaking change to a released API and needs a deprecation release
first. It must not be folded into a code move.
- The `examples/` directory must keep existing in the packaged layout even after
gui/ leaves it: src/orisys/configs.py anchors its run-root detection on a
sibling examples/ folder.
Also updates examples/README.md to say "lives here for now" instead of "is moving
out", so nothing reads as work in progress. The GUI itself is untouched, and the
only guidance offered is that new SDK work should not build on it.
The two canonical examples taught the advanced path: they sequenced
get_img() -> compute_deformation() -> compute_contact() -> read_info() by hand
and unpacked a 13-element tuple positionally, which is what led developers to
reach for the compute backend, the capture queue and the stitch mode. The
managed alternative already existed and was documented nowhere.
Library (add-only, nothing removed):
- FrameSnapshot.image_size_raw carries the capture resolution, so a caller can
compare it with the processed frame instead of reaching into Sensor.
- StreamPipeline.reset() resets the tracker and force filters *safely*. It is
queued and applied by the flow stage before its next frame, never inline:
Sensor.reset rebases initial_img on the current Sensor.img, which the flow
stage is reading concurrently, so a caller-thread reset would capture a
half-written reference frame. Idempotent.
- TactileProcessor.pipeline(produce) and FingerRuntime.pipeline() build a
pipeline without the caller naming a backend concept; the latter is
`with runtime.pipeline(contact=True) as pipe`.
Examples:
- examples/basic_pipeline.py and examples/finger_pipeline.py rewritten onto
StreamPipeline + FrameSnapshot: one object, one call per frame, no tuple, and
no compute backend, queue or stitch setting in sight.
- examples/archive/basic_pipeline_manual.py and _finger_pipeline_manual.py keep
the previous versions byte-for-byte apart from a supersede header, so code
copied from them keeps working. The finger header also records the archived
--show defect (store_true with default=True, so it could never be disabled).
- examples/_display.py holds the shared display helpers, so an example no longer
hand-rolls depth normalisation and colormap application.
- examples/README.md leads with the recommended pair and documents the manual
form as still-supported, and states that examples/gui/ is moving to
orisys-studio.
Tests: three added to tests/test_pipeline.py, covering the reset queue (it must
not run on the caller's thread and must land before the first compute_flow),
image_size_raw, and the None case when a producer reports no size. Verified the
reset test fails when reset() is made inline, so it discriminates.
Verified end-to-end against real media: basic_pipeline on data/sample/s1_480p.mp4
(box) reaches ~113 FPS and exits 0; finger_pipeline on data/dd02-0703/1.mp4
(finger) reaches ~140 FPS with mask coverage 0.41 and exits 0. Both archived
manual versions still run. tests/test_pipeline.py: 20 passed. Full suite:
342 passed, 3 failed - all three failures reproduce on the pristine tree
(import precedence, longrun timing, and a stale ruff version literal in
docs/code-review.md) and are unrelated to this change.
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.
`tools/lint_gate.py` now also runs `D:\orisys_ws\scripts\doc_lint.py`, the
workspace's single documentation gate, alongside Ruff:
- changed Markdown by default, the whole corpus under --all
- `--files` names Python files explicitly, so it skips the doc gate
- `--no-docs` opts out
- the docs verdict is reported even when Ruff is missing, so a missing
linter cannot hide it (the exit code still signals the environment problem)
The doc rules live in exactly one place on purpose: this file is duplicated
across three repositories and had already drifted, so adding a fourth copy of
lint logic would repeat the mistake. Failing checks are the documentation
budget, inventory membership, a declared kind, unresolved mojibake, paragraph
walls, and duplicate explanations across documents. Emphasis density is
advisory only - measured as a continuum from 12% to 48% across the corpus, so
no threshold separates signal from noise.
Pre-existing oversized documents are recorded as budget-exempt with a written
reason in D:\orisys_ws\docs\inventory.json, and pre-existing findings are
baselined there, so this gate is red only for new regression.
With Ruff unavailable in the current environment the doc half still reports,
which is how it was verified.
The `_perf/` measurement bench was gitignored and had never been committed, so
23 of the 27 scripts cited by the perf documents were already lost. The 11
surviving files (4 scripts, cfg_dm1.json, 5 result JSONs, the 53 MB MJPG clip)
have been moved to D:\orisys_ws\docs\performance\perf-measurements\ and the
scripts patched to resolve their defaults next to themselves. The directory has
been removed from this repo.
These three files said the scripts were deleted, which was only half true:
they are moved, and the four surviving ones still run. Repointed:
- src/orisys/sensor.py: the FILTER_PRESETS comment now names the real location
(comment only; FILTER_PRESETS itself is unchanged).
- docs/filters.md and examples/filters/README.md: the same correction for the
latency/noise measurement provenance.
No behaviour change.
orisys-sdk-perf-plan.md moved to D:\orisys_ws\docs\performance\ as part of the
2026-09-27 workspace cleanup. docs/filters.md and examples/filters/README.md now
name the new location; the _perf/ measurement scripts they also cited are deleted
(the document keeps every measured number).
Also ignore .scratch/, the new per-task scratch directory (see
D:\orisys_ws\AGENTS.md).