NetworkConsent network.consent@1

Generated at from openvibe-contracts v0.419.0 and openvibe-sdk v0.161.0.

Version
1.0.0
Owner
network
Visibility
public
Status
active
Compatibility
backward
Schema
https://openvibe.network/contracts/network/consent.v1.json

network.consent@1 (L24, data and AI by consent, 2026-10-31): one person's choice for one purpose. Nothing a person makes is off-limits to AI or data use by design; each use is off until that person turns it on, here. The record is the proof of what was allowed, by whom, under which wording and when: a choice is turned off by setting revoked_at, never by deleting the row. Stored by OpenVibe.Network (consents, with every change in consent_events), read by a person at GET /api/v1/me/consent and by services through POST /internal/consent/check (capability network.consent.read). A service that cannot reach Network treats every purpose as off.

Fields

FieldTypeRequiredDescriptionConstraints
idstringyesThe choice's own id (cns_<ULID>). A choice changed later (other kinds, another licence) is a new record; the old one is revoked.
  • pattern ^cns_[0-9A-HJKMNP-TV-Z]{26}$
subjectstringyesWhose choice it is. Only that person (or an account merge or deletion) changes it.
  • pattern ^usr_[0-9A-HJKMNP-TV-Z]{26}$
purposeenumyesWhat turning it on allows. ai.train: OpenVibe trains or fine-tunes models on the person's content. data.public: the person's content goes into OpenVibe's open dataset under the licence in options. face.recognize: the person's face is recognised (the features in options; OpenVibe.Vision keeps the encrypted templates). ai.looks is retired (0.256.0): the owner removed the rule that AI text never describes people (2026-10-31), so describing how someone looks needs no opt-in; it stays in the list so older readers still validate, and nothing writes it. app.data: one named app (client) may use the person's content for the purposes in options.
  • one of "ai.train", "data.public", "face.recognize", "ai.looks", "app.data"
onbooleanyesWhether the purpose is allowed now: true while the record is active (revoked_at null and expires_at not passed). A service never decides from this field alone; it asks the check.
kindsarray of enumyesWhich of the person's content it covers. Empty means every kind the purpose applies to. face.recognize and ai.looks take no kinds (they are about the person, not a piece of content).
  • maxItems 8
  • unique items
  • items: one of "streams", "vods", "clips", "voice", "chat", "posts", "pictures", "code"
clientstring | nullyesThe app the choice is for: null means OpenVibe itself; otherwise the OAuth client id of the app the person granted it to. app.data always names one. Since 0.310.0 an app may ask for any purpose at sign-in (consent:<purpose>, network.consent-claim@1): the grant is one record per purpose with this client and source oauth, and it allows that app only, never OpenVibe itself or another app.
  • pattern ^[A-Za-z0-9][A-Za-z0-9_.:-]{0,79}$
optionsobjectyesWhat the purpose needs beyond on and kinds. An empty object for ai.train and ai.looks.
  • no other fields
options.licenceenumdata.public only: the licence the person's content is published under.
  • one of "cc-by-4.0", "cc0-1.0"
options.featuresarray of enumface.recognize only: which recognition the person allows (OpenVibe.Vision's features). Empty means none yet.
  • maxItems 4
  • unique items
  • items: one of "verify", "find", "cast", "library"
options.purposesarray of enumapp.data only, and not written since 0.310.0: an app's consent screen grants each purpose as its own record (client set), so a reader asks for the purpose itself. Kept so older records still validate.
  • maxItems 4
  • unique items
  • items: one of "ai.train", "data.public", "face.recognize", "ai.looks"
text_versionstringyesThe exact wording the person saw when choosing (YYYY-MM-DD.n). A new wording never turns an existing choice on; it may only ask again.
  • pattern ^[0-9]{4}-[0-9]{2}-[0-9]{2}\.[0-9]{1,3}$
sourceenumyesWhere the choice was made: the account page, an app's consent screen at sign-in (consent:<purpose>, with client set), the person's own API call, or OpenVibe.Vision's older face consents moved into Network.
  • one of "account", "oauth", "api", "import:vision"
granted_atstringyesWhen the person turned it on.
  • format date-time
revoked_atstring | nullyesWhen it was turned off (by the person, by revoking the app, by a merge or by deleting the account), or null while it holds. Use stops on the next check; a model already trained keeps what it learned, and the next dataset release leaves the person's content out.
  • format date-time
expires_atstring | nullyesWhen the choice ends by itself (a time-limited grant, or the end of a face purpose), or null for no end.
  • format date-time

Examples

From the contract's own test fixtures: valid ones validate, rejected ones must fail.

Valid: ai-train-streams
{
  "id": "cns_01K6R3A1B2C3D4E5F6G7H8J9KA",
  "subject": "usr_01K6R2Z8C4V7M9Q3T5W1X2Y3Z4",
  "purpose": "ai.train",
  "on": true,
  "kinds": [
    "streams",
    "vods"
  ],
  "client": null,
  "options": {},
  "text_version": "2026-10-31.1",
  "source": "account",
  "granted_at": "2026-10-31T05:00:00.000Z",
  "revoked_at": null,
  "expires_at": null
}
Valid: app-data-revoked
{
  "id": "cns_01K6R3A1B2C3D4E5F6G7H8J9KC",
  "subject": "usr_01K6R2Z8C4V7M9Q3T5W1X2Y3Z4",
  "purpose": "app.data",
  "on": false,
  "kinds": [
    "pictures"
  ],
  "client": "app_01K6R3A1B2C3D4E5F6G7H8J9KD",
  "options": {
    "purposes": [
      "ai.train"
    ]
  },
  "text_version": "2026-10-31.1",
  "source": "oauth",
  "granted_at": "2026-10-31T05:00:00.000Z",
  "revoked_at": "2026-11-02T08:00:00.000Z",
  "expires_at": null
}
Valid: face-recognize
{
  "id": "cns_01K6R3A1B2C3D4E5F6G7H8J9KB",
  "subject": "usr_01K6R2Z8C4V7M9Q3T5W1X2Y3Z4",
  "purpose": "face.recognize",
  "on": true,
  "kinds": [],
  "client": null,
  "options": {
    "features": [
      "verify",
      "library"
    ]
  },
  "text_version": "2026-10-31.1",
  "source": "import:vision",
  "granted_at": "2026-10-31T05:00:00.000Z",
  "revoked_at": null,
  "expires_at": "2027-10-31T05:00:00.000Z"
}
Valid: oauth-app-train
{
  "id": "cns_01K9A3A1B2C3D4E5F6G7H8J9KC",
  "subject": "usr_01K6R2Z8C4V7M9Q3T5W1X2Y3Z4",
  "purpose": "ai.train",
  "on": true,
  "kinds": [],
  "client": "app_01K6R3A1B2C3D4E5F6G7H8J9KD",
  "options": {},
  "text_version": "2026-11-07.1",
  "source": "oauth",
  "granted_at": "2026-11-07T05:00:00.000Z",
  "revoked_at": null,
  "expires_at": null
}
Rejected: bad-id
{
  "id": "cns_123",
  "subject": "usr_01K6R2Z8C4V7M9Q3T5W1X2Y3Z4",
  "purpose": "ai.train",
  "on": true,
  "kinds": [
    "streams",
    "vods"
  ],
  "client": null,
  "options": {},
  "text_version": "2026-10-31.1",
  "source": "account",
  "granted_at": "2026-10-31T05:00:00.000Z",
  "revoked_at": null,
  "expires_at": null
}
Rejected: unknown-purpose
{
  "id": "cns_01K6R3A1B2C3D4E5F6G7H8J9KA",
  "subject": "usr_01K6R2Z8C4V7M9Q3T5W1X2Y3Z4",
  "purpose": "data.sell",
  "on": true,
  "kinds": [
    "streams",
    "vods"
  ],
  "client": null,
  "options": {},
  "text_version": "2026-10-31.1",
  "source": "account",
  "granted_at": "2026-10-31T05:00:00.000Z",
  "revoked_at": null,
  "expires_at": null
}

Validate

const contracts = require('openvibe-contracts');
contracts.validate('network.consent@1', value);   // { valid, errors: [{ path, message }] }