fluid-core/schemas/experiment.schema.json
tegwick fbbf56df7a Add FLUID wire contract schemas
Nine JSON Schemas covering the five record types from the schema spec,
plus backend requirements, feedback, the revision descriptor, routing
policy and the telemetry envelope. These are the integration boundary:
readable without any fluid-core code, so adapters may be written in any
language.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014KmVxhJ35tCo7rE7UnLwWu

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 1116572@bnt-lap001
Assistant-Session: 8ba9bb93-a72a-4883-b189-2499cce5c400
2026-09-04 01:55:47 +02:00

99 lines
4.5 KiB
JSON

{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://fluid.dev/schemas/experiment.schema.json",
"title": "FLUID experiment record",
"description": "Connects hypotheses to revisions under bounded conditions. Experiments must be interruptible (ArchitectureBlueprint.md section 16).",
"type": "object",
"properties": {
"fluid_experiment": {
"type": "object",
"properties": {
"schema_version": { "$ref": "common.schema.json#/$defs/schemaVersion" },
"id": { "$ref": "common.schema.json#/$defs/experimentId" },
"interface_id": { "$ref": "common.schema.json#/$defs/interfaceId" },
"hypothesis_refs": {
"type": "array",
"items": { "$ref": "common.schema.json#/$defs/hypothesisId" },
"minItems": 1,
"description": "An experiment without a hypothesis measures nothing in particular."
},
"mechanism": {
"enum": ["sandbox", "shadow", "synthetic", "replay", "canary", "opt_in", "cohort", "tenant", "percentage"]
},
"control_revision": { "$ref": "common.schema.json#/$defs/revisionId" },
"candidate_revisions": {
"type": "array",
"items": { "$ref": "common.schema.json#/$defs/revisionId" },
"minItems": 1
},
"cohorts": { "type": "array", "items": { "$ref": "common.schema.json#/$defs/cohortId" } },
"allocation": {
"type": "object",
"description": "Shares by revision id or by the reserved key 'control'. Allocation is deterministic and enacted by the router, never by this record.",
"additionalProperties": { "$ref": "common.schema.json#/$defs/unitInterval" },
"minProperties": 2
},
"start_at": { "$ref": "common.schema.json#/$defs/timestamp" },
"planned_end_at": { "oneOf": [{ "$ref": "common.schema.json#/$defs/timestamp" }, { "type": "null" }] },
"max_duration_hours": { "type": "number", "exclusiveMinimum": 0 },
"metrics": {
"type": "object",
"description": "Primary metrics and guardrails are kept distinct so a scalar can never hide a regression (ArchitectureBlueprint.md section 48.5).",
"properties": {
"primary": { "type": "array", "items": { "type": "string" }, "minItems": 1 },
"guardrails": { "type": "array", "items": { "type": "string" } },
"secondary": { "type": "array", "items": { "type": "string" } },
"learning": { "type": "array", "items": { "type": "string" } }
},
"required": ["primary"],
"additionalProperties": false
},
"start_conditions": { "type": "array", "items": { "type": "string" } },
"stop_conditions": {
"type": "array",
"items": { "type": "string" },
"minItems": 1,
"description": "Every experiment has a stop condition (ArchitectureBlueprint.md section 55, invariant 7)."
},
"amendments": {
"type": "array",
"description": "Success criteria may not be changed after results are visible without recording the amendment (ArchitectureBlueprint.md section 18).",
"items": {
"type": "object",
"properties": {
"at": { "$ref": "common.schema.json#/$defs/timestamp" },
"actor": { "$ref": "common.schema.json#/$defs/actor" },
"change": { "type": "string", "minLength": 1 },
"reason": { "type": "string", "minLength": 1 }
},
"required": ["at", "actor", "change", "reason"],
"additionalProperties": false
}
},
"result": {
"type": "object",
"properties": {
"state": { "enum": ["PLANNED", "RUNNING", "STOPPED", "COMPLETED", "ABANDONED"] },
"preferred_revision": { "oneOf": [{ "$ref": "common.schema.json#/$defs/revisionId" }, { "type": "null" }] },
"stopped_reason": { "type": ["string", "null"] },
"evidence_refs": { "type": "array", "items": { "$ref": "common.schema.json#/$defs/evidenceRef" } }
},
"required": ["state"],
"additionalProperties": false
}
},
"required": [
"schema_version", "id", "interface_id", "hypothesis_refs",
"control_revision", "candidate_revisions", "allocation",
"metrics", "stop_conditions", "result"
],
"additionalProperties": false
}
},
"required": ["fluid_experiment"],
"additionalProperties": false
}