openvibers/openvibe.media Commits

Point fabric doc at openvibe.media and mark pastes moved in object docs (#17)

OP OpenVibers committed 3 Oct 2026 · 0897241ab7 · 2 files, +8 −3

checks run by GitHub CI (test, test-pg) · CI ✓ 3/3 · review SHIP by DeepSeek harness

https://github.com/OpenVibers/OpenVibe.Media/pull/17

Changes

ddiff --git a/docs/media-fabric.md b/docs/media-fabric.md
iindex e409e57..1086371 100644
---- a/docs/media-fabric.md
++++ b/docs/media-fabric.md
@@@ -14,7 +14,7 @@ presentation; they ask Media for an object and a delivery URL and never know whe
**Online (the Media Fabric).** Every object a viewer can ask for has an immediately retrievable copy:
```
--viewer → media.openvibe.network → delivery router
++viewer → openvibe.media → delivery router
├─ OpenVibe edge (the Media host's NVMe cache; later edge nodes) capacity-bounded, prepaid bandwidth
├─ global CDN (Bunny in front of B2; Cloudflare only in front of R2)
└─ hot object tier: R2 Standard
ddiff --git a/docs/object-model.md b/docs/object-model.md
iindex 0d7de0b..83360ee 100644
---- a/docs/object-model.md
++++ b/docs/object-model.md
@@@ -3,7 +3,8 @@
Roadmap Wave 4 turns Media from predecessor-shaped VOD/clip/file tables into one canonical object
platform. Every stored blob is a **media object** with an id `med_<ULID>`. The inherited
`vods`, `clips`, `files` and screenshot `pastes` rows stay as they are, and each one is now a typed
--projection over an object through its `object_id` column. Every existing URL and v1 response is
++projection over an object through its `object_id` column. Pastes moved to OpenVibe.Community on
++2026-09-22: Media keeps the frozen `pastes` rows and their screenshot/avatar objects, read-only. Every existing URL and v1 response is
unchanged. New code talks to objects through the [v2 API](#object-api-v2).
Code: `server/objects/` (`model.js`, `routes.js`, `backfill.js`, `reconcile.js`, `invariant.js`,
@@@ -53,6 +54,10 @@ the transitional `media.media-ref@1` legacy form in `legacy_ref`, which is uniqu
| avatar (screenshot paste with `metadata.kind = 'avatar'`) | avatar | `legacy:<app>:avatar:<slug>` |
| `vods`/`clips.thumbnail_url` (`/t/<name>`) | thumbnail | `legacy:<app>:thumbnail:<name>` |
++Paste rows are frozen since pastes moved to OpenVibe.Community (2026-09-22): no new screenshot or
++avatar objects are created through Media's paste API, and the existing ones cannot be deleted
++(`DELETE` answers 409 `media.object.legacy_managed`).
++
Every v2 route that takes `:id` accepts either form. Native v2 objects have `legacy_ref = NULL`.
### How a row maps to its object
@@@ -519,7 +524,7 @@ While any hold applies:
- Quarantine cleanup and the boot junk sweep skip the object.
- Finalize never deletes a held recording that turned out empty (no file, or zero bytes): it keeps the row and the file and settles it as failed (`missing_file` / `zero_byte`, quarantined, `vod.failed`).
- `deleteVodObjects` keeps the bytes.
-- - Paste screenshot removal keeps the file.
++ - Paste screenshot removal no longer exists (the paste API is read-only since pastes moved to OpenVibe.Community).
- A `BEFORE DELETE` trigger on each projected table, plus a trigger on `media_objects.lifecycle_status`, refuses the change, so paths nobody has hooked are still covered. The triggers are the `_v2` ones (clip-aware); an older database has its first-version guards replaced at start.
- **No tier move.** `moveToCold`, `moveToHot`, `promoteToR2` and `demoteFromR2` return `{ ok: false, held: true }` (the admin moves answer it, R2 moves are logged as `refused`), and the sweep counts these as `skippedHeld` instead of errors. A held native object is never promoted to or demoted from the R2 cache either (logged as `refused`; a hold placed while its bytes were being copied wins, and the unrecorded copy is removed). A hold freezes an object's placement: `moveToHot` is refused too, because restoring flips the row to local and drops an R2 copy. A clip cut from a held VOD in B2/R2 is cut from the cloud copy instead of fetching the VOD home. Row updates that only record where the bytes already are (the sweep finding a local file gone while B2 has the copy, the legacy-tier migration) still happen: they move nothing.