Skip to content

feat(control,cli,web): GET /api/v1/system/capabilities + CapabilitiesPage (ADR-W030, #9) - #263

Merged
aperim-agent merged 7 commits into
mainfrom
feat/system-capabilities
Jul 11, 2026
Merged

feat(control,cli,web): GET /api/v1/system/capabilities + CapabilitiesPage (ADR-W030, #9)#263
aperim-agent merged 7 commits into
mainfrom
feat/system-capabilities

Conversation

@aperim-agent

Copy link
Copy Markdown
Collaborator

What

Adds the honest default-build capability + licence surface (management-completeness §2.7, task #9) — the missing /system/* counterpart to the existing /preview/capabilities.

  • GET /api/v1/system/capabilities (viewer-read, system-global — no per-object BOLA axis), returning a new multiview_control::system::SystemCapabilities DTO:
    • backends: codec decode/encode + software composite, each with available (from hal::probe), max_resolution?, decode_resize?.
    • compositor: the SA-0 acceleration tier (class / device_type? / driver?) from the resolved wgpu AdapterReport (ADR-0035).
    • build: effective build-profile licence (LGPL-clean | GPL), redistributable, compiled features, ndi — the machine-readable form of ADR-0012's "effective license reported per artifact".
    • ndi_attribution?: the mandatory NDI® is a registered trademark of Vizrt NDI AB + ndi.video, present iff the ndi feature is compiled (AGENTS.md §G).
  • CapabilitiesPage at /system/capabilities (nav + route): Backends matrix / Compositor / Build & licence panels. Status by value + label, never colour alone (WCAG 1.4.1).

Design & isolation

  • DTO lives in multiview-control with primitives/enums only — zero dep on multiview-hal. The CLI maps hal::probe + cfg!(feature) + the resolved adapter onto it and installs it via a new static AppState::with_capabilities snapshot — no engine channel (invariant Bump vite from 6.4.3 to 8.0.16 in /web #10). Design recorded in ADR-W030.
  • Compliance-critical effective_license is a pure, exhaustively-tested mapping pinned to §G/ADR-0012: gpl-codecs ⇒ GPL, else LGPL-clean; every shippable build redistributable (no nonfree feature; NDI runtime-loaded, never linked). TDD asserts the exact strings per feature-combo.

TDD

RED (f4f05dd9) → GREEN (f6e214f9): control 6/6, cli 3/3, web CapabilitiesPage 2/2. Local gate green — fmt, clippy -p multiview-control -p multiview-cli --lib -D warnings, crate tests, web eslint/tsc/vite build. Spec + client regenerated (gen-openapi + generate:api).

Scope boundary (rule 6)

This is the complete, honest default/software-tier surface. The SA-1+ vendor-caps deep probe (per-codec profiles, NVENC sessions, VRAM, host PSI, per-backend compiled_in) needs feature-gated backend code + GPU-hardware validation and is the separate tracked lane #180 (blocked by this). No empty/placeholder fields stand in for it.

Out of scope

The #180 deep probe; a separate /system/build alias (build info is inline per §3.4); wiring Output-editor encoder dropdowns to consume this.

🤖 Generated with Claude Code

aperim-agent and others added 7 commits July 11, 2026 13:38
…uild surface

Design-first record (task #9/#176, mgmt-completeness §2.7): assemble an honest
capability+licence DTO from hal::probe + cfg!(feature) + the resolved AdapterReport
rather than serialize a non-existent CapabilityReport (that rich telemetry is the
separate SA-1+ lane #180). Pins effective_license to AGENTS.md §G / ADR-0012,
build{} inline, viewer-read no-BOLA auth, control-keeps-no-hal-dep, and the static
with_capabilities snapshot (invariant #10).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ce tests

Failing tests first (rule 18). The SystemCapabilities DTO + CLI hal->DTO mapping
compile with incomplete first-cut bodies so assertions fail:
- control: gpl-codecs -> GPL (resolve still returns LGPL-clean); route 404 (not
  yet registered) for the viewer-200 + bad-bearer-401 cases.
- cli: software backends available on the default build (no backends yet); a
  resolved adapter classifies the compositor (class still None).

RED evidence:
  control: FAILED. 3 passed; 3 failed (gpl_codecs.., viewer_reads.., a_bad_bearer..)
  cli:     FAILED. 1 passed; 2 failed (software_backends.., a_resolved_adapter..)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ability DTO (ADR-W030)

Implement the honest default-build capability + licence surface (task #9/#176,
mgmt-completeness §2.7) to green.

multiview-control:
- SystemCapabilities DTO (system.rs): backends (codec decode/encode + software
  composite), compositor class/device/driver, build{effective_license,
  redistributable,features,ndi}, optional NDI attribution. Primitives/enums only
  — control keeps zero dep on multiview-hal.
- BuildInfo::resolve pins the compliance mapping (§G/ADR-0012): gpl-codecs -> GPL,
  else LGPL-clean; every shippable build redistributable. EffectiveLicense
  serializes to the exact strings 'LGPL-clean' / 'GPL'.
- GET /api/v1/system/capabilities route (routes/system.rs), viewer-read,
  system-global (no BOLA axis); registered in routes/mod + openapi.
- AppState::with_capabilities — a static startup snapshot, no engine channel
  (invariant #10); default is the coarse software-only surface.

multiview-cli:
- system_capabilities.rs maps hal::probe + cfg!(feature) + the resolved
  AdapterReport onto the DTO; graceful (absent backend -> available:false, never
  panics). Composite-stage GPU backends are NOT emitted as available:false rows
  (hal has no env probe for them) — the compositor field is authoritative.
- control.rs wires .with_capabilities(...) at startup (adapter read only under
  the gpu feature).

The SA-1+ vendor-caps deep probe (per-codec profiles, NVENC sessions, VRAM, PSI,
per-backend compiled_in) is the separate tracked lane #180.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…penAPI/client (ADR-W030)

Wire the web surface for GET /api/v1/system/capabilities and regenerate the
committed spec + generated client.

web:
- api/system.ts + api/systemQueries.ts: getSystemCapabilities + the
  useSystemCapabilities() TanStack hook (static startup snapshot; not polled).
- pages/CapabilitiesPage.tsx (/system/capabilities): three panels — Backends
  matrix, Compositor tier, Build & licence (effective licence, redistributable,
  compiled features, NDI attribution). Status by value + label, never colour
  alone (WCAG 1.4.1). Nav entry + route added.
- pages/CapabilitiesPage.test.tsx: MSW render test (availability, compositor
  class, exact licence string, NDI attribution shown iff the ndi feature is on).

control: rename the handler capabilities -> system_capabilities so its OpenAPI
operationId no longer collides with preview::capabilities in the generated client.

regen: docs/api/openapi.json + web/src/api/schema.ts.

Web gate green: eslint 0-warnings, tsc --noEmit, lingui compile + vite build,
vitest (CapabilitiesPage 2/2).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds the CapabilitiesPage + nav <Trans> strings to the source and locale
catalogs (en/ar/pseudo) so the i18n catalog-freshness CI gate passes.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Run the gate's canonical i18n:extract --clean + i18n:compile and commit the
regenerated compiled catalogs (en/ar messages.ts) so the i18n catalog-freshness
CI gate passes (the production macro strips the source fallback, so compiled
catalogs must match the .po sources).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…profile

Codex review (rule 16) on PR #263: the compile-time-resolver test
unconditionally asserted `LGPL-clean` + no-NDI-attribution, but
`resolve_system_capabilities` correctly returns `GPL` under
`--features gpl-codecs` and includes attribution under `--features ndi`.
The test therefore would FAIL for exactly the compliance-sensitive
profiles it claims to validate, passing on default CI only because CI
builds default features — a mis-scoped test.

Gate the expectations on the profile the test binary is compiled with
(`GPL` when `gpl-codecs` else `LGPL-clean`; attribution present when
`ndi` else absent), mirroring the `cfg!` bridge inside the resolver.
This strengthens coverage (the GPL/NDI profiles are now asserted, not
skipped) rather than weakening it; the exhaustive per-combo mapping is
already runtime-tested in `multiview-control` via `BuildInfo::resolve`.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@aperim-agent
aperim-agent merged commit 192e1b9 into main Jul 11, 2026
35 checks passed
aperim-agent added a commit that referenced this pull request Jul 12, 2026
Add the ProbeStatus / DeviceCapability / CgroupLimits / HostInfo /
DetectionInfo wire types + the observed_at / devices / host / detection
fields on SystemCapabilities, with serde tests encoding the three
contracts: ProbeStatus is snake_case on the wire, unknown optionals are
omitted (never a fabricated zero), and observed_at is ALWAYS serialized
(the provenance anchor, ADR-M014 review finding #2). The RED serde config
is deliberately wrong on all three (no rename_all, no skips, observed_at
carries a skip) so the tests fail first; the green commit fixes them.
Types are primitives/enums only — zero multiview-hal dep (the #263/W030
boundary). Per ADR-M014 §2/§6.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant