You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
PR edgecommons/edgecommons#57 (design: core/docs/platform/DESIGN-cli-scaffold-parity.md) establishes a component baseline that every CLI-scaffolded component now starts from: kebab naming, rev-pinned core dependency, Diataxis docs synced to the site, org CI + a 90% coverage gate, governance files, config.schema.json, and — for southbound adapters — the standardized sb/* command family (now including the sb/pause/sb/resume/reconnect/repoll lifecycle verbs promoted into core/docs/SOUTHBOUND.md §2.2), the §5 southbound_health measure set plus the operational-metric family pattern, the edge-console panel trio, and a device seam with an in-process simulator. This issue evaluates camera-adapter against that baseline and tracks adoption.
Where the component actually is. camera-adapter is an assembled, runnable component, not a work-in-progress: main.rs builds the full EdgeCommonsBuilder runtime (config validation seam, command router, readiness gating, supervisors), main CI is green (build/test/clippy via the org reusable workflow, a 90% line + 95% diff coverage gate, an MSRV check, an RTSP-feature build, and a Docker job that builds both image targets and runs the binary), the repo is listed in registry/components.json, and it ships a comprehensive Diataxis docs/ set plus deterministic ONVIF/RTSP/GenICam simulator validation. The gaps below are parity and hygiene items, not assembly.
Gap analysis against the baseline
Cross-cutting (items 1-6)
#
Item
Status
Evidence
1
Kebab naming
MET
Crate/bin camera-adapter; GG component com.mbreissi.edgecommons.CameraAdapter (PascalCase reverse-DNS, as required); recipe artifact s3://.../camera-adapter/0.1.0/camera-adapter; Dockerfile, k8s (app.kubernetes.io/name: camera-adapter), compose all agree.
2
Dependency and lockfile
PARTIAL
Core dep pinned by git rev (rev = "36a70c48...") with the gitignored .cargo/config.toml[patch] sibling override — both MET. Cargo.lock is deliberately not committed, with a documented three-way-constraint rationale in .gitignore and .github/workflows/ci.yml (a [patch]-ed build rewrites the lock to a path source; the RTSP validation container mounts the workspace read-only; file-replicator does the same). This conflicts with the baseline's "commit the lockfile" rule and edgecommons component validate will warn on it — needs an explicit org decision, not a silent local fix (see P2).
3
Diataxis docs, present tense
PARTIAL
docs/{README,tutorial,how-to-guides,explanation,sample-configurations}.md + reference/{configuration,messaging-interface,metrics}.md all present, high quality, current-state present tense; extra reference/compatibility.md and deployment/{host,greengrass,kubernetes}.md. Missing the adapter reference/data-types.md page — though the baseline's data-types page is the southbound signal value-mapping table, and this adapter publishes capture announcements rather than SouthboundSignalUpdate envelopes (see P2).
4
CI + coverage
PARTIAL
ci.yml calls edgecommons/.github/.github/workflows/component-ci.yml@main with language: RUST; coverage job enforces 90% line + a 95% diff gate (exceeds the baseline); additional MSRV, RTSP-feature, and image-build jobs. Missing: deploy-docs.yml, so doc-only pushes do not refresh the docs site for this registered component.
5
Governance
PARTIAL
DESIGN.md and LICENSE (BUSL-1.1) present. Missing AGENTS.md and CLAUDE.md (@AGENTS.md import). Manifest license declarations (Cargo.toml says Apache-2.0) diverge from the LICENSE file — already tracked as #7; not duplicated here.
6
config.schema.json
MISSING
No schema file anywhere in the repo, so edgecommons component validate cannot check camera-adapter configs. Config validation exists only in code (src/config.rs).
Adapter items (7-10)
#
Item
Status
Evidence
7
sb/* command surface
PARTIAL
Rich domain family on the D-U28 component inbox: sb/status, sb/list, sb/discover, sb/capture, sb/capture-submit, sb/capture-group(-submit), sb/capture-status, sb/capture-cancel, sb/queue-status, sb/queue-clear, sb/reconnect, sb/ptz, sb/ptz-stop, sb/ptz-presets — SOUTHBOUND §2.2 itself cites sb/capture as the sanctioned domain-verb example. The universal sb/status is MET; reconnect is MET. Missing: the standardized lifecycle verbs sb/pause/sb/resume; repoll has no direct mapping (on-demand + scheduled capture; nearest analog is sb/capture) and needs an explicit applicability decision. sb/read/sb/write/sb/signals/sb/browse are signal-adapter conventions per §2.2 — N/A here (sb/list/sb/discover are the inventory/browse analogs). Instance routing follows the D-EIP-13 semantics (body instance, optional iff exactly one camera) but the error codes are adapter-local (INVALID_REQUEST, INSTANCE_REQUIRED, UNKNOWN_INSTANCE, CAMERA_UNAVAILABLE) rather than the standardized names (BAD_ARGS, NO_SUCH_INSTANCE, DEVICE_UNAVAILABLE).
8
Metrics
PARTIAL
southbound_health emitted per instance with the exact §5 measure set (connectionState, publishLatencyMs, pollLatencyMs, readErrors, staleSignals, + optional reconnects) — MET, including the stale-signal threshold and emit-on-transition. Two real operational families exist (camera_captures, camera_queue) with well-reasoned measures, but they do not follow the family pattern: no (total, interval) counter pairs (interval-only Count/60 measures) and no instance/verb/result dimensions.
9
Edge-console panels
MISSING
No register_panel call anywhere in src/; the adapter registers no overview/signals/diagnostics panels.
10
Device seam + in-process sim
MET
CameraBackendFactory/CameraSession seam in src/backend/ with the protocol backends (onvif, rtsp, genicam_aravis) behind it and UNS/metrics in front; the in-process SimBackend is compiled into every build and drives the deterministic test suite.
Prioritized remediation plan
P0 — assemble/build to a runnable component + core contract: already satisfied
No P0 work. The component is assembled, main CI is green end-to-end, the shipped Docker images build and run from a clean clone, southbound_health carries the canonical §5 set, and commands ride the D-U28 UNS inbox. (Recorded here because earlier internal notes described the repo as unassembled with a broken default build; that state is obsolete.)
P1 — adapter parity with SOUTHBOUND §2.2 / §5
sb/pause / sb/resume. Implement the standardized lifecycle verbs: suspend/resume a camera instance's scheduled captures and command dispatch (in-flight captures run to completion; new work refused with a stable code while paused), idempotent, confirmed replies { paused, changed }, instance-routed like the existing verbs, surfaced in sb/status and the docs. This is the one hard contract gap — §2.2 now names pause/resume/reconnect/repoll as the standard instance-control family a real adapter serves.
repoll applicability decision. Either map it to "trigger the instance's scheduled capture now" or record N/A in DESIGN.md and the messaging reference (the adapter is capture-on-demand/schedule, not poll-loop based). Do not add it silently either way.
Error-code reconciliation. Align the routing/availability codes with the standardized set (INSTANCE_REQUIRED/INVALID_REQUEST -> BAD_ARGS, UNKNOWN_INSTANCE -> NO_SUCH_INSTANCE, CAMERA_UNAVAILABLE -> DEVICE_UNAVAILABLE) — or record the divergence explicitly in DESIGN.md and docs/reference/messaging-interface.md if the richer local codes are kept. The domain-specific codes (CAPTURE_TIMEOUT, PTZ_*, STORAGE_PRESSURE, ...) stay.
Operational-metric family pattern. Bring camera_captures/camera_queue (or a successor family set) to the reference pattern: per-family (total, interval) counter pairs with interval reset on emit, low-cardinality dimensions (instance, verb, result), keeping the existing measures' semantics. A CameraCommand family covering command requests/latency/errors closes the command-observability half.
Edge-console panels. Register the overview/signals/diagnostics trio via register_panel (order 10/20/30, scope: "instance"), bound to the verbs the adapter actually serves: overview = connection/queue/paused state + sb/reconnect (+ pause/resume from item 1); signals = the camera roster and capture surface (sb/list, sb/status, sb/capture, sb/capture-status); diagnostics = sb/discover, sb/queue-status.
config.schema.json. Model the component's component.global/component.instances[] config so edgecommons component validate checks camera configs; keep it in lockstep with src/config.rs and docs/reference/configuration.md.
deploy-docs.yml. Add the hook-guarded docs-rebuild trigger workflow so doc-only pushes refresh the published site for this registered component.
docs/reference/data-types.md decision. Either add the page documenting the adapter's published data shapes (capture announcement, thumbnail, terminal app/image/* payloads, sidecar metadata) or record that the signal value-mapping page is N/A for an image adapter and where those shapes are documented instead (messaging-interface.md).
Lockfile policy decision (org-level). The repo documents why a committed Cargo.lock, the gitignored [patch] override, and the read-only simulator mounts cannot coexist — the same position file-replicator holds — while the baseline says commit it and component validate will warn. Resolve deliberately (e.g. accept the documented exception for [patch]-developed Rust components, or commit a git-sourced lock and adjust the harness) and record the outcome in DESIGN.md; do not silently suppress the warning.
Definition of done: each P1/P2 item lands with its docs updated in the same change (messaging reference, metrics reference, DESIGN.md), the coverage gates stay at or above their current levels, and decisions (repoll, error codes, data-types, lockfile) are recorded rather than implied.
Context
PR edgecommons/edgecommons#57 (design:
core/docs/platform/DESIGN-cli-scaffold-parity.md) establishes a component baseline that every CLI-scaffolded component now starts from: kebab naming, rev-pinned core dependency, Diataxis docs synced to the site, org CI + a 90% coverage gate, governance files,config.schema.json, and — for southbound adapters — the standardizedsb/*command family (now including thesb/pause/sb/resume/reconnect/repolllifecycle verbs promoted intocore/docs/SOUTHBOUND.md§2.2), the §5southbound_healthmeasure set plus the operational-metric family pattern, the edge-console panel trio, and a device seam with an in-process simulator. This issue evaluates camera-adapter against that baseline and tracks adoption.Where the component actually is. camera-adapter is an assembled, runnable component, not a work-in-progress:
main.rsbuilds the fullEdgeCommonsBuilderruntime (config validation seam, command router, readiness gating, supervisors),mainCI is green (build/test/clippy via the org reusable workflow, a 90% line + 95% diff coverage gate, an MSRV check, an RTSP-feature build, and a Docker job that builds both image targets and runs the binary), the repo is listed inregistry/components.json, and it ships a comprehensive Diataxisdocs/set plus deterministic ONVIF/RTSP/GenICam simulator validation. The gaps below are parity and hygiene items, not assembly.Gap analysis against the baseline
Cross-cutting (items 1-6)
camera-adapter; GG componentcom.mbreissi.edgecommons.CameraAdapter(PascalCase reverse-DNS, as required); recipe artifacts3://.../camera-adapter/0.1.0/camera-adapter; Dockerfile, k8s (app.kubernetes.io/name: camera-adapter), compose all agree.rev = "36a70c48...") with the gitignored.cargo/config.toml[patch]sibling override — both MET.Cargo.lockis deliberately not committed, with a documented three-way-constraint rationale in.gitignoreand.github/workflows/ci.yml(a[patch]-ed build rewrites the lock to a path source; the RTSP validation container mounts the workspace read-only; file-replicator does the same). This conflicts with the baseline's "commit the lockfile" rule andedgecommons component validatewill warn on it — needs an explicit org decision, not a silent local fix (see P2).docs/{README,tutorial,how-to-guides,explanation,sample-configurations}.md+reference/{configuration,messaging-interface,metrics}.mdall present, high quality, current-state present tense; extrareference/compatibility.mdanddeployment/{host,greengrass,kubernetes}.md. Missing the adapterreference/data-types.mdpage — though the baseline's data-types page is the southbound signal value-mapping table, and this adapter publishes capture announcements rather thanSouthboundSignalUpdateenvelopes (see P2).ci.ymlcallsedgecommons/.github/.github/workflows/component-ci.yml@mainwithlanguage: RUST; coverage job enforces 90% line + a 95% diff gate (exceeds the baseline); additional MSRV, RTSP-feature, and image-build jobs. Missing:deploy-docs.yml, so doc-only pushes do not refresh the docs site for this registered component.DESIGN.mdandLICENSE(BUSL-1.1) present. MissingAGENTS.mdandCLAUDE.md(@AGENTS.mdimport). Manifest license declarations (Cargo.tomlsaysApache-2.0) diverge from the LICENSE file — already tracked as #7; not duplicated here.config.schema.jsonedgecommons component validatecannot check camera-adapter configs. Config validation exists only in code (src/config.rs).Adapter items (7-10)
sb/*command surfacesb/status,sb/list,sb/discover,sb/capture,sb/capture-submit,sb/capture-group(-submit),sb/capture-status,sb/capture-cancel,sb/queue-status,sb/queue-clear,sb/reconnect,sb/ptz,sb/ptz-stop,sb/ptz-presets— SOUTHBOUND §2.2 itself citessb/captureas the sanctioned domain-verb example. The universalsb/statusis MET;reconnectis MET. Missing: the standardized lifecycle verbssb/pause/sb/resume;repollhas no direct mapping (on-demand + scheduled capture; nearest analog issb/capture) and needs an explicit applicability decision.sb/read/sb/write/sb/signals/sb/browseare signal-adapter conventions per §2.2 — N/A here (sb/list/sb/discoverare the inventory/browse analogs). Instance routing follows the D-EIP-13 semantics (bodyinstance, optional iff exactly one camera) but the error codes are adapter-local (INVALID_REQUEST,INSTANCE_REQUIRED,UNKNOWN_INSTANCE,CAMERA_UNAVAILABLE) rather than the standardized names (BAD_ARGS,NO_SUCH_INSTANCE,DEVICE_UNAVAILABLE).southbound_healthemitted per instance with the exact §5 measure set (connectionState,publishLatencyMs,pollLatencyMs,readErrors,staleSignals, + optionalreconnects) — MET, including the stale-signal threshold and emit-on-transition. Two real operational families exist (camera_captures,camera_queue) with well-reasoned measures, but they do not follow the family pattern: no(total, interval)counter pairs (interval-only Count/60 measures) and noinstance/verb/resultdimensions.register_panelcall anywhere insrc/; the adapter registers nooverview/signals/diagnosticspanels.CameraBackendFactory/CameraSessionseam insrc/backend/with the protocol backends (onvif,rtsp,genicam_aravis) behind it and UNS/metrics in front; the in-processSimBackendis compiled into every build and drives the deterministic test suite.Prioritized remediation plan
P0 — assemble/build to a runnable component + core contract: already satisfied
No P0 work. The component is assembled,
mainCI is green end-to-end, the shipped Docker images build and run from a clean clone,southbound_healthcarries the canonical §5 set, and commands ride the D-U28 UNS inbox. (Recorded here because earlier internal notes described the repo as unassembled with a broken default build; that state is obsolete.)P1 — adapter parity with SOUTHBOUND §2.2 / §5
sb/pause/sb/resume. Implement the standardized lifecycle verbs: suspend/resume a camera instance's scheduled captures and command dispatch (in-flight captures run to completion; new work refused with a stable code while paused), idempotent, confirmed replies{ paused, changed }, instance-routed like the existing verbs, surfaced insb/statusand the docs. This is the one hard contract gap — §2.2 now names pause/resume/reconnect/repoll as the standard instance-control family a real adapter serves.repollapplicability decision. Either map it to "trigger the instance's scheduled capture now" or record N/A inDESIGN.mdand the messaging reference (the adapter is capture-on-demand/schedule, not poll-loop based). Do not add it silently either way.INSTANCE_REQUIRED/INVALID_REQUEST->BAD_ARGS,UNKNOWN_INSTANCE->NO_SUCH_INSTANCE,CAMERA_UNAVAILABLE->DEVICE_UNAVAILABLE) — or record the divergence explicitly inDESIGN.mdanddocs/reference/messaging-interface.mdif the richer local codes are kept. The domain-specific codes (CAPTURE_TIMEOUT,PTZ_*,STORAGE_PRESSURE, ...) stay.camera_captures/camera_queue(or a successor family set) to the reference pattern: per-family(total, interval)counter pairs with interval reset on emit, low-cardinality dimensions (instance,verb,result), keeping the existing measures' semantics. ACameraCommandfamily covering command requests/latency/errors closes the command-observability half.overview/signals/diagnosticstrio viaregister_panel(order 10/20/30,scope: "instance"), bound to the verbs the adapter actually serves: overview = connection/queue/paused state +sb/reconnect(+ pause/resume from item 1); signals = the camera roster and capture surface (sb/list,sb/status,sb/capture,sb/capture-status); diagnostics =sb/discover,sb/queue-status.P2 — hygiene
AGENTS.md(component shape, seam, config location, validation expectations, inherited org conventions) andCLAUDE.md(short header +@AGENTS.mdimport + local-dev notes: the.cargopatch override, the simulator harnesses).DESIGN.mdalready exists.config.schema.json. Model the component'scomponent.global/component.instances[]config soedgecommons component validatechecks camera configs; keep it in lockstep withsrc/config.rsanddocs/reference/configuration.md.deploy-docs.yml. Add the hook-guarded docs-rebuild trigger workflow so doc-only pushes refresh the published site for this registered component.docs/reference/data-types.mddecision. Either add the page documenting the adapter's published data shapes (capture announcement, thumbnail, terminalapp/image/*payloads, sidecar metadata) or record that the signal value-mapping page is N/A for an image adapter and where those shapes are documented instead (messaging-interface.md).Cargo.lock, the gitignored[patch]override, and the read-only simulator mounts cannot coexist — the same position file-replicator holds — while the baseline says commit it andcomponent validatewill warn. Resolve deliberately (e.g. accept the documented exception for[patch]-developed Rust components, or commit a git-sourced lock and adjust the harness) and record the outcome inDESIGN.md; do not silently suppress the warning.Definition of done: each P1/P2 item lands with its docs updated in the same change (messaging reference, metrics reference, DESIGN.md), the coverage gates stay at or above their current levels, and decisions (repoll, error codes, data-types, lockfile) are recorded rather than implied.