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
This commit is contained in:
parent
7d2fc2af5d
commit
fbbf56df7a
11 changed files with 1242 additions and 0 deletions
83
schemas/backend-requirement.schema.json
Normal file
83
schemas/backend-requirement.schema.json
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "https://fluid.dev/schemas/backend-requirement.schema.json",
|
||||
"title": "FLUID backend capability requirement",
|
||||
"description": "Capability the interface needs but has no authority to build. FLUID escalates rather than crossing the boundary (FluidAPIStandards.md section 30).",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"fluid_backend_requirement": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"schema_version": { "$ref": "common.schema.json#/$defs/schemaVersion" },
|
||||
"id": { "$ref": "common.schema.json#/$defs/backendRequirementId" },
|
||||
"originating_interface": { "$ref": "common.schema.json#/$defs/interfaceId" },
|
||||
"originating_revision": { "oneOf": [{ "$ref": "common.schema.json#/$defs/revisionId" }, { "type": "null" }] },
|
||||
"originating_hypothesis": { "oneOf": [{ "$ref": "common.schema.json#/$defs/hypothesisId" }, { "type": "null" }] },
|
||||
"backend_service": { "type": "string", "minLength": 1 },
|
||||
|
||||
"capability": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"title": { "type": "string", "minLength": 1 },
|
||||
"description": { "type": "string", "minLength": 1 }
|
||||
},
|
||||
"required": ["title", "description"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
|
||||
"semantics": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"consistency": { "type": "string" },
|
||||
"required_fields": { "type": "array", "items": { "type": "string" } }
|
||||
},
|
||||
"additionalProperties": true
|
||||
},
|
||||
|
||||
"quality": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"p95_latency_ms": { "type": "number", "minimum": 0 },
|
||||
"availability": { "$ref": "common.schema.json#/$defs/unitInterval" }
|
||||
},
|
||||
"additionalProperties": true
|
||||
},
|
||||
|
||||
"security": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"authorization_scope": { "type": "string" },
|
||||
"tenant_isolation": { "type": "string" }
|
||||
},
|
||||
"additionalProperties": true
|
||||
},
|
||||
|
||||
"expected_usage": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"requests_per_day": { "type": "integer", "minimum": 0 }
|
||||
},
|
||||
"additionalProperties": true
|
||||
},
|
||||
|
||||
"urgency": { "enum": ["LOW", "MEDIUM", "HIGH"] },
|
||||
|
||||
"disposition": {
|
||||
"type": "object",
|
||||
"description": "The backend decides. Repeated OUT_OF_SCOPE feeds boundary learning (ArchitectureBlueprint.md section 22).",
|
||||
"properties": {
|
||||
"state": { "enum": ["OPEN", "ACCEPTED", "PLANNED", "AVAILABLE", "PARTIALLY_AVAILABLE", "OUT_OF_SCOPE", "REJECTED", "SUPERSEDED"] },
|
||||
"reason": { "type": ["string", "null"] },
|
||||
"target_ref": { "type": ["string", "null"] }
|
||||
},
|
||||
"required": ["state"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["schema_version", "id", "originating_interface", "backend_service", "capability", "disposition"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["fluid_backend_requirement"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
161
schemas/common.schema.json
Normal file
161
schemas/common.schema.json
Normal file
|
|
@ -0,0 +1,161 @@
|
|||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "https://fluid.dev/schemas/common.schema.json",
|
||||
"title": "FLUID common definitions",
|
||||
"description": "Shared identifier, reference and measurement types. Identifier prefixes follow FluidHypothesisRevisionSchema.md section 16.",
|
||||
"$defs": {
|
||||
"schemaVersion": {
|
||||
"type": "string",
|
||||
"const": "0.1"
|
||||
},
|
||||
"interfaceId": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"pattern": "^[a-z0-9]([a-z0-9-]*[a-z0-9])?$",
|
||||
"description": "Stable identifier of the owning interface."
|
||||
},
|
||||
"hypothesisId": { "type": "string", "pattern": "^H-[0-9A-Za-z_-]+$" },
|
||||
"revisionId": { "type": "string", "pattern": "^R-[0-9A-Za-z_-]+$" },
|
||||
"experimentId": { "type": "string", "pattern": "^E-[0-9A-Za-z_-]+$" },
|
||||
"pressureId": { "type": "string", "pattern": "^P-[0-9A-Za-z_-]+$" },
|
||||
"backendRequirementId": { "type": "string", "pattern": "^BR-[0-9A-Za-z_-]+$" },
|
||||
"decisionId": { "type": "string", "pattern": "^D-[0-9A-Za-z_-]+$" },
|
||||
"eventId": { "type": "string", "pattern": "^EV-[0-9A-Za-z_-]+$" },
|
||||
"feedbackId": { "type": "string", "pattern": "^F-[0-9A-Za-z_-]+$" },
|
||||
"cohortId": { "type": "string", "minLength": 1 },
|
||||
|
||||
"timestamp": { "type": "string", "format": "date-time" },
|
||||
|
||||
"evidenceRef": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"description": "Opaque reference into the evidence store, conventionally '<kind>:<locator>' such as 'telemetry:invoice-pattern-2026w36'."
|
||||
},
|
||||
"artifactRef": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"description": "Opaque reference into the artifact store."
|
||||
},
|
||||
"digest": {
|
||||
"type": "string",
|
||||
"pattern": "^sha256:[a-f0-9]{64}$",
|
||||
"description": "Content address of an artifact."
|
||||
},
|
||||
|
||||
"actor": {
|
||||
"type": "object",
|
||||
"description": "Who or what performed an action. FLUID distinguishes these because trust levels differ (ArchitectureBlueprint.md section 47).",
|
||||
"properties": {
|
||||
"type": { "enum": ["human", "daimon", "policy", "system", "consumer"] },
|
||||
"id": { "type": "string", "minLength": 1 },
|
||||
"model_or_agent": { "type": "string" }
|
||||
},
|
||||
"required": ["type", "id"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
|
||||
"observationWindow": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"start": { "$ref": "common.schema.json#/$defs/timestamp" },
|
||||
"end": {
|
||||
"oneOf": [
|
||||
{ "$ref": "common.schema.json#/$defs/timestamp" },
|
||||
{ "type": "null" }
|
||||
],
|
||||
"description": "Null while the window is still open."
|
||||
}
|
||||
},
|
||||
"required": ["start"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
|
||||
"unitInterval": { "type": "number", "minimum": 0, "maximum": 1 },
|
||||
|
||||
"pressureClass": {
|
||||
"enum": [
|
||||
"natural_usage",
|
||||
"successful_but_inefficient_usage",
|
||||
"recoverable_misunderstanding",
|
||||
"repeated_expectation_mismatch",
|
||||
"poor_discoverability",
|
||||
"missing_interface_capability",
|
||||
"missing_backend_capability",
|
||||
"out_of_scope_demand",
|
||||
"prohibited_demand",
|
||||
"implementation_failure"
|
||||
],
|
||||
"description": "FluidAPIStandards.md section 13."
|
||||
},
|
||||
|
||||
"adaptationClass": {
|
||||
"enum": ["presentation", "contract", "composition", "implementation", "requirement_escalation"],
|
||||
"description": "FluidAPIStandards.md section 16."
|
||||
},
|
||||
|
||||
"guardrail": {
|
||||
"type": "object",
|
||||
"description": "A constraint that must not regress beyond threshold. Guardrails are evaluated deterministically.",
|
||||
"properties": {
|
||||
"metric": { "type": "string", "minLength": 1 },
|
||||
"operator": { "enum": ["<", "<=", "==", "!=", ">=", ">"] },
|
||||
"threshold": { "type": ["number", "boolean", "string"] }
|
||||
},
|
||||
"required": ["metric", "operator", "threshold"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
|
||||
"expectedOutcome": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"metric": { "type": "string", "minLength": 1 },
|
||||
"cohort": { "type": "string" },
|
||||
"baseline": { "type": "number" },
|
||||
"target": { "type": "number" },
|
||||
"direction": { "enum": ["lower", "higher", "unchanged"] }
|
||||
},
|
||||
"required": ["metric", "target", "direction"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
|
||||
"complexityDelta": {
|
||||
"type": "object",
|
||||
"description": "Standard dimensions, implementation-defined scoring (FluidAPIStandards.md section 22).",
|
||||
"properties": {
|
||||
"surface_area": { "type": "number" },
|
||||
"concept_count": { "type": "number" },
|
||||
"operation_count": { "type": "number" },
|
||||
"parameter_dimensionality": { "type": "number" },
|
||||
"semantic_overlap": { "type": "number" },
|
||||
"alternative_path_count": { "type": "number" },
|
||||
"dependency_count": { "type": "number" },
|
||||
"backend_composition_count": { "type": "number" },
|
||||
"exception_count": { "type": "number" },
|
||||
"active_revision_count": { "type": "number" },
|
||||
"cognitive_load": { "type": "number" }
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
|
||||
"fitnessDimensions": {
|
||||
"type": "object",
|
||||
"description": "FluidAPIStandards.md section 20. No universal scalar is defined on purpose.",
|
||||
"properties": {
|
||||
"client_utility": { "type": "number" },
|
||||
"correctness": { "type": "number" },
|
||||
"reliability": { "type": "number" },
|
||||
"availability": { "type": "number" },
|
||||
"performance": { "type": "number" },
|
||||
"discoverability": { "type": "number" },
|
||||
"simplicity": { "type": "number" },
|
||||
"compatibility": { "type": "number" },
|
||||
"security": { "type": "number" },
|
||||
"maintainability": { "type": "number" },
|
||||
"operational_cost": { "type": "number" },
|
||||
"implementation_cost": { "type": "number" },
|
||||
"resource_consumption": { "type": "number" }
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
}
|
||||
35
schemas/event.schema.json
Normal file
35
schemas/event.schema.json
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "https://fluid.dev/schemas/event.schema.json",
|
||||
"title": "FLUID audit event",
|
||||
"description": "Append-only record of a material lifecycle transition. FLUID evolution is itself a system behavior that must remain reconstructable (FluidHypothesisRevisionSchema.md section 15).",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"fluid_event": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"schema_version": { "$ref": "common.schema.json#/$defs/schemaVersion" },
|
||||
"id": { "$ref": "common.schema.json#/$defs/eventId" },
|
||||
"occurred_at": { "$ref": "common.schema.json#/$defs/timestamp" },
|
||||
"entity_type": { "enum": ["pressure", "hypothesis", "revision", "experiment", "backend_requirement", "intent", "decision", "routing_policy"] },
|
||||
"entity_id": { "type": "string", "minLength": 1 },
|
||||
"event_type": { "type": "string", "minLength": 1 },
|
||||
"actor": { "$ref": "common.schema.json#/$defs/actor" },
|
||||
"inputs": {
|
||||
"type": "array",
|
||||
"items": { "type": "string" },
|
||||
"description": "Identifiers of the records this transition drew on."
|
||||
},
|
||||
"reason": { "type": "string" },
|
||||
"evidence_refs": {
|
||||
"type": "array",
|
||||
"items": { "$ref": "common.schema.json#/$defs/evidenceRef" }
|
||||
}
|
||||
},
|
||||
"required": ["schema_version", "id", "occurred_at", "entity_type", "entity_id", "event_type", "actor"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["fluid_event"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
99
schemas/experiment.schema.json
Normal file
99
schemas/experiment.schema.json
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
{
|
||||
"$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
|
||||
}
|
||||
40
schemas/feedback.schema.json
Normal file
40
schemas/feedback.schema.json
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "https://fluid.dev/schemas/feedback.schema.json",
|
||||
"title": "FLUID explicit consumer feedback",
|
||||
"description": "Structured feedback from a consumer. Treated as evidence and never as authority to change anything (FluidAPIStandards.md section 15).",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"fluid_feedback": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"schema_version": { "$ref": "common.schema.json#/$defs/schemaVersion" },
|
||||
"id": { "$ref": "common.schema.json#/$defs/feedbackId" },
|
||||
"interface_id": { "$ref": "common.schema.json#/$defs/interfaceId" },
|
||||
"received_at": { "$ref": "common.schema.json#/$defs/timestamp" },
|
||||
"cohort": { "$ref": "common.schema.json#/$defs/cohortId" },
|
||||
"revision": { "$ref": "common.schema.json#/$defs/revisionId" },
|
||||
"goal": { "type": "string" },
|
||||
"attempt": { "type": "string" },
|
||||
"attempted_operations": { "type": "array", "items": { "type": "string" } },
|
||||
"outcome": { "type": "string" },
|
||||
"missing_capability": { "type": "string" },
|
||||
"workaround": { "type": ["string", "array"], "items": { "type": "string" } },
|
||||
"impact": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"description": { "type": "string" },
|
||||
"calls": { "type": "integer", "minimum": 0 },
|
||||
"latency_ms": { "type": "number", "minimum": 0 }
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"confidence": { "$ref": "common.schema.json#/$defs/unitInterval" }
|
||||
},
|
||||
"required": ["schema_version", "id", "interface_id", "received_at", "goal"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["fluid_feedback"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
228
schemas/hypothesis.schema.json
Normal file
228
schemas/hypothesis.schema.json
Normal file
|
|
@ -0,0 +1,228 @@
|
|||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "https://fluid.dev/schemas/hypothesis.schema.json",
|
||||
"title": "FLUID hypothesis record",
|
||||
"description": "Why an interface change should be explored. Observation, explanation, prediction, intervention and result stay separate on purpose (FluidHypothesisRevisionSchema.md section 18).",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"fluid_hypothesis": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"schema_version": { "$ref": "common.schema.json#/$defs/schemaVersion" },
|
||||
"id": { "$ref": "common.schema.json#/$defs/hypothesisId" },
|
||||
"interface_id": { "$ref": "common.schema.json#/$defs/interfaceId" },
|
||||
"state": {
|
||||
"enum": ["DRAFT", "READY", "PRIORITIZED", "DESIGNING", "EXPERIMENTING", "EVALUATING", "ACCEPTED", "REJECTED", "SUPERSEDED", "DEFERRED"]
|
||||
},
|
||||
"created_at": { "$ref": "common.schema.json#/$defs/timestamp" },
|
||||
"created_by": { "$ref": "common.schema.json#/$defs/actor" },
|
||||
"title": { "type": "string", "minLength": 1 },
|
||||
|
||||
"observation": {
|
||||
"type": "object",
|
||||
"description": "What was seen. Not what it means.",
|
||||
"properties": {
|
||||
"summary": { "type": "string", "minLength": 1 },
|
||||
"evidence_refs": {
|
||||
"type": "array",
|
||||
"items": { "$ref": "common.schema.json#/$defs/evidenceRef" },
|
||||
"minItems": 1
|
||||
},
|
||||
"affected_cohorts": { "type": "array", "items": { "$ref": "common.schema.json#/$defs/cohortId" } },
|
||||
"observation_window": { "$ref": "common.schema.json#/$defs/observationWindow" }
|
||||
},
|
||||
"required": ["summary", "evidence_refs"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
|
||||
"pressure": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"classes": { "type": "array", "items": { "$ref": "common.schema.json#/$defs/pressureClass" }, "minItems": 1 },
|
||||
"pressure_refs": { "type": "array", "items": { "$ref": "common.schema.json#/$defs/pressureId" } },
|
||||
"severity": { "$ref": "common.schema.json#/$defs/unitInterval" },
|
||||
"confidence": { "$ref": "common.schema.json#/$defs/unitInterval" }
|
||||
},
|
||||
"required": ["classes"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
|
||||
"explanation": {
|
||||
"type": "object",
|
||||
"description": "What we think explains the observation.",
|
||||
"properties": {
|
||||
"claim": { "type": "string", "minLength": 1 },
|
||||
"reach": {
|
||||
"type": "object",
|
||||
"description": "Explanatory reach is a prioritization signal, never a correctness claim (FluidAPIStandards.md section 18).",
|
||||
"properties": {
|
||||
"score": { "type": "number" },
|
||||
"explains": { "type": "array", "items": { "$ref": "common.schema.json#/$defs/pressureId" } },
|
||||
"notes": { "type": "string" }
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["claim"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
|
||||
"proposed_adaptation": {
|
||||
"type": "object",
|
||||
"description": "What we propose to change.",
|
||||
"properties": {
|
||||
"class": { "$ref": "common.schema.json#/$defs/adaptationClass" },
|
||||
"summary": { "type": "string", "minLength": 1 },
|
||||
"candidate_contract": {
|
||||
"type": "object",
|
||||
"description": "Shape is protocol-specific and deliberately unconstrained.",
|
||||
"additionalProperties": true
|
||||
},
|
||||
"implementation_scope": { "enum": ["interface_only", "interface_and_backend", "documentation_only"] }
|
||||
},
|
||||
"required": ["class", "summary"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
|
||||
"backend_requirements": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"required": { "type": "boolean" },
|
||||
"requirement_refs": { "type": "array", "items": { "$ref": "common.schema.json#/$defs/backendRequirementId" } }
|
||||
},
|
||||
"required": ["required"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
|
||||
"expected_outcomes": {
|
||||
"type": "array",
|
||||
"items": { "$ref": "common.schema.json#/$defs/expectedOutcome" },
|
||||
"minItems": 1,
|
||||
"description": "A hypothesis must be falsifiable (FluidAPIStandards.md section 17)."
|
||||
},
|
||||
"guardrails": {
|
||||
"type": "array",
|
||||
"items": { "$ref": "common.schema.json#/$defs/guardrail" }
|
||||
},
|
||||
|
||||
"fitness_dimensions": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"expected": { "$ref": "common.schema.json#/$defs/fitnessDimensions" }
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
|
||||
"complexity": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"expected_delta": { "$ref": "common.schema.json#/$defs/complexityDelta" },
|
||||
"score": { "type": "number" }
|
||||
},
|
||||
"required": ["expected_delta"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
|
||||
"risk": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"level": { "enum": ["LOW", "MEDIUM", "HIGH", "CRITICAL"] },
|
||||
"reasons": { "type": "array", "items": { "type": "string" } }
|
||||
},
|
||||
"required": ["level"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
|
||||
"economics": {
|
||||
"type": "object",
|
||||
"description": "A hypothesis may be valuable but not yet worth exploring (ArchitectureBlueprint.md section 29).",
|
||||
"properties": {
|
||||
"estimated_experiment_cost": { "type": "number", "minimum": 0 },
|
||||
"estimated_implementation_cost": { "type": "number", "minimum": 0 },
|
||||
"currency": { "type": "string" },
|
||||
"expected_value_class": { "enum": ["LOW", "MEDIUM", "HIGH"] }
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
|
||||
"learning_value": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"score": { "type": "number" },
|
||||
"notes": { "type": "string" }
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
|
||||
"priority": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"score": { "type": "number" },
|
||||
"decided_by": { "type": "string" }
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
|
||||
"competition": {
|
||||
"type": "object",
|
||||
"description": "Competing hypotheses are legitimate (FluidAPIStandards.md section 19).",
|
||||
"properties": {
|
||||
"group_id": { "type": "string", "minLength": 1 },
|
||||
"alternatives": { "type": "array", "items": { "$ref": "common.schema.json#/$defs/hypothesisId" } }
|
||||
},
|
||||
"required": ["group_id"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
|
||||
"success_criteria": {
|
||||
"type": "object",
|
||||
"properties": { "expression": { "type": "string", "minLength": 1 } },
|
||||
"required": ["expression"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"failure_criteria": {
|
||||
"type": "object",
|
||||
"properties": { "expression": { "type": "string", "minLength": 1 } },
|
||||
"required": ["expression"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
|
||||
"candidate_revision_refs": { "type": "array", "items": { "$ref": "common.schema.json#/$defs/revisionId" } },
|
||||
"experiment_refs": { "type": "array", "items": { "$ref": "common.schema.json#/$defs/experimentId" } },
|
||||
|
||||
"outcome": {
|
||||
"type": "object",
|
||||
"description": "What happened afterwards. Null until evaluation completes.",
|
||||
"properties": {
|
||||
"status": {
|
||||
"oneOf": [
|
||||
{ "enum": ["CONFIRMED", "REFUTED", "INCONCLUSIVE"] },
|
||||
{ "type": "null" }
|
||||
]
|
||||
},
|
||||
"summary": { "type": ["string", "null"] },
|
||||
"evidence_refs": { "type": "array", "items": { "$ref": "common.schema.json#/$defs/evidenceRef" } }
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
|
||||
"audit": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"decision_refs": { "type": "array", "items": { "$ref": "common.schema.json#/$defs/decisionId" } },
|
||||
"immutable_event_refs": { "type": "array", "items": { "$ref": "common.schema.json#/$defs/eventId" } }
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"schema_version", "id", "interface_id", "state", "title",
|
||||
"observation", "pressure", "explanation", "proposed_adaptation",
|
||||
"expected_outcomes", "guardrails", "complexity", "risk", "success_criteria"
|
||||
],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["fluid_hypothesis"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
53
schemas/pressure.schema.json
Normal file
53
schemas/pressure.schema.json
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "https://fluid.dev/schemas/pressure.schema.json",
|
||||
"title": "FLUID pressure record",
|
||||
"description": "Evidence that the interface differs materially from consumer needs. Pressure is evidence, not truth (FluidAPIStandards.md section 13).",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"fluid_pressure": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"schema_version": { "$ref": "common.schema.json#/$defs/schemaVersion" },
|
||||
"id": { "$ref": "common.schema.json#/$defs/pressureId" },
|
||||
"interface_id": { "$ref": "common.schema.json#/$defs/interfaceId" },
|
||||
"class": { "$ref": "common.schema.json#/$defs/pressureClass" },
|
||||
"first_seen": { "$ref": "common.schema.json#/$defs/timestamp" },
|
||||
"last_seen": { "$ref": "common.schema.json#/$defs/timestamp" },
|
||||
"affected_cohorts": {
|
||||
"type": "array",
|
||||
"items": { "$ref": "common.schema.json#/$defs/cohortId" }
|
||||
},
|
||||
"frequency": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"observations": { "type": "integer", "minimum": 0 },
|
||||
"independent_consumers": { "type": "integer", "minimum": 0 }
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"severity": { "$ref": "common.schema.json#/$defs/unitInterval" },
|
||||
"confidence": { "$ref": "common.schema.json#/$defs/unitInterval" },
|
||||
"summary": { "type": "string", "minLength": 1 },
|
||||
"evidence_refs": {
|
||||
"type": "array",
|
||||
"items": { "$ref": "common.schema.json#/$defs/evidenceRef" },
|
||||
"minItems": 1,
|
||||
"description": "A pressure record without evidence references is not auditable and must be rejected."
|
||||
},
|
||||
"status": {
|
||||
"enum": ["OPEN", "ANALYZING", "EXPLAINED", "ADDRESSED", "DISMISSED", "OUT_OF_SCOPE"],
|
||||
"description": "ArchitectureBlueprint.md section 9. Pressure may remain unresolved on purpose."
|
||||
},
|
||||
"linked_hypotheses": {
|
||||
"type": "array",
|
||||
"items": { "$ref": "common.schema.json#/$defs/hypothesisId" }
|
||||
}
|
||||
},
|
||||
"required": ["schema_version", "id", "interface_id", "class", "first_seen", "last_seen", "summary", "evidence_refs", "status"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["fluid_pressure"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
124
schemas/revision-descriptor.schema.json
Normal file
124
schemas/revision-descriptor.schema.json
Normal file
|
|
@ -0,0 +1,124 @@
|
|||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "https://fluid.dev/schemas/revision-descriptor.schema.json",
|
||||
"title": "FLUID revision descriptor",
|
||||
"description": "The runtime-facing projection of a revision, deliberately small enough to be consumed deterministically by infrastructure (ArchitectureBlueprint.md section 36). This is a wire artifact: the gateway must be able to read it without any fluid-core library.",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"revision": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"schema_version": { "$ref": "common.schema.json#/$defs/schemaVersion" },
|
||||
"id": { "$ref": "common.schema.json#/$defs/revisionId" },
|
||||
"interface": { "$ref": "common.schema.json#/$defs/interfaceId" },
|
||||
"state": {
|
||||
"enum": ["created", "verified", "experiment", "candidate", "stable", "deprecated", "retired"],
|
||||
"description": "The router refuses to route to created, failed or retired revisions (ArchitectureBlueprint.md section 5.3)."
|
||||
},
|
||||
|
||||
"contract": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": { "enum": ["openapi", "graphql", "protobuf", "asyncapi", "jsonschema", "custom"] },
|
||||
"digest": { "$ref": "common.schema.json#/$defs/digest" },
|
||||
"source": { "type": "string", "description": "Where the contract artifact can be fetched." }
|
||||
},
|
||||
"required": ["type", "digest"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
|
||||
"runtime": {
|
||||
"type": "object",
|
||||
"description": "Out-of-process attachment: the adapter is an upstream reached over the network, so it may be implemented in any language.",
|
||||
"properties": {
|
||||
"upstream": {
|
||||
"type": "string",
|
||||
"format": "uri",
|
||||
"description": "Base URL of the adapter process serving this revision."
|
||||
},
|
||||
"image": { "type": "string" },
|
||||
"digest": { "$ref": "common.schema.json#/$defs/digest" },
|
||||
"timeout_ms": { "type": "integer", "exclusiveMinimum": 0, "default": 5000 },
|
||||
"retry": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"max_attempts": { "type": "integer", "minimum": 1, "default": 1 },
|
||||
"backoff_ms": { "type": "integer", "minimum": 0 },
|
||||
"retry_on": { "type": "array", "items": { "type": "string" } }
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"circuit_breaker": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"failure_threshold": { "type": "integer", "minimum": 1 },
|
||||
"reset_after_ms": { "type": "integer", "exclusiveMinimum": 0 }
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["upstream"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
|
||||
"intent": {
|
||||
"type": "object",
|
||||
"description": "Which interface evolution intent governs this revision. Required: a revision with no governing intent cannot be audited.",
|
||||
"properties": {
|
||||
"version": { "type": "string", "minLength": 1 },
|
||||
"digest": { "$ref": "common.schema.json#/$defs/digest" }
|
||||
},
|
||||
"required": ["version"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
|
||||
"routing": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"eligible_cohorts": {
|
||||
"type": "array",
|
||||
"items": { "$ref": "common.schema.json#/$defs/cohortId" },
|
||||
"description": "Empty or absent means all cohorts are eligible."
|
||||
},
|
||||
"max_traffic_share": {
|
||||
"$ref": "common.schema.json#/$defs/unitInterval",
|
||||
"description": "Ceiling the router enforces regardless of what a routing policy asks for."
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
|
||||
"policy": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"compatibility": {
|
||||
"enum": ["backward_compatible", "forward_compatible", "additive", "behavioral_change", "breaking", "migration_only", "internal_only"]
|
||||
},
|
||||
"security_check": { "enum": ["pending", "passed", "failed"] },
|
||||
"policy_check": { "enum": ["pending", "passed", "failed"] },
|
||||
"rollback_to": { "oneOf": [{ "$ref": "common.schema.json#/$defs/revisionId" }, { "type": "null" }] }
|
||||
},
|
||||
"required": ["compatibility", "security_check"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
|
||||
"signature": {
|
||||
"type": "object",
|
||||
"description": "The router accepts only signed published descriptors (ArchitectureBlueprint.md section 35). The signature covers the canonical form of this document with the signature member removed.",
|
||||
"properties": {
|
||||
"algorithm": { "enum": ["ed25519"] },
|
||||
"key_id": { "type": "string", "minLength": 1 },
|
||||
"value": { "type": "string", "contentEncoding": "base64" },
|
||||
"signed_at": { "$ref": "common.schema.json#/$defs/timestamp" }
|
||||
},
|
||||
"required": ["algorithm", "key_id", "value"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["schema_version", "id", "interface", "state", "contract", "runtime", "intent", "policy"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["revision"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
235
schemas/revision.schema.json
Normal file
235
schemas/revision.schema.json
Normal file
|
|
@ -0,0 +1,235 @@
|
|||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "https://fluid.dev/schemas/revision.schema.json",
|
||||
"title": "FLUID revision record",
|
||||
"description": "What deterministic interface state was built, verified, exposed and measured. Published revisions should be immutable; corrections create successors (FluidAPIStandards.md section 8).",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"fluid_revision": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"schema_version": { "$ref": "common.schema.json#/$defs/schemaVersion" },
|
||||
"id": { "$ref": "common.schema.json#/$defs/revisionId" },
|
||||
"interface_id": { "$ref": "common.schema.json#/$defs/interfaceId" },
|
||||
"revision_number": { "type": "integer", "minimum": 0 },
|
||||
"parent_revision": {
|
||||
"oneOf": [
|
||||
{ "$ref": "common.schema.json#/$defs/revisionId" },
|
||||
{ "type": "null" }
|
||||
],
|
||||
"description": "Null marks genesis."
|
||||
},
|
||||
"state": {
|
||||
"enum": ["CREATED", "VERIFIED", "EXPERIMENT", "CANDIDATE", "STABLE", "DEPRECATED", "RETIRED"]
|
||||
},
|
||||
"created_at": { "$ref": "common.schema.json#/$defs/timestamp" },
|
||||
"created_by": { "$ref": "common.schema.json#/$defs/actor" },
|
||||
|
||||
"contract": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": { "enum": ["openapi", "graphql", "protobuf", "asyncapi", "jsonschema", "custom"] },
|
||||
"version": { "type": "string" },
|
||||
"artifact_ref": { "$ref": "common.schema.json#/$defs/artifactRef" },
|
||||
"digest": { "$ref": "common.schema.json#/$defs/digest" }
|
||||
},
|
||||
"required": ["type", "artifact_ref", "digest"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
|
||||
"implementation": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"artifact_ref": { "$ref": "common.schema.json#/$defs/artifactRef" },
|
||||
"source_ref": { "type": "string" },
|
||||
"build_ref": { "type": "string" },
|
||||
"digest": { "$ref": "common.schema.json#/$defs/digest" }
|
||||
},
|
||||
"required": ["artifact_ref", "digest"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
|
||||
"interface_evolution_intent": {
|
||||
"type": "object",
|
||||
"description": "Every revision is governed by a specific intent version, so audit can ask whether the change was valid under the intent that existed at the time (ArchitectureBlueprint.md section 27).",
|
||||
"properties": {
|
||||
"version": { "type": "string", "minLength": 1 },
|
||||
"artifact_ref": { "$ref": "common.schema.json#/$defs/artifactRef" }
|
||||
},
|
||||
"required": ["version"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
|
||||
"originating_hypotheses": { "type": "array", "items": { "$ref": "common.schema.json#/$defs/hypothesisId" } },
|
||||
"backend_requirements": { "type": "array", "items": { "$ref": "common.schema.json#/$defs/backendRequirementId" } },
|
||||
|
||||
"compatibility": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"class": {
|
||||
"enum": ["BACKWARD_COMPATIBLE", "FORWARD_COMPATIBLE", "ADDITIVE", "BEHAVIORAL_CHANGE", "BREAKING", "MIGRATION_ONLY", "INTERNAL_ONLY"]
|
||||
},
|
||||
"breaking_changes": { "type": "array", "items": { "type": "string" } },
|
||||
"deprecations": { "type": "array", "items": { "type": "string" } },
|
||||
"supersedes": { "type": "array", "items": { "$ref": "common.schema.json#/$defs/revisionId" } },
|
||||
"compatibility_evidence_refs": { "type": "array", "items": { "$ref": "common.schema.json#/$defs/evidenceRef" } }
|
||||
},
|
||||
"required": ["class"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
|
||||
"adaptation_classes": { "type": "array", "items": { "$ref": "common.schema.json#/$defs/adaptationClass" } },
|
||||
|
||||
"verification": {
|
||||
"type": "object",
|
||||
"description": "The primary safety barrier between adaptive generation and deterministic runtime (ArchitectureBlueprint.md section 15).",
|
||||
"properties": {
|
||||
"status": { "enum": ["PENDING", "PASSED", "FAILED"] },
|
||||
"test_refs": { "type": "array", "items": { "type": "string" } },
|
||||
"security_check": { "enum": ["PENDING", "PASSED", "FAILED"] },
|
||||
"policy_check": { "enum": ["PENDING", "PASSED", "FAILED"] }
|
||||
},
|
||||
"required": ["status"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
|
||||
"complexity": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"before": { "$ref": "common.schema.json#/$defs/complexityDelta" },
|
||||
"after": { "$ref": "common.schema.json#/$defs/complexityDelta" },
|
||||
"delta_score": { "type": "number" },
|
||||
"budget_status": { "enum": ["WITHIN_BUDGET", "AT_BUDGET", "OVER_BUDGET"] }
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
|
||||
"deployment": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"environments": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": { "type": "string" },
|
||||
"started_at": { "$ref": "common.schema.json#/$defs/timestamp" },
|
||||
"routing_policy_ref": { "type": "string" }
|
||||
},
|
||||
"required": ["name"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"current_exposure": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"traffic_share": { "$ref": "common.schema.json#/$defs/unitInterval" },
|
||||
"cohorts": { "type": "array", "items": { "$ref": "common.schema.json#/$defs/cohortId" } }
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
|
||||
"fitness": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"baseline_revision": { "oneOf": [{ "$ref": "common.schema.json#/$defs/revisionId" }, { "type": "null" }] },
|
||||
"measurement_window": { "$ref": "common.schema.json#/$defs/observationWindow" },
|
||||
"metrics": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"baseline": { "type": ["number", "null"] },
|
||||
"current": { "type": ["number", "null"] },
|
||||
"target": { "type": ["number", "null"] },
|
||||
"guardrail": { "type": ["number", "null"] }
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
|
||||
"adoption": {
|
||||
"type": "object",
|
||||
"description": "Adoption is evidence, not proof of quality (FluidAPIStandards.md section 32).",
|
||||
"properties": {
|
||||
"eligible_consumers": { "type": ["integer", "null"], "minimum": 0 },
|
||||
"active_consumers": { "type": ["integer", "null"], "minimum": 0 },
|
||||
"adoption_rate": { "oneOf": [{ "$ref": "common.schema.json#/$defs/unitInterval" }, { "type": "null" }] },
|
||||
"retained_adoption_rate": { "oneOf": [{ "$ref": "common.schema.json#/$defs/unitInterval" }, { "type": "null" }] }
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
|
||||
"economics": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"build_cost": { "type": "number", "minimum": 0 },
|
||||
"experiment_cost_to_date": { "type": "number", "minimum": 0 },
|
||||
"currency": { "type": "string" }
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
|
||||
"promotion": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"eligible": { "type": "boolean" },
|
||||
"recommended_state": {
|
||||
"oneOf": [
|
||||
{ "enum": ["CREATED", "VERIFIED", "EXPERIMENT", "CANDIDATE", "STABLE", "DEPRECATED", "RETIRED"] },
|
||||
{ "type": "null" }
|
||||
]
|
||||
},
|
||||
"recommendation_reason": { "type": ["string", "null"] },
|
||||
"authorized_by": { "oneOf": [{ "$ref": "common.schema.json#/$defs/actor" }, { "type": "null" }] },
|
||||
"authorized_at": { "oneOf": [{ "$ref": "common.schema.json#/$defs/timestamp" }, { "type": "null" }] }
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
|
||||
"rollback": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"supported": { "type": "boolean" },
|
||||
"target_revision": { "oneOf": [{ "$ref": "common.schema.json#/$defs/revisionId" }, { "type": "null" }] },
|
||||
"procedure_ref": { "type": "string" }
|
||||
},
|
||||
"required": ["supported"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
|
||||
"provenance": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"decision_refs": { "type": "array", "items": { "$ref": "common.schema.json#/$defs/decisionId" } },
|
||||
"experiment_refs": { "type": "array", "items": { "$ref": "common.schema.json#/$defs/experimentId" } },
|
||||
"telemetry_refs": { "type": "array", "items": { "$ref": "common.schema.json#/$defs/evidenceRef" } }
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
|
||||
"audit": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"immutable_event_refs": { "type": "array", "items": { "$ref": "common.schema.json#/$defs/eventId" } }
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"schema_version", "id", "interface_id", "revision_number", "parent_revision",
|
||||
"state", "contract", "implementation", "interface_evolution_intent",
|
||||
"compatibility", "verification", "rollback", "provenance"
|
||||
],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["fluid_revision"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
71
schemas/routing-policy.schema.json
Normal file
71
schemas/routing-policy.schema.json
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "https://fluid.dev/schemas/routing-policy.schema.json",
|
||||
"title": "FLUID routing policy",
|
||||
"description": "Deterministic routing written by the experiment controller and consumed by the revision router. The controller never touches traffic itself; this separation keeps experimental intent out of the runtime decision mechanism (ArchitectureBlueprint.md section 17).",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"routing_policy": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"schema_version": { "$ref": "common.schema.json#/$defs/schemaVersion" },
|
||||
"id": { "type": "string", "minLength": 1 },
|
||||
"interface": { "$ref": "common.schema.json#/$defs/interfaceId" },
|
||||
"generation": {
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"description": "Monotonic. The router ignores a policy older than the one it holds."
|
||||
},
|
||||
"issued_at": { "$ref": "common.schema.json#/$defs/timestamp" },
|
||||
"issued_by": { "$ref": "common.schema.json#/$defs/actor" },
|
||||
|
||||
"default_revision": {
|
||||
"$ref": "common.schema.json#/$defs/revisionId",
|
||||
"description": "Where a request lands when no earlier resolution step matched."
|
||||
},
|
||||
|
||||
"rules": {
|
||||
"type": "array",
|
||||
"description": "Evaluated in order; the first matching rule wins. Matching must be a pure function of the request and its cohort assignment.",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"cohort": { "$ref": "common.schema.json#/$defs/cohortId" },
|
||||
"tenant": { "type": "string" },
|
||||
"experiment": { "$ref": "common.schema.json#/$defs/experimentId" },
|
||||
"allocation": {
|
||||
"type": "object",
|
||||
"description": "Revision id to traffic share. Shares must sum to 1. Assignment of a given consumer must be stable across requests.",
|
||||
"propertyNames": { "$ref": "common.schema.json#/$defs/revisionId" },
|
||||
"additionalProperties": { "$ref": "common.schema.json#/$defs/unitInterval" },
|
||||
"minProperties": 1
|
||||
},
|
||||
"sticky_by": {
|
||||
"enum": ["consumer_id", "tenant", "correlation_id", "none"],
|
||||
"default": "consumer_id",
|
||||
"description": "What keeps a long-lived consumer on one side of an experiment."
|
||||
}
|
||||
},
|
||||
"required": ["allocation"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
|
||||
"signature": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"algorithm": { "enum": ["ed25519"] },
|
||||
"key_id": { "type": "string", "minLength": 1 },
|
||||
"value": { "type": "string", "contentEncoding": "base64" }
|
||||
},
|
||||
"required": ["algorithm", "key_id", "value"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["schema_version", "interface", "generation", "default_revision", "rules"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["routing_policy"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
113
schemas/telemetry-envelope.schema.json
Normal file
113
schemas/telemetry-envelope.schema.json
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "https://fluid.dev/schemas/telemetry-envelope.schema.json",
|
||||
"title": "FLUID telemetry envelope",
|
||||
"description": "The normalized interaction event. Designed for interface learning, not unrestricted behavioral capture: raw payload capture is never the default and redaction happens before an event reaches the store (ArchitectureBlueprint.md section 6.2).",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"fluid_telemetry": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"schema_version": { "$ref": "common.schema.json#/$defs/schemaVersion" },
|
||||
"id": { "type": "string", "minLength": 1 },
|
||||
"occurred_at": { "$ref": "common.schema.json#/$defs/timestamp" },
|
||||
"interface_id": { "$ref": "common.schema.json#/$defs/interfaceId" },
|
||||
"kind": {
|
||||
"enum": ["request", "error", "sequence", "adoption", "feedback"],
|
||||
"description": "ArchitectureBlueprint.md section 6.1."
|
||||
},
|
||||
|
||||
"correlation_id": {
|
||||
"type": "string",
|
||||
"description": "Ties an event to the response the consumer saw, and to the other events in its call chain."
|
||||
},
|
||||
"consumer_ref": {
|
||||
"type": "string",
|
||||
"description": "Pseudonymous and stable. Never a raw end-user identifier."
|
||||
},
|
||||
"cohort": { "$ref": "common.schema.json#/$defs/cohortId" },
|
||||
"revision": { "$ref": "common.schema.json#/$defs/revisionId" },
|
||||
"experiment": { "oneOf": [{ "$ref": "common.schema.json#/$defs/experimentId" }, { "type": "null" }] },
|
||||
|
||||
"resolution": {
|
||||
"type": "object",
|
||||
"description": "Why this revision was chosen. Revision resolution must be deterministic and auditable (ArchitectureBlueprint.md section 5.2).",
|
||||
"properties": {
|
||||
"reason": {
|
||||
"enum": ["explicit_revision", "bound_contract", "experiment_assignment", "cohort_rule", "stable_default"]
|
||||
},
|
||||
"policy_generation": { "type": "integer", "minimum": 0 }
|
||||
},
|
||||
"required": ["reason"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
|
||||
"request": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"operation": { "type": "string" },
|
||||
"route": { "type": "string" },
|
||||
"method": { "type": "string" },
|
||||
"status": { "type": "integer" },
|
||||
"latency_ms": { "type": "number", "minimum": 0 },
|
||||
"request_bytes": { "type": "integer", "minimum": 0 },
|
||||
"response_bytes": { "type": "integer", "minimum": 0 }
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
|
||||
"error": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"class": {
|
||||
"enum": ["validation", "unknown_path", "unknown_field", "unsupported_parameter", "authorization", "backend_failure", "timeout", "policy_rejection"]
|
||||
},
|
||||
"detail": { "type": "string", "description": "Redacted. Must not carry backend internals or consumer data." },
|
||||
"field": { "type": "string" }
|
||||
},
|
||||
"required": ["class"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
|
||||
"sequence": {
|
||||
"type": "object",
|
||||
"description": "Interaction topology is often more informative than error counts (ArchitectureBlueprint.md section 6.4).",
|
||||
"properties": {
|
||||
"chain_id": { "type": "string" },
|
||||
"position": { "type": "integer", "minimum": 0 },
|
||||
"pattern": { "type": "string" },
|
||||
"repeat_count": { "type": "integer", "minimum": 0 }
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
|
||||
"adoption": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"event": { "enum": ["first_use", "continued_use", "migration", "reversion", "deprecation_response"] },
|
||||
"from_revision": { "oneOf": [{ "$ref": "common.schema.json#/$defs/revisionId" }, { "type": "null" }] }
|
||||
},
|
||||
"required": ["event"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
|
||||
"feedback_ref": { "$ref": "common.schema.json#/$defs/feedbackId" },
|
||||
|
||||
"redaction": {
|
||||
"type": "object",
|
||||
"description": "What the privacy filter removed. Recorded so analysis knows what it cannot see.",
|
||||
"properties": {
|
||||
"applied": { "type": "boolean" },
|
||||
"rules": { "type": "array", "items": { "type": "string" } }
|
||||
},
|
||||
"required": ["applied"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["schema_version", "id", "occurred_at", "interface_id", "kind"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["fluid_telemetry"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue