T06: optimization-case schema, fail-closed evaluator, cadence and decision template. Every option including the baseline must present all ten decision fields; one unknown blocks the comparison. Validated on the storage case (Hetzner computes and loses to Scaleway by EUR 29.14/month on operator labour; Host Europe blocks on four named gaps) and on the non-storage reef-railiance k3s rightsizing case (low utilization is real, but nothing is costable while the railiance01 price is unknown). T07: portfolio report over coverage, lifecycle, utilization, cost, renewals, risks, open cases, and next actions, derived only from committed evidence. Portfolio spend is reported null rather than as a partial sum, unattributed cost is a named list rather than a spread, and unmeasurable resources are reported rather than dropped. RESOURCE-WP-0003 is finished; both cases remain blocked_on_evidence against live delegated records in other repositories. RESOURCE-WP-0002 is untouched. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
101 lines
5.2 KiB
JSON
101 lines
5.2 KiB
JSON
{
|
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
"$id": "https://coulomb.social/resource-control/planning-evidence.schema.json",
|
|
"title": "Resource-control planning evidence v0.1",
|
|
"oneOf": [
|
|
{"$ref": "#/$defs/forecast"},
|
|
{"$ref": "#/$defs/usage_observation"},
|
|
{"$ref": "#/$defs/allocation"},
|
|
{"$ref": "#/$defs/optimization"},
|
|
{"$ref": "#/$defs/commitment_candidate"}
|
|
],
|
|
"$defs": {
|
|
"money": {"type": "string", "pattern": "^(0|[1-9][0-9]*)\\.[0-9]{2}$"},
|
|
"common": {
|
|
"type": "object",
|
|
"required": ["schema_version", "record_type", "record_id", "resource_id", "period_start", "period_end", "source_evidence", "created_at"],
|
|
"properties": {
|
|
"schema_version": {"const": "0.1"},
|
|
"record_type": {"enum": ["forecast", "usage_observation", "allocation", "optimization", "commitment_candidate"]},
|
|
"record_id": {"type": "string", "minLength": 1},
|
|
"revision_of": {"type": ["string", "null"]},
|
|
"resource_id": {"type": "string", "pattern": "^resource:"},
|
|
"service_id": {"type": ["string", "null"]},
|
|
"workload_id": {"type": ["string", "null"]},
|
|
"tenant_id": {"type": ["string", "null"]},
|
|
"environment": {"type": ["string", "null"]},
|
|
"cost_attribution_key": {"type": ["string", "null"]},
|
|
"period_start": {"type": "string", "format": "date"},
|
|
"period_end": {"type": "string", "format": "date"},
|
|
"source_evidence": {"type": "array", "items": {"type": "string"}},
|
|
"created_at": {"type": "string", "format": "date-time"}
|
|
}
|
|
},
|
|
"cost_breakdown": {
|
|
"type": "object",
|
|
"additionalProperties": false,
|
|
"required": ["infrastructure", "internal_labor", "external_services", "setup", "other"],
|
|
"properties": {
|
|
"infrastructure": {"$ref": "#/$defs/money"},
|
|
"internal_labor": {"$ref": "#/$defs/money"},
|
|
"external_services": {"$ref": "#/$defs/money"},
|
|
"setup": {"$ref": "#/$defs/money"},
|
|
"other": {"$ref": "#/$defs/money"}
|
|
}
|
|
},
|
|
"forecast": {
|
|
"allOf": [
|
|
{"$ref": "#/$defs/common"},
|
|
{
|
|
"type": "object",
|
|
"required": ["currency", "scenario", "forecast_version", "costs", "assumptions"],
|
|
"properties": {
|
|
"record_type": {"const": "forecast"},
|
|
"currency": {"type": "string", "pattern": "^[A-Z]{3}$"},
|
|
"scenario": {"enum": ["low", "base", "high"]},
|
|
"forecast_version": {"type": "string", "minLength": 1},
|
|
"costs": {"$ref": "#/$defs/cost_breakdown"},
|
|
"uncertainty": {"type": ["string", "null"]},
|
|
"assumptions": {"type": "array", "items": {"type": "string"}}
|
|
}
|
|
}
|
|
],
|
|
"unevaluatedProperties": false
|
|
},
|
|
"usage_observation": {
|
|
"allOf": [
|
|
{"$ref": "#/$defs/common"},
|
|
{
|
|
"type": "object",
|
|
"required": ["measures"],
|
|
"properties": {
|
|
"record_type": {"const": "usage_observation"},
|
|
"measures": {"type": "array", "items": {"type": "object", "additionalProperties": false, "required": ["name", "value", "unit"], "properties": {"name": {"type": "string"}, "value": {"type": "string"}, "unit": {"type": "string"}}}}
|
|
}
|
|
}
|
|
],
|
|
"unevaluatedProperties": false
|
|
},
|
|
"allocation": {
|
|
"allOf": [
|
|
{"$ref": "#/$defs/common"},
|
|
{"type": "object", "required": ["currency", "financial_fact_ids", "method", "allocated_amount", "shares", "residual_share"], "properties": {"record_type": {"const": "allocation"}, "currency": {"type": "string", "pattern": "^[A-Z]{3}$"}, "financial_fact_ids": {"type": "array", "minItems": 1, "items": {"type": "string"}}, "method": {"type": "string"}, "allocated_amount": {"$ref": "#/$defs/money"}, "shares": {"type": "array"}, "residual_share": {"type": "string"}}}
|
|
],
|
|
"unevaluatedProperties": false
|
|
},
|
|
"optimization": {
|
|
"allOf": [
|
|
{"$ref": "#/$defs/common"},
|
|
{"type": "object", "required": ["currency", "baseline", "alternative", "one_time_cost", "expected_period_savings", "assumptions"], "properties": {"record_type": {"const": "optimization"}, "currency": {"type": "string", "pattern": "^[A-Z]{3}$"}, "baseline": {"$ref": "#/$defs/cost_breakdown"}, "alternative": {"$ref": "#/$defs/cost_breakdown"}, "one_time_cost": {"$ref": "#/$defs/money"}, "expected_period_savings": {"$ref": "#/$defs/money"}, "assumptions": {"type": "array", "items": {"type": "string"}}}}
|
|
],
|
|
"unevaluatedProperties": false
|
|
},
|
|
"commitment_candidate": {
|
|
"allOf": [
|
|
{"$ref": "#/$defs/common"},
|
|
{"type": "object", "required": ["currency", "setup_cost", "recurring_cost", "cadence", "term_start", "approval_status"], "properties": {"record_type": {"const": "commitment_candidate"}, "currency": {"type": "string", "pattern": "^[A-Z]{3}$"}, "setup_cost": {"$ref": "#/$defs/money"}, "recurring_cost": {"$ref": "#/$defs/money"}, "cadence": {"enum": ["monthly", "quarterly", "annual", "one_time"]}, "term_start": {"type": "string", "format": "date"}, "term_end": {"type": ["string", "null"], "format": "date"}, "approval_status": {"const": "candidate"}}}
|
|
],
|
|
"unevaluatedProperties": false
|
|
}
|
|
}
|
|
}
|