openvibers/openvibe.reviews Commits

openvibe-shared v1.5.0 (Track R release manifest), openvibe-contracts v0.32.0, openvibe-sdk v0.5.0

OP OpenVibers committed 23 Sept 2026 · 2411fe1907 · 7 files, +31 −21

- /release.json is mounted with release.mount(app, { registry }): POST /release-metrics takes open
  tabs' update reports into /metrics (release_client_updates_total). On contracts 0.32.0 the
  manifest carries the release-manifest 1.1.0 fields; no components are declared, so every
  release still prompts a reload. test/resolution.test.js validates the served manifest against
  the contracts.
- identity.service-token-claims 1.2.0 (contracts 0.26.0) requires project_id and env on app tokens:
  the test helper's app tokens carry them, as Network's do. serviceAuth now refuses a sandbox app
  token itself with token.sandbox_refused, the code Reviews already answered; no reviews.*
  capability can be granted to a developer app (all first-party).
- SDK 0.4.0 -> 0.5.0 only adds the Media objects client. README and STATUS list the new pins.

Changes

ddiff --git a/README.md b/README.md
iindex 4b09119..cd6ba46 100644
---- a/README.md
++++ b/README.md
@@@ -193,7 +193,7 @@ by editors; signals arrive only from Sources.
- OpenVibe.Community — discussion threads (`community.comment.write`)
- OpenVibe.AI — optional, proposes summaries through `reviews.summary.propose`
- OpenVibe.Search — consumes the index events
--- packages: openvibe-publishing v0.2.1, openvibe-contracts v0.20.0, openvibe-shared v1.3.0, openvibe-sdk v0.4.0
++- packages: openvibe-publishing v0.2.1, openvibe-contracts v0.32.0, openvibe-shared v1.5.0, openvibe-sdk v0.5.0
## Acceptance (tested in `test/`)
ddiff --git a/STATUS.json b/STATUS.json
iindex 1a22819..21e3cc3 100644
---- a/STATUS.json
++++ b/STATUS.json
@@@ -7,8 +7,8 @@
"runtime": "node 22, express, better-sqlite3",
"port": 4830,
"domain": "openvibe.reviews",
-- "contracts": "openvibe-contracts v0.20.0",
-- "packages": ["openvibe-publishing v0.2.1", "openvibe-shared v1.3.0", "openvibe-sdk v0.4.0"],
++ "contracts": "openvibe-contracts v0.32.0",
++ "packages": ["openvibe-publishing v0.2.1", "openvibe-shared v1.5.0", "openvibe-sdk v0.5.0"],
"capabilities": ["reviews.entity.resolve", "reviews.entity.manage", "reviews.entity.merge", "reviews.entity.split", "reviews.signal.import", "reviews.summary.propose", "reviews.summary.publish", "reviews.correction.submit"],
"capabilitiesRegistered": true,
"deployed": true,
ddiff --git a/package-lock.json b/package-lock.json
iindex 0920dcb..ca8e599 100644
---- a/package-lock.json
++++ b/package-lock.json
@@@ -14,10 +14,10 @@
"dotenv": "^16.4.7",
"express": "^4.21.2",
"express-rate-limit": "^7.5.0",
-- "openvibe-contracts": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.20.0",
++ "openvibe-contracts": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.32.0",
"openvibe-publishing": "https://codeload.github.com/OpenVibers/OpenVibe.Publishing/tar.gz/refs/tags/v0.2.1",
-- "openvibe-sdk": "https://codeload.github.com/OpenVibers/OpenVibe.SDK/tar.gz/refs/tags/v0.4.0",
-- "openvibe-shared": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v1.3.0"
++ "openvibe-sdk": "https://codeload.github.com/OpenVibers/OpenVibe.SDK/tar.gz/refs/tags/v0.5.0",
++ "openvibe-shared": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v1.5.0"
},
"engines": {
"node": ">=22.0.0"
@@@ -999,9 +999,9 @@
}
},
"node_modules/openvibe-contracts": {
-- "version": "0.20.0",
-- "resolved": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.20.0",
-- "integrity": "sha512-0sUKklq2taKCInqh83ys8akGOaZ4KemDWW5Dy4HdLI4dtL6Jd7RUBaEytsJKcISIza2dSPXb7V+xC3jJUuSDow==",
++ "version": "0.32.0",
++ "resolved": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.32.0",
++ "integrity": "sha512-ntN58SIG03YDxbhsiIzOM5GRH19jRMHZUYWI3xU2VwovExagF5DdwApLVfezsu84UTJ+V2Jfn+LWDc+Oz8ab+g==",
"license": "AGPL-3.0-only",
"dependencies": {
"ajv": "^8.17.1",
@@@ -1044,18 +1044,18 @@
}
},
"node_modules/openvibe-sdk": {
-- "version": "0.4.0",
-- "resolved": "https://codeload.github.com/OpenVibers/OpenVibe.SDK/tar.gz/refs/tags/v0.4.0",
-- "integrity": "sha512-Hyz55YOMIs0xwCQ1NXsN0sUYhlbKXAX3uWY2fPCdEEL18FXUYVhK8wlG/5JMMypFHnjDiSd9VHzBNG12hWsmkQ==",
++ "version": "0.5.0",
++ "resolved": "https://codeload.github.com/OpenVibers/OpenVibe.SDK/tar.gz/refs/tags/v0.5.0",
++ "integrity": "sha512-QVJkR5iazQX0ZwIrDp2A88ZeYYBSXEmSzhpgURPUSnzezIM3jz0HBhVKowyhkvg2aBO61XNf77eb4zJGkMjZiw==",
"license": "MIT",
"engines": {
"node": ">=20"
}
},
"node_modules/openvibe-shared": {
-- "version": "1.3.0",
-- "resolved": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v1.3.0",
-- "integrity": "sha512-w8yl/5+9eend8I2O/DzAJnEAL2N3GTUY7c7pzK+MLJuLAGD8FmJJQ9gwbgyrq70Snjt3ebrg3TlpORhRAp2kgA==",
++ "version": "1.5.0",
++ "resolved": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v1.5.0",
++ "integrity": "sha512-cehnscuYMkJwuCYGcI6wPSswbUn0bhTyGAaD5feNCoO//2e9gyC7cgjkEcIOtM8DQF3yTuUNyXnOwckIeM4fUg==",
"license": "MIT",
"dependencies": {
"jsonwebtoken": "^9.0.0"
ddiff --git a/package.json b/package.json
iindex 0a75c47..764bf84 100644
---- a/package.json
++++ b/package.json
@@@ -19,10 +19,10 @@
"dotenv": "^16.4.7",
"express": "^4.21.2",
"express-rate-limit": "^7.5.0",
-- "openvibe-contracts": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.20.0",
++ "openvibe-contracts": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.32.0",
"openvibe-publishing": "https://codeload.github.com/OpenVibers/OpenVibe.Publishing/tar.gz/refs/tags/v0.2.1",
-- "openvibe-sdk": "https://codeload.github.com/OpenVibers/OpenVibe.SDK/tar.gz/refs/tags/v0.4.0",
-- "openvibe-shared": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v1.3.0"
++ "openvibe-sdk": "https://codeload.github.com/OpenVibers/OpenVibe.SDK/tar.gz/refs/tags/v0.5.0",
++ "openvibe-shared": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v1.5.0"
},
"engines": {
"node": ">=22.0.0"
ddiff --git a/server/app.js b/server/app.js
iindex 5c5a4cb..c76a99d 100644
---- a/server/app.js
++++ b/server/app.js
@@@ -78,7 +78,8 @@ function createApp({ config, svc, viewers, platform, sync, keys, db, log = conso
app.use('/internal', http.middleware(), consumer.router);
app.get('/api/health', (_req, res) => res.json({ status: 'ok', service: 'openvibe-reviews', version: VERSION }));
-- app.get('/release.json', release.handler);
++ // GET /release.json (ADR-016) and POST /release-metrics: open tabs' update reports into /metrics.
++ release.mount(app, { registry: metrics.registry });
const ready = createReadiness({
service: 'reviews', release: release.release,
checks: [
ddiff --git a/test/helpers.js b/test/helpers.js
iindex 3812fc9..3a28612 100644
---- a/test/helpers.js
++++ b/test/helpers.js
@@@ -31,10 +31,14 @@ function userToken({ subject: sub = READER, username = 'someone', role = 'user',
const editorToken = () => userToken({ subject: EDITOR, username: 'editor' });
const readerToken = () => userToken({ subject: READER, username: 'reader' });
--/** A principal token: svc:<client> by default; `sub` + `actorType` for an app:/mod: principal, `extra` for on_behalf_of, env… */
++/**
++ * A principal token: svc:<client> by default; `sub` + `actorType` for an app:/mod: principal, `extra` for on_behalf_of, env…
++ * An app token carries its developer project and env, as Network's do (identity.service-token-claims 1.2.0).
++ */
function serviceToken({ client = 'ai', cap = [], aud = 'openvibe.reviews', exp = 300, sub, actorType = 'service', extra = {} } = {}) {
const now = Math.floor(Date.now() / 1000);
-- return serviceAuth.signServiceToken({ iss: ISSUER, sub: sub || `svc:${client}`, actor_type: actorType, aud: [aud], cap, ns: [], iat: now, exp: now + exp, jti: `tok_${crypto.randomBytes(8).toString('hex')}`, ...extra }, privateKey);
++ const app = actorType === 'app' ? { project_id: 'prj_01J8ZQ4Y7N3M2K1H0G9F8E7D6C', env: 'production' } : {};
++ return serviceAuth.signServiceToken({ iss: ISSUER, sub: sub || `svc:${client}`, actor_type: actorType, aud: [aud], cap, ns: [], iat: now, exp: now + exp, jti: `tok_${crypto.randomBytes(8).toString('hex')}`, ...app, ...extra }, privateKey);
}
const quiet = { log() {}, warn() {}, error() {} };
ddiff --git a/test/resolution.test.js b/test/resolution.test.js
iindex 3cbe935..556c737 100644
---- a/test/resolution.test.js
++++ b/test/resolution.test.js
@@@ -88,6 +88,11 @@ t('API identity: bad tokens are refused, never downgraded; editor actions need a
assert.strictEqual(ready.status, 200);
assert.strictEqual(ready.json.ready, true);
assert.strictEqual((await req(h, 'GET', '/api/health')).json.service, 'openvibe-reviews');
++ // The release manifest (registry.release-manifest@1) names where open tabs report updates.
++ const rel = await req(h, 'GET', '/release.json');
++ assert.strictEqual(rel.json.service, 'reviews');
++ assert.deepStrictEqual(require('openvibe-contracts').validate('registry.release-manifest@1', rel.json).errors, []);
++ assert.strictEqual(rel.json.metrics_url, '/release-metrics');
const nf = await req(h, 'GET', '/api/v1/nope');
assert.strictEqual(nf.status, 404);
assert.match(nf.headers.get('content-type'), /problem\+json/);