Generate contract types, pin fixtures to spec, add build and ADRs
Some checks failed
ci / build (push) Failing after 1m6s

Completes FLUID-WP-0002. The record types in internal/contract are
generated from schemas/ by a dependency-free generator; fixtures
transcribed from the spec's worked examples validate against those
schemas and round-trip through the generated types with
DisallowUnknownFields, so a spec change that misses the schemas fails
CI rather than drifting silently.

Adds identifier prefix helpers, Makefile, GitHub Actions, and five ADRs
recording the Go choice, out-of-process attachment, the wire contract as
boundary, the evidence store, and revision identity.

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:
tegwick 2026-09-04 02:03:12 +02:00
parent fbbf56df7a
commit 76912adef8
44 changed files with 4010 additions and 7 deletions

View file

@ -0,0 +1,28 @@
# Schema fixtures
Every file here is transcribed from a worked example in `spec/`. They exist so
that a change to the specification which is not reflected in `schemas/` fails
the build.
Two deviations from the spec text are deliberate and are the only ones allowed:
1. **Placeholder digests.** The spec writes `sha256:<digest>`. Fixtures use a
syntactically valid digest, because the schema constrains the format.
2. **Placeholder artifact paths.** The spec writes `contractRef: ...`. Fixtures
use a plausible reference.
Anything else that differs from the spec is a bug in the fixture or in the
schema, not a licence to relax the schema.
| Fixture | Source |
|---|---|
| `hypothesis.yaml` | `FluidHypothesisRevisionSchema.md` §3 |
| `revision.yaml` | `FluidHypothesisRevisionSchema.md` §8 |
| `experiment.yaml` | `FluidHypothesisRevisionSchema.md` §12 |
| `pressure.yaml` | `FluidHypothesisRevisionSchema.md` §13 |
| `backend-requirement.yaml` | `FluidHypothesisRevisionSchema.md` §14 |
| `event.yaml` | `FluidHypothesisRevisionSchema.md` §15 |
| `revision-descriptor.yaml` | `ArchitectureBlueprint.md` §36 |
| `routing-policy.yaml` | `ArchitectureBlueprint.md` §17 |
| `feedback.yaml` | `FluidAPIStandards.md` §15, `ArchitectureBlueprint.md` §38 |
| `telemetry-envelope.yaml` | `ArchitectureBlueprint.md` §6.1 |

View file

@ -0,0 +1,37 @@
fluid_backend_requirement:
schema_version: "0.1"
id: "BR-0041"
originating_interface: "customer-context-api"
originating_revision: "R-0081"
originating_hypothesis: "H-0212"
backend_service: "payments-service"
capability:
title: "Historical payment-state query"
description: >
Retrieve payment state as of a specified timestamp.
semantics:
consistency: "snapshot"
required_fields:
- "payment_id"
- "state"
- "effective_at"
quality:
p95_latency_ms: 250
availability: 0.999
security:
authorization_scope: "payments.read"
tenant_isolation: "required"
expected_usage:
requests_per_day: 120000
disposition:
state: "PLANNED"
reason: null
target_ref: "payments-service/roadmap#412"

View file

@ -0,0 +1,24 @@
fluid_event:
schema_version: "0.1"
id: "EV-990281"
occurred_at: "2026-09-09T11:31:02Z"
entity_type: "revision"
entity_id: "R-000221"
event_type: "PROMOTION_RECOMMENDED"
actor:
type: "daimon"
id: "fluid-daimon/customer-finance-api"
inputs:
- "H-000184"
- "E-000093"
reason: >
Candidate met primary success target and violated no guardrails.
evidence_refs:
- "metrics:E-000093/window-4"

View file

@ -0,0 +1,41 @@
fluid_experiment:
schema_version: "0.1"
id: "E-000093"
interface_id: "customer-finance-api"
hypothesis_refs:
- "H-000184"
control_revision: "R-000220"
candidate_revisions:
- "R-000221"
cohorts:
- "partner-integrations"
- "coding-agents"
allocation:
control: 0.72
candidate: 0.28
start_at: "2026-09-05T08:00:00Z"
planned_end_at: "2026-10-05T08:00:00Z"
metrics:
primary:
- "requests_per_completed_task"
guardrails:
- "p95_latency_ms"
- "error_rate"
- "authorization_scope_change"
stop_conditions:
- "hard_guardrail_violation"
- "security_failure"
- "manual_stop"
result:
state: "RUNNING"
preferred_revision: null
evidence_refs: []

View file

@ -0,0 +1,22 @@
fluid_feedback:
schema_version: "0.1"
id: "F-9821"
interface_id: "customer-finance-api"
received_at: "2026-08-28T09:12:00Z"
cohort: "coding-agents"
revision: "R-000220"
goal: "produce monthly account statement"
missing_capability: "consolidated-period-summary"
attempted_operations:
- "list-transactions"
- "get-balances"
outcome: "capability unavailable"
workaround:
- "aggregate-locally"
- "infer-closing-balance"
confidence: 0.94
impact:
calls: 18
latency_ms: 2810

View file

@ -0,0 +1,156 @@
fluid_hypothesis:
schema_version: "0.1"
id: "H-000184"
interface_id: "customer-finance-api"
state: "PRIORITIZED"
created_at: "2026-09-04T12:00:00Z"
created_by:
type: "daimon"
id: "fluid-daimon/customer-finance-api"
title: "Provide direct latest-invoice capability"
observation:
summary: >
A significant consumer cohort retrieves invoice collections,
sorts them by issue date, and discards all but the first item.
evidence_refs:
- "telemetry:invoice-pattern-2026w36"
- "feedback:F-9821"
affected_cohorts:
- "partner-integrations"
- "coding-agents"
observation_window:
start: "2026-08-15T00:00:00Z"
end: "2026-09-01T00:00:00Z"
pressure:
classes:
- "successful_but_inefficient_usage"
- "repeated_expectation_mismatch"
severity: 0.61
confidence: 0.88
explanation:
claim: >
Consumers treat "latest invoice" as a domain-level concept
and the existing generic collection interface does not present
that concept directly.
reach:
score: 0.42
explains:
- "P-1831"
- "P-1834"
notes: >
Medium reach: explains several related request patterns
but not broader financial-context pressure.
proposed_adaptation:
class: "contract"
summary: >
Add an explicit latest-invoice retrieval capability.
candidate_contract:
method: "GET"
path: "/customers/{id}/invoices/latest"
implementation_scope: "interface_only"
backend_requirements:
required: false
requirement_refs: []
expected_outcomes:
- metric: "requests_per_completed_task"
cohort: "all"
baseline: 2.7
target: 1.2
direction: "lower"
- metric: "client_side_sort_workarounds"
cohort: "all"
baseline: 1.0
target: 0.2
direction: "lower"
guardrails:
- metric: "p95_latency_ms"
operator: "<="
threshold: 315
- metric: "authorization_scope_change"
operator: "=="
threshold: false
- metric: "backend_query_count_delta"
operator: "<="
threshold: 0
fitness_dimensions:
expected:
client_utility: 0.70
correctness: 0.00
reliability: 0.00
performance: 0.10
discoverability: 0.65
simplicity: -0.15
compatibility: 0.00
security: 0.00
maintainability: -0.05
operational_cost: 0.00
complexity:
expected_delta:
surface_area: 1
concept_count: 0
operation_count: 1
semantic_overlap: 0.1
cognitive_load: -0.2
score: 0.18
risk:
level: "LOW"
reasons:
- "read-only operation"
- "no authorization expansion"
economics:
estimated_experiment_cost: 18.00
estimated_implementation_cost: 40.00
currency: "EUR"
expected_value_class: "MEDIUM"
learning_value:
score: 0.56
notes: >
Useful signal for whether first-class convenience resources
improve agent and partner integration behavior.
priority:
score: 0.71
decided_by: "optimization-policy-v3"
success_criteria:
expression: >
requests_per_completed_task <= 1.2
AND no hard guardrail violation
failure_criteria:
expression: >
any hard guardrail violation
OR adoption below 5% after 30 days when equally discoverable
candidate_revision_refs:
- "R-000221"
experiment_refs:
- "E-000093"
outcome:
status: null
summary: null
evidence_refs: []
audit:
decision_refs:
- "D-2811"
immutable_event_refs:
- "EV-990218"

View file

@ -0,0 +1,38 @@
{
"fluid_backend_requirement": {
"backend_service": "payments-service",
"capability": {
"description": "Retrieve payment state as of a specified timestamp.\n",
"title": "Historical payment-state query"
},
"disposition": {
"reason": null,
"state": "PLANNED",
"target_ref": "payments-service/roadmap#412"
},
"expected_usage": {
"requests_per_day": 120000
},
"id": "BR-0041",
"originating_hypothesis": "H-0212",
"originating_interface": "customer-context-api",
"originating_revision": "R-0081",
"quality": {
"availability": 0.999,
"p95_latency_ms": 250
},
"schema_version": "0.1",
"security": {
"authorization_scope": "payments.read",
"tenant_isolation": "required"
},
"semantics": {
"consistency": "snapshot",
"required_fields": [
"payment_id",
"state",
"effective_at"
]
}
}
}

View file

@ -0,0 +1,22 @@
{
"fluid_event": {
"actor": {
"id": "fluid-daimon/customer-finance-api",
"type": "daimon"
},
"entity_id": "R-000221",
"entity_type": "revision",
"event_type": "PROMOTION_RECOMMENDED",
"evidence_refs": [
"metrics:E-000093/window-4"
],
"id": "EV-990281",
"inputs": [
"H-000184",
"E-000093"
],
"occurred_at": "2026-09-09T11:31:02Z",
"reason": "Candidate met primary success target and violated no guardrails.\n",
"schema_version": "0.1"
}
}

View file

@ -0,0 +1,44 @@
{
"fluid_experiment": {
"allocation": {
"candidate": 0.28,
"control": 0.72
},
"candidate_revisions": [
"R-000221"
],
"cohorts": [
"partner-integrations",
"coding-agents"
],
"control_revision": "R-000220",
"hypothesis_refs": [
"H-000184"
],
"id": "E-000093",
"interface_id": "customer-finance-api",
"metrics": {
"guardrails": [
"p95_latency_ms",
"error_rate",
"authorization_scope_change"
],
"primary": [
"requests_per_completed_task"
]
},
"planned_end_at": "2026-10-05T08:00:00Z",
"result": {
"evidence_refs": [],
"preferred_revision": null,
"state": "RUNNING"
},
"schema_version": "0.1",
"start_at": "2026-09-05T08:00:00Z",
"stop_conditions": [
"hard_guardrail_violation",
"security_failure",
"manual_stop"
]
}
}

View file

@ -0,0 +1,26 @@
{
"fluid_feedback": {
"attempted_operations": [
"list-transactions",
"get-balances"
],
"cohort": "coding-agents",
"confidence": 0.94,
"goal": "produce monthly account statement",
"id": "F-9821",
"impact": {
"calls": 18,
"latency_ms": 2810
},
"interface_id": "customer-finance-api",
"missing_capability": "consolidated-period-summary",
"outcome": "capability unavailable",
"received_at": "2026-08-28T09:12:00Z",
"revision": "R-000220",
"schema_version": "0.1",
"workaround": [
"aggregate-locally",
"infer-closing-balance"
]
}
}

View file

@ -0,0 +1,164 @@
{
"fluid_hypothesis": {
"audit": {
"decision_refs": [
"D-2811"
],
"immutable_event_refs": [
"EV-990218"
]
},
"backend_requirements": {
"required": false,
"requirement_refs": []
},
"candidate_revision_refs": [
"R-000221"
],
"complexity": {
"expected_delta": {
"cognitive_load": -0.2,
"concept_count": 0,
"operation_count": 1,
"semantic_overlap": 0.1,
"surface_area": 1
},
"score": 0.18
},
"created_at": "2026-09-04T12:00:00Z",
"created_by": {
"id": "fluid-daimon/customer-finance-api",
"type": "daimon"
},
"economics": {
"currency": "EUR",
"estimated_experiment_cost": 18.0,
"estimated_implementation_cost": 40.0,
"expected_value_class": "MEDIUM"
},
"expected_outcomes": [
{
"baseline": 2.7,
"cohort": "all",
"direction": "lower",
"metric": "requests_per_completed_task",
"target": 1.2
},
{
"baseline": 1.0,
"cohort": "all",
"direction": "lower",
"metric": "client_side_sort_workarounds",
"target": 0.2
}
],
"experiment_refs": [
"E-000093"
],
"explanation": {
"claim": "Consumers treat \"latest invoice\" as a domain-level concept and the existing generic collection interface does not present that concept directly.\n",
"reach": {
"explains": [
"P-1831",
"P-1834"
],
"notes": "Medium reach: explains several related request patterns but not broader financial-context pressure.\n",
"score": 0.42
}
},
"failure_criteria": {
"expression": "any hard guardrail violation OR adoption below 5% after 30 days when equally discoverable\n"
},
"fitness_dimensions": {
"expected": {
"client_utility": 0.7,
"compatibility": 0.0,
"correctness": 0.0,
"discoverability": 0.65,
"maintainability": -0.05,
"operational_cost": 0.0,
"performance": 0.1,
"reliability": 0.0,
"security": 0.0,
"simplicity": -0.15
}
},
"guardrails": [
{
"metric": "p95_latency_ms",
"operator": "<=",
"threshold": 315
},
{
"metric": "authorization_scope_change",
"operator": "==",
"threshold": false
},
{
"metric": "backend_query_count_delta",
"operator": "<=",
"threshold": 0
}
],
"id": "H-000184",
"interface_id": "customer-finance-api",
"learning_value": {
"notes": "Useful signal for whether first-class convenience resources improve agent and partner integration behavior.\n",
"score": 0.56
},
"observation": {
"affected_cohorts": [
"partner-integrations",
"coding-agents"
],
"evidence_refs": [
"telemetry:invoice-pattern-2026w36",
"feedback:F-9821"
],
"observation_window": {
"end": "2026-09-01T00:00:00Z",
"start": "2026-08-15T00:00:00Z"
},
"summary": "A significant consumer cohort retrieves invoice collections, sorts them by issue date, and discards all but the first item.\n"
},
"outcome": {
"evidence_refs": [],
"status": null,
"summary": null
},
"pressure": {
"classes": [
"successful_but_inefficient_usage",
"repeated_expectation_mismatch"
],
"confidence": 0.88,
"severity": 0.61
},
"priority": {
"decided_by": "optimization-policy-v3",
"score": 0.71
},
"proposed_adaptation": {
"candidate_contract": {
"method": "GET",
"path": "/customers/{id}/invoices/latest"
},
"class": "contract",
"implementation_scope": "interface_only",
"summary": "Add an explicit latest-invoice retrieval capability.\n"
},
"risk": {
"level": "LOW",
"reasons": [
"read-only operation",
"no authorization expansion"
]
},
"schema_version": "0.1",
"state": "PRIORITIZED",
"success_criteria": {
"expression": "requests_per_completed_task <= 1.2 AND no hard guardrail violation\n"
},
"title": "Provide direct latest-invoice capability"
}
}

View file

@ -0,0 +1,25 @@
{
"fluid_pressure": {
"affected_cohorts": [
"partner-integrations"
],
"class": "successful_but_inefficient_usage",
"evidence_refs": [
"telemetry:query-pattern-712"
],
"first_seen": "2026-08-15T10:11:00Z",
"frequency": {
"independent_consumers": 83,
"observations": 1740
},
"id": "P-1831",
"interface_id": "customer-finance-api",
"last_seen": "2026-09-01T12:15:00Z",
"linked_hypotheses": [
"H-000184"
],
"schema_version": "0.1",
"status": "OPEN",
"summary": "Consumers repeatedly retrieve complete invoice collections to determine the latest invoice.\n"
}
}

View file

@ -0,0 +1,35 @@
{
"revision": {
"contract": {
"digest": "sha256:3b1f9c2e7a4d8b6051e2c9f0a7d4b83e15c6f2a9d0b7e4c1836a5f2d9c0b7e41",
"source": "artifact:openapi/customer-finance-api/r22",
"type": "openapi"
},
"id": "R-000221",
"intent": {
"version": "IEI-7"
},
"interface": "customer-finance-api",
"policy": {
"compatibility": "additive",
"policy_check": "passed",
"rollback_to": "R-000220",
"security_check": "passed"
},
"routing": {
"eligible_cohorts": [
"partner-integrations",
"coding-agents"
],
"max_traffic_share": 0.3
},
"runtime": {
"digest": "sha256:3b1f9c2e7a4d8b6051e2c9f0a7d4b83e15c6f2a9d0b7e4c1836a5f2d9c0b7e41",
"image": "registry/fluid/customer-finance:R-42",
"timeout_ms": 5000,
"upstream": "http://adapter-r22.fluid-runtime.svc:8080"
},
"schema_version": "0.1",
"state": "candidate"
}
}

View file

@ -0,0 +1,150 @@
{
"fluid_revision": {
"adaptation_classes": [
"contract"
],
"adoption": {
"active_consumers": 119,
"adoption_rate": 0.289,
"eligible_consumers": 412,
"retained_adoption_rate": null
},
"audit": {
"immutable_event_refs": [
"EV-990221",
"EV-990244",
"EV-990281"
]
},
"backend_requirements": [],
"compatibility": {
"breaking_changes": [],
"class": "BACKWARD_COMPATIBLE",
"compatibility_evidence_refs": [
"test:compat-suite-775"
],
"deprecations": [],
"supersedes": []
},
"complexity": {
"after": {
"operation_count": 40,
"surface_area": 42
},
"before": {
"operation_count": 39,
"surface_area": 41
},
"budget_status": "WITHIN_BUDGET",
"delta_score": 0.18
},
"contract": {
"artifact_ref": "artifact:openapi/customer-finance-api/r22",
"digest": "sha256:3b1f9c2e7a4d8b6051e2c9f0a7d4b83e15c6f2a9d0b7e4c1836a5f2d9c0b7e41",
"type": "openapi",
"version": "3.1"
},
"created_at": "2026-09-04T13:10:00Z",
"created_by": {
"id": "fluid-daimon/customer-finance-api",
"type": "daimon"
},
"deployment": {
"current_exposure": {
"cohorts": [
"partner-integrations",
"coding-agents"
],
"traffic_share": 0.28
},
"environments": [
{
"name": "production",
"routing_policy_ref": "route-policy:rp-118",
"started_at": "2026-09-05T08:00:00Z"
}
]
},
"economics": {
"build_cost": 38.2,
"currency": "EUR",
"experiment_cost_to_date": 12.4
},
"fitness": {
"baseline_revision": "R-000220",
"measurement_window": {
"end": null,
"start": "2026-09-05T08:00:00Z"
},
"metrics": {
"error_rate": {
"baseline": 0.008,
"current": 0.007
},
"p95_latency_ms": {
"baseline": 300,
"current": 302,
"guardrail": 315
},
"requests_per_completed_task": {
"baseline": 2.7,
"current": 1.15,
"target": 1.2
}
}
},
"id": "R-000221",
"implementation": {
"artifact_ref": "artifact:adapter/customer-finance-api/r22",
"build_ref": "build:8871",
"digest": "sha256:3b1f9c2e7a4d8b6051e2c9f0a7d4b83e15c6f2a9d0b7e4c1836a5f2d9c0b7e41",
"source_ref": "git:9f4c2ab"
},
"interface_evolution_intent": {
"artifact_ref": "artifact:intent/customer-finance-api/IEI-7",
"version": "IEI-7"
},
"interface_id": "customer-finance-api",
"originating_hypotheses": [
"H-000184"
],
"parent_revision": "R-000220",
"promotion": {
"authorized_at": null,
"authorized_by": null,
"eligible": true,
"recommendation_reason": "Target fitness reached with no guardrail violations.\n",
"recommended_state": "STABLE"
},
"provenance": {
"decision_refs": [
"D-2811"
],
"experiment_refs": [
"E-000093"
],
"telemetry_refs": [
"telemetry:invoice-pattern-2026w36"
]
},
"revision_number": 22,
"rollback": {
"procedure_ref": "runbook:rollback-r22",
"supported": true,
"target_revision": "R-000220"
},
"schema_version": "0.1",
"state": "CANDIDATE",
"verification": {
"policy_check": "PASSED",
"security_check": "PASSED",
"status": "PASSED",
"test_refs": [
"test:unit-12081",
"test:contract-8821",
"test:security-610",
"test:compat-suite-775"
]
}
}
}

View file

@ -0,0 +1,25 @@
{
"routing_policy": {
"default_revision": "R-000220",
"generation": 118,
"id": "rp-118",
"interface": "customer-finance-api",
"issued_at": "2026-09-05T08:00:00Z",
"issued_by": {
"id": "fluid-experiment-controller",
"type": "system"
},
"rules": [
{
"allocation": {
"R-000220": 0.8,
"R-000221": 0.2
},
"cohort": "coding-agents",
"experiment": "E-000093",
"sticky_by": "consumer_id"
}
],
"schema_version": "0.1"
}
}

View file

@ -0,0 +1,34 @@
{
"fluid_telemetry": {
"cohort": "coding-agents",
"consumer_ref": "psu-4d1e9c",
"correlation_id": "c-7f21ab90",
"experiment": "E-000093",
"id": "tl-01J8Z3XK7QW2",
"interface_id": "customer-finance-api",
"kind": "request",
"occurred_at": "2026-09-05T08:14:22Z",
"redaction": {
"applied": true,
"rules": [
"drop-path-parameters",
"pseudonymize-consumer"
]
},
"request": {
"latency_ms": 118.4,
"method": "GET",
"operation": "getLatestInvoice",
"request_bytes": 0,
"response_bytes": 812,
"route": "/customers/{id}/invoices/latest",
"status": 200
},
"resolution": {
"policy_generation": 118,
"reason": "experiment_assignment"
},
"revision": "R-000221",
"schema_version": "0.1"
}
}

View file

@ -0,0 +1,29 @@
fluid_pressure:
schema_version: "0.1"
id: "P-1831"
interface_id: "customer-finance-api"
class: "successful_but_inefficient_usage"
first_seen: "2026-08-15T10:11:00Z"
last_seen: "2026-09-01T12:15:00Z"
affected_cohorts:
- "partner-integrations"
frequency:
observations: 1740
independent_consumers: 83
summary: >
Consumers repeatedly retrieve complete invoice collections
to determine the latest invoice.
evidence_refs:
- "telemetry:query-pattern-712"
status: "OPEN"
linked_hypotheses:
- "H-000184"

View file

@ -0,0 +1,32 @@
revision:
schema_version: "0.1"
id: "R-000221"
interface: "customer-finance-api"
state: "candidate"
contract:
type: "openapi"
digest: "sha256:3b1f9c2e7a4d8b6051e2c9f0a7d4b83e15c6f2a9d0b7e4c1836a5f2d9c0b7e41"
source: "artifact:openapi/customer-finance-api/r22"
runtime:
upstream: "http://adapter-r22.fluid-runtime.svc:8080"
image: "registry/fluid/customer-finance:R-42"
digest: "sha256:3b1f9c2e7a4d8b6051e2c9f0a7d4b83e15c6f2a9d0b7e4c1836a5f2d9c0b7e41"
timeout_ms: 5000
intent:
version: "IEI-7"
routing:
eligible_cohorts:
- "partner-integrations"
- "coding-agents"
max_traffic_share: 0.30
policy:
compatibility: "additive"
security_check: "passed"
policy_check: "passed"
rollback_to: "R-000220"

View file

@ -0,0 +1,134 @@
fluid_revision:
schema_version: "0.1"
id: "R-000221"
interface_id: "customer-finance-api"
revision_number: 22
parent_revision: "R-000220"
state: "CANDIDATE"
created_at: "2026-09-04T13:10:00Z"
created_by:
type: "daimon"
id: "fluid-daimon/customer-finance-api"
contract:
type: "openapi"
version: "3.1"
artifact_ref: "artifact:openapi/customer-finance-api/r22"
digest: "sha256:3b1f9c2e7a4d8b6051e2c9f0a7d4b83e15c6f2a9d0b7e4c1836a5f2d9c0b7e41"
implementation:
artifact_ref: "artifact:adapter/customer-finance-api/r22"
source_ref: "git:9f4c2ab"
build_ref: "build:8871"
digest: "sha256:3b1f9c2e7a4d8b6051e2c9f0a7d4b83e15c6f2a9d0b7e4c1836a5f2d9c0b7e41"
interface_evolution_intent:
version: "IEI-7"
artifact_ref: "artifact:intent/customer-finance-api/IEI-7"
originating_hypotheses:
- "H-000184"
backend_requirements: []
compatibility:
class: "BACKWARD_COMPATIBLE"
breaking_changes: []
deprecations: []
supersedes: []
compatibility_evidence_refs:
- "test:compat-suite-775"
adaptation_classes:
- "contract"
verification:
status: "PASSED"
test_refs:
- "test:unit-12081"
- "test:contract-8821"
- "test:security-610"
- "test:compat-suite-775"
security_check: "PASSED"
policy_check: "PASSED"
complexity:
before:
surface_area: 41
operation_count: 39
after:
surface_area: 42
operation_count: 40
delta_score: 0.18
budget_status: "WITHIN_BUDGET"
deployment:
environments:
- name: "production"
started_at: "2026-09-05T08:00:00Z"
routing_policy_ref: "route-policy:rp-118"
current_exposure:
traffic_share: 0.28
cohorts:
- "partner-integrations"
- "coding-agents"
fitness:
baseline_revision: "R-000220"
measurement_window:
start: "2026-09-05T08:00:00Z"
end: null
metrics:
requests_per_completed_task:
baseline: 2.7
current: 1.15
target: 1.2
p95_latency_ms:
baseline: 300
current: 302
guardrail: 315
error_rate:
baseline: 0.008
current: 0.007
adoption:
eligible_consumers: 412
active_consumers: 119
adoption_rate: 0.289
retained_adoption_rate: null
economics:
build_cost: 38.20
experiment_cost_to_date: 12.40
currency: "EUR"
promotion:
eligible: true
recommended_state: "STABLE"
recommendation_reason: >
Target fitness reached with no guardrail violations.
authorized_by: null
authorized_at: null
rollback:
supported: true
target_revision: "R-000220"
procedure_ref: "runbook:rollback-r22"
provenance:
decision_refs:
- "D-2811"
experiment_refs:
- "E-000093"
telemetry_refs:
- "telemetry:invoice-pattern-2026w36"
audit:
immutable_event_refs:
- "EV-990221"
- "EV-990244"
- "EV-990281"

View file

@ -0,0 +1,20 @@
routing_policy:
schema_version: "0.1"
id: "rp-118"
interface: "customer-finance-api"
generation: 118
issued_at: "2026-09-05T08:00:00Z"
issued_by:
type: "system"
id: "fluid-experiment-controller"
default_revision: "R-000220"
rules:
- cohort: "coding-agents"
experiment: "E-000093"
allocation:
R-000220: 0.80
R-000221: 0.20
sticky_by: "consumer_id"

View file

@ -0,0 +1,32 @@
fluid_telemetry:
schema_version: "0.1"
id: "tl-01J8Z3XK7QW2"
occurred_at: "2026-09-05T08:14:22Z"
interface_id: "customer-finance-api"
kind: "request"
correlation_id: "c-7f21ab90"
consumer_ref: "psu-4d1e9c"
cohort: "coding-agents"
revision: "R-000221"
experiment: "E-000093"
resolution:
reason: "experiment_assignment"
policy_generation: 118
request:
operation: "getLatestInvoice"
route: "/customers/{id}/invoices/latest"
method: "GET"
status: 200
latency_ms: 118.4
request_bytes: 0
response_bytes: 812
redaction:
applied: true
rules:
- "drop-path-parameters"
- "pseudonymize-consumer"

193
conformance/validate_schemas.py Executable file
View file

@ -0,0 +1,193 @@
#!/usr/bin/env python3
"""Validate the schema fixtures against the FLUID wire-contract schemas.
Every fixture is transcribed from a worked example in spec/. If the
specification moves and the schemas do not, this fails the build.
"""
import json
import pathlib
import sys
import yaml
from jsonschema import Draft202012Validator, RefResolver
ROOT = pathlib.Path(__file__).resolve().parent.parent
SCHEMAS = ROOT / "schemas"
FIXTURES = ROOT / "conformance" / "fixtures"
# fixture stem -> schema stem
PAIRS = {
"pressure": "pressure",
"hypothesis": "hypothesis",
"revision": "revision",
"experiment": "experiment",
"event": "event",
"feedback": "feedback",
"backend-requirement": "backend-requirement",
"revision-descriptor": "revision-descriptor",
"routing-policy": "routing-policy",
"telemetry-envelope": "telemetry-envelope",
}
def load_store():
"""Map every schema by both its $id and its bare filename.
Schemas cross-reference each other as "common.schema.json#/$defs/...",
a relative reference, so the bare filename has to resolve too.
"""
store = {}
for path in SCHEMAS.glob("*.schema.json"):
schema = json.loads(path.read_text())
store[path.name] = schema
if "$id" in schema:
store[schema["$id"]] = schema
return store
# Instances that MUST be rejected. Without these the suite could pass
# vacuously if reference resolution silently degraded to "accept anything".
NEGATIVE = [
(
"pressure",
"pressure without evidence references is not auditable",
{"fluid_pressure": {
"schema_version": "0.1", "id": "P-1", "interface_id": "x",
"class": "natural_usage", "first_seen": "2026-01-01T00:00:00Z",
"last_seen": "2026-01-01T00:00:00Z", "summary": "s",
"evidence_refs": [], "status": "OPEN"}},
),
(
"pressure",
"pressure class outside the standard taxonomy",
{"fluid_pressure": {
"schema_version": "0.1", "id": "P-1", "interface_id": "x",
"class": "vibes", "first_seen": "2026-01-01T00:00:00Z",
"last_seen": "2026-01-01T00:00:00Z", "summary": "s",
"evidence_refs": ["telemetry:1"], "status": "OPEN"}},
),
(
"hypothesis",
"hypothesis with no falsifiable expected outcome",
{"fluid_hypothesis": {
"schema_version": "0.1", "id": "H-1", "interface_id": "x",
"state": "DRAFT", "title": "t",
"observation": {"summary": "s", "evidence_refs": ["telemetry:1"]},
"pressure": {"classes": ["natural_usage"]},
"explanation": {"claim": "c"},
"proposed_adaptation": {"class": "contract", "summary": "s"},
"expected_outcomes": [],
"guardrails": [],
"complexity": {"expected_delta": {}},
"risk": {"level": "LOW"},
"success_criteria": {"expression": "e"}}},
),
(
"experiment",
"experiment with no stop condition is not interruptible by policy",
{"fluid_experiment": {
"schema_version": "0.1", "id": "E-1", "interface_id": "x",
"hypothesis_refs": ["H-1"], "control_revision": "R-1",
"candidate_revisions": ["R-2"],
"allocation": {"control": 0.9, "candidate": 0.1},
"metrics": {"primary": ["m"]},
"stop_conditions": [],
"result": {"state": "PLANNED"}}},
),
(
"revision-descriptor",
"descriptor with no governing intent cannot be audited",
{"revision": {
"schema_version": "0.1", "id": "R-1", "interface": "x",
"state": "stable",
"contract": {"type": "openapi", "digest": "sha256:" + "0" * 64},
"runtime": {"upstream": "http://a:8080"},
"policy": {"compatibility": "additive", "security_check": "passed"}}},
),
(
"revision-descriptor",
"unknown revision state",
{"revision": {
"schema_version": "0.1", "id": "R-1", "interface": "x",
"state": "probably-fine",
"contract": {"type": "openapi", "digest": "sha256:" + "0" * 64},
"runtime": {"upstream": "http://a:8080"},
"intent": {"version": "IEI-1"},
"policy": {"compatibility": "additive", "security_check": "passed"}}},
),
]
def run_negative(store):
failures = 0
for schema_stem, why, instance in NEGATIVE:
schema = json.loads((SCHEMAS / f"{schema_stem}.schema.json").read_text())
resolver = RefResolver(base_uri="", referrer=schema, store=store)
validator = Draft202012Validator(schema, resolver=resolver)
if validator.is_valid(instance):
print(f"FAIL rejected-case accepted: {why}")
failures += 1
else:
print(f"ok rejects: {why}")
return failures
def main() -> int:
store = load_store()
failures = 0
for fixture_stem, schema_stem in sorted(PAIRS.items()):
fixture_path = FIXTURES / f"{fixture_stem}.yaml"
schema_path = SCHEMAS / f"{schema_stem}.schema.json"
if not fixture_path.exists():
print(f"MISSING {fixture_path.relative_to(ROOT)}")
failures += 1
continue
schema = json.loads(schema_path.read_text())
instance = yaml.safe_load(fixture_path.read_text())
resolver = RefResolver(base_uri="", referrer=schema, store=store)
validator = Draft202012Validator(schema, resolver=resolver)
errors = sorted(validator.iter_errors(instance), key=lambda e: list(e.path))
if errors:
failures += 1
print(f"FAIL {fixture_stem}")
for err in errors:
where = "/".join(str(p) for p in err.absolute_path) or "<root>"
print(f" {where}: {err.message}")
else:
print(f"ok {fixture_stem}")
# A schema that no fixture exercises is a schema nothing protects.
unexercised = {
p.stem.removesuffix(".schema")
for p in SCHEMAS.glob("*.schema.json")
} - set(PAIRS.values()) - {"common"}
for stem in sorted(unexercised):
print(f"WARN {stem}.schema.json has no fixture")
# Emit JSON copies so the Go round-trip test can read fixtures without a
# YAML dependency (the build stays free of third-party Go modules).
json_dir = FIXTURES / "json"
json_dir.mkdir(exist_ok=True)
for fixture_stem in PAIRS:
instance = yaml.safe_load((FIXTURES / f"{fixture_stem}.yaml").read_text())
(json_dir / f"{fixture_stem}.json").write_text(
json.dumps(instance, indent=2, sort_keys=True) + "\n"
)
print()
failures += run_negative(store)
if failures:
print(f"\n{failures} check(s) failed")
return 1
print(f"\nAll {len(PAIRS)} fixtures validate; all {len(NEGATIVE)} rejected cases refused")
return 0
if __name__ == "__main__":
sys.exit(main())