What shipped on OpenVibe.Media

Every change deployed to OpenVibe, newest first. Each line is a commit from the OpenVibers repositories, linked to the change itself. When enough have gathered, or a large feature lands, they are written up as Patch notes on openvibe.blog. JSON: /api/v1/changelog.

2026-09-24

9de5cb9Channel lookups through Live's canonical lineage resolver (D20): the dev-data API's @username selector asks OpenVibe.Live /internal/lineage/resolve with Media's service token (live.lineage.resolve) for the channel and its Live user id…OpenVibers · 04:51 UTC
984e7adSECURITY.md: how to report a vulnerability ([email protected], 7-day reply, scope, supported versions)OpenVibers · 04:51 UTC
7114433R2 tier decisions are recorded and explainable: every promotion to and demotion from the R2 popularity cache gets a media_tier_decisions row with the inputs it saw (view_count, last_accessed_at, provider, recording, hold, size…OpenVibers · 04:51 UTC
5099c97thumbnail.regenerate refuses a recording with nothing to take a frame from. The five failed jobs on production (all at 2026-09-23 21:36:41, created by app:live, generate_failed) were Live asking for thumbnails of VODs 3044, 5537, 5540…OpenVibers · 04:51 UTC
039dc48Events media.object.deleted and media.object.visibility_changed through the outbox, so consumers (Search, Live, Community) learn that an object went away or stopped being public (Media emitted neither). Payloads are minimal…OpenVibers · 04:51 UTC
a90d0edCrawler basics at the openvibe.media origin: /robots.txt (openvibe-shared seo.robotsTxt: AI and search crawlers named; /api/, /auth/, /internal/, /o/, /metrics, /release-metrics and the /live/ dev-data endpoints disallowed; the sitemap)…OpenVibers · 04:51 UTC
cb17f29RTMP pull SSRF: POST /vods/:id/ingest/rtmp makes ffmpeg connect to the URL it is given, and any rtmp:// or rtmps:// URL was accepted, so an app key (or a leaked one) could point Media's ffmpeg at any host and port it can reach. The…OpenVibers · 04:51 UTC
e5e6f09object.hash job: sha256 for local copies in bounded batches, recorded on the object (content_hash, with metadata.hash_basis = the file and size it read) and on its local location (checksum, verified_at). Only 14 of 2,839 ready objects had…OpenVibers · 04:51 UTC
47b4349trust proxy is loopback only (was true): req.ip is the X-Forwarded-For that the local nginx set when a request came through it, and the socket address for anyone else, so a caller reaching port 4100 directly (HOST defaults to 0.0.0.0) can…OpenVibers · 04:51 UTC
20a602evod.duration.reconcile: stored VOD durations are compared with a measurement of the real file in bounded batches, offloaded VODs included, and clearly wrong values are repaired (the health scanner only repaired durations <= 0 and skipped…OpenVibers · 04:51 UTC
24f1962vod.finalize job: a recording whose finalize failed or never ran is retried on media_jobs with backoff, instead of a one-shot boot sweep whose failure was swallowed and a stat failure that only cleared is_recording. The orphan sweep (in…OpenVibers · 04:51 UTC
cc84bf1VOD durations are measured, never estimated: finalize stores what the file says and vods.duration_source says where it came from. probe = ffprobe's container duration of the finished file; remux = the last packet time of a stream-copy pass…OpenVibers · 04:51 UTC

2026-09-23

0724119objects-verify test: read the re-upload from the run that first checked the object, not from media_verifications, which keeps only the latest verdict; when batch rotation re-verified the object in a later run (same-second verified_at…OpenVibers · 23:54 UTC
6c2d384Opening the database no longer fails a clip being cut: getDb() ran the restart recovery ('processing' clips → failed) every time any process opened media.db, so a backfill or operator script run on the host while the service cut a clip…OpenVibers · 23:51 UTC
ce6a02agitleaks: allow the owner-subject test's made-up INTERNAL_API_KEY, matched on path and valueOpenVibers · 23:48 UTC
31c2899Owner subjects: every media object that names an app-local owner (owner_app + owner_user_id) gets the owner's canonical Network subject in owner_subject, so Live's lineage resolver and other consumers read owner.subject instead of…OpenVibers · 23:46 UTC
0c27f0bopenvibe-shared v1.5.1 (Track R release manifest), openvibe-contracts v0.33.0, openvibe-sdk v0.5.0OpenVibers · 23:16 UTC
6e74eb0Restore drills: MEDIA_DRILL=1 makes Media a read-only instance on a restored copy of media.db, so `ovhost drill media` can boot one next to production. It refuses to start unless DB_PATH is set and outside the checkout and…OpenVibers · 22:55 UTC
ee39be1Clips say who made them: POST /clips keeps auto_generated and the description when the app itself asks (an app-key call with no X-OV-User-Id), and never when the call acts for one of the app's users. Both fields were dropped, so every AI…OpenVibers · 21:23 UTC
ad2217bJob events carry a projection, not the job: media.job.<transition> payloads are queue.jobEvent (id, app_id, object_id, type, status, attempts, max_attempts, error_code, cancel_requested, has_result, run_after, decided_at, created_at…OpenVibers · 21:23 UTC
5d44df5Docs: the single-part PUT's refusals include the multipart size, content type and open-session answersOpenVibers · 20:50 UTC
0ffbde5Multipart complete is idempotent: completing a session that already completed (a retry after its answer was lost) returns the ready object instead of 409, as the single-part complete does; the SDK objects client (openvibe-sdk 0.5.0)…OpenVibers · 20:49 UTC
d006749Wave 4: media job system, multipart and presigned uploads, R2 eviction drillOpenVibers · 20:44 UTC
9de4b25/p/:slug/screenshot: a slug Media doesn't hold (pastes made in Community since the move) goes to Community like /p/:slug and /raw; a private one answers the same way. Hero-moment thumbnails linked here and showed broken imagesOpenVibers · 20:04 UTC
454dc09CI: run the shared security workflow (gitleaks secret scan + dependency audit, Track Q)OpenVibers · 19:33 UTC
cbf8410Media's Events outbox row is written in the state change's transaction: webhooks.announce() runs the change (VOD ready/quarantine/delete, clip ready/failed, object ready + invariant row) and events.record() in ONE SQLite transaction, then…OpenVibers · 19:30 UTC
22ba4aaDocs: STATUS.json and README match production (2026-09-23)OpenVibers · 18:33 UTC
e42af9eScheduled copy verification: every 10 min verify the 50 least recently verified ready objects (local stat + sha256 up to 64 MB, B2/R2 HEAD + size), record verdicts on media_locations, media_verifications and media_verify_runs, restore a…OpenVibers · 18:33 UTC
dfb2172Private items answer exactly like missing ones: /v and /c returned 403 "This media is private", which confirmed that a private recording (or, through the basename form of /v, a file name) exists; now the same 404 and body as an unknown id…OpenVibers · 18:29 UTC
2601b0esystemd: TimeoutStopSec 30 → 80 so a stop during a recording lets the recorder's 60 s trailer grace (and the 70 s forced exit) finish instead of SIGKILL cutting the fileOpenVibers · 17:15 UTC
4b99e02nginx: client address headers only from $remote_addr (realip). X-Forwarded-For was appended to and CF-Connecting-IP passed through from the client, so a request reaching the origin without Cloudflare (DNS-only host or the bare IP) chose…OpenVibers · 16:14 UTC
20189e9Developer-project tenants: no inline HTML/SVG from /f, race-free files quota, retained deletes countOpenVibers · 15:50 UTC
1c8f67dopenvibe-contracts v0.28.0OpenVibers · 04:23 UTC
bfc9e1bDeveloper-project tenants (Wave 20, ADR-014): app tokens get a Media tenant per projectOpenVibers · 04:17 UTC
d3f81b9Token-only tenants for wiki and blog (10 GB each)OpenVibers · 02:46 UTC
3007461Token-only tenants for tools (20 GB, job results) and games (10 GB, map-editor assets)OpenVibers · 02:15 UTC
e5525bdTruthful GET /api/ready and loopback-only GET /metrics (openvibe-shared v1.3.0)OpenVibers · 02:01 UTC
927d451GET /release.json (ADR-016); openvibe-shared v1.2.0OpenVibers · 01:49 UTC
1122f52Media outcomes as durable events: vod/clip ready|failed, object uploaded and storage alerts also go to OpenVibe.Events through an outbox (openvibe-sdk 0.2.2); webhooks unchanged; openvibe-contracts v0.8.0OpenVibers · 01:34 UTC
76f3a44openvibe-shared is the pinned OpenVibe.Shared v1.0.0 release (vendor/ is gone); openvibe-contracts v0.7.0OpenVibers · 01:13 UTC
cced10fCanonical object model (Wave 4): media_objects with locations, relationships, variants, jobs, retention holds and the public-size invariant; vods/clips/files/screenshot pastes become projections via object_idOpenVibers · 01:01 UTC

2026-09-22

ddfefcfPaste cutover switches: PASTES_FROZEN_APPS answers 410 to paste writes for apps that moved to Community; PASTES_MOVED_TO 301s /p/:slug and its raw text there; screenshot bytes stay served hereOpenVibers · 23:14 UTC
747d7dbopenvibe-contracts v0.5.1OpenVibers · 23:07 UTC
2db74cfService-principal tokens on the tenant API; token-only 'community' tenant; paste export bundle for Community's importerOpenVibers · 23:07 UTC
13fcdfeCI: npm test on Node 22 on every push to main and every PROpenVibers · 21:36 UTC

2026-09-21

6114bc6vendor sync: openvibe-shared navbar + ring icons now draw solid Font Awesome glyphs (no FA CSS dependency)OpenVibers · 16:58 UTC
f2047ffVOD finalize: keep anything 2s or longer; delete zero-byte recordings instead of quarantining themOpenVibers · 16:20 UTC

2026-09-18

28c1009Avatar ingest: pinned lookup answers both the single and the list formOpenVibers · 14:49 UTC
145b45aAvatar ingestion: fetch a user-supplied link safely (public addresses only, pinned connection, size and redirect caps), re-encode with sharp, store as an unlisted avatar paste; internal-only routeOpenVibers · 14:49 UTC
4214448vendor sync: shared navbar (drawer, chips, sections)OpenVibers · 14:44 UTC