Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
a1a0348
refactor(paper): 统一策略真实评估与市场时间契约
mirror29 Aug 14, 2026
b7c1704
feat(evolver): 完成单代演化持久化异步闭环
mirror29 Aug 14, 2026
2999cb1
feat(orchestration): 接入显式授权的演化工具
mirror29 Aug 14, 2026
82b7856
feat(dashboard): 增加演化列表与候选详情
mirror29 Aug 14, 2026
ee0fc1b
chore(infra): 接入 Evolver 开发部署链路
mirror29 Aug 14, 2026
de5a004
fix(qa): ISSUE-001 — 补齐演化页面上下文文案
mirror29 Aug 14, 2026
2af8650
test(qa): regression test for ISSUE-001 — 演化上下文文案
mirror29 Aug 14, 2026
2a033b7
fix(orchestration): 阻止同轮对话绕过显式审批
mirror29 Aug 18, 2026
7ed4937
fix(evolution): 隔离候选源码执行并严格应用 diff
mirror29 Aug 20, 2026
e213311
fix(evolution): 收口异步运行时竞态与总期限
mirror29 Aug 20, 2026
4854bad
docs(evolution): 记录 E1 生产闭环收口方案
mirror29 Aug 20, 2026
d3538dc
fix(infra): 加固 0038 演化迁移数据安全
mirror29 Aug 20, 2026
179b648
fix(evolver): 完善金融冻结数据集语义
mirror29 Aug 20, 2026
7881bd6
ci(evolution): 将 Paper 与 Evolver 测试设为必跑
mirror29 Aug 20, 2026
649f948
fix(orchestration): 收紧认证与显式审批闸门
mirror29 Aug 20, 2026
06e1752
fix(dashboard): 修复多租户隔离——审批/候选池 401 与系统调度日志泄露
mirror29 Aug 21, 2026
3f7d163
fix(paper): 风控锁按账户隔离(risk_locks 补 account_id)
mirror29 Aug 21, 2026
ee0cdf7
Merge remote-tracking branch 'origin/main' into feat/e1-evolution-pro…
Aug 25, 2026
f50dc50
fix(ci): E1 evolver 步骤在 migrations 目录跑 alembic
Aug 25, 2026
88dd186
fix(ci): evolver 测试连 CI 已建的迁移测试库
Aug 25, 2026
512f5ff
fix(ci): paper 测试 JWT_SECRET 与 conftest 一致
Aug 25, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,21 @@ DATA_SERVICE_URL=http://localhost:8001
PAPER_SERVICE_URL=http://localhost:8002
RESEARCH_SERVICE_URL=http://localhost:8003
FACTOR_SERVICE_URL=http://localhost:8004
EVOLVER_SERVICE_URL=http://localhost:8005

DATA_SERVICE_PORT=8001
PAPER_SERVICE_PORT=8002
RESEARCH_SERVICE_PORT=8003
FACTOR_SERVICE_PORT=8004
EVOLVER_SERVICE_PORT=8005
# 可选 self-host capability gate;false 时 Dashboard 明确返回“演化服务未启用”。
EVOLVER_ENABLED=true

# Evolver E1 单 worker / 单副本;每个 run 只跑一代候选。
EVOLVER_MAX_RUNNING_RUNS=1
EVOLVER_ACCOUNT_ACTIVE_LIMIT=2
EVOLVER_JOB_TIMEOUT_S=300
EVOLVER_JOB_MEM_GB=2

# factor 服务可选项(ADR-0043):qlib Alpha158 风格因子纯 pandas 本地算,默认开;
# 设 false 可整源关闭。snapshot top-N 去相关阈值默认 0.85(1.0 = 关闭去相关)
Expand Down
31 changes: 29 additions & 2 deletions .github/workflows/build-images.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
name: Build & Push Images

# CI 构建 6 个生产镜像(data/paper/research/factor + mastra + dashboard)并推送 GHCR。
# CI 构建 7 个生产镜像(data/paper/research/factor/evolver + mastra + dashboard)并推送 GHCR。
# VPS 端只 `docker compose pull` 不 `build`,绕开小内存机现场 build OOM。
# 见 docs/miro/decisions/0058。部署仍是手动 `scripts/deploy.sh`(非自动 CD)。
# 部署仍是手动 `scripts/deploy.sh`(非自动 CD)。
#
# 镜像命名:ghcr.io/<owner>/inalpha-<service>:{latest,<sha>}
# migrate 服务复用 inalpha-paper 镜像(不单独构建)。
Expand Down Expand Up @@ -69,6 +69,33 @@ jobs:
cache-from: type=gha,scope=${{ matrix.service }}
cache-to: type=gha,mode=max,scope=${{ matrix.service }}

evolver:
name: build · evolver
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Resolve owner (lowercase)
id: meta
run: echo "owner=${GITHUB_REPOSITORY_OWNER,,}" >> "$GITHUB_OUTPUT"
- uses: docker/setup-buildx-action@v3
- name: Log in to GHCR
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build & push
uses: docker/build-push-action@v6
with:
context: services
file: infra/docker/Dockerfile.evolver
push: true
tags: |
${{ env.REGISTRY }}/${{ steps.meta.outputs.owner }}/inalpha-evolver:latest
${{ env.REGISTRY }}/${{ steps.meta.outputs.owner }}/inalpha-evolver:${{ github.sha }}
cache-from: type=gha,scope=evolver
cache-to: type=gha,mode=max,scope=evolver

mastra:
name: build · mastra
runs-on: ubuntu-latest
Expand Down
57 changes: 56 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
service: [data, paper, research, factor]
service: [data, paper, research, factor, evolver]
steps:
- uses: actions/checkout@v4
- name: Install uv
Expand All @@ -189,3 +189,58 @@ jobs:
- name: Mypy (best-effort, allow failure)
working-directory: services/${{ matrix.service }}
run: uv run mypy . || true

python-e1-tests:
name: E1 · ${{ matrix.service }} pytest
runs-on: ubuntu-latest
timeout-minutes: 30
strategy:
fail-fast: false
matrix:
service: [paper, evolver]
services:
timescaledb:
image: timescale/timescaledb:2.27.2-pg17
env:
POSTGRES_USER: quant
POSTGRES_PASSWORD: devpass
POSTGRES_DB: inalpha_migration_ci_test
ports:
- 5432:5432
options: >-
--health-cmd "pg_isready -U quant -d inalpha_migration_ci_test"
--health-interval 5s
--health-timeout 5s
--health-retries 20
env:
DATABASE_URL: postgresql+psycopg://quant:devpass@localhost:5432/inalpha_test
INALPHA_MIGRATION_TEST_DATABASE_URL: postgresql+psycopg://quant:devpass@localhost:5432/inalpha_migration_ci_test
EVOLVER_TEST_DATABASE_URL: postgresql+psycopg://quant:devpass@localhost:5432/inalpha_migration_ci_test
JWT_SECRET: test-secret-do-not-use-in-prod-please-and-thank-you
DATA_SERVICE_URL: http://data-mock.test
PAPER_POOL_DISABLED: "1"
INALPHA_LIVE_RUNNER_RESUME_ON_STARTUP: "false"
steps:
- uses: actions/checkout@v4
- name: Install uv
uses: astral-sh/setup-uv@v3
with:
enable-cache: true
- name: Set up Python
run: uv python install 3.12
- name: Sync dependencies
working-directory: services/${{ matrix.service }}
run: uv sync --frozen
- name: Apply schema for Evolver tests
if: matrix.service == 'evolver'
working-directory: infra/migrations
run: uv run --project ../../services/evolver alembic upgrade head
env:
DATABASE_URL: postgresql+psycopg://quant:devpass@localhost:5432/inalpha_migration_ci_test
- name: Run service tests
working-directory: services/${{ matrix.service }}
run: uv run pytest -q tests
- name: Verify migration round trip
if: matrix.service == 'evolver'
working-directory: services/evolver
run: uv run pytest -q ../../infra/migrations/tests/test_migration_0038.py
52 changes: 49 additions & 3 deletions apps/dashboard/messages/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -497,6 +497,9 @@
"risk": "Risk panel",
"activity": "Agent log",
"divination": "Divination",
"evolution_list": "Strategy evolution",
"evolution_run_detail": "Evolution run",
"evolution_candidate_detail": "Evolution candidate",
"overview": "Overview"
}
}
Expand Down Expand Up @@ -540,8 +543,8 @@
"truncated": "Showing the latest {n} — earlier ones aren't listed here.",
"filter": {
"all": "All",
"done": "Done",
"running": "Running"
"terminal": "Finished",
"active": "Active"
},
"col": {
"run": "Run",
Expand All @@ -552,7 +555,50 @@
"rejected": "Blocked",
"cost": "Cost",
"time": "Time"
}
},
"detail": {
"back": "Back to evolution",
"title": "Evolution Run",
"abort": "Abort run",
"abortTitle": "Abort this evolution run?",
"abortDescription": "The current stage will be cancelled and no further slots will run. LLM costs already incurred cannot be reversed.",
"cancel": "Cancel",
"confirmAbort": "Abort run",
"aborting": "Aborting…",
"candidates": "Candidate slots",
"summary": "Run summary",
"stage": "Stage",
"attempts": "Attempts",
"succeeded": "Succeeded",
"rejected": "Blocked",
"cost": "Cost",
"failure": "Failure code",
"dataset": "Frozen dataset",
"seedReport": "Seed report",
"baseline": "Market baseline",
"notAvailable": "Not available yet",
"noCandidates": "No slots have been created yet.",
"slot": "Slot",
"outcome": "Outcome",
"fitness": "Fitness"
},
"candidate": {
"back": "Back to evolution run",
"title": "Candidate #{slot}",
"error": "Rejection / failure",
"stage": "Stage",
"fitness": "Fitness",
"risk": "Overfitting risk",
"cost": "Cost",
"diff": "Unified diff",
"source": "Strategy source",
"evaluation": "Evaluation snapshot",
"copy": "Copy",
"copied": "Copied",
"notAvailable": "Not available yet"
},
"loadMore": "Load more",
"loadingMore": "Loading…"
},
"backtests": {
"back": "Agent Activity",
Expand Down
52 changes: 49 additions & 3 deletions apps/dashboard/messages/zh.json
Original file line number Diff line number Diff line change
Expand Up @@ -497,6 +497,9 @@
"risk": "风控面板",
"activity": "Agent 日志",
"divination": "占卜台",
"evolution_list": "策略演化",
"evolution_run_detail": "演化运行",
"evolution_candidate_detail": "演化候选",
"overview": "总览"
}
}
Expand Down Expand Up @@ -540,8 +543,8 @@
"truncated": "仅展示最近 {n} 条,更早的记录未列出。",
"filter": {
"all": "全部",
"done": "已完成",
"running": "运行中"
"terminal": "已结束",
"active": "进行中"
},
"col": {
"run": "运行",
Expand All @@ -552,7 +555,50 @@
"rejected": "阻断",
"cost": "费用",
"time": "时间"
}
},
"detail": {
"back": "返回演化列表",
"title": "演化运行",
"abort": "中止运行",
"abortTitle": "确认中止演化?",
"abortDescription": "当前阶段会被取消,后续 slot 不再执行。已经发生的 LLM 费用不会撤销。",
"cancel": "取消",
"confirmAbort": "确认中止",
"aborting": "正在中止…",
"candidates": "候选 slot",
"summary": "运行摘要",
"stage": "阶段",
"attempts": "尝试",
"succeeded": "成功",
"rejected": "阻断",
"cost": "费用",
"failure": "失败码",
"dataset": "冻结数据集",
"seedReport": "种子报告",
"baseline": "市场基准",
"notAvailable": "尚不可用",
"noCandidates": "尚未产生 slot。",
"slot": "Slot",
"outcome": "结果",
"fitness": "适应度"
},
"candidate": {
"back": "返回演化运行",
"title": "候选 #{slot}",
"error": "拒绝 / 失败原因",
"stage": "阶段",
"fitness": "适应度",
"risk": "过拟合风险",
"cost": "费用",
"diff": "统一 Diff",
"source": "策略源码",
"evaluation": "评估快照",
"copy": "复制",
"copied": "已复制",
"notAvailable": "尚不可用"
},
"loadMore": "加载更多",
"loadingMore": "正在加载…"
},
"backtests": {
"back": "Agent 活动",
Expand Down
14 changes: 14 additions & 0 deletions apps/dashboard/src/app/[locale]/evolution/[runId]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { setRequestLocale } from "next-intl/server";

import { EvolutionRunDetailClient } from "@/components/evolution/EvolutionRunDetailClient";

/** 单次 E1 演化运行及其 slot 结果。 */
export default async function EvolutionRunPage({
params,
}: {
params: Promise<{ locale: string; runId: string }>;
}) {
const { locale, runId } = await params;
setRequestLocale(locale);
return <EvolutionRunDetailClient runId={runId} />;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { setRequestLocale } from "next-intl/server";

import { EvolutionCandidateDetailClient } from "@/components/evolution/EvolutionCandidateDetailClient";

/** 单个 E1 演化 slot 详情。 */
export default async function EvolutionCandidatePage({
params,
}: {
params: Promise<{ locale: string; candidateId: string }>;
}) {
const { locale, candidateId } = await params;
setRequestLocale(locale);
return <EvolutionCandidateDetailClient candidateId={candidateId} />;
}
Loading
Loading