Bump vite from 6.4.3 to 8.0.16 in /web - #10
Closed
dependabot[bot] wants to merge 2 commits into
Closed
Conversation
Multiview — an efficient, hardware-accelerated Rust live video multiview/mosaic generator. It ingests many live sources (RTSP/HLS/SRT/RTMP/NDI/file/synthetic), composites them into a templated grid on CPU or GPU, and writes HLS/file output; the encode-once-mux-many design fans one encode to many transports. Highlights: - Fixed-cadence output clock — one valid frame per tick, never stalls; inputs are sampled, never pacing (the cardinal continuous-output invariant). - Custom CPU/GPU compositor with a fixed linear-light colour pipeline (NV12 throughout); per-tile overlays, captions (HLS WebVTT + DVB-sub), analog/wall clocks, audio meters, and fault badges. - 16-crate Rust workspace under strict typing + TDD + adversarial-review guardrails; LGPL-clean default build (GPL codecs + NDI opt-in). - Multi-arch Docker images, docker compose examples, and SemVer release automation. Status: early stage — the engine ingests, composites, encodes, and writes HLS/file output today; the web UI, control API, and live RTSP/NDI/RTMP output servers are built as libraries and on the near-term roadmap (see ROADMAP.md). Dual-licensed MIT OR Apache-2.0. Developed iteratively with AI assistance; the full internal development history is retained privately. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 6.4.3 to 8.0.16. - [Release notes](https://github.com/vitejs/vite/releases) - [Changelog](https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md) - [Commits](https://github.com/vitejs/vite/commits/v8.0.16/packages/vite) --- updated-dependencies: - dependency-name: vite dependency-version: 8.0.16 dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com>
Contributor
Author
|
OK, I won't notify you again about this release, but will get in touch when a new version is available. If you'd rather skip all updates until the next major or minor version, let me know by commenting If you change your mind, just re-open this PR and I'll resolve any conflicts on it. |
troykelly
pushed a commit
that referenced
this pull request
Jun 7, 2026
…-L1 §2/§3) Complete the safe NDI handle set on the NdiV6 resolver: - NdiReceiver (recv.rs): non-blocking video sampling (inv #1/#2/#10 — sampled, never pacing). capture_video returns the latest frame or None on timeout/non-video; audio + metadata are null sinks so only video is allocated. RecvVideoFrame owns the SDK buffer and frees it exactly-once on Drop, borrowing the receiver (&'r) so the free target is alive by construction (no dangling free is expressible). UYVY_BGRA color format, highest bandwidth. - NdiFinder (find.rs): source discovery. current_sources copies each name into an owned NdiSourceName before returning — callers never hold a pointer into the finder's transient array. - Runtime init (table.rs): NdiV6::ensure_initialized() calls NDIlib_initialize (idempotent); every handle calls it on construct. Sending works without it, but discovery (advertise/browse) needs it. All unsafe stays in this crate; consumers stay forbid(unsafe_code). Hardware-validated on the SDK-equipped x86_64 box (tests/live_loopback.rs): one process sends a UYVY luma gradient, discovers its own source via the finder, connects a receiver, and captures the frame back — 64x64 UYVY, mean luma round-trips at 127.0 (the sent gradient mean). NDI carries video over SpeedHQ (visually lossless, not bit-exact), so the assertion is structural (geometry + mean-luma band), matching the GPU/codec SSIM/PSNR testing tier. (The headless box has no mDNS, so discovery is backed by the SDK's ndi-discovery-server via ndi-config.v1.json — a host-side test harness concern, nothing in the repo.) clippy -D warnings green default AND --features bindings; fmt clean; default build stays LGPL-clean (recv/find gated on `bindings`). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
troykelly
pushed a commit
that referenced
this pull request
Jun 7, 2026
Wire the production NdiReceiver: `SdkNdiReceiver` delegates the receive seam (receive → sample) to the safe NdiReceiver from multiview-ndi-sys. multiview-input stays forbid(unsafe_code). NdiProducer is unchanged (generic over dyn NdiReceiver), so swapping FakeNdiReceiver for SdkNdiReceiver is the only difference between a unit test and live ingest. - Sampled, never pacing (inv #1/#2/#10): each receive() is a bounded non-blocking capture on the ingest thread; no frame this instant → ReceivedFrame::None (last-good held, tile rides its state machine). - Copies pixels out of SDK-owned memory before the RecvVideoFrame drops (free-exactly-once); negative NDI timecode → genpts fallback; a malformed geometry is a typed skip, never a panic. - Drop order: receiver before capability (the receiver holds fn pointers into the capability's still-mapped Library). - New opt-in feature `ndi-bindings` = ndi + multiview-ndi-sys/bindings (build-time bindgen over the licensed header); plain `--features ndi` stays SDK-free and CI-buildable. Default build stays LGPL-clean. - ndi-sys: NdiRuntime is now Send (the SDK table is process-global + immutable, the Library is Send) so a live receiver can move onto the ingest thread; deliberately not Sync (owned, never shared by ref). Hardware-validated on the SDK-equipped x86_64 box (tests/ndi_live.rs, live_ingest): a sys NdiSender publishes a UYVY gradient, the finder discovers it, and the production NdiProducer over SdkNdiReceiver yields a 64x64 NV12 ProducedFrame (pixels=6144 = w*h*3/2) — proving the whole ingest path: recv_capture → recv_free → ReceivedVideoFrame → UYVY→NV12 → ProducedFrame. The CI-safe probe test is retained. clippy -D warnings green: default, --features ndi (SDK-free), and --features ndi-bindings (on box); fmt clean. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
troykelly
pushed a commit
that referenced
this pull request
Jun 7, 2026
…loudflare first) Design for automatic TLS on the multiview-control plane, from the acme-tls-research ultracode workflow (4 grounded lanes + synthesis): - DNS-01 challenge ONLY (HTTP-01/TLS-ALPN-01 rejected — need wildcards + no inbound :80/:443 reachability). - rustls, no openssl: instant-acme 0.8.5 (Apache-2.0, DNS-01 first-class); rustls-acme rejected (TLS-ALPN-01-only trap); axum-server tls-rustls for hot cert reload (RustlsConfig::reload_from_pem, atomic swap, no restart). - Pluggable async DnsProvider trait (object-safe, opaque TxtRecordHandle newtype — not dyn Any); Cloudflare the first impl, hand-written over reqwest+rustls (the official `cloudflare` crate is BSD-3 + native-tls → rejected). Route53/GCP/RFC2136 drop in as one impl + one config variant. - Renewal = detached fail-soft background tokio task (⅓-lifetime + jitter, keep serving the existing cert on failure) — cannot violate inv #10. - Least-privilege Cloudflare token (Zone.DNS:Edit, single zone) via 1Password/env, never committed; CAA + RFC 8657 account binding; staging-first; authoritative-NS propagation polling. - Tiered: TLS-0 static cert → TLS-1 ACME core → TLS-2 DnsProvider+CF → TLS-3 config+hot-reload renewal → TLS-4 hardening/isolation soak. Off-by-default `tls`/`acme` features; default build stays plain-HTTP + LGPL-clean. Adds docs/research/acme-tls.md + ADR-0029 (Proposed) + the TLS-0..4 backlog in work-schedule.md; indexes both READMEs. Also indexes ADR-0028 (NDI), which was unlisted. Docs only — no code. (Backlog task #70.) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
troykelly
pushed a commit
that referenced
this pull request
Jun 7, 2026
…UX, backend) The control plane required a token for every privileged route + the realtime WS, but the SPA had no way to discover that or to disable it — so an un-authenticated browser just looped "reconnecting". Backend half of the fix (task #71): - AppState.auth_disabled (default false — secure) + with_auth_disabled() builder + auth_required(). When set, BOTH auth paths (the REST `Principal` extractor and the realtime `resolve_principal`) short-circuit to Principal::local_admin() (Role::Admin, unscoped) so the whole API + WS/SSE are open with no token. - New UNAUTHENTICATED GET /api/v1/auth/status → { auth_required, authenticated }: the SPA reads it to decide whether to show a login gate, and validates an entered key by calling it with the token (authenticated reflects the presented credential). Leaks nothing else. - CLI: MULTIVIEW_CONTROL_AUTH=disabled|off|none|0 turns auth off (env wins; anything else keeps it ON), with a loud WARN that the listener is open — use only on a trusted/local network. Secure by default: unset/any-other value = auth required. Inv #10 untouched (no engine coupling). Tests (tests/auth_disabled.rs): auth-on → protected route 401 without a token, /auth/status reports {required:true, authenticated:false}, and {authenticated:true} with a valid token; auth-off → protected route 200 with no token, status {required:false, authenticated:true}. Existing auth (7) + openapi (9) tests unaffected. fmt + clippy -D warnings clean; cargo check --workspace green. Next: the SPA login gate (show a key-entry page when auth_required and unauthenticated; skip it when not required). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
troykelly
pushed a commit
that referenced
this pull request
Jun 7, 2026
…ision) Replace the "passthrough = sanctioned exception to invariant #1" framing with an invariant-#1-PRESERVING **guarded passthrough**, from an adversarially-verified fan-out (12 load-bearing claims, 8 held / 4 refined): - A passthrough is a degenerate, compositor-less `EngineRuntime` ticking at the program cadence (never `.await`s the demuxer); the byte copy runs on a separate egress thread. Source-paced for DATA, clock-paced for the LIVENESS decision via a wait-free `PacketLiveness` watchdog (fails safe). - On loss it splices a **pre-baked, param-matched, IDR-led slate** (black / SMPTE bars + 1 kHz tone / silence), encoded ONCE (no held NVENC session), replayed through the existing encoder-less `PacketMuxSink` — so it meets the operator's BLACK/SMPTE+tone rule at packet-copy steady-state cost. - Robustness ladder (cheapest valid rung first): matched-slate-splice → container-discontinuity → full-transcode; per-program `robustness_floor` (default `SlateOnLoss`; `PassthroughFallback`/Reject removed). Folds the four refinements: recovery gates on a strict-IDR classifier (`is_idr`, not `is_key` — CRA/recovery-point mis-splice); the per-stream monotonic clamp+offset (not FFmpeg flags) is the non-monotonic-DTS abort guard; explicit dedicated egress thread + drop-oldest/SINK_WEDGE_GRACE detach for isolation (#10); three prerequisite code gaps (Demuxer interrupt+rw_timeout, is_idr, in-band-PS/Annex-B BSF). Adds the GP-0..12 backlog; supersedes MP-3. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
troykelly
pushed a commit
that referenced
this pull request
Jun 7, 2026
…(topic `system`) Keystone for the cpu/gpu/encoder-decoder dashboard. Per operator guidance, LIVE high-rate metrics are PUSHED over the realtime stream (conflated + drop-oldest, like `audio.meters`), never polled via REST — only cold historic windows (the data decisions are made from) are RESTful. - `SystemMetrics` + `GpuMetrics` + `GpuVendor` wire types (numeric only) and a new `Event::SystemMetrics` variant (`t="system.metrics"`), internally-tagged. - `Topic::System` is now classified high-rate: latest-only, excluded from the lossless replay ring; the engine never back-pressures a slow client (inv #10). - AsyncAPI generator documents the new message + schemas. - Round-trip + high-rate + GPU-free-host contract tests. clippy/fmt/test green; `cargo check --workspace` green (no broken exhaustive matches). Next: an off-hot-path poller (CPU /proc/stat + NVML) publishing on `system`, then a desktop footer with sparklines (+ a System detail tab). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
troykelly
pushed a commit
that referenced
this pull request
Jun 7, 2026
…e engine event stream Add an off-hot-path system-metrics task (~1.3 Hz) that samples whole-system CPU (/proc/stat), host memory (/proc/meminfo), and per-GPU load, assembles a multiview_events::SystemMetrics, and PUSHES Event::SystemMetrics onto the engine's drop-oldest event broadcast so the WebUI footer lights up with live data (pushed over the realtime stream, never polled — inv #10). - multiview-hal: object-safe `LoadSource` seam + always-compiled `NullLoadPoller` (no-GPU) and `cuda`-gated `NvmlLoadPoller` over the existing NVML probe; graceful init-or-null fallback, no GPU/toolchain needed to build. - multiview-cli: `system_metrics` module with a pure, unit-testable `assemble_metrics` (DeviceLoad -> GpuMetrics, Vendor -> GpuVendor, optional NVENC fields, GPU-free host -> empty gpus, honest-None unknowns) and the tokio task spawned in the run path next to the engine publisher; self-stops on the run's StopSignal. New cli `cuda` feature selects the NVML poller (implied by `nvidia`), else the null poller; default build stays pure-Rust, GPU-free, LGPL-clean. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
troykelly
pushed a commit
that referenced
this pull request
Jun 7, 2026
…0..14 backlog) From a verification-hardened fan-out (20 agents; 10/12 load-bearing claims held, 2 refined). Answers the operator's delivery concerns BEFORE implementation: - Serving model bifurcated by latency tier, not file type: master playlist + closed segments + init.mp4 are STATIC-frontable (nginx/traefik/CDN/object store with the right headers); the LL-HLS live playlist + blocking-reload (_HLS_msn/_HLS_part) + byte-range parts are served by Multiview's OWN async axum origin (a static server has no "wait until it exists" primitive). The origin is a client of an engine-published drop-oldest snapshot — hard-capped + time-bounded held GETs, can never back-pressure the engine (inv #10). - CMAF/fMP4 default container (Safari-native LL-HLS needs it; TS opt-in legacy); byte-range parts into one growing .m4s, not discrete per-part files. - Configurable locations: base_url (no-op when unset), segment_dir split, init_name; rolling-playlist + DVR + atomic-publish (temp+fsync+rename) + grace-period deferred-unlink pruning foundation; drop the unbounded program.ts. - Header contract (explicit Content-Type incl. the .m4s gap, AWS-style Cache-Control tiers, Origin-reflecting CORS + Vary, Accept-Ranges) + reference nginx/traefik/CDN configs operators only honor, not invent. Folds the two review corrections: fMP4 is NOT a muxer-name swap (needs movflags AVDictionary plumbing + per-part fragment flush + shared init); stock nginx already serves .m3u8/.ts correctly, so the present bugs are no-Cache-Control / no-CORS / no-Accept-Ranges (the .m4s MIME gap is post-CMAF). HLS-0..14 backlog, encode-once (#7) preserved. Supersedes the parked live-playlist 404 fix (now HLS-0/1). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
troykelly
pushed a commit
that referenced
this pull request
Jun 8, 2026
…ilover (ADR-0030) Assemble the merged guarded-passthrough primitives (GP-1 is_idr, GP-4 BakedSlate, GP-5 PacketLiveness, GP-6 RestampAccumulator) into the live copy-vs-slate failover splice seam: a GuardedPacketSource that implements PacketSource and is the sole producer feeding PacketMuxSink::run_av. - Copies the live input while healthy; on loss flips a wait-free AtomicU8 decision flag (the GP-5 watchdog should_splice, Release-written by evaluate, Acquire-read by next_packet) to SLATE and emits the pre-baked slate, looped by advancing the GP-6 restamp offset per wrap. - Re-stamp via one RestampAccumulator per stream (video + audio) across BOTH seams; the monotonic clamp (last_dts+1) is the abort guard, raw deltas (B-frame reorder) preserved; rebase at input->slate, each slate loop wrap, and slate->input recovery. - Recovery is is_idr-gated (GP-1 is_idr, NOT is_key): discard input until a true strict-IDR video AU before resuming copy — an is_key recovery-point I-frame never re-enters. - Threading: per-call decision self-driven from an injected MonotonicClock in the pull model, equivalently driveable by a clock thread (GP-8) via decision_flag(); fail-safe (a stale liveness read biases to SLATE, never false-LIVE). next_packet never blocks on the input; the drop-oldest + SINK_WEDGE_GRACE detach posture wrapping the mux thread sheds a wedged push peer (#1/#10). Additive only: a new guarded module + GuardedPacketSource (ffmpeg-gated) + a non-optional pure-Rust multiview-framestore dep; the existing SegmentState / PacketMuxSink batch paths are untouched. No unsafe, no FFI (forbid(unsafe_code)); calls multiview-ffmpeg safe wrappers only. Tests (RED->GREEN): healthy copy-through restamped; input->slate splice past the threshold with strictly-increasing DTS; is_idr-gated recovery (+ never on is_key); slate loop across many wraps with no DTS discontinuity; fail-safe to slate; a proptest over arbitrary live/slate sequences; and an end-to-end drive through the REAL strict-DTS MP4 muxer (av_interleaved_write_frame aborts on non-monotonic DTS) confirming the seam muxes a decodable container. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
troykelly
pushed a commit
that referenced
this pull request
Jun 8, 2026
…ms realtime (ADR-0034)
Surface each input's StreamInventory (RT-2) as read-only discovery so the
API/UI can show every elementary stream an input offers.
- events: Event::InputStreams{input_id, inventory: StreamInventory} on the
existing Topic::Inputs (internally-tagged input.streams, never untagged);
round-trip + envelope tests; AsyncAPI message + schema.
- cli: probe each path-backed source's StreamInventory once at build time
(off the output-clock thread), fold it into the conflated EngineStateSnapshot
under inputs.<id>.streams, and emit exactly one input.streams delta per
probed input at run start (inv #10 — never on the hot loop).
- control: GET /api/v1/inputs/{id}/streams reads the off-engine cached snapshot
(never touches the output-clock thread); BOLA authorize_object; 404 unknown/
unprobed; RFC 9457 problem; utoipa StreamInventoryDoc mirror + pin test.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
troykelly
pushed a commit
that referenced
this pull request
Jun 8, 2026
…the placement loop (ADR-0035) From a verification-hardened fan-out (21 agents; 11/14 claims held, 3 refined). Key finding: the placement engine is ~90% BUILT but never WIRED — the cost model (cost.rs), the DRF placement policy (select.rs select_device), the engine controller (placement.rs observe), and the degradation loop (degrade.rs) all exist, pure + tested, but are NEVER called with live loads in the run; the LoadSource feeds only the UI footer. And the silent GPU→CPU fallback is computed-then-discarded: EngineRuntime::backend_kind() already knows it fell back, but that fact reaches NOTHING — not an event, not a warning, not a hardware cross-check. ADR-0035 defines the sense→detect→warn→plan→apply subsystem on the EXISTING parts: - DETECT: probe actually-usable backends (wgpu adapter device_type, NVDEC/NVENC via libav) + cross-check vs NVML-discovered hardware. - WARN: an actionable HealthWarning catalog (gpu-present-no-vulkan-adapter w/ the libvulkan/graphics remediation, software-decode/encode-on-gpu-host, nvenc-ceiling, vram-pressure, cpu-saturation, degradation-active), LATCHED/debounced, with a load-bearing NO-FALSE-POSITIVE rule (fires only on hardware-present AND software-tier-resolved → zero warnings on a CPU-only/software host). - PLAN+APPLY: wire LoadSource→select_device/PlacementController into the run, net of co-tenant (ours-vs-total) load, affinity-preserving (never fragment a pipeline, GPU-placement principle), inv #1/#9/#10 — the runtime re-plan runs OFF the output-clock thread (NOT the per-tick hook; folded from the adversarial review). SA-0..N backlog; SA-0 = the smallest win: detect+warn the compositor mismatch so the silent fallback that burned 5 CPU cores becomes a clear banner + /api/v1/health. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
troykelly
pushed a commit
that referenced
this pull request
Jun 8, 2026
…tor fallback (ADR-0035)
DETECT (multiview-hal): composite_probe — classify the wgpu adapter (device_type
!= Cpu, with the llvmpipe/lavapipe/swiftshader driver guard, Gl never a blanket
exclusion) and the both-halves MISMATCH cross-check (hardware discovered via
DeviceLoad>=1 OR EnvProbe present, AND composite resolved software/CPU). The
no-false-positive rule is structural: a GPU-free or software-only host trips
neither half.
WARN (multiview-events): HealthWarning { code, severity, subsystem, message,
remediation, since, active } as a richer sibling of Alert (never mutating Alert),
+ Event::HealthWarningRaised/Cleared routed on Topic::Alerts, latched code
gpu-present-no-vulkan-adapter, registered in AsyncAPI.
SURFACE (multiview-control): WarningRepository + warning_ingest (copy of
alarm_ingest: lagged-skip, swallow-and-skip; inv #10) + GET /api/v1/health (RBAC
read, RFC 9457) + emit_capability_warnings helper (the catalog copy/remediation),
registered in OpenAPI.
UI (web): useHealth hook + HealthBanner (severity icon+text, message, code,
remediation; colour-independent WCAG; renders nothing when clean) mounted
globally; Lingui strings extracted+compiled.
The cli build path makes one thin gpu-gated call (capability_warn::probe_and_emit
+ control's run_warning_ingest wiring) — build-time, off the output-clock thread
(inv #1), emitting only through the drop-oldest publisher (inv #10). CPU fallback
preserved; the silent info-only fallback becomes a loud warn log + banner +
/api/v1/health entry.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
troykelly
pushed a commit
that referenced
this pull request
Jun 8, 2026
…no per-frame alloc churn) (EFF) GREEN for EFF-0 (efficiency-budget §2.4 / safety rule §5: "frame buffers come from per-device pools allocated at start, never per-frame"). Before, the wgpu compositor created its full transient GPU surface set on every `composite()` call — the Rgba16Float linear canvas (~16.6 MB @1080p, ~66 MB @4k), the tile texture arrays, the NV12 y_out/uv_out planes, two padded readback buffers, the composite/encode uniform + tile-params buffers, and (overlay) a second overlaid canvas + overlay uniform/prim buffers + atlas — then freed them via Drop. That is ~26 MB/tick no-overlay (~42 MB/tick overlay), ~2.6 GB/s @4K25 of allocate-then-free GPU churn and a 4K throughput limiter. Now a `SurfacePool` (Mutex on GpuCompositor, interior mutability under the existing `&self` signature) holds every one of those surfaces, allocated once at first-frame sizing and REUSED every tick: - canvas-sized surfaces (canvas_lin, overlaid, y_out, uv_out, both readback buffers) are exact-keyed on (canvas_w, canvas_h) — a resize is rare, not per-tick; - tile arrays are grow-only on the max tile extent, always MAX_TILES layers; - uniform/tile-params/overlay-prim buffers are allocated once at their bounded max (COPY_DST) and refilled in place with queue.write_buffer; the 1x1 atlas placeholder is allocated once. Per-tick GPU allocations: BEFORE ~9 (no-overlay) / ~13 (overlay) create_* calls per composite → AFTER 0 in steady state (one-time pool fill; a genuine resize reallocates only the affected surfaces, then reuse resumes). Output is byte/SSIM-identical: the shaders read only the freshly-written region of each (possibly oversized) surface — tile arrays via textureLoad clamped to src_w/src_h, storage buffers via the `count`-bounded loop — so an oversized pooled surface samples exactly the same texels as a tight one. Inv #5 (NV12 throughout; the linear canvas is full-canvas, not per-tile RGBA) and #1/#10 (the pool lock is synchronous, never held across an .await, never back-pressures the engine) hold. Tests: GPU-free `gpu::pool` unit tests prove the allocate-once-then-reuse / reallocate-on-resize-then-reuse / grow-only-reuse counter logic end-to-end via `ensure_cached` (no adapter needed); the GPU-gated `gpu_surface_pool` integration test drives N ticks and asserts the allocation count is bounded (not ∝ N) + resize-then-reuse, skipping gracefully where no adapter exists. All existing compositor tests (incl. the gpu_compositor SSIM/byte-identity + RT-6 scale-at-composite suites) stay green. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
troykelly
pushed a commit
that referenced
this pull request
Jun 8, 2026
…gmented (ADR-0037) From a verification-hardened fan-out (21 agents; 10/14 claims held, 4 refined). Industry ISO/Program terminology per operator: ISO = isolated per-SOURCE faithful recording of EVERY elementary stream (video/audio/subtitle/data/SCTE-35/timecode); Program/PGM = the composited output. Key as-built findings: ISO taps Demuxer::read_packet() (all streams) BEFORE the video-only best_stream selection that today DISCARDS non-video (libav.rs:172); the tee is a ref-counted packet.clone (av_packet_ref, no payload copy) into an off-hot-path bounded DROP-OLDEST queue — the exact GuardedPacketSource/fanout never-block posture (inv #1/#10). v1 = faithful copy-remux of all streams via the safe Muxer (stream-copy, no re-encode); byte-exact TS/SRT dump deferred (needs a raw-AVIO tee). Program = a rotating file sink in the encode-once fan-out (RT-12 sink-mover, inv #7). Segmentation + time(30m/1h/7d)/size retention REUSE the ADR-0032 HLS rolling-window + atomic-publish (<seg>.tmp→rename). Disk-pressure (statvfs) disarms at a threshold + warns; write-failure → ADR-0035 HealthWarning + capped-backoff retry + auto-resume; never panics, never unbounded- buffers, never stalls. CRITICAL: ISO PRESERVES original source timestamps/timebase (archive as-is) — it does NOT re-stamp from the output tick (unlike the live path); RestampAccumulator is used only to keep the muxer from aborting at a segment seam. Folded refinements: a StreamCodecParameters::from_parameters constructor + a dedicated IsoMuxSink keyed by stream_index (not the program-side Video|Audio StreamKind). REC-0..N backlog; REC-0 = the bulletproof bounded-drop-oldest + backoff write path (everything builds on the never-take-out-the-engine guarantee). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
troykelly
pushed a commit
that referenced
this pull request
Jun 8, 2026
…ifier + /routing endpoints (ADR-0034)
Make the already-built in-program routing crosspoints reachable + applied
live (the RT-6 video rebind_cell, RT-8a/RT-9 audio repoint/repoint_crossfade,
RT-10a subtitle repoint primitives), end-to-end:
* Commands (multiview-control): additive `Command::RouteVideo/RouteAudio/
RouteSubtitle` (non_exhaustive); `SwapSource` becomes the desugared alias of
`RouteVideo{..., Video, Best}` (back-compat, same engine intent).
`Command::route_intent()` is the control->engine desugar bridge (control
depends on engine, not the reverse).
* Engine apply (multiview-engine::route): `RouteApplier` drains a batch of
engine-native `RouteIntent`s at the frame boundary and re-points the LIVE
crosspoint via the existing O(1) primitives — rebind_cell / repoint_crossfade
(cross-fade by default, pop-free) / SubtitleLayer::repoint. Resolves the
StreamSelector (Index/Language/Best/StreamId) against the input's
StreamInventory; coalesces a batch to <=1 re-point per destination/tick;
never blocks the output clock (inv #1/#10).
* #11 classifier + /routing/plan (multiview-control::routing): inspects the
destination's pinned params and returns {class1 | reset_lite | class2} + a
coerced-degradation flag. Honest at the edges: in-program re-point onto an
existing destination is Class-1; a cold-target video spin-up is Reset-lite;
an audio breakaway onto a discrete track whose pinned layout differs is
Class-2 (or operator-confirmed coerced Class-1).
* /routing/{video|audio|subtitle}/take + /routing/plan endpoints: resolve the
class, submit the Route command via submit_accepted (Idempotency-Key, RFC
9457, BOLA authorize_object, shed-503); 200 {class, applied} for a hot
Class-1/Reset-lite re-point vs 202 {operation_id} for a Class-2 migration.
OpenAPI regenerated (additive routes + StreamRefDoc/RouteTargetDoc mirrors).
No cli change required (the bus forwards Command::* generically via the drain's
non_exhaustive wildcard arm). No web change.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
troykelly
pushed a commit
that referenced
this pull request
Jun 8, 2026
…gh one MultiviewProgram, no behaviour change (ADR-0030)
Introduce the `Program` abstraction (ADR-0030 / MP-0) and route the existing
single-program run path through ONE `MultiviewProgram`, a behaviour-preserving
MOVE of `Pipeline::drive_streaming`'s per-program clock/drive/run-loop core —
proven by every existing invariant/pipeline test passing UNCHANGED.
- multiview-config: new `program` module — `ProgramId` (validated newtype,
reserved `"main"`), internally-tagged `ProgramKind` (#[non_exhaustive], only
`Multiview` populated — passthrough/transcode land in MP-3/MP-4, no stub
variant), and `ProgramSpec` (+ `main_multiview` desugaring). No `programs:`
schema root yet (MP-5).
- multiview-engine: new `MultiviewProgram` owns its `ProgramId` + per-program
`EngineRuntime` (clock + compositor drive + time source + pacer) + its own
`StopSignal`, and drives the protected per-tick loop via thin delegations to
`run_with_control`/`run_for_with_control`. Built from a `ProgramSpec` (cadence
contract enforced; wrong kind → typed `Error::WrongProgramKind`, never a panic).
- multiview-cli: `Pipeline::drive_streaming` now builds ONE `MultiviewProgram`
from a `ProgramSpec` desugared from the legacy config block (stored on
`Pipeline`) and drives the loop through it instead of an inline `EngineRuntime`.
The audio-bus tick, subtitle/overlay bake, and the per-frame command-drain
`control` hook are preserved verbatim. `PipelineError::Program { program, .. }`
carries `ProgramId` context.
Acceptance (unchanged through the move): #1 output-clock, #7 encode-once, #10
isolation. Protected engine soak/chaos (runtime.rs/isolation.rs) + the cli
streaming/pipeline tests pass byte-identical, none modified.
Gates: cargo fmt --check clean; cargo clippy --workspace --all-targets -D warnings
+ cargo clippy -p multiview-cli --features ffmpeg -D warnings clean;
cargo test -p multiview-engine -p multiview-config (335) + -p multiview-cli
--features ffmpeg (112) all green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
troykelly
added a commit
that referenced
this pull request
Jun 8, 2026
Fixed-cadence output clock + EngineRuntime drive loop (out_pts=f(tick)), arc-swap/broadcast isolation (inv #10), supervisor, admission/degradation loop; X.733 alarm state machine + content probes; tally arbiter/salvo/scheduler/multi-head; PTS servo (gated ptp); HA failover model. Inv #1/#10 adversarially verified. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
troykelly
added a commit
that referenced
this pull request
Jun 8, 2026
…ass, meters, subtitles Render overlays to pixels efficiently per ADR-0016 (off-by-default `overlay` feature): - Text engine: cosmic-text + swash shaping into an etagere shelf-packed, byte-capped, LRU glyph atlas (per-glyph cache → unchanged strings upload nothing); bundled OFL fonts (JetBrains Mono + Noto Sans) via rust-embed; one rasterizer feeds both the GPU quads and the CPU-reference coverage-bitmap blit. - Overlay compositing sub-pass: premultiplied source-over into the Rgba16Float LINEAR canvas between composite and NV12 encode (inv #5/#8); GPU compute (behind +wgpu, naga-validated) + CPU reference; in-shader primitives (meter bars, safe-area/center-cross, tally borders, rounded alert cards), batched. - Meters/scopes draw-data (dBFS→bar deflection, conflated ~30 Hz); subtitle SRT/VTT burn-in via the text engine + ASS via the off-by-default `libass` feature; overlays wired into the engine drive loop + cli run path, off the hot path (inv #1/#10). Efficiency proven by criterion benches (T2 zero re-raster on unchanged frame; T3 zero per-frame heap alloc; T4 bounded atlas; T5 batched per-label cost). OFL fonts attributed in NOTICE; cargo-deny clean incl. the overlay feature. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
troykelly
added a commit
that referenced
this pull request
Jun 8, 2026
…er + subtitle wiring Rework the run pipeline so each source decodes on its own thread, scales to its tile, and publishes NV12 into the per-tile framestore as frames arrive — replacing the buffer-all-to-EOF path that hung on live streams (so live HLS/RTSP now ingest under a bounded --duration) AND fixing the full-frame PiP green chroma cast (verified by eye: the full-canvas tile now renders natural color). Feed the dB meter real per-tick program-audio loudness (R128) instead of a constant, and wire subtitle cues into the overlay burn-in. New tests: streaming_ingest, subtitle_meter_pipeline; compositor pipeline regression. Inputs sampled into last-good stores, never pacing the output clock (inv #1/#10). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
troykelly
added a commit
that referenced
this pull request
Jun 8, 2026
…rm decoders (ADR-0019) Pure CaptionCue model (text + premultiplied-RGBA bitmap cues, regions, ASS markup stripper) always compiled + native-dep-free; CaptionDecoder behind the ffmpeg feature wraps the linked libav subtitle decoders — dvb_teletext (libzvbi, page-selectable), dvb_subtitle (dvbsub bitmaps), CEA-608/708 (cc_dec), WebVTT, SubRip, mov_text, ASS — emitting cues rebased to the ns timeline. 'No cue right now' is normal (empty Vec, never an error/stall — inv #1/#10). Fixed: the ass_text_field comma-count (libav emits the 8-field event form, so the Text field is after the 8th comma — keeps commas inside \pos(x,y)); unsafe // SAFETY allows; a double-mutable-borrow; clippy. 64 tests pass. docs/io/captions.md + ADR-0019 (Proposed). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This was referenced Jun 16, 2026
Merged
Merged
This was referenced Jul 10, 2026
feat(control,events): live authz revocation on established WS/SSE sessions (ADR-RT010, task #9)
#231
Merged
Merged
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Bumps vite from 6.4.3 to 8.0.16.
Release notes
Sourced from vite's releases.
... (truncated)
Changelog
Sourced from vite's changelog.
... (truncated)
Commits
f94df87release: v8.0.16dc245c7fix: reject windows alternate paths (#22572)50b9512fix(deps): reject UNC paths for launch-editor-middleware (#22571)8d1b019release: v8.0.152686d7dfix(deps): update all non-major dependencies (#22511)3052a67chore(deps): update rolldown-related dependencies (#22566)e3cfb9dfix(optimizer): close the rolldown bundle when write() rejects (#22528)6978a9crefactor: correct logic incollectAllModulesfunction (#22562)646dbedfeat: update rolldown to 1.0.3 (#22538)85a0efffix: capitalize error messages and remove spurious space in parse error (#22488)Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting
@dependabot rebase.Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR:
@dependabot rebasewill rebase this PR@dependabot recreatewill recreate this PR, overwriting any edits that have been made to it@dependabot show <dependency name> ignore conditionswill show all of the ignore conditions of the specified dependency@dependabot ignore this major versionwill close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)@dependabot ignore this minor versionwill close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)@dependabot ignore this dependencywill close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)