openvibers/openvibe.codes Commits

account-data: pin openvibe-sdk 0.74.0 and guard every table with a person column (#182)

OP OpenVibers committed 14 days ago · cbdb7cea31 · 6 files, +31 −17

telemetry_samples is the SDK's entry now (same telemetry.json, same anonymize), so Codes' own entry goes. The test runs uncovered() and asserts the list is empty, with account_data_events exempted as the ledger of requests itself.

Changes

ddiff --git a/README.md b/README.md
iindex 99a1a3d..04057e2 100644
---- a/README.md
++++ b/README.md
@@@ -94,7 +94,7 @@ More: [docs/cli.md](docs/cli.md).
- **OpenVibe.Network** — SSO (OAuth client `codes`, PKCE S256) and its JWKS.
- **PostgreSQL 18 and Valkey 9** (OpenVibe.Host `roles/data/`, ADR-035): `openvibe-sdk/db`; Valkey holds the per-actor limit counters (optional).
--- **openvibe-contracts v0.243.0**, **openvibe-sdk v0.73.0**, **openvibe-shared v4.48.0** (pinned tag tarballs).
++- **openvibe-contracts v0.243.0**, **openvibe-sdk v0.74.0**, **openvibe-shared v4.48.0** (pinned tag tarballs).
No path in Codes sends or accepts a shared loopback key (tested by grep and at runtime).
@@@ -170,6 +170,6 @@ Part of the [OpenVibe network](https://openvibe.network). Built in the open by [
<!-- versions:start -->
- openvibe-contracts: v0.247.0
--- openvibe-sdk: v0.73.0
++- openvibe-sdk: v0.74.0
- openvibe-shared: v4.48.0
<!-- versions:end -->
ddiff --git a/STATUS.json b/STATUS.json
iindex 2cdb69a..f53f433 100644
---- a/STATUS.json
++++ b/STATUS.json
@@@ -8,11 +8,11 @@
"port": 4900,
"domain": "openvibe.codes",
"contracts": "openvibe-contracts v0.247.0",
-- "sdk": "openvibe-sdk v0.73.0",
++ "sdk": "openvibe-sdk v0.74.0",
"shared": "openvibe-shared v4.48.0",
"packages": [
"openvibe-contracts v0.247.0",
-- "openvibe-sdk v0.73.0",
++ "openvibe-sdk v0.74.0",
"openvibe-shared v4.48.0"
],
"summary": "Public at https://openvibe.codes (sudo ovhost deploy codes; unit openvibe-codes on 127.0.0.1:4900). Since 2026-10-08 Codes is the open coding-agent harness: openvibe-codes (a command-line tool and Node.js module, v0.5.0) runs a coding task on Claude Code, Claude Code on another provider, Codex, OpenCode, Command Code, MiniMax Code, Aider, the DeepSeek API or a person's own OpenAI-compatible model on their machine, hands it to the next agent when one fails or goes quiet, and keeps every run; the site carries the agent catalog with a public routing API, getting started, Improve OpenVibe and the community documents. The developer console that used to live here moved to OpenVibe.Services (https://openvibe.services) and every one of its addresses answers a permanent redirect there.",
ddiff --git a/package-lock.json b/package-lock.json
iindex 08777d2..9593973 100644
---- a/package-lock.json
++++ b/package-lock.json
@@@ -16,7 +16,7 @@
"helmet": "^8.1.0",
"iovalkey": "^0.4.0",
"openvibe-contracts": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.247.0",
-- "openvibe-sdk": "https://codeload.github.com/OpenVibers/OpenVibe.SDK/tar.gz/refs/tags/v0.73.0",
++ "openvibe-sdk": "https://codeload.github.com/OpenVibers/OpenVibe.SDK/tar.gz/refs/tags/v0.74.0",
"openvibe-shared": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v4.48.0",
"pg": "^8.23.0"
},
@@@ -1165,9 +1165,9 @@
}
},
"node_modules/openvibe-sdk": {
-- "version": "0.73.0",
-- "resolved": "https://codeload.github.com/OpenVibers/OpenVibe.SDK/tar.gz/refs/tags/v0.73.0",
-- "integrity": "sha512-XClxoVm9M6RA8eXlGgYZ0u6q9n5h79mCXqAAEg9fX21KgcqP69RmG+cX+6wrOf7TaEj7eSBWMxHjiIeIa9N7Dg==",
++ "version": "0.74.0",
++ "resolved": "https://codeload.github.com/OpenVibers/OpenVibe.SDK/tar.gz/refs/tags/v0.74.0",
++ "integrity": "sha512-DO9KVPnUriY/I4lX6ZEJtXaUvRDbJyqnqJxvlpl+zkNGFILpmuBXVJogNOCfK071Qci1gg7C4Iw1Xrseklcajg==",
"license": "MIT",
"bin": {
"openvibe-download": "bin/openvibe-download.js"
ddiff --git a/package.json b/package.json
iindex 8cab16c..fed476d 100644
---- a/package.json
++++ b/package.json
@@@ -31,7 +31,7 @@
"helmet": "^8.1.0",
"iovalkey": "^0.4.0",
"openvibe-contracts": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.247.0",
-- "openvibe-sdk": "https://codeload.github.com/OpenVibers/OpenVibe.SDK/tar.gz/refs/tags/v0.73.0",
++ "openvibe-sdk": "https://codeload.github.com/OpenVibers/OpenVibe.SDK/tar.gz/refs/tags/v0.74.0",
"openvibe-shared": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v4.48.0",
"pg": "^8.23.0"
},
ddiff --git a/server/account-data.js b/server/account-data.js
iindex b39ed38..bd9c438 100644
---- a/server/account-data.js
++++ b/server/account-data.js
@@@ -9,12 +9,15 @@
* - the run tokens minted for their attempts (codes_run_tokens, C3: ids and expiry, never the token);
* - their workspace choices (codes_user_settings, C4b);
* - the events Codes sent about them (codes_outbox);
-- * - telemetry samples that name them.
++ * - telemetry samples that name them: the SDK covers telemetry_samples itself (telemetry.json, then subject NULL).
*
* Export carries the tasks whole, and the task-keyed rows as session-lines.json, attempts.json and proof.json.
* Deletion erases everything task-keyed and then the tasks, in one transaction. Telemetry samples stay as numbers with
* the person's id removed. The Run jobs themselves are OpenVibe.Run's records (usage billed to the project) and are
* Run's to answer for.
++ *
++ * test/account-data.test.js asserts uncovered() is empty, so a new table with a person column fails CI until it is
++ * added to TABLES or TASK_KEYED, or exempted there with a reason.
*/
const { createAccountData, TOPICS } = require('openvibe-sdk/account-data');
@@@ -33,12 +36,6 @@ const TABLES = [
// The token itself is never stored; its jti is an internal handle and stays out of the export.
{ table: 'codes_run_tokens', subject: 'subject', file: 'run-tokens.json', order: 'created_at', columns: ['id', 'task_id', 'attempt_id', 'provider', 'expires_at', 'created_at'] },
{ table: 'codes_outbox', subject: 'subject', file: 'events-sent.json', order: 'created_at', columns: ['event_id', 'topic', 'created_at', 'published_at'] },
-- {
-- table: 'telemetry_samples', subject: 'subject', file: 'telemetry.json', order: 'at',
-- columns: ['at', 'operation', 'resource', 'status', 'latency_ms'],
-- // The sample stays (latency and error rates are the service's), without the person in it.
-- erase: { anonymize: {} },
-- },
];
// The rows that hang under a person's tasks: exported under the task, erased before it.
ddiff --git a/test/account-data.test.js b/test/account-data.test.js
iindex 0721c05..c9e71e4 100644
---- a/test/account-data.test.js
++++ b/test/account-data.test.js
@@@ -7,9 +7,10 @@
*/
const assert = require('assert');
const http = require('http');
--const { createNetworkSender } = require('openvibe-sdk/account-data');
++const { createNetworkSender, uncovered } = require('openvibe-sdk/account-data');
const { signDeliveryHeaders } = require('openvibe-sdk/events');
const { ids } = require('openvibe-contracts');
++const { TABLES, TASK_KEYED } = require('../server/account-data');
const { boot, check, done } = require('./helpers/boot');
const SECRET = `whsec_${'fixture'.repeat(6)}`;
@@@ -63,6 +64,18 @@ async function startNetworkStub() {
const ev = (id, type, payload) => ({ event_id: id, event_type: type, source: 'network', version: 1, timestamp: new Date().toISOString(), payload });
try {
++ await check('every table that names a person is covered, task-keyed or exempted with a reason', async () => {
++ const missing = await uncovered(db, {
++ tables: TABLES,
++ taskKeyed: TASK_KEYED.map((k) => k.table),
++ exempt: {
++ account_data_events: 'the ledger of requests itself: which export and deletion Codes applied',
++ event_outbox: 'no person column (the SDK outbox keeps envelopes); dropped with the console in 0002 anyway',
++ },
++ });
++ assert.deepStrictEqual(missing, [], `a table with a person column is neither covered nor exempted: ${missing.join(', ')}`);
++ });
++
await check('an unsigned delivery is refused', async () => {
const r = await deliver(ev(`evt_${ids.ulid()}`, 'network.account.deleted', { deletion_id: `del_${ids.ulid()}`, subject: ada, aliases: [] }), { secret: null });
assert.strictEqual(r.status, 401);
@@@ -86,6 +99,10 @@ async function startNetworkStub() {
}
const tok = part.body.files.find((x) => x.name === 'run-tokens.json').content[0];
assert.ok(!('jti' in tok), 'a run token’s jti stays out of the export');
++ const telemetry = part.body.files.find((x) => x.name === 'telemetry.json');
++ assert.ok(telemetry, 'telemetry.json is in the export (the SDK covers the table)');
++ assert.strictEqual(telemetry.content.length, 1, 'Ada’s sample only');
++ assert.deepStrictEqual(Object.keys(telemetry.content[0]).sort(), ['at', 'latency_ms', 'operation', 'resource', 'service', 'status']);
});
await check('a deletion erases them, keeps everyone else’s, and confirms once', async () => {