AiDeepDive ai.deep-dive@1

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

Version
1.0.0
Owner
ai
Visibility
public
Status
active
Compatibility
backward
Decision
ADR-015
Schema
https://openvibe.network/contracts/ai/deep-dive.v1.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

FieldTypeRequiredDescriptionConstraints
idstringyesThe run id; a deep dive is a run (GET /api/v1/deep-dives/{id}).
  • pattern ^run_[0-9A-HJKMNP-TV-Z]{26}$
schemaconstyes
  • = "ai.deep-dive@1"
run_idstringyes
  • pattern ^run_[0-9A-HJKMNP-TV-Z]{26}$
statusenumyes
  • one of "queued", "running", "choosing", "succeeded", "failed", "cancelled"
inputobjectyes
  • no other fields
input.questionstringyes
  • minLength 1
  • maxLength 500
input.depthenumyes
  • one of "quick", "thorough", "expert"
input.max_sitesintegeryes
  • minimum 1
  • maximum 30
input.sitesarray of stringSites the person named when starting the run.
  • maxItems 30
  • items: pattern ^https?://
  • items: format uri
stepsarray of objectyes
  • items: no other fields
steps[].keyenumyes
  • one of "plan", "search", "choose", "capture", "analyse", "synthesise", "report"
steps[].statusenumyes
  • one of "pending", "running", "done", "skipped", "failed"
steps[].detailstring | null
  • maxLength 300
steps[].started_atstring | null
  • format date-time
steps[].finished_atstring | null
  • format date-time
sourcesarray of objectyes
  • items: no other fields
sources[].idstringyes
  • pattern ^src_[A-Za-z0-9_-]{1,40}$
sources[].kindenumyes
  • one of "web", "picture", "icon", "project", "rules", "component", "named"
sources[].titlestringyes
  • maxLength 400
sources[].urlstringyes
  • pattern ^https?://
  • format uri
sources[].publisherstring | null
  • maxLength 200
sources[].enginestring | null
  • maxLength 80
sources[].snippetstring | null
  • maxLength 2000
sources[].licensestring | null
  • maxLength 120
sources[].read_atstringyes
  • format date-time
capturesarray of objectyes
  • items: no other fields
captures[].idstringyes
  • pattern ^cap_[A-Za-z0-9_-]{1,40}$
captures[].source_idstringyes
  • pattern ^src_[A-Za-z0-9_-]{1,40}$
captures[].urlstringyes
  • pattern ^https?://
  • format uri
captures[].final_urlstring | null
  • pattern ^https?://
  • format uri
captures[].titlestring | null
  • maxLength 400
captures[].captured_atstringyes
  • format date-time
captures[].viewportenumyes
  • one of 390, 1280
captures[].themeenumyes
  • one of "light", "dark"
captures[].full_pagebooleanyes
captures[].media_idstring | null
  • pattern ^med_[0-9A-HJKMNP-TV-Z]{26}$
captures[].widthinteger | null
  • minimum 1
captures[].heightinteger | null
  • minimum 1
captures[].cropsarray of objectyes
  • items: no other fields
captures[].crops[].idstringyes
  • pattern ^crop_[A-Za-z0-9_-]{1,40}$
captures[].crops[].media_idstringyes
  • pattern ^med_[0-9A-HJKMNP-TV-Z]{26}$
captures[].crops[].yintegeryes
  • minimum 0
captures[].crops[].heightintegeryes
  • minimum 1
captures[].domobject | null
captures[].extrasobject | null
captures[].skipstring | nullWhy the capture did not happen: robots_disallowed, not_public, no_chrome, timeout, …
  • maxLength 200
captures[].cachedboolean
analysisarray of objectyes
  • items: no other fields
analysis[].source_idstringyes
  • pattern ^src_[A-Za-z0-9_-]{1,40}$
analysis[].urlstringyes
  • pattern ^https?://
  • format uri
analysis[].summarystringyes
  • maxLength 4000
analysis[].first_impressionstring
  • maxLength 2000
analysis[].hierarchystring
  • maxLength 2000
analysis[].densitystring
  • maxLength 2000
analysis[].typestring
  • maxLength 2000
analysis[].colourstring
  • maxLength 2000
analysis[].motionstring
  • maxLength 2000
analysis[].wordsstring
  • maxLength 2000
analysis[].strengthsarray of stringyes
  • maxItems 12
  • items: maxLength 600
analysis[].weaknessesarray of stringyes
  • maxItems 12
  • items: maxLength 600
analysis[].accessibilitystring | null
  • maxLength 2000
analysis[].speedstring | null
  • maxLength 2000
analysis[].evidencehttps://openvibe.network/contracts/ai/deep-dive.v1.json#/$defs/evidenceyes
synthesisobjectyes
  • no other fields
synthesis.patternsarray of objectyes
  • items: no other fields
synthesis.patterns[].namestringyes
  • maxLength 160
synthesis.patterns[].whatstringyes
  • maxLength 1200
synthesis.patterns[].sitesarray of stringyes
  • maxItems 30
  • items: pattern ^src_[A-Za-z0-9_-]{1,40}$
synthesis.patterns[].usage_countinteger
  • minimum 0
  • maximum 30
synthesis.patterns[].evidencehttps://openvibe.network/contracts/ai/deep-dive.v1.json#/$defs/evidenceyes
synthesis.comparisonobjectyes
  • no other fields
synthesis.comparison.columnsarray of stringyes
  • maxItems 12
  • items: maxLength 120
synthesis.comparison.rowsarray of arrayyes
  • items: maxItems 12
synthesis.bestobjectyes
  • no other fields
synthesis.best.source_idstringyes
  • pattern ^src_[A-Za-z0-9_-]{1,40}$
synthesis.best.whatstringyes
  • maxLength 2000
synthesis.best.evidencehttps://openvibe.network/contracts/ai/deep-dive.v1.json#/$defs/evidenceyes
synthesis.mistakesarray of objectyes
  • items: no other fields
synthesis.mistakes[].whatstringyes
  • maxLength 1200
synthesis.mistakes[].evidencehttps://openvibe.network/contracts/ai/deep-dive.v1.json#/$defs/evidenceyes
synthesis.gapstringyes
  • maxLength 2000
synthesis.reference_tokensobjectyes
  • no other fields
synthesis.reference_tokens.palettesarray of objectyes
  • items: no other fields
synthesis.reference_tokens.palettes[].source_idstringyes
  • pattern ^src_[A-Za-z0-9_-]{1,40}$
synthesis.reference_tokens.palettes[].coloursarray of stringyes
  • maxItems 16
  • items: maxLength 40
synthesis.reference_tokens.type_scalesarray of objectyes
  • items: no other fields
synthesis.reference_tokens.type_scales[].source_idstringyes
  • pattern ^src_[A-Za-z0-9_-]{1,40}$
synthesis.reference_tokens.type_scales[].familiesarray of stringyes
  • maxItems 8
  • items: maxLength 120
synthesis.reference_tokens.type_scales[].sizesarray of stringyes
  • maxItems 16
  • items: maxLength 40
synthesis.reference_tokens.spacingarray of objectyes
  • items: no other fields
synthesis.reference_tokens.spacing[].source_idstringyes
  • pattern ^src_[A-Za-z0-9_-]{1,40}$
synthesis.reference_tokens.spacing[].stepsarray of stringyes
  • maxItems 16
  • items: maxLength 40
synthesis.doarray of stringyes
  • maxItems 20
  • items: maxLength 600
synthesis.dontarray of stringyes
  • maxItems 20
  • items: maxLength 600
synthesis.accessibilityarray of stringyes
  • maxItems 20
  • items: maxLength 600
synthesis.speedarray of stringyes
  • maxItems 20
  • items: maxLength 600
recommendationsarray of objectyes
  • items: no other fields
recommendations[].idstringyes
  • pattern ^rec_[A-Za-z0-9_-]{1,40}$
recommendations[].whatstringyes
  • maxLength 1200
recommendations[].whystringyes
  • maxLength 2000
recommendations[].ruleobjectyes
  • no other fields
recommendations[].rule.idstring | null
  • maxLength 120
recommendations[].rule.statusenumyes
  • one of "follows", "would_change", "none"
recommendations[].rule.textstringyes
  • maxLength 600
recommendations[].evidencehttps://openvibe.network/contracts/ai/deep-dive.v1.json#/$defs/evidenceyes
receiptobjectyes
  • no other fields
receipt.price_usdnumberyes
  • minimum 0
receipt.held_usdnumberyes
  • minimum 0
receipt.cost_usdnumberyes
  • minimum 0
receipt.captures_countintegeryes
  • minimum 0
receipt.syntheticbooleanyes
receipt.modelsarray of objectyes
  • items: no other fields
receipt.models[].stepenumyes
  • one of "plan", "choose", "analyse", "synthesise"
receipt.models[].providerstring | nullyes
  • maxLength 80
receipt.models[].modelstring | nullyes
  • maxLength 200
receipt.models[].tokens_inintegeryes
  • minimum 0
receipt.models[].tokens_outintegeryes
  • minimum 0
receipt.models[].cost_usdnumberyes
  • minimum 0
receipt.models[].msintegeryes
  • minimum 0
gapsarray of stringyes
  • maxItems 40
  • items: maxLength 400
created_atstringyes
  • format date-time
updated_atstringyes
  • format date-time
finished_atstring | 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 }] }