feat: add Super Alpha research, management and MCP workflows
Deploy production / deploy (push) Successful in 56s

This commit is contained in:
yuxuanhui
2026-09-13 12:32:16 +08:00
parent 7c8188df9c
commit e256d6fef1
59 changed files with 3766 additions and 125 deletions
+16 -4
View File
@@ -16,10 +16,16 @@ class Platform:
self.detail_fail = False
self.fail_child = None
self.missing = False
self.selection_reads = []
self.selection_result = {"count": 2, "results": [{"id": "component1", "value": 0.3}, {"id": "component2", "value": 0.7}]}
self.actual_components = {"count": 2, "results": [{"id": "component1"}, {"id": "component2"}]}
self.secret = "synthetic-platform-secret"
def __call__(self, request):
path = request.url.path
if path == "/simulations/super-selection":
self.selection_reads.append(dict(request.url.params))
return httpx.Response(200, json=self.selection_result)
if path == "/authentication":
return httpx.Response(201, json={})
if path == "/simulations" and request.method == "POST":
@@ -39,29 +45,35 @@ class Platform:
ids = []
for i, item in enumerate(data):
child = parent if len(data) == 1 else f"{parent}c{i}"
aid = self.existing_alpha_ids[i] if self.existing_alpha_ids else f"alpha{parent}{i}"
aid = self.existing_alpha_ids[i] if self.existing_alpha_ids and item["type"] != "SUPER" else f"alpha{parent}{i}"
progress = {
"status": "COMPLETE",
"alpha": aid,
"regular": item["regular"],
"regular": item.get("regular", ""),
"settings": item["settings"],
}
if i == self.fail_child:
progress = {
"status": "FAILED",
"regular": item["regular"],
"regular": item.get("regular", ""),
"settings": item["settings"],
"message": "invalid expression",
}
self.simulations[child] = progress
self.alphas[aid] = {
"id": aid,
"regular": {"code": item["regular"]},
"regular": {"code": item.get("regular", "")},
"type": "REGULAR",
"settings": item["settings"],
"is": {"sharpe": None, "fitness": 0.8},
"status": "UNSUBMITTED",
}
if item["type"] == "SUPER":
assert len(data) == 1, "SUPER must be submitted singly"
self.simulations[child].update(type="SUPER", selection=item["selection"], combo=item["combo"])
self.simulations[child].pop("regular", None)
self.alphas[aid].update(type="SUPER", selection={"code": item["selection"], "description": "Selection rationale"}, combo={"code": item["combo"], "description": "Combo rationale"}, components=self.actual_components)
self.alphas[aid].pop("regular", None)
ids.append(child)
if len(data) > 1:
self.simulations[parent] = {
+74
View File
@@ -0,0 +1,74 @@
"""Disposable PostgreSQL compatibility/concurrency acceptance, no external platform calls.
SUPER_TEST_DATABASE_URL must point to the local wq_superalpha_test database.
"""
import asyncio
import os
from urllib.parse import urlsplit
import httpx
from alembic import command
from alembic.config import Config
from cryptography.fernet import Fernet
from sqlalchemy import select
from app.alphas import upsert_alpha
from app.config import Settings
from app.main import create_app
from app.models import BacktestItem, Research
from app.superalpha.contracts import PlanSave
from app.superalpha.service import SuperResearch
from app.worldquant import WqClient
from tests.backtest_fake import Platform
from tests.test_backtests import execute, preview, setup, start
from tests.test_superalpha import plan, test_plan_selection_build_versions_and_generic_run
async def seed(settings):
app = create_app(settings, WqClient(settings, transport=httpx.MockTransport(Platform())))
async with app.router.lifespan_context(app):
_, lane = await setup(app)
async with app.state.sessions.begin() as db:
await upsert_alpha(db, {"id": "legacy-super", "type": "SUPER", "selection": {"code": "turnover < 0.2"}, "combo": {"code": "1"}})
(await db.get(Research, "legacy-super")).note = "keep historical note"
async with httpx.AsyncClient(transport=httpx.ASGITransport(app=app), base_url="http://testserver", headers={"X-WQ-Request": "1"}) as client:
await client.post("/api/v1/auth/login", json={"username": "admin", "password": "synthetic-admin-only"})
run = await start(client, await preview(client), "legacy")
await execute(app, lane, run["backtest_run_id"])
async def verify(settings):
app = create_app(settings, WqClient(settings, transport=httpx.MockTransport(Platform())))
async with app.router.lifespan_context(app):
async with app.state.sessions() as db:
assert (await db.get(Research, "legacy-super")).note == "keep historical note"
item = await db.scalar(select(BacktestItem))
assert item.alpha_type == "REGULAR" and item.selection is None and item.combo is None
assert item.persistence_status == "saved"
async with httpx.AsyncClient(transport=httpx.ASGITransport(app=app), base_url="http://testserver", headers={"X-WQ-Request": "1"}) as client:
await client.post("/api/v1/auth/login", json={"username": "admin", "password": "synthetic-admin-only"})
await test_plan_selection_build_versions_and_generic_run(app, client)
imported = (await client.get("/api/v1/alphas?management_scope=super&q=legacy-super")).json()
assert imported["total"] == 1
async def save_same():
async with app.state.sessions.begin() as db:
return await SuperResearch(db).save(PlanSave(plan=plan(), idempotency_key="concurrent-save"))
first, second = await asyncio.gather(save_same(), save_same())
assert first == second
print("PostgreSQL: preserved REGULAR backtest and existing SUPER/notes; SUPER lifecycle and concurrent save replay passed")
if __name__ == "__main__":
url = os.environ["SUPER_TEST_DATABASE_URL"]
parsed = urlsplit(url)
if parsed.hostname not in {"127.0.0.1", "localhost"} or parsed.path != "/wq_superalpha_test":
raise SystemExit("Refusing non-local/non-disposable database")
key = Fernet.generate_key().decode()
os.environ.update(DATABASE_URL=url, ADMIN_PASSWORD="synthetic-admin-only", ENCRYPTION_KEY=key, WQ_EMAIL="", WQ_PASSWORD="")
settings = Settings(_env_file=None, database_url=url, admin_password="synthetic-admin-only", encryption_key=key, enable_runner=False, public_origin="http://testserver")
config = Config("alembic.ini")
command.upgrade(config, "head")
asyncio.run(seed(settings))
command.downgrade(config, "0020")
command.upgrade(config, "head")
asyncio.run(verify(settings))
+1 -1
View File
@@ -162,7 +162,7 @@ async def test_official_sdk_client_and_error_contract(mcp_app):
async with ClientSession(streams[0], streams[1]) as client:
await client.initialize()
listed = await client.list_tools()
assert len(listed.tools) == 21
assert len(listed.tools) == 29
assert any(tool.name == "get_pyramid_distribution" for tool in listed.tools)
assert {"search_data_preparations", "get_data_preparation"} <= {t.name for t in listed.tools}
caps = await client.call_tool("get_research_capabilities", {})
+210
View File
@@ -0,0 +1,210 @@
"""SUPER public HTTP/MCP acceptance using isolated persistence and synthetic upstream."""
import asyncio
from copy import deepcopy
import pytest
from fastapi import HTTPException
from sqlalchemy import func, select
from app.backtests.contracts import Candidate
from app.models import SimulationAttempt, SuperSelectionSnapshot
from app.superalpha.evidence import parse_components
from tests.test_backtests import PARAMS, candidate, execute, preview, setup, start
from tests.test_mcp import credentials, invoke, mcp_app # noqa: F401
SETTINGS = PARAMS | {"selectionHandling": "POSITIVE", "selectionLimit": 100, "componentActivation": "IS"}
def super_candidate(index=0, **changes):
return {"client_item_id": f"super-{index}", "alpha_type": "SUPER", "selection": f"turnover < {0.1 + index / 10}", "combo": "alpha", "settings": SETTINGS} | changes
def plan(**changes):
return {"name": "Super 研究", "hypothesis": "降低组件换手", "selection": "turnover < {threshold}", "combo": "alpha", "variables": {"threshold": {"kind": "number", "values": [0.1, 0.2]}}, "settings": SETTINGS, "include_baseline": True} | changes
async def test_plan_selection_build_versions_and_generic_run(app, logged_in):
platform, lane = await setup(app)
body = {"plan": plan(), "idempotency_key": "save1"}
saved = (await logged_in.post("/api/v1/superalpha/plans", json=body)).json()
assert saved["version"] == 1, saved
assert (await logged_in.post("/api/v1/superalpha/plans", json=body)).json() == saved
selection = {"selection": "turnover < 0.1", "settings": SETTINGS, "plan_id": saved["id"], "version": 1}
job = (await logged_in.post("/api/v1/superalpha/selections", json=selection)).json()
assert (await logged_in.post("/api/v1/superalpha/selections", json=selection)).json()["job_id"] == job["job_id"]
await app.state.runner.run_next()
snap = (await logged_in.get(f"/api/v1/superalpha/selections?job_id={job['job_id']}&limit=1")).json()
assert snap["complete"] and snap["has_more"] and snap["total"] == 2, snap
assert len(platform.selection_reads) == 1 and not platform.posts
assert set(platform.selection_reads[0]) == {"selection", "instrumentType", "region", "delay", "selectionLimit", "selectionHandling"}
build = {"plan_id": saved["id"], "version": 1, "selection_snapshot_ids": [snap["snapshot_id"]], "idempotency_key": "build1"}
exp = (await logged_in.post("/api/v1/superalpha/candidates", json=build)).json()
assert exp["total"] == 4, exp
assert (await logged_in.post("/api/v1/superalpha/candidates", json=build)).json() == exp
# A subset keeps the original experiment's evidence without claiming it applies to every candidate.
p = await logged_in.post(f"/api/v1/superalpha/experiments/{exp['id']}/preview", json={"candidate_ids": ["super-2", "super-2-baseline"]})
assert p.status_code == 200, p.text
assert p.json()["batch_count"] == 2 and not platform.posts
rid = (await start(logged_in, p.json()))["backtest_run_id"]
await execute(app, lane, rid)
result = (await logged_in.get(f"/api/v1/backtests/runs/{rid}/results")).json()
assert all(i["persistence_status"] == "saved" and i["alpha_type"] == "SUPER" for i in result["items"]), result
assert len(platform.posts) == 2 and all(len(p) == 1 for p in platform.posts)
item = result["items"][0]
actual = (await logged_in.get(f"/api/v1/backtests/items/{item['id']}/artifact?kind=components")).json()
assert actual["complete"] and actual["source"] == "actual" and actual["snapshot_id"] != snap["snapshot_id"]
assert actual["component_hash"] == snap["component_hash"]
alpha = (await logged_in.get(f"/api/v1/superalpha/alphas/{item['alpha_id']}")).json()
assert alpha["descriptions"]["combo"] == "Combo rationale"
assert alpha["sources"]["items"][0]["source"]["superalpha_plan_version"] == 1
changed = body | {"plan": plan(name="修订"), "plan_id": saved["id"], "version": 1, "idempotency_key": "save2"}
assert (await logged_in.post("/api/v1/superalpha/plans", json=changed)).json()["version"] == 2
assert (await logged_in.post("/api/v1/superalpha/plans", json=changed | {"idempotency_key": "save3"})).status_code == 409
assert (await logged_in.delete(f"/api/v1/superalpha/plans/{saved['id']}?version=2")).status_code == 200
assert (await logged_in.get(f"/api/v1/superalpha/plans/{saved['id']}?version=1")).json()["content"]["name"] == "Super 研究"
rows = (await logged_in.get(f"/api/v1/superalpha/experiments/{exp['id']}/results")).json()
assert rows["total"] == 2 and rows["items"][0]["pnl_fetched_at"] is None
async with app.state.sessions() as db:
assert await db.scalar(select(func.count()).select_from(SuperSelectionSnapshot)) == 3
async def test_mixed_run_isolation_facets_export_and_strict_match(app, logged_in):
platform, lane = await setup(app)
p = await preview(logged_in, [candidate(0), candidate(1), super_candidate(), super_candidate(1)])
assert p["batch_count"] == 3
rid = (await start(logged_in, p))["backtest_run_id"]
await execute(app, lane, rid)
assert len(platform.posts) == 3
results = (await logged_in.get(f"/api/v1/backtests/runs/{rid}/results")).json()["items"]
assert all(i["persistence_status"] == "saved" for i in results), results
for scope, kind in (("super", "SUPER"), ("non_super", "REGULAR")):
page = (await logged_in.get(f"/api/v1/alphas?management_scope={scope}")).json()
assert page["total"] == 2 and all(i["alpha_type"] == kind for i in page["items"])
facets = (await logged_in.get(f"/api/v1/alphas/facets?management_scope={scope}")).json()
assert facets["alpha_type"] == [kind], facets
export = await logged_in.get(f"/api/v1/alphas/export?management_scope={scope}")
assert export.status_code == 200
assert all(i["alpha_id"] in export.text for i in results if i["alpha_type"] == kind)
assert all(i["alpha_id"] not in export.text for i in results if i["alpha_type"] != kind)
rid2 = (await start(logged_in, await preview(logged_in, [super_candidate(9)]), "mismatch"))["backtest_run_id"]
async with app.state.sessions() as db:
aid = await db.scalar(select(SimulationAttempt.id).where(SimulationAttempt.run_id == rid2))
await lane.step(aid)
next(reversed(platform.alphas.values()))["combo"]["code"] = "WRONG"
await lane.step(aid)
row = (await logged_in.get(f"/api/v1/backtests/runs/{rid2}/results")).json()["items"][0]
assert row["persistence_status"] != "saved"
assert (await logged_in.get("/api/v1/backtests/runs?alpha_type=SUPER")).json()["total"] == 2
@pytest.mark.parametrize("reject", ["unknown", "missing_location", "rate"])
async def test_super_reliability_no_unknown_resubmission(app, logged_in, reject):
platform, lane = await setup(app)
platform.reject = reject
rid = (await start(logged_in, await preview(logged_in, [super_candidate()])))["backtest_run_id"]
async with app.state.sessions() as db:
aid = await db.scalar(select(SimulationAttempt.id).where(SimulationAttempt.run_id == rid))
for _ in range(app.state.settings.retry_attempts + 1):
await lane.step(aid)
await asyncio.sleep(0.02)
if reject == "rate":
assert len(platform.posts) == app.state.settings.retry_attempts
else:
await lane.start()
await lane.stop()
await logged_in.post(f"/api/v1/backtests/runs/{rid}/control", json={"action": "recover", "version": 1})
await lane.step(aid)
assert len(platform.posts) == 1
async def test_unknown_components_and_recovery(app, logged_in):
platform, lane = await setup(app)
platform.actual_components = None
platform.detail_fail = True
rid = (await start(logged_in, await preview(logged_in, [super_candidate()])))["backtest_run_id"]
ids = await execute(app, lane, rid)
platform.detail_fail = False
await logged_in.post(f"/api/v1/backtests/runs/{rid}/control", json={"action": "recover", "version": 1})
await lane.step(ids[0])
item = (await logged_in.get(f"/api/v1/backtests/runs/{rid}/results")).json()["items"][0]
assert item["persistence_status"] == "saved" and len(platform.posts) == 1
components = (await logged_in.get(f"/api/v1/backtests/items/{item['id']}/artifact?kind=components")).json()
assert components["complete"] is False and components["component_hash"] is None
async def test_sampling_validation_and_component_evidence(app, logged_in):
await setup(app)
for invalid in (super_candidate(selection=" "), super_candidate(combo=""), super_candidate(expression="close"), super_candidate(settings=PARAMS)):
with pytest.raises(ValueError):
Candidate.model_validate(invalid)
assert (await logged_in.get("/api/v1/superalpha/selections")).status_code == 422
assert parse_components({"count": 0, "results": []})["complete"]
for raw in (["a"], {"count": 2, "results": ["a"]}, {"count": 2, "results": ["a", "a"]}, {"count": 1, "results": ["a"], "next": "next"}):
assert not parse_components(raw)["complete"]
complete = parse_components({"count": 1, "results": ["a"], "warnings": ["synthetic warning"]})
assert complete["complete"] and complete["warnings"] == ["synthetic warning"]
args = {"plan": plan(variables={"threshold": {"kind": "number", "values": list(range(100))}}), "mode": "random", "limit": 5, "seed": 42, "idempotency_key": "random1"}
a = (await logged_in.post("/api/v1/superalpha/candidates", json=args)).json()
b = (await logged_in.post("/api/v1/superalpha/candidates", json=args | {"idempotency_key": "random2"})).json()
assert a["candidates"] == b["candidates"] and a["total"] == 10
bad = deepcopy(args)
bad["plan"]["setting_variants"] = {"selectionLimit": [0]}
assert (await logged_in.post("/api/v1/superalpha/candidates", json=bad)).status_code == 422
async def test_mcp_interop_permissions_inline_and_sources(mcp_app): # noqa: F811
app = mcp_app
principal, _ = await credentials(app, {"research:read", "research:write", "research:refresh", "backtests:execute"})
saved = await invoke(app, principal, "save_superalpha_plan", {"plan": plan(), "idempotency_key": "mcp-plan"})
built = await invoke(app, principal, "build_superalpha_candidates", {"plan_id": saved["id"], "version": 1, "idempotency_key": "mcp-build"})
assert not built["starts_backtests"] and built["total"] == 4
assert (await invoke(app, principal, "get_superalpha_plan", {"experiment_id": built["id"], "limit": 1}))["has_more"]
submit = {"name": "MCP SUPER", "candidates": built["candidates"][:1], "source": {"research_id": built["id"], "superalpha_plan_id": saved["id"], "superalpha_plan_version": 1}, "duplicate_policy": "rerun", "idempotency_key": "mcp-run"}
result = await invoke(app, principal, "submit_backtests", submit)
assert result == await invoke(app, principal, "submit_backtests", submit)
rid = result["backtest_run_id"]
await execute(app, app.state.runner.backtests, rid)
results = await invoke(app, principal, "get_backtest_results", {"run_id": rid})
item = results["items"][0]
assert item["persistence_status"] == "saved", results
alpha = await invoke(app, principal, "get_superalpha", {"alpha_id": item["alpha_id"]})
assert alpha["alpha_type"] == "SUPER" and "#superalphas?" in alpha["web_url"]
forged = deepcopy(submit)
forged["idempotency_key"] = "forged"
forged["candidates"][0]["combo"] = "WRONG"
assert (await app.state.mcp.invoke(principal, "submit_backtests", forged)).is_error
direct = submit | {"source": {}, "candidates": [super_candidate(9)], "idempotency_key": "direct"}
assert (await invoke(app, principal, "submit_backtests", direct))["source"]["superalpha_plan_id"] is None
readonly, _ = await credentials(app, {"research:read"})
with pytest.raises(HTTPException) as exc:
await app.state.mcp.invoke(readonly, "save_superalpha_plan", {"plan": plan(), "idempotency_key": "denied"})
assert exc.value.status_code == 403
async def test_metadata_stage_constraints_selection_recovery_and_cancel(app, logged_in):
from app.catalog.research_metadata import ResearchMetadata
from app.models import Job
from app.superalpha.jobs import run_selection
platform, _ = await setup(app)
async with app.state.sessions.begin() as db:
await ResearchMetadata(db).publish("settings", "settings", {"items": [{"instrument_type": "EQUITY", "region": "USA", "delay": 1, "universe": "TOP3000", "neutralizations": ["INDUSTRY"], "fields": {"selectionLimit": {"maximum": 50}}}]})
await ResearchMetadata(db).publish("operators", "operators", {"items": [
{"name": "combo_a", "category": "Combo", "scope": ["COMBO"]},
{"name": "not_combo", "category": "Other", "scope": ["UNKNOWN_COMBO"]},
{"name": "unspecified", "category": "Other", "scope": None}]})
assert (await logged_in.post("/api/v1/superalpha/plans", json={"plan": plan(), "idempotency_key": "bad-settings"})).status_code == 422
p = await logged_in.post("/api/v1/backtests/previews", json={"inline": {"name": "bad", "candidates": [super_candidate()]}})
assert p.status_code == 422
assert [o["name"] for o in (await logged_in.get("/api/v1/catalog/operators?stage=COMBO")).json()["items"]] == ["combo_a"]
payload = {"selection": "turnover", "settings": SETTINGS | {"selectionLimit": 50}}
job = (await logged_in.post("/api/v1/superalpha/selections", json=payload)).json()
await app.state.runner.run_next()
await run_selection(app.state.runner, job["job_id"], payload) # Restart after commit preserves evidence.
assert len(platform.selection_reads) == 1
cancelled = (await logged_in.post("/api/v1/superalpha/selections", json=payload)).json()
async with app.state.sessions.begin() as db:
(await db.get(Job, cancelled["job_id"])).cancel_requested = True
await app.state.runner.run_next()
async with app.state.sessions() as db:
assert (await db.get(Job, cancelled["job_id"])).status == "cancelled"
assert await db.scalar(select(func.count()).select_from(SuperSelectionSnapshot)) == 1