Skip to content
-
Compatibility register: C-89 blog. Blog moved to PostgreSQL on 2026-09-28 at 13:52 UTC (release 8c8259f, import verified). Its SQLite file stays read-only as the rollback until 2026-10-05.OpenVibers · 28 Sept 2026
dcbef2c
-
Compatibility register: C-89 wiki. Wiki moved to PostgreSQL on 2026-09-28 at 13:29 UTC (release ec90476, import verified). Its SQLite file stays read-only as the rollback until 2026-10-05.OpenVibers · 28 Sept 2026
9a3aadc
-
Compatibility register: a PostgreSQL switches section (ADR-035, WS-X2), one row per service at its switch. The first is C-89 tips: Tips moved to PostgreSQL on 2026-09-28 at 12:46 UTC (release 9987de4, import verified), and its SQLite file stays read-only as the rollback until 2026-10-05. Then it is archived to B2 and deleted.OpenVibers · 28 Sept 2026
339da31
-
Fewer false operator pages. OpenVibeDeployDrift reads max_over_time(openvibe_deploy_drift_seconds[2h]): a Network restart drops the series for about a minute, which reset the rule's for: 1h and made the alert resolve and fire again every few hours (2026-09-28). browser-watch checks a failed release again after 30 minutes instead of keeping it red until the next release or day, so a transient failure clears on its own; a pass still holds for a day.OpenVibers · 28 Sept 2026
45f3d15
-
ovhost nodes report: this inventory's machines, reported to Network's node registry (roadmap WS-X1 step 3, ADR-034 §12). host.json gains nodeSource and nodes (network.node@1 without health: id, name, roles, region-level location, provider, beacon); the inventory refuses an address or ip field, duplicate ids and non-https beacons, because the registry is public. Health is measured on every run: each beacon's 2xx within 2 s is up, a slower 2xx degraded, anything else down. The report is validated against network.node-report-request@1 before a token is asked for, and is sent with Host's principal (scope network.node.report); no secret or token is printed. openvibe-nodes.timer runs it every 5 minutes; openvibe_nodes_report.prom feeds the new OpenVibeNodeReportStale and OpenVibeNodeDown alerts. openvibe-contracts pinned at v0.76.0. docs/nodes.md; test/nodes.test.js.OpenVibers · 28 Sept 2026
a8fdc46
-
The deploy controller, phase 1 (roadmap WS-X11, D72): ovhost reconcile. Main at its last green CI commit is the desired state, and a 5-minute timer makes each service whose inventory says deploy.policy auto run it without a person. Per pass and service: plan with a fetch; up to date or only documentation and tests changed (the baseline's rule) means nothing; otherwise GitHub's check runs for that exact commit must all be completed and passed (none, running, red or unreachable wait or block, never deploy on hope); then the same lib.deploy as ovhost deploy --wait-idle (freezes, protected sessions, readiness, automatic rollback) and the release notification. gated and manual services are only reported. Each pass goes to /var/lib/openvibe-host/reconcile.json and the textfile collector; OpenVibeReconcileFailed (page) and OpenVibeReconcileStalled (ticket) read it. The inventory validates deploy.policy (default manual). openvibe-reconcile.service and .timer; an optional read-only token in /etc/openvibe/reconcile.env. test/reconcile.test.js on the fake host: docs-only deploys nothing; no CI, pending and red never deploy; green deploys, and the next pass finds it current; manual waits; a dry run writes nothing; GitHub unreachable is unknown. npm test 40/40.OpenVibers · 28 Sept 2026
1bfffab
-
Data role alerts: a group openvibe-data with DataPostgresDown, DataPgBouncerDown and DataValkeyDown (page after 2 minutes), DataWalArchiveFailing (page: point-in-time recovery at risk), DataPostgresConnectionsHigh (over 80% of max_connections), DataBackupStale (no good pgBackRest backup for 26 hours) and DataValkeyMemoryHigh (over 90% of maxmemory). A successful backup writes openvibe_pgbackrest_last_success_timestamp_seconds to the textfile collector through a helper run by ExecStartPost, which systemd runs only when the backup itself succeeded.OpenVibers · 28 Sept 2026
61e8a95
-
Data role: a running full backup is seen as running. A oneshot unit reads 'activating' while it runs, which is-active does not count, so the step now reads ActiveState and treats active or activating as a backup in progress (starting it again was harmless, since systemd joins the running job, but the log said otherwise).OpenVibers · 28 Sept 2026
63c38aa
-
Data role: the pgBackRest step reads the stanza's status instead of guessing. A second run while the first full backup was still going took 'no valid backups' for 'no stanza' and tried stanza-create against the backup's lock. Now it creates the stanza only when pgBackRest says it is missing (status 1 or 3), starts a full backup only when none is valid and none is running (status 2), and warns on any other status.OpenVibers · 28 Sept 2026
16cf27b
-
Data role: service roles can no longer connect to the maintenance database. PostgreSQL lets PUBLIC connect to 'postgres' by default, so the end-to-end check on the host showed a service's runtime role reaching it (catalogs only). Connect is revoked from PUBLIC there and granted to the PgBouncer auth and monitoring roles alone; each service database already refused everyone but its own roles. The check also confirmed SCRAM through PgBouncer, DML-only runtime roles with a 15 s statement timeout, and Valkey users confined to their prefix without dangerous commands.OpenVibers · 28 Sept 2026
a52e41e
-
Data role: Valkey takes no end-of-line comments (its first start on the host refused 'maxmemory-policy volatile-lru # …'), so the comment has its own line, and the test checks every Valkey line. The role also sets vm.overcommit_memory = 1 (sysctl.d), as Valkey's startup warning recommends for background saves, and resets a failed Valkey unit before restarting it, since systemd refuses a unit that hit its start limit.OpenVibers · 28 Sept 2026
6e2807f
-
The data role in code (ADR-035, roadmap WS-X2): roles/data/provision.sh installs and configures PostgreSQL 18, PgBouncer, pgBackRest, Valkey and their Prometheus exporters, so any machine can take the role the way this host does. Everything listens on loopback until the private network exists. PostgreSQL is tuned for the shared host (shared_buffers 1 GB, effective_cache_size 4 GB, work_mem 16 MB, 120 connections behind the pooler), uses SCRAM, pg_stat_statements, and WAL archiving through pgBackRest. PgBouncer runs transaction pooling with SCRAM through auth_query (pgbouncer.get_auth, SECURITY DEFINER), so there is no password list to maintain. Valkey uses volatile-lru (only TTL keys are evicted), AOF every second, and ACLs with default off, admin and monitor users, and service users kept in services.acl. pgBackRest keeps an encrypted repository beside ovhost's pruned backup prefix in the same B2 bucket, with a weekly full and daily differential by systemd timer and 14 days of point-in-time recovery. The exporters are bound to 127.0.0.1, because the host firewall is off. add-service.sh gives a service its database, owner role, pooled runtime role (DML only, statement_timeout 15 s, lock_timeout 5 s) and a Valkey user confined to ov:<svc>:*, and writes DATABASE_URL, DATABASE_DIRECT_URL, VALKEY_URL and VALKEY_PREFIX into its env file. Passwords are generated once into /etc/openvibe/data.env (root, 0600) and reach PostgreSQL as SCRAM secrets and Valkey as SHA-256 hashes; nothing prints a secret. .gitignore's data/ rule gains a roles/data/ exception. The Prometheus config generator takes the inventory's exporters. test/data-role.test.js (scripts parse, loopback, SCRAM, transaction pooling, volatile-lru, archiving, no printed secret) and the Prometheus config test. npm test 39/39.OpenVibers · 28 Sept 2026
3479300
-
The browser check names the sites it did not check (roadmap WS-Q task 7). A registry site whose root is not HTML was dropped with one stderr line, so the report's "23/23 sites pass" said nothing about it. Each such site is now kept in a not-checked list: the Markdown report adds "Not checked (n): <site> (<why>)" and "x/y sites pass (n more not checked)", and the console summary prints "skip <origin>: <why> (not checked, not counted as passing)". The exit code and the JSON report are unchanged. test/browser-check.test.js checks both lines. npm test 38/38.OpenVibers · 28 Sept 2026
02c68f6
-
npm test no longer counts a skipped test as passed (roadmap WS-Q task 7; openvibe-shared/test-runner, Shared v1.25.0). test/run.js counted every file that exited 0 as passed, even one that had skipped part of its work. It is now the shared runner (same files, one at a time as before, 60 s timeout per file): a test prints "<label>: skipped (<why>)" for what it could not run, the same line scripts/release-acceptance.js reads, and that file is listed with ○ and its reasons and not counted as passed; --strict makes a skip fail the run. announce.test.js skipped its payload schema check without a word when the installed openvibe-contracts predates host.release.published@1; it now prints "announce payload schema: skipped (…)" then (the pinned 0.66.0 has the schema, so the check runs here). openvibe-shared is pinned at v1.25.0 (from v1.22.0; 1.23 and 1.24 add the web runtime, release-watch fixes and the readiness skip, and /api/ready answers as before because its db check really runs; README and STATUS.json follow). npm test (Node 22) 38/38.OpenVibers · 28 Sept 2026
ee84fbc
-
docs/deploy-strategies.md: the strategies have been in production since the 2026-09-27 cutover, and every service deploys and rolls back with ovhost. The state said 'Not on the host yet' and the checklist 'Nothing here has been run'; the checklist is kept as the record and as the procedure for a new host.OpenVibers · 28 Sept 2026
6d2aaaa
-
README and STATUS.json are current (roadmap WS-U task 3): the README gains Capabilities (the three host.* capabilities and the grants Host uses: events.event.publish, network.operator.alert, network.status.incident), Deploy (the ovhost CLI checkout and its timers; the Stage B service with sudo ovhost deploy host, unit, port, env file, state, rollback) and Security (SECURITY.md, the threat review, secrets, the operator plane, tenants, egress) sections. Stale facts corrected: every service deploys with ovhost since the 2026-09-27 cutover (not only 20), ovhost is no longer read-only, Stage B runs on loopback, restore drills ran on the host, incident controls and release notifications exist, and the install steps were done; Depends on names the current pins (contracts v0.66.0, sdk v0.12.0, shared v1.22.0). STATUS.json gains contracts and features, updates Stage A and the packages, and is updated 2026-09-28.OpenVibers · 28 Sept 2026
5d35e9d
-
Per-actor limits on the dashboard's and the API's writes (roadmap WS-R task 4; openvibe-sdk 0.11.0 -> 0.12.0 openvibe-sdk/limits). server/http/actor-limits.js runs after the viewer is resolved and counts a signed-in person by subject, or a service by its principal (a service here manages its own projects): HOST_LIMITS_MINUTE / _HOUR (120 and 3000), and tighter on top for deploy uploads (10 a minute, 100 an hour: stored and unpacked), domain verification (10/100: DNS lookups) and new projects (5/30). Past a limit: 429 rate_limited with Retry-After before the route runs, logged and counted in host_rate_limited_total. Anonymous callers and reads keep the per-address limits. HOST_ACTOR_LIMITS=off is a rollback lever; the Stage B suites, which deploy dozens of times a minute as one person, boot with it off. test/actor-limits.test.js covers the limits themselves. npm test 38/38.OpenVibers · 28 Sept 2026
2b63389
-
docs/release-acceptance.md: the release-lifecycle acceptance suite (D46, roadmap WS-P task 16) — how to run it, how a gate is judged, which gates measure each D46 quantity, the scenario table (gate, evidence, budget, where each number comes from), what it found, what is open, and two recorded runs of 2026-09-27.OpenVibers · 27 Sept 2026
9e603ad
-
Release-lifecycle acceptance suite (D46, roadmap WS-P task 16): lib/acceptance.js holds the 14 D46 scenarios as 63 gates and scripts/release-acceptance.js runs them.OpenVibers · 27 Sept 2026
cfd3860
-
pnpm-build: install with --config.confirmModulesPurge=false. When pnpm decides node_modules must be rebuilt (made under other settings, as production's Games checkout was), it asks first; under ovhost nothing answers, so it installed nothing and exited 0. Games 8200c2c's new dependency (openvibe-shared) never appeared, the deploy failed its dependency check and restored the checkout (nothing restarted). Reproduced in a copy of the production checkout; with the flag the install rebuilds node_modules and links the dependency, and the next install does not ask again.OpenVibers · 27 Sept 2026
d8e8f7d
-
multi-app: a oneshot unit the unitsMatch glob catches is a job, not a service (found in the WS-N task 11 cutover, 2026-09-27). openvibe-tools*.service also matches openvibe-toolsjob.service, the job proof its timer runs (Type=oneshot, inactive between runs): the first ovhost deploy of Tools restarted it, then waited for it to stay active, so the deploy read not ready and so did its rollback (Tools itself was healthy throughout). Units found by the glob are now asked their Type (systemd show gains Type); oneshot ones are named in the plan ('jobs ... not restarted, not waited on') and left alone. test/strategy-in-place.test.js adds such a unit and checks it is not restarted.OpenVibers · 27 Sept 2026
08acfbd
-
ovhost absorbs the per-repository deploy scripts (roadmap WS-N task 11). A service entry's `strategy` picks the engine and the defaults the script it replaces encoded: git-checkout (the default, what ovhost did before), multi-app (Tools: apps/_* skipped, untracked lockfiles the release tracks removed before the merge, preflight checks in each app, every openvibe-tools* unit file restarted via unitsMatch, ready.release and ready.allUnits), static-build (Sites: tracked dist/ restored from git before the merge, npm ci, node build.js, repo vhosts behind nginx -t, one release notification per dist/*/release.json), pnpm-build (Games: one pnpm install --frozen-lockfile for the workspace, pnpm build, generated dist-types/, rebuild on restore) and release-layout (Live, OpenRe; lib/release-layout.js: a release prepared in releases/<id> while current serves, node_modules hard-linked unless dependencies changed, node --check on changed files, an atomic current switch, static-only switches without a restart, the release's unit files, readiness with /release.json naming the new sha, switch back on failure, pruning that keeps any release a worker instance runs from, --prepare-only, ovhost rollback to the release the log says current replaced). The socket rule: pid 1 must hold the listener; only when the socket unit file changed or systemd does not hold the port is the service stopped, the socket restarted and the service started (systemd.rebindSocket, the only socket restart). --wait-idle now also holds a report-policy service. ovhost capabilities <svc> and --version are what the repositories' deploy.sh wrappers probe (deploy-api=1) before handing over, falling back to their deploy-legacy.sh otherwise. docs/deploy-strategies.md: the engines, every inventory field, the rule-by-rule mapping, what was not ported and why, the production cutover checklist and the proposed /etc/openvibe/host.json diff (not applied); host.example.json carries it. Tests: test/strategy-release-layout.test.js, test/strategy-in-place.test.js (fake host: worktrees, symlinked paths, mv -Tf, cp -al, pnpm). Version 0.3.0.OpenVibers · 27 Sept 2026
e4c7a58
-
SSRF regression test for tenant-named hosts (roadmap WS-R task 5). A custom domain is the one host a tenant names, and it is proven by a DNS TXT record through the configured resolver, never by a request to it: test/security-ssrf.test.js adds domains that name or resolve to internal addresses in every spelling (loopback, decimal, hex, IPv6, mapped, metadata, private, .localhost/.local/.internal names), verifies them, serves requests with those Host headers and absolute-form targets, and records every outbound request and connection of the process: only the stand-in Network and the dashboard itself are reached (a real domain is added and verified as the control). And a ratchet over the files in server/ that make outbound requests. The other classes are already pinned for Host: tenant isolation and existence oracles (host-isolation.test.js, the private and IDOR classes), deployment secrets out of public state (host-secrets-dashboard.test.js).OpenVibers · 26 Sept 2026
94e1616
-
docs/operator-alerts.md: the browser check's settle window, retry delay and failure details.OpenVibers · 26 Sept 2026
8a981f5
-
browser-watch keeps what failed: per route, the axe rule ids with up to 3 targets, the first console errors, overflow offenders and bad statuses (at most 20, clipped), in the site's state file for the operator (never in metrics); the CLI line points at it. A Live axe failure on 2026-09-26 left only a count behind.OpenVibers · 26 Sept 2026
18d8822
-
browser-watch: a release is judged once its process has run 3 minutes (/release.json booted_at), and the confirming second run of a failure waits a minute first. On 2026-09-26 a check minutes after a Live restart failed on 4 console errors from reconnecting sockets and paged; a run a few minutes later passed. --force still checks at once.OpenVibers · 26 Sept 2026
87bca98
-
Incident, maintenance and DNS controls (roadmap WS-N task 12; Contracts v0.66.0, pinned from 0.62.0). ovhost incident open|update|list and maintenance schedule|start|complete post to openvibe.network/status with Host's token (network.status.incident). ovhost freeze|unfreeze hold deploys of a service or all (exit 6; --force goes through loudly; rollbacks never frozen), and a window scheduled with --freeze is lifted by complete. ovhost dns list|ensure|delete drives Cloudflare from the operator's workstation: token from --token-file or ~/.config/cloudflare-token, never printed; dry run unless --apply; web records name their proxy mode; DNS-only names and _ service records never proxied; duplicates refused; no inventory needed. docs/incidents-and-dns.md; test/incidents.test.js, test/dns.test.jsOpenVibers · 26 Sept 2026
59c31fe
-
The notification bell hears new notifications as they happen (notificationsRealtime; Shared 1.22.0, roadmap WS-E task 3): Network's network.notification.created over OpenVibe.Events' realtime stream, with polling as the fallback. Only a signed-in bell with a Network token opens a stream.OpenVibers · 26 Sept 2026
764e746
-
browser-watch: all 23 public sites, and one alert per site across releases. The release moves from openvibe_browser_check_ok's labels to openvibe_browser_check_release_info{service,release}, which the alert summary reads. Before this, each new release of a failing site resolved one alert and opened another. The first run over every site found two real regressions (Search's palette ignoring the network theme; Billing's /policy table scroller), both fixed and deployed.OpenVibers · 26 Sept 2026
3d5d8e7
-
The release UX check (roadmap WS-H task 11): ovhost browser-watch --sites live (openvibe-browsercheck.timer, every 5 minutes) checks each watched site in Chrome after every release (read from /release.json) and once a day. Chrome runs as the unprivileged ovcheck account through runuser, and a failure is confirmed by a second run. The outcome goes to openvibe_browsercheck.prom: OpenVibeBrowserCheckFailed (page) goes through ovhost alerts relay to the operator, and OpenVibeBrowserCheckMissed notices when no check finished for 26 hours. A run that broke records nothing and is retried. The browser-check hook gains asUser/home and returns stdout. docs/operator-alerts.md; test/browser-watch.test.jsOpenVibers · 26 Sept 2026
9d4c552
More commits