Skip to content

Adopt the CLI-scaffold-parity component baseline #8

Description

@mbreissi

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 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

  1. 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.
  2. 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.
  3. 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.
  4. 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.
  5. 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.

P2 — hygiene

  1. Governance files. Add AGENTS.md (component shape, seam, config location, validation expectations, inherited org conventions) and CLAUDE.md (short header + @AGENTS.md import + local-dev notes: the .cargo patch override, the simulator harnesses). DESIGN.md already exists.
  2. 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.
  3. deploy-docs.yml. Add the hook-guarded docs-rebuild trigger workflow so doc-only pushes refresh the published site for this registered component.
  4. 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).
  5. 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.
  6. License declarations. Already tracked in License: reconcile license declarations to BSL 1.1 (BUSL-1.1) #7 (manifest says Apache-2.0, LICENSE is BUSL-1.1) — fold into that issue, not this one.

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions