fix(ci): publish quant engine lite verification (#1)
CI / lite (push) Successful in 3s

This commit was merged in pull request #1.
This commit is contained in:
2026-08-20 21:36:32 +08:00
parent c04acf0ab6
commit 60027c8d3e
4 changed files with 129 additions and 0 deletions
+32
View File
@@ -0,0 +1,32 @@
name: CI
on:
push:
branches: [main]
pull_request:
branches: [main]
concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: true
permissions:
contents: read
jobs:
lite:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@524e936cd9e579adf00e308bfdf971aebc7de09e
with:
persist-credentials: false
- name: Gitea 合规校验
run: |
if git ls-tree -r HEAD | awk '$1==160000' | grep -q .; then echo "HEAD 含 gitlink"; exit 1; fi
if git ls-files .DS_Store | grep -q .; then echo "跟踪 .DS_Store"; exit 1; fi
if git grep -n -I -E 'sk-[A-Za-z0-9]{20,}|AKIA[0-9A-Z]{16}|ghp_[A-Za-z0-9]{36}|xox[baprs]-[A-Za-z0-9-]{10,}' HEAD | grep -q .; then echo "检出疑似凭证"; exit 1; fi
echo "Gitea 合规校验通过"
- name: 架构模块契约测试
run: python3 tests/governance/test_module_spec.py
- name: Syntax check
run: git ls-files -z '*.py' | xargs -0 python3 -m py_compile
+41
View File
@@ -0,0 +1,41 @@
{
"schema_version": 1,
"module_id": "quant_engine",
"authority": {"scope": "module_metadata", "subject": "quant_engine", "owner": "quant-engine-owner", "source": "MODULE_SPEC.yaml", "revision": 1, "effective_from": "2026-08-20T00:00:00+08:00"},
"repository": {"name": "quant_engine", "workspace_id": "researchhub", "type": "research_engine", "maturity": "operational"},
"bounded_context": {
"domain": "quantitative-research-engine",
"responsibility": "Own reusable quantitative research calculations for factors, indicators, execution simulation, backtesting, portfolio decomposition, risk, and performance metrics.",
"prohibited_responsibilities": [
"Presenting research calculations, simulations, backtests, or metrics as investment advice or guaranteed performance",
"Submitting live orders, routing trades, managing brokerage accounts, or claiming transaction execution",
"Owning market-data source facts, research-result publication, or platform presentation state",
"Loading provider credentials, brokerage credentials, or production secrets",
"Changing financial model semantics through module metadata"
]
},
"capabilities": [
{"id": "factor-and-indicator-calculation", "summary": "Calculate reusable alpha factors and technical indicators from caller-supplied data.", "status": "operational"},
{"id": "execution-simulation", "summary": "Simulate costs, slippage, market constraints, fills, NAV, and PnL without live order routing.", "status": "operational"},
{"id": "portfolio-backtesting", "summary": "Run weight-based backtests and benchmark comparisons.", "status": "operational"},
{"id": "risk-and-performance-analysis", "summary": "Calculate portfolio decomposition, risk contribution, and performance statistics.", "status": "operational"}
],
"data": {"owns": [
{"asset_id": "quantitative-model-implementations", "kind": "model", "classification": "internal"},
{"asset_id": "simulation-and-metric-results", "kind": "artifact", "classification": "confidential"}
]},
"contracts": {"provides": [], "consumes": []},
"dependencies": [],
"agent_context": {
"default_entrypoints": [
{"path": "README.md", "purpose": "Current engine scope, modules, dependencies, and non-live usage examples."},
{"path": "pyproject.toml", "purpose": "Supported Python version, package version, dependencies, and quality configuration."}
],
"excluded_paths": ["graphify-out", ".venv", "build", "dist"],
"max_default_tokens": 8000
},
"verification": {"commands": [
{"id": "module-metadata", "argv": ["python3", "tests/governance/test_module_spec.py"], "cwd": ".", "network": false, "required": true},
{"id": "unit-tests", "argv": ["python3", "-m", "pytest"], "cwd": ".", "network": false, "required": true}
]}
}
+24
View File
@@ -0,0 +1,24 @@
from __future__ import annotations
import re
import unittest
from pathlib import Path
ROOT = Path(__file__).resolve().parents[2]
class CiContractTests(unittest.TestCase):
def test_ci_is_one_dependency_free_lite_gate(self) -> None:
workflow = (ROOT / ".gitea/workflows/ci.yml").read_text(encoding="utf-8")
jobs = workflow.split("jobs:", 1)[1]
self.assertEqual(re.findall(r"(?m)^ ([a-z][a-z0-9_-]*):\s*$", jobs), ["lite"])
self.assertIn("actions/checkout@524e936cd9e579adf00e308bfdf971aebc7de09e", workflow)
self.assertIn("persist-credentials: false", workflow)
self.assertIn("python3 tests/governance/test_module_spec.py", workflow)
for forbidden in ("setup-python", "pip ", "curl ", "wget ", "docker pull"):
self.assertNotIn(forbidden, workflow)
if __name__ == "__main__":
unittest.main()
+32
View File
@@ -0,0 +1,32 @@
from __future__ import annotations
import json
import unittest
from pathlib import Path
ROOT = Path(__file__).resolve().parents[2]
class ModuleSpecTests(unittest.TestCase):
def test_module_spec_declares_pure_research_engine_boundary(self) -> None:
spec = json.loads((ROOT / "MODULE_SPEC.yaml").read_text(encoding="utf-8"))
self.assertEqual(spec["module_id"], "quant_engine")
self.assertEqual(spec["authority"]["subject"], spec["module_id"])
self.assertEqual(spec["repository"]["type"], "research_engine")
self.assertEqual(spec["bounded_context"]["domain"], "quantitative-research-engine")
prohibited = " ".join(spec["bounded_context"]["prohibited_responsibilities"]).lower()
for term in ("investment advice", "live order", "credentials", "source facts"):
self.assertIn(term, prohibited)
self.assertEqual(spec["contracts"], {"provides": [], "consumes": []})
self.assertEqual(spec["dependencies"], [])
self.assertTrue(
all(
command["required"] and not command["network"]
for command in spec["verification"]["commands"]
)
)
if __name__ == "__main__":
unittest.main()