Commits
-
finish-f2: Changed: the server-boot wait in test/perf-budget.test.js…OpenVibers · 1 Oct 2026
3fde10c -
finish-f1: I changed one thing: nodemodules is no longer tracked, and…OpenVibers · 1 Oct 2026
8ca5a49 -
Decouple avatar ingest from server/pastes/routes.js — reportOpenVibers · 1 Oct 2026
90c4ee2 -
Merge pull request #2 from OpenVibers/agent/bump-openvibe-shared-v2.3.1-mupvaip1OpenVibers · 1 Oct 2026
ee19867 -
Bump openvibe-shared v1.29.2 → v2.3.1OpenVibers · 1 Oct 2026
14d6846 -
Media serves Live and OpenRe on their own service tokens (plan T4, Media cleanup D8): every v1 tenant route Live or OpenRe calls names the verb it performs (read, list, upload, delete), so a token is checked against the right capability and namespace; under a first-party service token (svc:) X-OV-User-Id scopes a write to that user exactly as the app key did (a developer app's token never names a user this way); only routes that opt in (project: true) treat a /<project_id>/ segment as a developer-project tenant, so naming a verb never opens a first-party route to app tokens. test/service-token-tenant.test.js. Both suites green (verified); the token tests rerun after the svc-only tightening.OpenVibers · 29 Sept 2026
29be23a -
X-Internal-Key is gone from Media (plan T2, the last step): POST /internal/avatar-ingest takes only a Network service token holding media.avatar.ingest, loopback only; guardOrKey, config.network.internalApiKey and INTERNAL_API_KEY are deleted (production no longer sets it), and the visitor-hash secret is VIEW_HASH_SECRET or MEDIA_SECRET with a named warning when neither is set in production. Tests: token with the capability passes, without it 403, wrong audience and sandbox 401, no credential or a forged Bearer refused. npm test and test:pg 75/76, 1 skipped (verified).OpenVibers · 29 Sept 2026
809b06b -
X-Internal-Key retirement, Media's step (plan T2): POST /internal/avatar-ingest takes Network's service token with media.avatar.ingest (server/service-guard.js, loopback only; a Bearer is judged on the token alone, the key still passes without one until Network stops sending it). The owner resolution to Network's resolve-batch sends only Media's token: the key fallback is gone, and a refused token is retried once with a fresh one. openvibe-contracts v0.79.0. Tests: capability, audience, sandbox, a bad Bearer beside the key, the public edge, the key alone; the key is never sent to Network. npm test and test:pg green.OpenVibers · 29 Sept 2026
8364eee -
Origin shield on in production: edge.openvibe.media (DNS-only, DNS-01 certificate), the nginx shield, MEDIA_SHIELD=b2. The edge also hides B2's object headers (x-amz-version-id, x-bz-*). docs/media-fabric.md records the switch-on and the probe (302 from openvibe.media, 206 with the exact range, MISS then HIT, no B2 header).OpenVibers · 29 Sept 2026
a174534 -
Origin shield: viewers keep the one public URL. A shield-eligible read (a public or unlisted B2 copy, never private, sandbox or a recording) that arrives on openvibe.media answers a 302 to the same path on the DNS-only edge host, where the bytes come from the slice cache; on the edge it is served, never redirected again; never a scheme-relative target. Nothing changes until MEDIA_SHIELD and MEDIA_SHIELD_HOST are set. The repo's nginx files carry the security.txt include the host has. npm test 74/75 (N-1 skipped as designed).OpenVibers · 29 Sept 2026
2ab62eb -
Origin shield (F1b) review fixes, still inert until MEDIA_SHIELD is set. The edge is known from X-Media-Shield-Host, which only the edge server block sets and openvibe.media clears (req.hostname honoured a client's X-Forwarded-Host), and routes check it before presigning. A URL signed for any B2 host but the one nginx proxies to keeps its 302 (a changed MEDIA_B2_ENDPOINT would have 403'd every slice); a test pins shield.js and the nginx snippet to the same host. Overwriting a shielded key (a repair, or a re-upload within ten minutes of a delete) refreshes its slices after the upload; purges run four slices at a time and send no dead Host header. nginx: the edge block gets openvibe.media's body size, timeouts and /metrics 404; the refresh listener is loopback-only (allow/deny); the shield location hides B2's Content-Disposition, Cache-Control, Expires, Set-Cookie and request ids and adds nosniff and noindex. The internal presign lives six hours. docs/media-fabric.md F1b decisions updated. npm test 74/75 (N-1 skipped as designed).OpenVibers · 29 Sept 2026
29e6ada -
Media Fabric F1b, off until the edge host exists: the origin shield. For a public B2 copy Node answers with X-Accel-Redirect into nginx's /_media_shield/b2/ (a 10 MB slice cache with proxy_cache_lock, keyed by object path and slice, never the signature; an hour-long internal presign) instead of redirecting the viewer. It answers only on MEDIA_SHIELD_HOST, a DNS-only edge name: openvibe.media is behind Cloudflare's proxy, whose video terms are unverified, so bytes that went viewer to B2 never start flowing through it. Private and sandbox bytes never enter the cache; deleting a shielded object refreshes its slices through a loopback-only listener. nginx config in deploy/nginx (cache 5 GB, min_free 20 GB so recordings keep their disk; shield logs never carry the signed query); decisions in docs/media-fabric.md. Tests: placement-shield (targeting, edge-host gate, private/sandbox, purge ranges), placement, objects-api.OpenVibers · 29 Sept 2026
8c19184 -
Media Fabric F1a: every read goes through one placement router (docs/media-fabric.md).OpenVibers · 29 Sept 2026
b2bdc44 -
docs/media-fabric.md: the accepted design for Media's storage and delivery (owner, 2026-09-29). Two fabrics (online: B2 canonical, R2 Standard hot, Bunny/CDN, the Media host's NVMe edge; archive/backup separately, deep archive never online); provider classes with capability probes and live prices in media.cost_tiers; segment-native CMAF/HLS video with a growing DVR playlist, write-behind segment durability, packing after finalize, keyframes forced on the source's boundaries and one timeline index; clips that reference the source; derivatives as cost-managed computed caches (AV1 for viral VODs); one placement engine per object x region x segment bucket under budgets with two-phase moves, dry-run and a simulator; sticky, canaried multi-CDN routing with a single-flight origin shield and tokenized private media; one telemetry schema, Valkey rollups, player QoE and seek SLOs, cascaded control loops and provider-bill calibration. Build order F1-F6.OpenVibers · 29 Sept 2026
12c6811 -
scripts/retire-r2.js and its test are removed: R2 stays as Media's fast tier (owner, 2026-09-29), so a tool that empties it has no place here. It ran once (its report is on the host); promotion is back on and the sweep refills R2. The storage placement engine (plan T4) is next.OpenVibers · 29 Sept 2026
1535276 -
Two uploads/thumbnail paths no longer hang on a database error: a multipart part's completion read (getSession) sat outside its try, so a rejected read was an unhandled rejection and the PUT never answered; it now answers 500 media.object.store_failed. A thumbnail probe whose close handler throws resolves the request (null thumbnail) instead of leaving it unsettled. Tests: test/multipart-part-db-error.test.js, test/thumbnail-probe-throw.test.js. Found by the estate-wide floating-promise sweep; fixed by DeepSeek, reviewed independently (VERDICT: SHIP). npm test 67/68, 1 skipped (N-1 SQL across the PostgreSQL switch). npm test 67/68 test files passed, 1 skipped (n-1.test.js: N-1 SQL: skipped (the recorded N-1 releas.OpenVibers · 29 Sept 2026
bbb7765 -
retire-r2.js reads Media's start time in microseconds: systemctl's default whole seconds put a restart made in the same second as the gates before them, so --execute refused.OpenVibers · 29 Sept 2026
ea989e1 -
retire-r2.js --gates writes its settings revisions as Media itself (no actor): the config store takes a subject reference or none, and refused the bare string.OpenVibers · 29 Sept 2026
262aa44 -
scripts/retire-r2.js retires the R2 cache tier (plan T4: B2 is canonical, R2 held 19 popular VODs as a cache). --gates closes promotion (storage_tier.r2Enabled, object_tier.active) and records when; --execute refuses until Media has restarted after that, so no sweep can promote or verify a key being removed. Each VOD served from R2 is proven first (B2 and R2 sizes and vods.file_size agree; the full sha256 of the B2 copy equals the R2 copy's and content_hash) and then demoted by the engine's demoteFromR2; each native object's canonical copy must hash to content_hash before tiering.demote (logged); a key no row on R2 still references goes only when B2 holds identical bytes. Recording, held and unproven rows keep their copies, and so do their bucket keys. Dry run by default. Reviewed independently (FIX: bucket keys of refused rows, projected objects, the gates, a second unproven delete; all fixed) and covered by test/retire-r2.test.js. Deleted together with the R2 code once it has run.OpenVibers · 29 Sept 2026
fec18a6 -
The SQLite era is gone (on PostgreSQL since 2026-09-28; no compatibility kept): the one-time migrate-to-postgres script, the *_DB_PATH settings (config, .env.example, systemd unit, test helpers), the unused better-sqlite3 dependency and its lockfile entries, and docs, docstrings and STATUS lines about SQLite or its rollback window. observability.test.js waits up to 30 s for the real server to boot (a cold PGlite boot plus migrations missed the 10 s window on a loaded machine). Reviewed independently (VERDICT: SHIP). npm test 64/65 test files passed, 1 skipped (n-1.test.js: N-1 SQL: skipped (the recorded N-1 releas.OpenVibers · 29 Sept 2026
dbdcbee -
Recordings end when ffmpeg ends again (broken by the PostgreSQL switch this morning), and avatar ingest awaits its slug.OpenVibers · 29 Sept 2026
197a8f5 -
openvibe-shared v1.29.2 (from its earlier pin): navbar dropdowns are no longer clipped by the links row, changing the theme repaints the page background, bright accents get dark button text (WCAG), the navbar brand is more compact. npm test: 63/64 test files passed, 1 skipped (n-1.test.js: N-1 SQL: skipped (N-1 runs on SOpenVibers · 29 Sept 2026
5224f70 -
openvibe-shared v1.28.1 (from its earlier pin): the account panel keeps its sections' height on phones, the codes mark at rest shows its V, no empty space under the footer on phones. npm test: 63/64 test files passed, 1 skipped (n-1.test.js: N-1 SQL: skipped (N-1 runs on SOpenVibers · 29 Sept 2026
a865d84 -
Readiness and /metrics await the events outbox status: events.status() is async on PostgreSQL, so /api/ready read a promise and reported the running relay as skipped (seen right after the switch).OpenVibers · 28 Sept 2026
fe084de -
Media on PostgreSQL (ADR-035, roadmap WS-X2): openvibe-sdk/db, async throughout, jobs and quotas safe under concurrency.OpenVibers · 28 Sept 2026
e3f2239 -
npm test no longer counts a skipped test as passed (roadmap WS-Q task 7; Shared v1.25.0 openvibe-shared/test-runner). The test script was a shell loop that stopped at the first failure and counted nothing, so a test that printed "⚠️ ffmpeg not found: … skipped" and exited 0 was as good as a pass. test/run.js is now the shared runner: every file, one at a time as before (parallel 1), a 300 s timeout per file, and a summary; a file that prints "<label>: skipped (<why>)" is listed with ○ and not counted as passed, and --strict fails on it. The six tests that skipped in free-form words now print that line: jobs-invariant (split/remux execution), clip-cut-job (clip.cut), jobs-previews (preview jobs), duration-reconcile (measurement checks) and vod-duration (real-file finalize check) without ffmpeg, and trust-proxy (direct-caller check) without a non-loopback interface. openvibe-shared is pinned at v1.25.0 (from v1.24.0), named in the README. npm test (Node 22) 64/64 test files passed.OpenVibers · 28 Sept 2026
47b21bd -
H15 repair: resize, and the legacy row follows (roadmap WS-G task 7, found by the no-fake-green readiness sweep). Media's readiness is degraded again by 3 objects with no good copy: VODs 939, 1277 and 1309, the same three the 2026-09-25 repair rebaselined from their B2 copies (size and sha256 re-recorded). On 2026-09-26/27 a projection from the legacy vods row (model.js vodProjection, size_bytes = file_size) put the mid-upload sizes back (63708377, 13631488, 786432) and kept the new hashes, so scheduled verification found each B2 copy's size wrong and marked it corrupt, and the three are not playable. New plan action resize: a corrupt B2/R2 copy whose downloaded bytes hash to the object's own content_hash is the object, and only its recorded size is re-recorded (apply refuses bytes that do not match the hash). rebaseline and resize now also write the size to the legacy vods row behind the object (file_size), so its projection agrees and cannot undo the repair; rollback restores that row too. scripts/h15-repair.js passes the downloaded facts to plan. test/h15-repair.test.js covers resize, a mismatched hash (lost), no download (lost), the legacy row on resize and rebaseline, and rollback. npm test passes.OpenVibers · 28 Sept 2026
8b2e542 -
Media's readiness has no fake green (roadmap WS-Q task 7, Shared v1.24.0). events_outbox answered ok with { enabled: false } while the relay was off, and an unconfigured remote tier (b2, r2) had no check at all, so nothing showed it was not in use. The relay off is now skipped with the reason (detail { enabled: false } kept), and an unconfigured tier is listed as remote_<name> skipped "not configured"; neither is ever ok, and an optional skip leaves a service whose checks passed ready. Drill mode still lists no remote tier. openvibe-shared is pinned at v1.24.0 (from v1.22.0), named in the README. test/observability.test.js checks both skips (the configured-tier and failure cases are unchanged). npm test passes.OpenVibers · 28 Sept 2026
51283d3 -
README and STATUS.json are current (roadmap WS-U task 3): the README gains Purpose (the opening overview), Owns, Does not own, Depends on, Capabilities (the nine media.* capabilities and the grants Media uses at Network, Live and Events), Acceptance (what the test files prove), Security (SECURITY.md, auth, private data, exposure, egress, secrets by name) and Deploy (sudo ovhost deploy media, the recording guard, unit, port, env file, vhost, N-1, rollback and its media_jobs blocker) sections. Stale facts corrected: pastes belong to OpenVibe.Community since 2026-09-22 (the overview and the /p/:slug row said Media is their canonical home), and the layout names the current pins (shared v1.22.0, contracts v0.71.0, sdk v0.12.0). STATUS.json is new, in the shape of Search's, updated 2026-09-28.OpenVibers · 28 Sept 2026
14cac06 -
/limits.json lists the per-actor rate limits as rate_limits (roadmap WS-R task 4): every named limit the routes declared (object upload, parts, complete, delete, jobs, files, me), with its numbers per caller per minute and hour and 429 rate_limited past it, so Codes' limits page shows what is enforced. test/limits.test.js checks the upload and part numbers. npm test passes.OpenVibers · 28 Sept 2026
6248363