refactor: unify data preparations and research input snapshots
Deploy production / deploy (push) Successful in 53s

This commit is contained in:
yuxuanhui
2026-09-12 01:24:02 +08:00
parent 849f86fef7
commit 394438e753
82 changed files with 4146 additions and 2076 deletions
+12 -24
View File
@@ -11,7 +11,7 @@ from app.ai.tools import CAPABILITIES
from app.alphas import upsert_alpha
from app.backtests.contracts import PreviewInput, RerunInput, SubsetInput
from app.business import Business
from app.models import BacktestPreview, BacktestRun, Research, TemplateInput
from app.models import BacktestPreview, BacktestRun, Research, ResearchInputSnapshot
from tests.test_ai import configure, single_tool_factory
from tests.test_backtests import execute, setup, start
from tests.test_catalog import SCOPE, prepare, sync
@@ -47,7 +47,7 @@ def construction(input_id):
return {
"name": "字段研究",
"hypothesis": "显式字段排序",
"template_input_id": input_id,
"input_snapshot_id": input_id,
"candidates": [
{
"client_item_id": "one",
@@ -66,7 +66,7 @@ async def test_chatbox_catalog_to_results_and_alpha_sources(app, logged_in, fixe
conversation = (await logged_in.post("/api/v1/ai/conversations")).json()["id"]
context = {"page": "datasets", "catalog_scope": SCOPE, "dataset_id": "TEST_FIN"}
if use_saved_input:
context["template_input_id"] = fixed_input["id"]
context["input_snapshot_id"] = fixed_input["id"]
run = await ask(logged_in, conversation, "研究此输入" if use_saved_input else "自行选字段研究", context)
assert run["status"] == "waiting_approval", run
assert not platform.posts
@@ -75,7 +75,7 @@ async def test_chatbox_catalog_to_results_and_alpha_sources(app, logged_in, fixe
assert source["kind"] == "chatbox"
assert source["reference"] == conversation
assert source["research_id"] == run["id"]
assert source["template_input_id"]
assert source["input_snapshot_id"]
assert approval["preview"]["backtest"]["items"][0]["expression"] == "rank(TEST_FIN_001)"
async with app.state.sessions() as db:
assert await db.scalar(select(func.count()).select_from(BacktestRun)) == 0
@@ -128,7 +128,7 @@ async def test_invalid_construction_has_no_partial_preview(logged_in, app, fixed
elif invalid == "unknown_type":
item["bindings"]["signal"] = {"field_id": "TEST_FIN_122", "field_type": "MATRIX"}
else:
body["template_input_id"] = "missing"
body["input_snapshot_id"] = "missing"
response = await logged_in.post("/api/v1/backtests/research-previews", json=body)
assert response.status_code == (404 if invalid == "missing_input" else 422), response.text
async with app.state.sessions() as db:
@@ -144,15 +144,10 @@ async def test_input_pagination_old_types_and_explicit_exclusions(app, logged_in
assert page["field_count"] == page["total"] == 123 and len(page["items"]) == 23
assert page["items"][-1]["field_type"] == "FUTURE_TYPE" and not page["has_more"]
assert page["_meta"]["source"] == "local_database"
selected = await tool(
"prepare_research_input",
{
"scope": SCOPE,
"dataset_id": "TEST_FIN",
"collection_version": fixed_input["collection_version"],
"field_ids": ["TEST_FIN_001"],
},
)
subset = (await logged_in.post("/api/v1/data-preparations", json={"name": "one field", "scope": SCOPE,
"fields": [{"scope": SCOPE, "dataset_id": "TEST_FIN", "field_id": "TEST_FIN_001", "source": "local",
"collection_version": fixed_input["fields"][0]["collection_version"]}]})).json()
selected = await tool("prepare_research_input", {"items": [{"id": subset["id"], "version": subset["version"]}]})
assert selected["field_count"] == 1
bad = construction(selected["id"])
bad["candidates"][0]["bindings"]["signal"]["field_id"] = "TEST_FIN_002"
@@ -166,19 +161,12 @@ async def test_input_pagination_old_types_and_explicit_exclusions(app, logged_in
"/api/v1/backtests/research-previews", json=construction(fixed_input["id"])
)
assert response.status_code == 201, response.text
await logged_in.patch(f"/api/v1/data-preparations/{subset['id']}", json={"name": "edited", "version": subset["version"]})
with pytest.raises(HTTPException) as exc:
await tool(
"prepare_research_input",
{
"scope": SCOPE,
"dataset_id": "TEST_FIN",
"collection_version": fixed_input["collection_version"],
"field_ids": ["TEST_FIN_001"],
},
)
await tool("prepare_research_input", {"items": [{"id": subset["id"], "version": subset["version"]}]})
assert exc.value.status_code == 409
async with app.state.sessions() as db:
assert await db.scalar(select(func.count()).select_from(TemplateInput)) == 2
assert await db.scalar(select(func.count()).select_from(ResearchInputSnapshot)) == 2
async def test_multiple_origins_preserve_research_and_do_not_duplicate_alphas(app, logged_in):