Harden sidecar release contract#76
Conversation
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: d01fd558d0
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| if ( | ||
| health.contractVersion !== undefined && | ||
| health.contractVersion !== SIDECAR_CONTRACT_VERSION |
There was a problem hiding this comment.
Require contractVersion in the readiness gate
This check only rejects a mismatched contractVersion when the field is present. If a user is still running an older or third-party sidecar that reports status: "ready" and schemaVersion: 2 but omits contractVersion, sidecarReadinessError returns null, so both the UI readiness check and the connect route accept an unversioned HTTP/WebSocket contract even though this change is intended to require contractVersion = 1. Treating undefined as incompatible would make the new release gate enforce the contract it advertises.
Useful? React with 👍 / 👎.
| }); | ||
| if (final) { | ||
| await this.uploadInflight; | ||
| if (this.uploadError) throw this.uploadError; |
There was a problem hiding this comment.
Preserve source cleanup when final drains fail
When a final pose upload fails, this new throw propagates out of BrowserPoseSource.stop() at its await this.drain() call before that method posts close, terminates the worker, clears the worker reference, or reports a stopped/error status. In the upload-failure path this leaves the MediaPipe worker and its listeners alive until page unload, and retries of stop() immediately throw the stored uploadError again. The stop methods need to perform their resource cleanup in a finally before rethrowing the drain failure.
Useful? React with 👍 / 👎.
Summary
/healthand enforce schema/contract compatibility in UI readiness and the API connect route before capture can start.schemaVersionandsource, and make final pose-stream drain failures reject so partial uploads cannot silently proceed to finalize./session/startrefusal responses and preserve app-side start-refusal status/details instead of flattening them to generic unreachable errors.contractVersion, so compatibility failures are predictable rather than implicitly accepted.readyhealth payloads when camera count is missing/zero, FPS is missing/zero, or a non-synthetic source reports no calibration id.skeleton_3d.npyand3dData_numFrames_numTrackedPoints_spatialXYZ.npywhen a recorded-output directory is passed.quality.reprojection_error_mm.rowing-tracker-sidecarstartup coverage, a repeatablenpm run test:sidecargate that includes sidecar tracer regressions, a GitHub sidecar release workflow, and compatibility/smoke-test docs.--freemocap-provider module:factoryas a live-runtime provider boundary for injected FreeMoCap adapters, with fake-provider contract coverage and fail-closed diagnostics when no provider is configured.--freemocap-recordingto process an existing FreeMoCap recording folder through the optional package's headless processor, reportinitializinghealth while it runs, refuse starts with409, then stream generatedoutput_dataor report processing errors through the ADR-0005 sidecar contract.--source freemocapwithout data/recording/provider, with explicit missing-package and installed-but-no-supported-live-API diagnostics instead of a generic unconfigured error.FreemocapSidecarSourcestart/stream/upload/stop path.reprojection_error_mmquality metadata when streaming ADR-0005 frames.high-reprojection-errormarker.Issue scope
high-reprojection-errormarker when recorded reprojection error exceeds the warning threshold.initializingreadiness, and contract coverage for generated output streaming.409, success becomesready, and processor failure becomeserror.Testing
python3 -m py_compile sidecar/src/rowing_tracker_sidecar/sources.pynpx tsc --noEmitnpm run test:sidecar(53/53)npm run test(252/252)npx tsx --test tests/freemocapSidecarSource.test.ts(10/10)npx tsx --test tests/sidecarCliContract.test.ts(15/15)npx tsx --test tests/sidecarPackageInstall.test.ts(1/1)npx eslint src/lib/mocap/freemocapSidecarSource.ts src/lib/mocap/poseFrameStream.ts src/app/mocap/page.tsx tests/freemocapSidecarSource.test.ts tests/sidecarCliContract.test.tsnpx eslint tests/sidecarCliContract.test.tsnpx eslint tests/sidecarCliContract.test.ts tests/sidecarPackageInstall.test.tsnpx eslint src/app/api/mocap/sessions/[id]/sidecar/connect/route.ts src/lib/mocap/sidecarClient.ts tests/sidecarCliContract.test.ts tests/sidecarPoseSource.test.tsnpx eslint tests/e2e/sidecar-hardware-smoke.spec.tsnpx eslint tests/e2e/mocap-capture.spec.tsPLAYWRIGHT_SKIP_SERVER=1 npm run test:e2e:sidecar-smoke(1 skipped by default)ROWING_TRACKER_SIDECAR_HARDWARE_SMOKE=1 ROWING_TRACKER_SIDECAR_HARDWARE_ALLOW_SYNTHETIC=1 PORT=3114 npm run test:e2e:sidecar-smoke(1/1 against the synthetic sidecar path)PORT=3113 npm run test:e2e -- tests/e2e/mocap-capture.spec.ts(4/4, including sidecar high-reprojection finalize flags)git diff --checknpm run buildpasses with the existing Turbopack/NFT warning innext.config.ts->src/app/api/achievements/image/save/route.tsnpm run lintstill fails on pre-existing unrelated repo-wide lint debt (118 errors, 161 warnings), not in the files touched by this PR