---
title: "ai.deep-dive@1 · OpenVibe.Services"
canonical: "https://openvibe.services/docs/contracts/ai.deep-dive"
updated: null
---

# ai.deep-dive@1 · OpenVibe.Services

HTML: [ai.deep-dive@1 · OpenVibe.Services](https://openvibe.services/docs/contracts/ai.deep-dive)

# AiDeepDive `ai.deep-dive@1`

Generated at 2026-11-13 06:25:48 UTC from [`openvibe-contracts v0.419.0`](https://github.com/OpenVibers/OpenVibe.Contracts/tree/v0.419.0) and [`openvibe-sdk v0.161.0`](https://github.com/OpenVibers/OpenVibe.SDK/tree/v0.161.0).

- Version: 1.0.0
- Owner: ai
- Visibility: public
- Status: active
- Compatibility: backward
- Decision: [ADR-015](/docs/adr/ADR-015)
- Schema: [`https://openvibe.network/contracts/ai/deep-dive.v1.json`](/docs/contracts/ai.deep-dive.json)

A deep dive: expert design research run by OpenVibe.AI (workflow design.deep\_dive) for OpenVibe.Exchange's /deep-dive page and, through the API, OpenVibe.Design. One document holds the question and depth (the input), the seven steps, every source read, every capture (a private Media object per viewport and theme, with its DOM facts and Expert extras), the per-site analysis, the synthesis across sites, the recommendations checked against OpenVibe's own rules, and the receipt of every model call and capture. Every claim carries its evidence: the site, the capture or crop, the URL and the date it was read. Nothing is copied: captures are private to the run's owner and the report shows them as attributed commentary.

## Fields

| Field | Type | Required | Description | Constraints |
| --- | --- | --- | --- | --- |
| `id` | string | yes | The run id; a deep dive is a run (GET /api/v1/deep-dives/{id}). | - `pattern ^run_[0-9A-HJKMNP-TV-Z]{26}$` |
| `schema` | const | yes |  | - `= "ai.deep-dive@1"` |
| `run_id` | string | yes |  | - `pattern ^run_[0-9A-HJKMNP-TV-Z]{26}$` |
| `status` | enum | yes |  | - `one of "queued", "running", "choosing", "succeeded", "failed", "cancelled"` |
| `input` | object | yes |  | - `no other fields` |
| `input.question` | string | yes |  | - `minLength 1`<br>- `maxLength 500` |
| `input.depth` | enum | yes |  | - `one of "quick", "thorough", "expert"` |
| `input.max_sites` | integer | yes |  | - `minimum 1`<br>- `maximum 30` |
| `input.sites` | array of string |  | Sites the person named when starting the run. | - `maxItems 30`<br>- `items: pattern ^https?://`<br>- `items: format uri` |
| `steps` | array of object | yes |  | - `items: no other fields` |
| `steps[].key` | enum | yes |  | - `one of "plan", "search", "choose", "capture", "analyse", "synthesise", "report"` |
| `steps[].status` | enum | yes |  | - `one of "pending", "running", "done", "skipped", "failed"` |
| `steps[].detail` | string \| null |  |  | - `maxLength 300` |
| `steps[].started_at` | string \| null |  |  | - `format date-time` |
| `steps[].finished_at` | string \| null |  |  | - `format date-time` |
| `sources` | array of object | yes |  | - `items: no other fields` |
| `sources[].id` | string | yes |  | - `pattern ^src_[A-Za-z0-9_-]{1,40}$` |
| `sources[].kind` | enum | yes |  | - `one of "web", "picture", "icon", "project", "rules", "component", "named"` |
| `sources[].title` | string | yes |  | - `maxLength 400` |
| `sources[].url` | string | yes |  | - `pattern ^https?://`<br>- `format uri` |
| `sources[].publisher` | string \| null |  |  | - `maxLength 200` |
| `sources[].engine` | string \| null |  |  | - `maxLength 80` |
| `sources[].snippet` | string \| null |  |  | - `maxLength 2000` |
| `sources[].license` | string \| null |  |  | - `maxLength 120` |
| `sources[].read_at` | string | yes |  | - `format date-time` |
| `captures` | array of object | yes |  | - `items: no other fields` |
| `captures[].id` | string | yes |  | - `pattern ^cap_[A-Za-z0-9_-]{1,40}$` |
| `captures[].source_id` | string | yes |  | - `pattern ^src_[A-Za-z0-9_-]{1,40}$` |
| `captures[].url` | string | yes |  | - `pattern ^https?://`<br>- `format uri` |
| `captures[].final_url` | string \| null |  |  | - `pattern ^https?://`<br>- `format uri` |
| `captures[].title` | string \| null |  |  | - `maxLength 400` |
| `captures[].captured_at` | string | yes |  | - `format date-time` |
| `captures[].viewport` | enum | yes |  | - `one of 390, 1280` |
| `captures[].theme` | enum | yes |  | - `one of "light", "dark"` |
| `captures[].full_page` | boolean | yes |  |  |
| `captures[].media_id` | string \| null |  |  | - `pattern ^med_[0-9A-HJKMNP-TV-Z]{26}$` |
| `captures[].width` | integer \| null |  |  | - `minimum 1` |
| `captures[].height` | integer \| null |  |  | - `minimum 1` |
| `captures[].crops` | array of object | yes |  | - `items: no other fields` |
| `captures[].crops[].id` | string | yes |  | - `pattern ^crop_[A-Za-z0-9_-]{1,40}$` |
| `captures[].crops[].media_id` | string | yes |  | - `pattern ^med_[0-9A-HJKMNP-TV-Z]{26}$` |
| `captures[].crops[].y` | integer | yes |  | - `minimum 0` |
| `captures[].crops[].height` | integer | yes |  | - `minimum 1` |
| `captures[].dom` | object \| null |  |  |  |
| `captures[].extras` | object \| null |  |  |  |
| `captures[].skip` | string \| null |  | Why the capture did not happen: robots\_disallowed, not\_public, no\_chrome, timeout, … | - `maxLength 200` |
| `captures[].cached` | boolean |  |  |  |
| `analysis` | array of object | yes |  | - `items: no other fields` |
| `analysis[].source_id` | string | yes |  | - `pattern ^src_[A-Za-z0-9_-]{1,40}$` |
| `analysis[].url` | string | yes |  | - `pattern ^https?://`<br>- `format uri` |
| `analysis[].summary` | string | yes |  | - `maxLength 4000` |
| `analysis[].first_impression` | string |  |  | - `maxLength 2000` |
| `analysis[].hierarchy` | string |  |  | - `maxLength 2000` |
| `analysis[].density` | string |  |  | - `maxLength 2000` |
| `analysis[].type` | string |  |  | - `maxLength 2000` |
| `analysis[].colour` | string |  |  | - `maxLength 2000` |
| `analysis[].motion` | string |  |  | - `maxLength 2000` |
| `analysis[].words` | string |  |  | - `maxLength 2000` |
| `analysis[].strengths` | array of string | yes |  | - `maxItems 12`<br>- `items: maxLength 600` |
| `analysis[].weaknesses` | array of string | yes |  | - `maxItems 12`<br>- `items: maxLength 600` |
| `analysis[].accessibility` | string \| null |  |  | - `maxLength 2000` |
| `analysis[].speed` | string \| null |  |  | - `maxLength 2000` |
| `analysis[].evidence` | `https://openvibe.network/contracts/ai/deep-dive.v1.json#/$defs/evidence` | yes |  |  |
| `synthesis` | object | yes |  | - `no other fields` |
| `synthesis.patterns` | array of object | yes |  | - `items: no other fields` |
| `synthesis.patterns[].name` | string | yes |  | - `maxLength 160` |
| `synthesis.patterns[].what` | string | yes |  | - `maxLength 1200` |
| `synthesis.patterns[].sites` | array of string | yes |  | - `maxItems 30`<br>- `items: pattern ^src_[A-Za-z0-9_-]{1,40}$` |
| `synthesis.patterns[].usage_count` | integer |  |  | - `minimum 0`<br>- `maximum 30` |
| `synthesis.patterns[].evidence` | `https://openvibe.network/contracts/ai/deep-dive.v1.json#/$defs/evidence` | yes |  |  |
| `synthesis.comparison` | object | yes |  | - `no other fields` |
| `synthesis.comparison.columns` | array of string | yes |  | - `maxItems 12`<br>- `items: maxLength 120` |
| `synthesis.comparison.rows` | array of array | yes |  | - `items: maxItems 12` |
| `synthesis.best` | object | yes |  | - `no other fields` |
| `synthesis.best.source_id` | string | yes |  | - `pattern ^src_[A-Za-z0-9_-]{1,40}$` |
| `synthesis.best.what` | string | yes |  | - `maxLength 2000` |
| `synthesis.best.evidence` | `https://openvibe.network/contracts/ai/deep-dive.v1.json#/$defs/evidence` | yes |  |  |
| `synthesis.mistakes` | array of object | yes |  | - `items: no other fields` |
| `synthesis.mistakes[].what` | string | yes |  | - `maxLength 1200` |
| `synthesis.mistakes[].evidence` | `https://openvibe.network/contracts/ai/deep-dive.v1.json#/$defs/evidence` | yes |  |  |
| `synthesis.gap` | string | yes |  | - `maxLength 2000` |
| `synthesis.reference_tokens` | object | yes |  | - `no other fields` |
| `synthesis.reference_tokens.palettes` | array of object | yes |  | - `items: no other fields` |
| `synthesis.reference_tokens.palettes[].source_id` | string | yes |  | - `pattern ^src_[A-Za-z0-9_-]{1,40}$` |
| `synthesis.reference_tokens.palettes[].colours` | array of string | yes |  | - `maxItems 16`<br>- `items: maxLength 40` |
| `synthesis.reference_tokens.type_scales` | array of object | yes |  | - `items: no other fields` |
| `synthesis.reference_tokens.type_scales[].source_id` | string | yes |  | - `pattern ^src_[A-Za-z0-9_-]{1,40}$` |
| `synthesis.reference_tokens.type_scales[].families` | array of string | yes |  | - `maxItems 8`<br>- `items: maxLength 120` |
| `synthesis.reference_tokens.type_scales[].sizes` | array of string | yes |  | - `maxItems 16`<br>- `items: maxLength 40` |
| `synthesis.reference_tokens.spacing` | array of object | yes |  | - `items: no other fields` |
| `synthesis.reference_tokens.spacing[].source_id` | string | yes |  | - `pattern ^src_[A-Za-z0-9_-]{1,40}$` |
| `synthesis.reference_tokens.spacing[].steps` | array of string | yes |  | - `maxItems 16`<br>- `items: maxLength 40` |
| `synthesis.do` | array of string | yes |  | - `maxItems 20`<br>- `items: maxLength 600` |
| `synthesis.dont` | array of string | yes |  | - `maxItems 20`<br>- `items: maxLength 600` |
| `synthesis.accessibility` | array of string | yes |  | - `maxItems 20`<br>- `items: maxLength 600` |
| `synthesis.speed` | array of string | yes |  | - `maxItems 20`<br>- `items: maxLength 600` |
| `recommendations` | array of object | yes |  | - `items: no other fields` |
| `recommendations[].id` | string | yes |  | - `pattern ^rec_[A-Za-z0-9_-]{1,40}$` |
| `recommendations[].what` | string | yes |  | - `maxLength 1200` |
| `recommendations[].why` | string | yes |  | - `maxLength 2000` |
| `recommendations[].rule` | object | yes |  | - `no other fields` |
| `recommendations[].rule.id` | string \| null |  |  | - `maxLength 120` |
| `recommendations[].rule.status` | enum | yes |  | - `one of "follows", "would_change", "none"` |
| `recommendations[].rule.text` | string | yes |  | - `maxLength 600` |
| `recommendations[].evidence` | `https://openvibe.network/contracts/ai/deep-dive.v1.json#/$defs/evidence` | yes |  |  |
| `receipt` | object | yes |  | - `no other fields` |
| `receipt.price_usd` | number | yes |  | - `minimum 0` |
| `receipt.held_usd` | number | yes |  | - `minimum 0` |
| `receipt.cost_usd` | number | yes |  | - `minimum 0` |
| `receipt.captures_count` | integer | yes |  | - `minimum 0` |
| `receipt.synthetic` | boolean | yes |  |  |
| `receipt.models` | array of object | yes |  | - `items: no other fields` |
| `receipt.models[].step` | enum | yes |  | - `one of "plan", "choose", "analyse", "synthesise"` |
| `receipt.models[].provider` | string \| null | yes |  | - `maxLength 80` |
| `receipt.models[].model` | string \| null | yes |  | - `maxLength 200` |
| `receipt.models[].tokens_in` | integer | yes |  | - `minimum 0` |
| `receipt.models[].tokens_out` | integer | yes |  | - `minimum 0` |
| `receipt.models[].cost_usd` | number | yes |  | - `minimum 0` |
| `receipt.models[].ms` | integer | yes |  | - `minimum 0` |
| `gaps` | array of string | yes |  | - `maxItems 40`<br>- `items: maxLength 400` |
| `created_at` | string | yes |  | - `format date-time` |
| `updated_at` | string | yes |  | - `format date-time` |
| `finished_at` | string \| null |  |  | - `format date-time` |

## Examples

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

 Valid: quick-robot-panel

~~~~
{
  "id": "run_01JAB2C3D4E5F6G7H8J9K0MNPQ",
  "schema": "ai.deep-dive@1",
  "run_id": "run_01JAB2C3D4E5F6G7H8J9K0MNPQ",
  "status": "succeeded",
  "input": {
    "question": "a phone-first robot control panel",
    "depth": "quick",
    "max_sites": 6,
    "sites": [
      "https://example.com/robot"
    ]
  },
  "steps": [
    {
      "key": "plan",
      "status": "done",
      "detail": "wrote 9 expert questions",
      "started_at": "2026-11-11T10:00:00.000Z",
      "finished_at": "2026-11-11T10:00:02.000Z"
    },
    {
      "key": "search",
      "status": "done",
      "detail": "4 engines, 12 sources",
      "started_at": "2026-11-11T10:00:02.000Z",
      "finished_at": "2026-11-11T10:00:40.000Z"
    },
    {
      "key": "choose",
      "status": "done",
      "detail": "6 sites chosen",
      "started_at": "2026-11-11T10:00:40.000Z",
      "finished_at": "2026-11-11T10:00:42.000Z"
    },
    {
      "key": "capture",
      "status": "done",
      "detail": "12 captures",
      "started_at": "2026-11-11T10:00:42.000Z",
      "finished_at": "2026-11-11T10:02:30.000Z"
    },
    {
      "key": "analyse",
      "status": "done",
      "detail": "6 sites read",
      "started_at": "2026-11-11T10:02:30.000Z",
      "finished_at": "2026-11-11T10:03:05.000Z"
    },
    {
      "key": "synthesise",
      "status": "done",
      "detail": "8 patterns",
      "started_at": "2026-11-11T10:03:05.000Z",
      "finished_at": "2026-11-11T10:03:20.000Z"
    },
    {
      "key": "report",
      "status": "done",
      "detail": "report ready",
      "started_at": "2026-11-11T10:03:20.000Z",
      "finished_at": "2026-11-11T10:03:21.000Z"
    }
  ],
  "sources": [
    {
      "id": "src_1",
      "kind": "web",
      "title": "A phone-first robot control panel",
      "url": "https://example.com/robot",
      "publisher": "example.com",
      "engine": "openvibe",
      "snippet": "A control panel laid out for one thumb.",
      "license": null,
      "read_at": "2026-11-11T10:00:10.000Z"
    }
  ],
  "captures": [
    {
      "id": "cap_1",
      "source_id": "src_1",
      "url": "https://example.com/robot",
      "final_url": "https://example.com/robot",
      "title": "A phone-first robot control panel",
      "captured_at": "2026-11-11T10:00:45.000Z",
      "viewport": 390,
      "theme": "light",
      "full_page": true,
      "media_id": "med_01JAB2C3D4E5F6G7H8J9K0MNPQ",
      "width": 390,
      "height": 2400,
      "crops": [
        {
          "id": "crop_1",
          "media_id": "med_01JAB2C3D4E5F6G7H8J9K0MNPR",
          "y": 0,
          "height": 844
        },
        {
          "id": "crop_2",
          "media_id": "med_01JAB2C3D4E5F6G7H8J9K0MNPS",
          "y": 844,
          "height": 844
        }
      ],
      "dom": {
        "fonts": {
          "families": [
            "Inter"
          ],
          "sizes": [
            "14px",
            "16px",
            "28px"
          ]
        },
        "colours": [
          {
            "value": "rgb(12, 14, 18)",
            "share": 0.71
          }
        ]
      },
      "extras": null,
      "skip": null,
      "cached": false
    }
  ],
  "analysis": [
    {
      "source_id": "src_1",
      "url": "https://example.com/robot",
      "summary": "One thumb reaches every primary control; the live camera fills the first screen.",
      "first_impression": "The robot's camera frame is the page.",
      "hierarchy": "One headline, one live frame, then the controls.",
      "density": "Spacious; four controls per screen.",
      "type": "One family, three sizes.",
      "colour": "Near-black on white with a single amber action.",
      "motion": "The frame pulses when connected.",
      "words": "Verbs on buttons, state in the status line.",
      "strengths": [
        "Every control sits in the bottom third",
        "State is written, not only coloured"
      ],
      "weaknesses": [
        "The Stop button is the same size as the rest"
      ],
      "accessibility": "The stop button has no accessible name.",
      "speed": "The first frame arrived once the socket opened; no skeleton.",
      "evidence": [
        {
          "claim": "Controls sit in the bottom third",
          "source_id": "src_1",
          "capture_id": "cap_1",
          "crop_id": "crop_2",
          "url": "https://example.com/robot",
          "read_at": "2026-11-11T10:00:45.000Z"
        },
        {
          "claim": "The stop button has no accessible name",
          "source_id": "src_1",
          "capture_id": "cap_1",
          "crop_id": null,
          "url": "https://example.com/robot",
          "read_at": "2026-11-11T10:00:45.000Z"
        }
      ]
    }
  ],
  "synthesis": {
    "patterns": [
      {
        "name": "Live view first",
        "what": "The camera or state view is the whole first screen, controls below it.",
        "sites": [
          "src_1"
        ],
        "usage_count": 1,
        "evidence": [
          {
            "claim": "The frame is the first screen",
            "source_id": "src_1",
            "capture_id": "cap_1",
            "crop_id": "crop_1",
            "url": "https://example.com/robot",
            "read_at": "2026-11-11T10:00:45.000Z"
          }
        ]
      }
    ],
    "comparison": {
      "columns": [
        "Site",
        "First screen",
        "Controls"
      ],
      "rows": [
        [
          "example.com",
          "live frame",
          "bottom third"
        ]
      ]
    },
    "best": {
      "source_id": "src_1",
      "what": "The live frame doubles as the connection state.",
      "evidence": [
        {
          "claim": "The frame carries the status line",
          "source_id": "src_1",
          "capture_id": "cap_1",
          "crop_id": "crop_1",
          "url": "https://example.com/robot",
          "read_at": "2026-11-11T10:00:45.000Z"
        }
      ]
    },
    "mistakes": [
      {
        "what": "The Stop button is not separated from the other controls.",
        "evidence": [
          {
            "claim": "All buttons share one row",
            "source_id": "src_1",
            "capture_id": "cap_1",
            "crop_id": "crop_2",
            "url": "https://example.com/robot",
            "read_at": "2026-11-11T10:00:45.000Z"
          }
        ]
      }
    ],
    "gap": "No control panel shows what the robot is about to do before the tap is sent.",
    "reference_tokens": {
      "palettes": [
        {
          "source_id": "src_1",
          "colours": [
            "#0c0e12",
            "#ffffff",
            "#f5a623"
          ]
        }
      ],
      "type_scales": [
        {
          "source_id": "src_1",
          "families": [
            "Inter"
          ],
          "sizes": [
            "14px",
            "16px",
            "28px"
          ]
        }
      ],
      "spacing": [
        {
          "source_id": "src_1",
          "steps": [
            "4px",
            "8px",
            "16px",
            "24px"
          ]
        }
      ]
    },
    "do": [
      "Keep every primary control in the thumb reach of one hand"
    ],
    "dont": [
      "Do not make the stop control share the row of ordinary actions"
    ],
    "accessibility": [
      "Name every icon-only control"
    ],
    "speed": [
      "Show the frame before the socket finishes connecting"
    ]
  },
  "recommendations": [
    {
      "id": "rec_1",
      "what": "Put the Stop button alone, at the bottom.",
      "why": "The best panel suggests it by layout; the failure here is that it does not.",
      "rule": {
        "id": "control.destructive-separation",
        "status": "follows",
        "text": "Destructive actions are separated from ordinary ones."
      },
      "evidence": [
        {
          "claim": "The stop shares the row",
          "source_id": "src_1",
          "capture_id": "cap_1",
          "crop_id": "crop_2",
          "url": "https://example.com/robot",
          "read_at": "2026-11-11T10:00:45.000Z"
        }
      ]
    }
  ],
  "receipt": {
    "price_usd": 0.2,
    "held_usd": 0.2,
    "cost_usd": 0.014,
    "captures_count": 12,
    "synthetic": false,
    "models": [
      {
        "step": "plan",
        "provider": "deepseek",
        "model": "deepseek-v4-flash",
        "tokens_in": 900,
        "tokens_out": 320,
        "cost_usd": 0.0004,
        "ms": 1800
      },
      {
        "step": "choose",
        "provider": "deepseek",
        "model": "deepseek-v4-flash",
        "tokens_in": 2400,
        "tokens_out": 500,
        "cost_usd": 0.0007,
        "ms": 2100
      },
      {
        "step": "analyse",
        "provider": "deepseek",
        "model": "deepseek-v4-pro",
        "tokens_in": 12000,
        "tokens_out": 4000,
        "cost_usd": 0.012,
        "ms": 26000
      },
      {
        "step": "synthesise",
        "provider": "deepseek",
        "model": "deepseek-v4-pro",
        "tokens_in": 6000,
        "tokens_out": 2500,
        "cost_usd": 0.007,
        "ms": 12000
      }
    ]
  },
  "gaps": [
    "No Expert extras were measured at Quick depth."
  ],
  "created_at": "2026-11-11T10:00:00.000Z",
  "updated_at": "2026-11-11T10:03:21.000Z",
  "finished_at": "2026-11-11T10:03:21.000Z"
}
~~~~

Rejected: unknown-status

~~~~
{
  "id": "run_01JAB2C3D4E5F6G7H8J9K0MNPQ",
  "schema": "ai.deep-dive@1",
  "run_id": "run_01JAB2C3D4E5F6G7H8J9K0MNPQ",
  "status": "finished",
  "input": {
    "question": "a phone-first robot control panel",
    "depth": "quick",
    "max_sites": 6
  },
  "steps": [],
  "sources": [],
  "captures": [],
  "analysis": [],
  "synthesis": {
    "patterns": [],
    "comparison": {
      "columns": [],
      "rows": []
    },
    "best": {
      "source_id": "src_1",
      "what": "x",
      "evidence": []
    },
    "mistakes": [],
    "gap": "",
    "reference_tokens": {
      "palettes": [],
      "type_scales": [],
      "spacing": []
    },
    "do": [],
    "dont": [],
    "accessibility": [],
    "speed": []
  },
  "recommendations": [],
  "receipt": {
    "price_usd": 0.2,
    "held_usd": 0.2,
    "cost_usd": 0,
    "models": [],
    "captures_count": 0,
    "synthetic": false
  },
  "gaps": [],
  "created_at": "2026-11-11T10:00:00.000Z",
  "updated_at": "2026-11-11T10:03:21.000Z"
}
~~~~

## Validate

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