Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
155 changes: 155 additions & 0 deletions services/ontology/schemas/callSession.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"schemaId": "e815ba40-ef85-4a2b-b6cf-e05a86d4afbd",
"title": "CallSession",
"description": "One audio/video call in a chat, transport-agnostic (full-mesh WebRTC or an SFU). Generalises the ad-hoc 'call' Message so a call and its recording are readable across applications: who was in it, when, how long, and where the recording and transcript live. The canonical envelope is written ONCE, on the vault that already holds the chat's canonical Chat envelope (the group's own vault for a group, the chat owner's vault for a 1:1) — never on the caller's vault, which changes from call to call. Every other participant holds a reference-mixin (isReference + canonicalOwnerEName + canonicalEnvelopeId) on their own vault, never a copy. The body carries references and metadata only: media and transcript are w3ds:// file URIs, never bytes.",
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "Stable call id, shared by every participant's record of the same call"
},
"chatId": {
"type": "string",
"description": "The conversation this call belongs to"
},
"transport": {
"type": "string",
"enum": ["mesh", "livekit"],
"description": "How the media was carried: peer-to-peer full mesh, or an SFU"
},
"callType": {
"type": "string",
"enum": ["audio", "video"],
"description": "Whether the call carried video"
},
"initiator": {
"type": "string",
"description": "eName of whoever started the call"
},
"participants": {
"type": "array",
"items": { "type": "string" },
"description": "eNames of everyone in the call, including the initiator"
},
"roomName": {
"type": "string",
"description": "SFU room name, when the transport used one"
},
"startedAt": {
"type": "string",
"format": "date-time",
"description": "When the call began"
},
"endedAt": {
"type": "string",
"format": "date-time",
"description": "When the call ended; absent while it is still running"
},
"durationSec": {
"type": "number",
"description": "Talk time in seconds; absent when unknown"
Comment on lines +49 to +51

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Reject negative durations.

durationSec accepts negative values. A call duration cannot be negative.

Add "minimum": 0 to this property.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@services/ontology/schemas/callSession.json` around lines 49 - 51, Update the
durationSec property in the call-session schema to enforce a minimum value of 0,
while preserving its existing number type and optional/unknown behavior.

},
"status": {
"type": "string",
"enum": ["active", "ended", "missed", "declined"],
"description": "Outcome of the call"
},
"recording": {
"type": "object",
"description": "Present only when the call was recorded. References only — no media bytes and no transcript text.",
"properties": {
"mode": {
"type": "string",
"enum": ["egress", "client"],
"description": "Recorded server-side by the SFU, or by a participant's client"
},
"mediaUri": {
"type": "string",
"description": "w3ds:// file URI of the composite recording"
},
"mediaSegments": {
"type": "array",
"items": { "type": "string" },
"description": "w3ds:// file URIs, when the composite was split into parts"
Comment on lines +67 to +74

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Validate w3ds:// file references.

These fields accept any string, including an HTTP URL or non-URI value. This conflicts with the cross-application file-reference contract.

Add a shared Draft-07 definitions entry with a ^w3ds://.+ pattern. Apply it to mediaUri, mediaSegments items, tracks[].uri, and transcriptUri.

Also applies to: 85-88, 94-96

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@services/ontology/schemas/callSession.json` around lines 67 - 74, Add a
shared Draft-07 definition for non-empty w3ds:// references using the ^w3ds://.+
pattern, then reference it from mediaUri, mediaSegments item values,
tracks[].uri, and transcriptUri. Preserve the existing array and object
structure while replacing unrestricted string schemas for these fields.

},
"mediaIsVideo": {
"type": "boolean",
"description": "Whether the composite carries video as well as audio"
},
"tracks": {
"type": "array",
"description": "Per-speaker media, one entry per participant captured",
"items": {
"type": "object",
"properties": {
"eName": { "type": "string" },
"uri": { "type": "string" },
"mime": { "type": "string" }
},
"required": ["eName", "uri"],
"additionalProperties": false
}
},
"transcriptUri": {
"type": "string",
"description": "w3ds:// file URI of the transcript"
},
"transcriptStatus": {
"type": "string",
"enum": ["pending", "done", "error", "skipped", "none"]
},
"analysisStatus": {
"type": "string",
"enum": ["pending", "done", "error", "skipped", "none"]
},
"recordedBy": {
"type": "string",
"description": "eName of whoever started the recording"
},
"recordingVault": {
"type": "string",
"description": "eName of the vault the media and transcript files live on"
}
},
"additionalProperties": false
},
"isReference": {
"type": "boolean",
"description": "True on a participant's pointer to a canonical CallSession held elsewhere"
},
"canonicalOwnerEName": {
"type": "string",
"description": "On a reference: the vault holding the canonical envelope"
},
"canonicalEnvelopeId": {
"type": "string",
"description": "On a reference: the canonical envelope's id on that vault"
Comment on lines +117 to +127

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== locate file =="
git ls-files | grep -F 'services/ontology/schemas/callSession.json' || true

echo "== file outline/size =="
wc -l services/ontology/schemas/callSession.json
echo "== relevant schema sections =="
sed -n '1,220p' services/ontology/schemas/callSession.json | cat -n

echo "== search related definitions/usages =="
rg -n "isReference|canonicalOwnerEName|canonicalEnvelopeId"| head -n 200

Repository: MetaState-Prototype-Project/prototype

Length of output: 8080


🌐 Web query:

JSON Schema 2020-12 if then else boolean true required keyword behavior

💡 Result:

In JSON Schema 2020-12, the if, then, and else keywords provide conditional validation, functioning similarly to an if-then-else programming construct [1][2][3]. Interaction with Boolean Schemas and Defaults When the then or else keywords are missing, they are effectively treated as the boolean true schema, which always passes validation [1][3]. Specifically: - If the if subschema validates successfully and then is missing, the validation succeeds as if the then subschema were true [1][3]. - If the if subschema fails to validate and else is missing, the validation succeeds as if the else subschema were true [1][3]. - If the if keyword is entirely absent, then and else are ignored [2][4]. Interaction with the Required Keyword The required keyword behaves consistently within the conditional structure [3]. When then or else is applied, the required constraint is evaluated just like any other validation keyword [2][4]. Common patterns for conditional requirements include: - If a condition is met (if subschema passes), use then to mandate specific fields using required [5][6]. - If a condition is not met (if subschema fails), use else to mandate different fields [6]. Key Behavioral Rules - The evaluation result of the if subschema determines which branch (then or else) is evaluated [2][3]. The result of the if subschema itself does not directly dictate the overall validation outcome; rather, the success of the chosen branch (then or else) determines the success of the conditional block [1][2][4]. - Only the applicable branch (then or else) is evaluated for validation; the other is completely ignored [2][4]. - Annotations from the if subschema are collected regardless of the outcomes of the then or else branches [1][2]. - These keywords do not interact across subschema boundaries (e.g., within branches of an allOf) [2][4].

Citations:


Require complete canonical reference mixins.

The schema only requires id, so invalid records like {"id":"call-1","isReference":true} and records with canonical pointer fields but no isReference are accepted. Require isReference; when it is true, require canonicalOwnerEName, canonicalEnvelopeId, sharedBy, and sharedAt; when it is false, reject those pointer fields.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@services/ontology/schemas/callSession.json` around lines 117 - 127, Update
the CallSession participant schema around isReference, canonicalOwnerEName, and
canonicalEnvelopeId to require isReference and enforce conditional reference
fields: true requires canonicalOwnerEName, canonicalEnvelopeId, sharedBy, and
sharedAt, while false rejects all canonical pointer fields. Preserve the
existing id requirement and use the schema’s conditional validation mechanism.

},
"sharedBy": {
"type": "string",
"description": "On a reference: who wrote the pointer"
},
"sharedAt": {
"type": "string",
"format": "date-time",
"description": "On a reference: when the pointer was written"
},
"createdAt": {
"type": "string",
"format": "date-time",
"description": "When this envelope was created"
},
"updatedAt": {
"type": "string",
"format": "date-time",
"description": "Body version: bumped whenever the body changes, so readers know a cached copy is stale"
},
"isArchived": {
"type": "boolean",
"description": "Whether the record is archived"
}
},
"required": ["id"],
"additionalProperties": false
}
Loading