📝 docs(tsl-api): resolve backtesting return contract

This commit is contained in:
csh
2026-08-25 13:16:45 +08:00
parent d1568c02cd
commit 9c8d77e1c4
7 changed files with 834 additions and 56 deletions
@@ -2,6 +2,7 @@
"""Library for validating and resolving evidence-backed framework profiles."""
import json
from copy import deepcopy
from pathlib import Path
from lookup import (
@@ -87,6 +88,17 @@ def validate_source_ids(data, rows):
errors.append(
f"{section}[{entry_index}].evidence references unknown source {source}"
)
if section == "contracts" and isinstance(entry, dict):
for schema_index, schema in enumerate(
entry.get("return_schemas", [])
):
for source in evidence_set(schema):
if source not in known_sources:
errors.append(
f"contracts[{entry_index}].return_schemas"
f"[{schema_index}].evidence references unknown source "
f"{source}"
)
return errors
@@ -209,6 +221,54 @@ def validate_framework(framework, rows, codegen_root, index):
f"{framework['qualified_name']}.contracts[{contract_index}] "
f"references unknown source {source}"
)
if not isinstance(contract, dict) or contract.get("status") != "resolved":
continue
discriminator = contract.get("mode_discriminator")
if not isinstance(discriminator, dict) or not discriminator.get("api"):
errors.append(
f"{framework['qualified_name']}.contracts[{contract_index}] resolved "
"contracts must contain mode_discriminator.api"
)
continue
configured_apis = {
normalize(entry.get("api", ""))
for entry in framework.get("configuration", [])
if isinstance(entry, dict)
}
if normalize(discriminator["api"]) not in configured_apis:
errors.append(
f"{framework['qualified_name']}.contracts[{contract_index}]."
f"mode_discriminator.api {discriminator['api']!r} is not a "
"configuration member"
)
schemas = contract.get("return_schemas")
if not isinstance(schemas, list) or not schemas:
errors.append(
f"{framework['qualified_name']}.contracts[{contract_index}] resolved "
"contracts must contain return_schemas"
)
continue
discriminator_field = discriminator["api"].rsplit(".", 1)[-1]
seen_values = set()
for schema_index, schema in enumerate(schemas):
path = (
f"{framework['qualified_name']}.contracts[{contract_index}]."
f"return_schemas[{schema_index}]"
)
if not isinstance(schema, dict):
errors.append(f"{path} must be an object")
continue
value = schema.get("when", {}).get(discriminator_field)
if value is None or str(value).strip() == "":
errors.append(f"{path}.when must select {discriminator_field}")
elif str(value) in seen_values:
errors.append(f"{path}.when duplicates {discriminator_field}={value}")
else:
seen_values.add(str(value))
if not isinstance(schema.get("fields"), list) or not schema["fields"]:
errors.append(f"{path}.fields must be a non-empty array")
if not evidence_set(schema):
errors.append(f"{path}.evidence must contain at least one source id")
return errors
@@ -225,6 +285,47 @@ def validate_index(data, rows, codegen_root):
return errors
def contract_mode_mapping(contract, configuration_api):
discriminator = contract.get("mode_discriminator", {})
return (
contract.get("status") == "resolved"
and normalize(discriminator.get("api", "")) == normalize(configuration_api)
and isinstance(contract.get("return_schemas"), list)
)
def resolved_contract_packet(contract, config):
packet = deepcopy(contract)
discriminator = packet.get("mode_discriminator")
packet["selected_return_schema"] = None
if not isinstance(discriminator, dict) or not discriminator.get("api"):
return packet
field = discriminator["api"].rsplit(".", 1)[-1]
schemas = packet.get("return_schemas", [])
values = [
str(schema.get("when", {}).get(field))
for schema in schemas
if schema.get("when", {}).get(field) is not None
]
packet["mode_discriminator"] = {
**discriminator,
"field": field,
"values": values,
}
if field in config:
requested = str(config[field])
packet["selected_return_schema"] = next(
(
schema
for schema in schemas
if str(schema.get("when", {}).get(field)) == requested
),
None,
)
return packet
def scaffold_packet(framework, config):
configured_names = {
entry["api"].rsplit(".", 1)[-1]
@@ -245,7 +346,15 @@ def scaffold_packet(framework, config):
}
)
for entry in framework["configuration"]:
if entry.get("contract_evidence_required") and entry["api"].rsplit(".", 1)[-1] in config:
field = entry["api"].rsplit(".", 1)[-1]
if not entry.get("contract_evidence_required") or field not in config:
continue
mapped_contracts = [
contract
for contract in framework["contracts"]
if contract_mode_mapping(contract, entry["api"])
]
if not mapped_contracts:
diagnostics.append(
{
"code": "CONTRACT_MODE_UNRESOLVED",
@@ -258,6 +367,29 @@ def scaffold_packet(framework, config):
"source_ids": entry.get("evidence", []),
}
)
continue
requested = str(config[field])
available = {
str(schema.get("when", {}).get(field))
for contract in mapped_contracts
for schema in contract.get("return_schemas", [])
if schema.get("when", {}).get(field) is not None
}
if requested not in available:
diagnostics.append(
{
"code": "CONTRACT_MODE_UNKNOWN",
"severity": "error",
"message": (
f"{entry['api']}={requested!r} has no recorded return schema."
),
"next_action": (
"Use one of the documented mode values: "
+ ", ".join(sorted(available))
),
"source_ids": entry.get("evidence", []),
}
)
contract_status = "resolved"
for contract in framework["contracts"]:
if contract.get("status") != "resolved":
@@ -271,6 +403,15 @@ def scaffold_packet(framework, config):
"source_ids": contract.get("evidence", []),
}
)
contracts = [
resolved_contract_packet(contract, config)
for contract in framework["contracts"]
]
if any(
diagnostic["code"] in {"CONTRACT_MODE_UNKNOWN", "CONTRACT_MODE_UNRESOLVED"}
for diagnostic in diagnostics
):
contract_status = "incomplete"
return {
"status": "resolved",
"scaffold_status": "resolved",
@@ -285,6 +426,7 @@ def scaffold_packet(framework, config):
"state_apis": framework["state_apis"],
"execution": framework["execution"],
"result_apis": framework["result_apis"],
"contracts": contracts,
"diagnostics": diagnostics,
"evidence": framework.get("evidence", []),
}