Commits
-
Fix content pack typings and the digest-less hello test assertionOpenVibers · 4 Oct 2026
d329c8a -
Gate joins on content digests and load Scraplandia's default mapOpenVibers · 4 Oct 2026
6a1f3a3 -
Merge games-content@2 pack definitions into content at server boot (#3)OpenVibers · 4 Oct 2026
545f6c1 -
Merge pull request #1 from OpenVibers/agent/games-follow-up-of-https-github-com-open-081839-mus4ed3wOpenVibers · 3 Oct 2026
64dae97 -
T8 READY NOW: docs and one test comment only, no behaviour change (#2)OpenVibers · 3 Oct 2026
d3d45b2 -
Make test runner fail when vitest exits nonzero with all files passedOpenVibers · 3 Oct 2026
0c57e20 -
Untrack committed nodemodules symlinks and ignore them in gitOpenVibers · 3 Oct 2026
67bcdb7 -
Run the slice test on a free port with a longer server start timeoutOpenVibers · 3 Oct 2026
882f831 -
Run Games' vitest files through test/run.js so ov test can shard themOpenVibers · 3 Oct 2026
1cae50b -
Rapier replaces Havok behind the unchanged physics seam (ADR-0007 M1 steps 4-7), and Games serves its own legal pages (plan T11 decision 6).OpenVibers · 29 Sept 2026
9201a6f -
Games M1 step 3 (ADR-0007): intent input. One frozen, versioned intent bitfield in packages/shared (the movement layer re-exports it, the protocol's copy is gone); look is absolute and quantised to int16 (1/65536 turn) on the wire, the server takes the client's angles as sent (yaw wrapped, pitch clamped to ±90°) so prediction integrates identical values; the input schema refuses unknown bits and out-of-range angles; PROTOCOL_VERSION 20 (old tabs reload). The client samples an InputSource (keyboard today, touch in M2 maps to the same intents; a test drives both to identical streams). Slice test: walks around the driven cart and up to the scattered loot instead of racing physics. typecheck, test, lint, slice and bundle green (verified).OpenVibers · 29 Sept 2026
2abbb15 -
The portal's JSON-LD comes from openvibe-shared/seo (plan T11): WebSite plus the game as the site's primary type, injected as the page is served instead of a hand-written block in index.html. The page is built once per file version (mtime), so the game server never reads the file per request; it keeps cache-control: no-cache. discovery.test.ts covers the tags and the injection.OpenVibers · 29 Sept 2026
203057f -
Movement state hash and determinism harness (ADR-0007 M1 step 2): stateHash.ts hashes the quantised PlayerMoveState (FNV-1a 32-bit over a documented big-endian stream; 1e-4 m, 1e-3 m/s) and measures divergence against the 1 mm / 1 cm/s cross-engine tolerance (a field added to PlayerMoveState but not hashed is a type error). determinism.test.ts: the same ~600-tick script is bit-identical run twice in one runtime, replays from a tick-300 snapshot to the same hash, and pins a multi-player hash; the mock against Havok forks at tick 102 on the first wall contact (the step-up probe's discrete branch) and at tick 147 (auto-bhop), recorded as a known failure with the numbers so Rapier (step 4) has a measured target: a hysteresis band on tryStepMove and a true capsule-vs-box sweep in the mock (decisions 8-9). typecheck, lint and test green (1051 passed, 9 skipped).OpenVibers · 29 Sept 2026
f328cfc -
Staff auth on openvibe-sdk v0.23.1's JWKS client (the last good keys through a Network outage, a rotation honoured on an unknown kid) and openvibe-contracts v0.78.0. Service and app principals are now checked by openvibe-contracts' verifyServiceToken with the key their kid names (else each key): the claim schema, issuer, audience and the sandbox refusal apply, which verifyUserToken(allowServiceTokens) had skipped. A refusal is a null with the reason logged; nothing the SDK says (it names the internal JWKS URL) reaches a caller. Tests: a sandbox token with games.mod.manage is refused, a svc: token with it passes, an unknown signing key is refused, cached keys verify through a JWKS outage. typecheck, lint, test, slice and bundle checks green.OpenVibers · 29 Sept 2026
5d18446 -
Physics conformance suite and an in-memory mock world (ADR-0007 M1 step 1): packages/physics/src/conformance.test.ts runs every seam case against MockPhysicsWorld and the Havok adapter (bodies, sweeps, joints, sleep and settle thresholds read through the adapter under test, gravity measured, per-engine landing heights pinned separately), with a guard that fails on a skip entry naming no case. The mock (@openvibe/physics/mock) now backs the gameplay movement tests in place of their ad-hoc stub, which exposed two mock bugs: a swept capsule's height is its total height including caps (it was 0.8 m too tall), and a capsule sweep meets a plane from either side (walls and ceilings were passed through), with the start-overlap guard both engines have. The two unrun smoke scripts are gone (the suite covers them). sliceTest waits for the recalled snapshot and meta.secured inside one budget (a race). Reviewed independently twice; pnpm typecheck, lint and test green (1036 passed, 9 skipped).OpenVibers · 29 Sept 2026
c24b7b1 -
M1 identity: the WebSocket authenticates at the upgrade, the editor key is gone, and the contracts pin is current (ADR-0007 decisions 8 and 12).OpenVibers · 29 Sept 2026
3ea36b3 -
M1: gameServer.ts (≈2,700 lines, one class) is split into 20 systems under apps/server/src/game/systems/ (sessions, movement, replication, manipulation, combat, vehicles, inventory, interaction, economy, production, npcs, social, worldEvents, persistence, mods, editor, environment, physics) sharing an explicit ServerContext; GameServer (299 lines) builds the context and systems, owns the one handler table (a duplicate message type is a startup error) and step(), which calls the systems in the exact previous order, written once as a list. Behaviour is unchanged: the persistence system keeps the forced final checkpoint and the returning player's drain(5000); ClientEditMode is exported from the protocol because movement uses the type. New handlerTable.test.ts: a duplicate type is refused and every protocol message type has exactly one handler. Built by DeepSeek from Claude's spec; reviewed independently on Command Code/MiniMax M3 (VERDICT: SHIP, method-by-method against HEAD). pnpm typecheck, lint, test 875/875, slice test OK.OpenVibers · 29 Sept 2026
cac9644 -
gitleaks: allow the made-up subject id usr_01JABCDEFGHJKMNPQRSTVWXYZ0 in flusher.test.ts (a test default, matched on path and value), which the generic-api-key rule flagged in 540f672.OpenVibers · 29 Sept 2026
5900501 -
M1 persistence: Games runs on PostgreSQL 18 + Valkey through openvibe-sdk (ADR-0007 decision 5). SQLite is gone (no data is restored; a new schema from scratch, no schema-version history). - packages/persistence: openPgStore on an openvibe-sdk/db handle, every repository async, batch upserts as multi-row INSERT ... ON CONFLICT in chunks of 500; migrations/0001_initial.sql: places, world_meta, world_entities and world_constraints keyed by place, characters (account_key is the subject, or guest: + sha256 of a guest token: a raw guest token is never stored), mods, grants, placements, audit, media mirrors, account data events, identity adoptions, and the SDK's event_outbox and token_revocations. transaction() hands the tx to its callback; the outbox enqueue takes it and refuses to run outside one. - The write-behind flusher (apps/server/src/game/flusher.ts): the tick builds a copy-on-write snapshot and never awaits I/O; one transaction at a time writes meta, NPCs (now dirty-tracked), entities, constraints, characters and their outbox events; a checkpoint while one is in flight is coalesced (flags stay set); a failed one restores its dirtiness. The shutdown checkpoint is never coalesced (queued behind one in flight), drain has a real deadline, a failed disconnect save retries in place with backoff, and a returning player's sign-in waits for queued saves before reading the character. - No database access on the tick: markets and env preload at boot, mod placements come from an in-memory mirror written through a serialized queue (rolled back if the write fails), an offline owner's friends load asynchronously (denied until loaded), hello resolves asynchronously with an in-flight guard. - Platform adapters on the SDK handle (createPgOutbox, createPgRevocationStore, account data), readiness via db.ready(), per-actor limits on Valkey when VALKEY_URL is set; development without DATABASE_URL runs on PGlite; migrations run as the owner on DATABASE_DIRECT_URL. Unhandled rejections closed in /api/v1/platform, readiness, the media mirror pass and account events; the Network revision advances only after its writes; a failed budget disable keeps enforcing. - openvibe-sdk v0.22.0, openvibe-shared v1.30.1; better-sqlite3 removed. Built by DeepSeek from Claude's spec; reviewed independently twice (FIX, FIX) and by Claude (the shutdown coalescing loss, drain deadline, disconnect retries and sign-in ordering fixed by Claude); every finding fixed with tests. pnpm typecheck, lint, test 872/872, slice test OK on PGlite, server bundle builds. Not deployed yet: production needs its database (roles/data/add-service.sh games) and Host's Games strategy moved off better-sqlite3 first.OpenVibers · 29 Sept 2026
540f672 -
ADR-0007: rewrite the moddable base (the base is the product, Scraplandia its first pack; Rapier; places and instances; PostgreSQL + Valkey with a write-behind flusher; declarative, QuickJS and Worker mods; phones a real target; OpenVibe.Play for achievements, stats, inventories and lobbies; milestones M1-M6). Nothing on openvibe.games is kept or restored, so M1 starts by deleting the legacy surface, with no shims and no redirects: - the Live legacy import (liveLegacyImport, importLiveLegacy, legacy_live_rows, docs/legacy-import.md); - identity adoption of ovn: keys (migrateIdentity, identityMigration, the ovn: prefix; sign-in keys on the token's subject and a token without one is refused) and IP-bound guest recovery (guest_ips, GUEST_IP_BINDING); the once-only ledger that account merge and deletion still use is renamed identity_adoptions; - the /api/texture alias and the /game and /canvas redirects; - map v1 (migrateV1ToV2, MAIN_TERRAIN_MIGRATED_ID, migrateLegacyMix, the client's legacyLayer, TerrainPatchData.mix): a v1 document is invalid, and the editor e2e checks that it opens empty; - the committed dist-types build output (366 files, now ignored) and the stale gameplay status doc. The guest cookie keys hq_token/hq_reload_ts became openvibe.token/openvibe.reload_ts. ADR-0006 notes that its identity adoption is superseded. The SQLite schema version went 13 -> 11: this build refuses the old world.db on purpose and is not deployed; PostgreSQL replaces the store next (M1), on a fresh database. Reviewed independently; its findings are fixed here (e2e v1 section, ADR notes) or in Live (links to /game and /canvas). pnpm typecheck, lint, test 843/843.OpenVibers · 29 Sept 2026
cfaf83c -
README and STATUS.json are current (roadmap WS-U task 3): the README gains Purpose (OpenVibe.Games: Scraplandia on openvibe.games), Owns, Does not own, Depends on, Capabilities (the four games.* capabilities in the manifest, and every grant the games principal uses, now including events.subscription.manage, network.modules.write and mods.grant.manage), Tests and Security (SECURITY.md, server authority, limits, identity, mods, secrets by name) sections; Production names the env file, database and rollback with its schema-version blocker. Stale facts corrected: Games pins openvibe-contracts v0.71.0 (not v0.8.0) and serves the OpenVibe Frame from its own pinned copy, not openvibe.network. STATUS.json is new, in the shape of Search's, updated 2026-09-28.OpenVibers · 28 Sept 2026
eb2d008 -
Per-actor limits on Games' HTTP writes (roadmap WS-R task 4; openvibe-sdk 0.11.0 -> 0.12.0 openvibe-sdk/limits). apps/server/src/net/actorLimits.ts counts the capability boundaries after the caller is authorised and before the body is read: editor map saves (30 a minute, 600 an hour) and asset uploads (60, 1200), by a hash of the editor credential, never the credential; and the mods API's writes (30, 300) by the staff or service actor. Past a limit: 429 problem+json rate_limited with Retry-After, logged. Gameplay is the WebSocket with its own per-socket flood control; reads and signed-out pages keep what they had. GAMES_LIMITS_MINUTE / _HOUR set the defaults (120 / 3000). apps/server/src/net/actorLimits.test.ts: one actor refused before the handler, another passes, the window reopens, the credential is hashed. Prettier on routes.ts and main.ts. pnpm test 882/882, typecheck clean.OpenVibers · 28 Sept 2026
51d8688 -
Prettier on the files the mod-principal and budget work touched (networkGrants, registry, runtime, routes' tests, revocationEvents, modLifecycleProof): formatting only, no change in behaviour.OpenVibers · 28 Sept 2026
b6a825d -
A late network.mod.grants_changed no longer undoes a newer grant (found by the production lifecycle proof: the register event, revision 1 with nothing approved, arrived after the API had applied revision 2's grant, so the prop flapped off and back on). ModRegistry keeps the Network revision each install was last set from: the API notes the revision of every answer it applied (install, grant, revoke-grant, revoke), and applyNetwork ignores an event at or below it, as network.mod.grants_changed@1 says. networkGrants.test.ts: older revisions change nothing, a newer one (a staff change) applies. pnpm test and typecheck pass.OpenVibers · 27 Sept 2026
1529a52 -
Mod budgets are enforced on the offending mod only (roadmap WS-M task 4), and mod security tests (task 5). The runtime already timed each reconcile against the manifest's cpuMs.OpenVibers · 27 Sept 2026
b5feaf8 -
apps/server/scripts/modLifecycleProof.ts: one production mod lifecycle (roadmap WS-M task 6, ADR-013). With the operator's probe principal (games.mod.manage on openvibe.games), a fresh proof mod (one inert prop far from spawn, published by a synthetic app) is installed with nothing approved (mod:<id> registered in Network, games.prop.place pending), granted games.prop.place (Network approves it first), used (the runtime places the prop: audit use) and revoked (Network and Games; the prop retracted: audit retract). Prints each step and the audit trail, exits 1 when a step is missing; nothing secret is printed. Typecheck clean.OpenVibers · 27 Sept 2026
b724b5a -
Mod grants live in OpenVibe.Network (roadmap WS-M task 3, ADR-013; Network c3a6441, Contracts 0.72.0 mods.grant.manage). With a platform client, the mods API asks Network first and applies only what it answered (apps/server/src/mods/networkGrants.ts): - install checks everything locally (ModRegistry.checkInstall), registers mod:<id> in Network, and grants what Network approved; - grant (checkGrant first), revoke-grant and revoke change the principal before the local copy. A Network refusal keeps its code and status; Network unreachable is 503 mod.grants_unavailable; in both cases nothing changes here. Enable and disable stay the runtime's own switch.OpenVibers · 27 Sept 2026
86fe34d -
Games takes part in account export and deletion (roadmap WS-B task 7, ADR-033; apps/server openvibe-contracts 0.53.0 -> 0.71.0). POST /internal/events takes network.account.export_requested and network.account.deleted (the boot subscriptions now include both) and hands them to apps/server/src/platform/accountData.ts, answered once applied (500 when it failed, so Events retries). Each is applied once per export or deletion (account_data_events, kept by the adapter beside the outbox).OpenVibers · 27 Sept 2026
fcb62c5 -
Games follows account merges (roadmap WS-B task 5, ADR-029). The platform events subscription now also asks for network.subject.merged; a delivery from Network with a valid payload calls store.identity.mergeSubject(from, into, merge_id), once per merge_id (subject_map row merge:<id>). The folded-in account's characters move to the survivor in one transaction: first each one whose own slot is free there, then the rest into the slots left (0-2); what does not fit stays with the folded-in account and is counted as kept. test: platformRepositories (own slot kept, clash placed, overflow kept, redelivery a no-op) and revocationEvents (the merge dispatch, other sources and bad payloads ignored, both topics subscribed).OpenVibers · 27 Sept 2026
9058cdd -
The game pages run their own pinned OpenVibe Frame (roadmap WS-P task 4, D42: the Games client). The server gains openvibe-shared 1.23.0 and serves its browser files at /shared (apps/server/src/net/sharedAssets.ts: only the files openvibe-shared/files lists, content-addressed with ?v= for a year, else five minutes, ETag and 304, the same rules as openvibe-shared/serve, which is Express-shaped while this server is plain node:http), next to /release.json. index.html, play.html and editor.html load theme-loader, navbar and footer from /shared/ instead of https://openvibe.network/shared/, so they run what Games pins and keep their frame while Network is down (Vite leaves the classic script tags as they are). Test: the pinned navbar with its hash and ETag, only listed files, and no page loading the frame from openvibe.network. pnpm test: 79 files, 866 tests.OpenVibers · 27 Sept 2026
8200c2c