The update system
Helpers as installed here: openvibe-shared v1.13.0 (frame: shipped(), updatesBody(), shippedScript()) and openvibe-sdk v0.11.0 (frame: mountFrame, frameTags, frameConfig, scriptUrls, DEFAULT_BASE).
Every OpenVibe site shows what shipped on it. It has three pieces: a "🚀 shipped X ago" line in the footer, a "Recently shipped" list on the home page, and a /updates page with the whole log. They all read one feed, so a commit that reaches production shows up everywhere without anyone writing release notes twice.
Where entries come from
OpenVibe.Blog watches every running service's release: the release in its /release.json, as OpenVibe.Network's registry reports it. When a release changes, GitHub's compare of the old and new commit gives the commits that shipped. Each one becomes an entry, with the commit message as its text, and batches of them are published as "Patch notes" posts. A service appears once it serves /release.json and its registry entry names its repository.
The feed
GET https://openvibe.network/api/v1/changelog?service=<id>&limit=<1-100>&before=<cursor>
→ { service, entries: [{ service, sha, short, subject, author, committed_at, deployed_at, major, url, post_id }],
latest_post: { id, title, url, published_at, entries } | null, posts, next }
It is public, CORS * and cached for 60 s (stale while the blog is down). Leave service out for the whole network.
Live sample: the last 3 entries for this site
28dbf08Moderation audit (ADR-022, WS-D task 1): codes.moderation.action from the outbox in the same transaction: release.revoked when Codes staff revoke a release their project role would not let them manage (also a staff project deletion)… ()fbe0ebeDocs: the update system (WS-A task 4) at /docs/updates: the network changelog feed and its shape (with a live sample), the data-ov-shipped markup, openvibe-shared/frame shipped()/updatesBody()/shippedScript() and openvibe-sdk/frame… ()eba81c5API explorer (WS-C task 6): /docs/api lists every service's OpenAPI 3.1 document from openvibe-contracts 0.51.0; /docs/api/:service shows each route with its method, capabilities, visibility, parameters, request and response schemas… ()
On a server-rendered site
const frame = require('openvibe-shared/frame');
frame.shipped({ service: 'myservice', title: 'Recently shipped on MySite' }) // home: pill + recent list
frame.updatesBody({ service: 'myservice', siteName: 'MySite' }) // the body of your /updates page
frame.shippedScript() // the <script> that fills them
The footer from openvibe-shared/footer already carries the "shipped X ago" line and an Updates link.
The markup, if you render it yourself
<a data-ov-shipped="latest" data-service="myservice" href="/updates" hidden></a>
<div data-ov-shipped="list" data-service="myservice" data-limit="5" data-more="/updates" data-title="Recently shipped" hidden></div>
<div data-ov-shipped="log" data-service="myservice" data-limit="50"></div>
shipped.js (served by every site from its pinned openvibe-shared) mounts every [data-ov-shipped] element: latest is the pill, list the recent changes, and log the full log with days, "Load more" and the Patch notes posts. Elements stay hidden until there is something to show.
In a browser app outside the network
import { mountFrame } from 'openvibe-sdk/frame';
await mountFrame({ service: 'myapp' }); // navbar and footer, with the shipped line
await mountFrame({ service: 'myapp', shipped: false }); // without it
Live's /updates, this site's and the whole network's are the same component.