openvibers/openvibe.media Commits

Readiness: virtual clips are not objects with no good copy (their bytes are their VOD's; five held /api/ready at degraded) (#138)

OP OpenVibers committed 27 days ago · 6b85ff43e1 · 2 files, +10 −3

Changes

ddiff --git a/server/objects/copy-report.js b/server/objects/copy-report.js
iindex f2288e3..6b6648a 100644
---- a/server/objects/copy-report.js
++++ b/server/objects/copy-report.js
@@@ -3,7 +3,7 @@
*
* A ready object has NO GOOD COPY when none of its locations is `present` (verified there) or
* `pending` (not verified yet, so possibly fine). That covers objects whose every copy was found
-- * missing/corrupt, and ready objects with no location row at all.
++ * missing/corrupt, and ready objects with no location row at all, except virtual clips (a window over their VOD).
*
* Pure SQL over a small `q` interface — { all(sql, params), get(sql, params) } — so the service
* (server/db/database.js), the metrics/readiness checks and the read-only report script
@@@ -12,8 +12,12 @@
*/
'use strict';
++// A virtual clip (clip-jobs makeVirtual: a window over its VOD's timeline) has no copy of its own by design: its bytes
++// are its VOD's, whose object is checked on its own. The same test as verify-job's selection; five of them held
++// /api/ready at "degraded" (2026-10-17).
const NO_GOOD_COPY_WHERE = `o.lifecycle_status = 'ready'
-- AND NOT EXISTS (SELECT 1 FROM media_locations l WHERE l.object_id = o.id AND l.state IN ('present', 'pending'))`;
++ AND NOT EXISTS (SELECT 1 FROM media_locations l WHERE l.object_id = o.id AND l.state IN ('present', 'pending'))
++ AND NOT (o.kind = 'clip' AND (CASE WHEN json_valid(o.metadata) THEN json_extract(o.metadata, '$.virtual') END) IS NOT NULL)`;
async function countNoGoodCopy(q, { appId = null } = {}) {
const r = await q.get(`SELECT COUNT(*) AS n FROM media_objects o WHERE ${NO_GOOD_COPY_WHERE}${appId ? ' AND o.app_id = ?' : ''}`, appId ? [appId] : []);
ddiff --git a/test/objects-verify.test.js b/test/objects-verify.test.js
iindex c08c850..908a696 100644
---- a/test/objects-verify.test.js
++++ b/test/objects-verify.test.js
@@@ -157,7 +157,10 @@ const crypto = require('crypto');
console.log('✅ never deletes: files, objects, locations and legacy rows all remain');
// ── Count, /metrics and /api/ready ──
-- assert.strictEqual(await copyReport.countNoGoodCopy(db), 3, 'c (remote corrupt), d (local gone), h (no locations)');
++ // A virtual clip (clip-jobs makeVirtual) has no copy of its own by design: its bytes are its VOD's.
++ await model.createObject({ app_id: 'live', kind: 'clip', lifecycle_status: 'ready', size_bytes: 0,
++ owner_user_id: 7, owner_subject: 'usr_01JAB2C3D4E5F6G7H8J9K0MNPQ', mime_type: 'video/mp4', metadata: { virtual: true } });
++ assert.strictEqual(await copyReport.countNoGoodCopy(db), 3, 'c (remote corrupt), d (local gone), h (no locations); not the virtual clip');
const st = await job.status();
assert.strictEqual(st.no_good_copy, 3);
assert.strictEqual(st.verified_objects, READY);