openvibers/openvibe.news Commits
README and STATUS.json are current (roadmap WS-U task 3): Capabilities is now a level-2 section and lists the grants News uses at Sources, Events, Network, Community and AI; Deploy says production deploys with sudo ovhost deploy news (unit, port, env file, rollback) and keeps the first-install steps; Security points to SECURITY.md; Depends on names the current pins (publishing v0.4.0, contracts v0.49.0, shared v1.22.0, sdk v0.12.0). STATUS.json gains contracts, features, the current package list and updated 2026-09-28.
Changes
@@@ -198,7 +198,7 @@ five minutes and are never built for a viewer.| `news.story.retracted` | public for a listable story; the retraction note || `news.index_document.upserted` / `.deleted` | `search.index-document@1` documents (provenance: the Sources items and the AI run) and tombstones, with a monotonic index revision |--### Capabilities (registered in openvibe-contracts v0.21.0)++## Capabilities (registered in openvibe-contracts v0.21.0)Service tokens use audience `openvibe.news`, one capability per route; the editor the service actsfor goes in `X-OV-Subject` and must be an editor:@@@ -214,12 +214,19 @@ Grants for these ids are decided with the contracts library's matching ruleopenvibe-contracts v0.21.0; `docs/capabilities-proposal/` and `docs/service-manifest-proposal.json`are the proposals they were released from.++Called elsewhere, as the service principal `news`: `sources.item.read` and optionally++`sources.source.read` (Sources), `events.event.publish` and `events.subscription.manage` (Events),++`identity.subject.resolve` (Network), `community.comment.write` and `community.comment.moderate`++(Community) and, only with `OV_AI_INTERNAL_URL`, `ai.run.create` (AI). The list with audiences is++under [Grants the Network must hold](#grants-the-network-must-hold).++## Depends on--- **Packages** (pinned by release tarball): `openvibe-publishing` v0.2.1 (revisions, citations,-- authorship, seo, index-hooks, ssr, taxonomy slugify), `openvibe-contracts` v0.33.0,-- `openvibe-shared` v1.5.1 (chrome, app icon, footer, legal, release, metrics, ready, seo),-- `openvibe-sdk` v0.5.0 (events outbox and inbox, webhook signatures v2, service tokens).++- **Packages** (pinned by release tarball): `openvibe-publishing` v0.4.0 (revisions, citations,++ authorship, seo, index-hooks, ssr, taxonomy slugify), `openvibe-contracts` v0.49.0,++ `openvibe-shared` v1.22.0 (chrome, app icon, footer, legal, release, metrics, ready, seo),++ `openvibe-sdk` v0.12.0 (events outbox and inbox, webhook signatures v2, service tokens, per-actor++ limits).- **OpenVibe.Sources** (4720): `sources.item.read`; optionally `sources.source.read` (outletnames and source health; without it the outlet is the URL's host).- **OpenVibe.Events** (4300): `events.event.publish`; `events.subscription.manage` to create the@@@ -298,6 +305,8 @@ call the service live.## Security and threat review++Reporting a vulnerability: [SECURITY.md](SECURITY.md).++- **Identity:** only verified Network JWTs (offline RS256) and service tokens for audience`openvibe.news`. A bad service token is refused, never downgraded. Identity never comes from abody or query; `X-OV-*` headers are ignored for browsers. AI deliveries can only write drafts.@@@ -363,6 +372,15 @@ fnm exec --using=22.22.1 npm run dev # http://localhost:4820 (set OV_OAUTH## Deploy (for the lead)++Production deploys with `sudo ovhost deploy news` on the host (strategy `git-checkout`: fetch,++fast-forward `/opt/openvibe.news`, install on a lockfile change, restart, wait for `/api/ready`).++The unit is `openvibe-news.service` on `127.0.0.1:4820`, the env file `/etc/openvibe/news.env`.++Rollback: ovhost puts the previous sha back by itself when `/api/ready` does not answer 2xx after the++restart; afterwards `sudo ovhost rollback news --to <sha>`. Nothing blocks a rollback: the schema++code only adds tables and columns.++++First install (done once; kept for a rebuild):++1. **Code and config:** put the code at `/opt/openvibe.news` and run `npm ci --omit=dev` on Node 22.Create `/etc/openvibe/news.env` (0600) from `.env.example` with `OV_OAUTH_CLIENT_SECRET`,`NEWS_EDITORS`, `NEWS_FORM_SECRET`, `NEWS_EVENTS_SECRET` (`openssl rand -hex 32`),@@@ -7,15 +7,43 @@"runtime": "node 22, express 4, better-sqlite3 11","port": 4820,"domain": "openvibe.news",-- "packages": ["openvibe-publishing v0.2.1", "openvibe-contracts v0.33.0", "openvibe-shared v1.5.1", "openvibe-sdk v0.5.0"],-- "capabilities": ["news.story.create", "news.story.read", "news.story.revise", "news.story.publish", "news.story.retract", "news.cluster.read", "news.cluster.manage", "news.source.attach", "news.timeline.update", "news.perspective.update", "news.topic.manage"],++ "contracts": "openvibe-contracts v0.49.0",++ "packages": ["openvibe-publishing v0.4.0", "openvibe-contracts v0.49.0", "openvibe-shared v1.22.0", "openvibe-sdk v0.12.0"],++ "capabilities": [++ "news.story.create",++ "news.story.read",++ "news.story.revise",++ "news.story.publish",++ "news.story.retract",++ "news.cluster.read",++ "news.cluster.manage",++ "news.source.attach",++ "news.timeline.update",++ "news.perspective.update",++ "news.topic.manage"++ ],"capabilitiesRegistered": true,"serviceManifestRegistered": true,"inputs": "OpenVibe.Sources items (category news) via the Events subscriptions sources.item.* and sources.fetch.failed (created in production 2026-09-23) and a cursor pull; every Sources seed is disabled, so no item has arrived yet (181 empty ingest runs, 0 source items)","ai": "optional seam (news.summarize_story, news.compare_perspectives) tested against a mock; not configured in production (OV_AI_INTERNAL_URL unset); OpenVibe.AI output only ever lands as a draft that needs a person's review","seed": "topics only (12 in production); no stories, source items or clusters","deployed": true,-- "deployment": "openvibe-ovh, unit openvibe-news, 127.0.0.1:4820 loopback only (release 1802e7d); /api/ready 200; production database holds 12 topics and 0 stories. Deployed internally, not launched: openvibe.news still serves the OpenVibe.Sites placeholder until a person verifies a news source's terms, enables it in Sources, and an editor publishes a reviewed story",++ "deployment": "Deployed with `sudo ovhost deploy news`: unit openvibe-news, 127.0.0.1:4820 loopback only; on 2026-09-23 /api/ready answered 200 and the production database held 12 topics and 0 stories. Deployed internally, not launched: openvibe.news still serves the OpenVibe.Sites placeholder until a person verifies a news source's terms, enables it in Sources, and an editor publishes a reviewed story","placeholderInSites": true,-- "updated": "2026-09-23"++ "updated": "2026-09-28",++ "features": [++ "Sources ingestion by Events subscription and cursor pull, with dedupe",++ "failed ingestion recorded, never fabricated",++ "deterministic, explained clusters with audited merge and split",++ "stories whose paragraphs cite Sources items; no publish without sources",++ "revisions, corrections, timelines, perspectives and final retractions",++ "independent-source index gate",++ "licensing limits on stored and shown text",++ "Community comment threads by reference",++ "optional OpenVibe.AI drafts that need a person's review",++ "server-rendered editorial and public pages useful without JavaScript",++ "/api/v1 by capability",++ "SDK outbox events and Search index documents",++ "per-actor limits (openvibe-sdk/limits)"++ ]}
@@ -198,7 +198,7 @@ five minutes and are never built for a viewer.
@@ -198,7 +198,7 @@ five minutes and are never built for a viewer.
| `news.story.retracted` | public for a listable story; the retraction note |
| `news.story.retracted` | public for a listable story; the retraction note |
| `news.index_document.upserted` / `.deleted` | `search.index-document@1` documents (provenance: the Sources items and the AI run) and tombstones, with a monotonic index revision |
| `news.index_document.upserted` / `.deleted` | `search.index-document@1` documents (provenance: the Sources items and the AI run) and tombstones, with a monotonic index revision |
-### Capabilities (registered in openvibe-contracts v0.21.0)
+## Capabilities (registered in openvibe-contracts v0.21.0)
Service tokens use audience `openvibe.news`, one capability per route; the editor the service acts
Service tokens use audience `openvibe.news`, one capability per route; the editor the service acts
for goes in `X-OV-Subject` and must be an editor:
for goes in `X-OV-Subject` and must be an editor:
@@ -214,12 +214,19 @@ Grants for these ids are decided with the contracts library's matching rule
@@ -214,12 +214,19 @@ Grants for these ids are decided with the contracts library's matching rule
openvibe-contracts v0.21.0; `docs/capabilities-proposal/` and `docs/service-manifest-proposal.json`
openvibe-contracts v0.21.0; `docs/capabilities-proposal/` and `docs/service-manifest-proposal.json`
are the proposals they were released from.
are the proposals they were released from.
+Called elsewhere, as the service principal `news`: `sources.item.read` and optionally
+`sources.source.read` (Sources), `events.event.publish` and `events.subscription.manage` (Events),
+`identity.subject.resolve` (Network), `community.comment.write` and `community.comment.moderate`
+(Community) and, only with `OV_AI_INTERNAL_URL`, `ai.run.create` (AI). The list with audiences is
+under [Grants the Network must hold](#grants-the-network-must-hold).
+
## Depends on
## Depends on
-- **Packages** (pinned by release tarball): `openvibe-publishing` v0.2.1 (revisions, citations,
- authorship, seo, index-hooks, ssr, taxonomy slugify), `openvibe-contracts` v0.33.0,
- `openvibe-shared` v1.5.1 (chrome, app icon, footer, legal, release, metrics, ready, seo),
- `openvibe-sdk` v0.5.0 (events outbox and inbox, webhook signatures v2, service tokens).
+- **Packages** (pinned by release tarball): `openvibe-publishing` v0.4.0 (revisions, citations,
+ authorship, seo, index-hooks, ssr, taxonomy slugify), `openvibe-contracts` v0.49.0,
+ `openvibe-shared` v1.22.0 (chrome, app icon, footer, legal, release, metrics, ready, seo),
+ `openvibe-sdk` v0.12.0 (events outbox and inbox, webhook signatures v2, service tokens, per-actor
+ limits).
- **OpenVibe.Sources** (4720): `sources.item.read`; optionally `sources.source.read` (outlet
- **OpenVibe.Sources** (4720): `sources.item.read`; optionally `sources.source.read` (outlet
names and source health; without it the outlet is the URL's host).
names and source health; without it the outlet is the URL's host).
- **OpenVibe.Events** (4300): `events.event.publish`; `events.subscription.manage` to create the
- **OpenVibe.Events** (4300): `events.event.publish`; `events.subscription.manage` to create the
@@ -298,6 +305,8 @@ call the service live.
@@ -298,6 +305,8 @@ call the service live.
## Security and threat review
## Security and threat review
+Reporting a vulnerability: [SECURITY.md](SECURITY.md).
+
- **Identity:** only verified Network JWTs (offline RS256) and service tokens for audience
- **Identity:** only verified Network JWTs (offline RS256) and service tokens for audience
`openvibe.news`. A bad service token is refused, never downgraded. Identity never comes from a
`openvibe.news`. A bad service token is refused, never downgraded. Identity never comes from a
body or query; `X-OV-*` headers are ignored for browsers. AI deliveries can only write drafts.
body or query; `X-OV-*` headers are ignored for browsers. AI deliveries can only write drafts.
@@ -363,6 +372,15 @@ fnm exec --using=22.22.1 npm run dev # http://localhost:4820 (set OV_OAUTH
@@ -363,6 +372,15 @@ fnm exec --using=22.22.1 npm run dev # http://localhost:4820 (set OV_OAUTH
## Deploy (for the lead)
## Deploy (for the lead)
+Production deploys with `sudo ovhost deploy news` on the host (strategy `git-checkout`: fetch,
+fast-forward `/opt/openvibe.news`, install on a lockfile change, restart, wait for `/api/ready`).
+The unit is `openvibe-news.service` on `127.0.0.1:4820`, the env file `/etc/openvibe/news.env`.
+Rollback: ovhost puts the previous sha back by itself when `/api/ready` does not answer 2xx after the
+restart; afterwards `sudo ovhost rollback news --to <sha>`. Nothing blocks a rollback: the schema
+code only adds tables and columns.
+
+First install (done once; kept for a rebuild):
+
1. **Code and config:** put the code at `/opt/openvibe.news` and run `npm ci --omit=dev` on Node 22.
1. **Code and config:** put the code at `/opt/openvibe.news` and run `npm ci --omit=dev` on Node 22.
Create `/etc/openvibe/news.env` (0600) from `.env.example` with `OV_OAUTH_CLIENT_SECRET`,
Create `/etc/openvibe/news.env` (0600) from `.env.example` with `OV_OAUTH_CLIENT_SECRET`,
`NEWS_EDITORS`, `NEWS_FORM_SECRET`, `NEWS_EVENTS_SECRET` (`openssl rand -hex 32`),
`NEWS_EDITORS`, `NEWS_FORM_SECRET`, `NEWS_EVENTS_SECRET` (`openssl rand -hex 32`),
@@ -7,15 +7,43 @@
@@ -7,15 +7,43 @@
"runtime": "node 22, express 4, better-sqlite3 11",
"runtime": "node 22, express 4, better-sqlite3 11",
"port": 4820,
"port": 4820,
"domain": "openvibe.news",
"domain": "openvibe.news",
- "packages": ["openvibe-publishing v0.2.1", "openvibe-contracts v0.33.0", "openvibe-shared v1.5.1", "openvibe-sdk v0.5.0"],
- "capabilities": ["news.story.create", "news.story.read", "news.story.revise", "news.story.publish", "news.story.retract", "news.cluster.read", "news.cluster.manage", "news.source.attach", "news.timeline.update", "news.perspective.update", "news.topic.manage"],
+ "contracts": "openvibe-contracts v0.49.0",
+ "packages": ["openvibe-publishing v0.4.0", "openvibe-contracts v0.49.0", "openvibe-shared v1.22.0", "openvibe-sdk v0.12.0"],
+ "capabilities": [
+ "news.story.create",
+ "news.story.read",
+ "news.story.revise",
+ "news.story.publish",
+ "news.story.retract",
+ "news.cluster.read",
+ "news.cluster.manage",
+ "news.source.attach",
+ "news.timeline.update",
+ "news.perspective.update",
+ "news.topic.manage"
+ ],
"capabilitiesRegistered": true,
"capabilitiesRegistered": true,
"serviceManifestRegistered": true,
"serviceManifestRegistered": true,
"inputs": "OpenVibe.Sources items (category news) via the Events subscriptions sources.item.* and sources.fetch.failed (created in production 2026-09-23) and a cursor pull; every Sources seed is disabled, so no item has arrived yet (181 empty ingest runs, 0 source items)",
"inputs": "OpenVibe.Sources items (category news) via the Events subscriptions sources.item.* and sources.fetch.failed (created in production 2026-09-23) and a cursor pull; every Sources seed is disabled, so no item has arrived yet (181 empty ingest runs, 0 source items)",
"ai": "optional seam (news.summarize_story, news.compare_perspectives) tested against a mock; not configured in production (OV_AI_INTERNAL_URL unset); OpenVibe.AI output only ever lands as a draft that needs a person's review",
"ai": "optional seam (news.summarize_story, news.compare_perspectives) tested against a mock; not configured in production (OV_AI_INTERNAL_URL unset); OpenVibe.AI output only ever lands as a draft that needs a person's review",
"seed": "topics only (12 in production); no stories, source items or clusters",
"seed": "topics only (12 in production); no stories, source items or clusters",
"deployed": true,
"deployed": true,
- "deployment": "openvibe-ovh, unit openvibe-news, 127.0.0.1:4820 loopback only (release 1802e7d); /api/ready 200; production database holds 12 topics and 0 stories. Deployed internally, not launched: openvibe.news still serves the OpenVibe.Sites placeholder until a person verifies a news source's terms, enables it in Sources, and an editor publishes a reviewed story",
+ "deployment": "Deployed with `sudo ovhost deploy news`: unit openvibe-news, 127.0.0.1:4820 loopback only; on 2026-09-23 /api/ready answered 200 and the production database held 12 topics and 0 stories. Deployed internally, not launched: openvibe.news still serves the OpenVibe.Sites placeholder until a person verifies a news source's terms, enables it in Sources, and an editor publishes a reviewed story",
"placeholderInSites": true,
"placeholderInSites": true,
- "updated": "2026-09-23"
+ "updated": "2026-09-28",
+ "features": [
+ "Sources ingestion by Events subscription and cursor pull, with dedupe",
+ "failed ingestion recorded, never fabricated",
+ "deterministic, explained clusters with audited merge and split",
+ "stories whose paragraphs cite Sources items; no publish without sources",
+ "revisions, corrections, timelines, perspectives and final retractions",
+ "independent-source index gate",
+ "licensing limits on stored and shown text",
+ "Community comment threads by reference",
+ "optional OpenVibe.AI drafts that need a person's review",
+ "server-rendered editorial and public pages useful without JavaScript",
+ "/api/v1 by capability",
+ "SDK outbox events and Search index documents",
+ "per-actor limits (openvibe-sdk/limits)"
+ ]
}
}