This commit was merged in pull request #1.
This commit is contained in:
@@ -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
|
||||||
@@ -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}
|
||||||
|
]}
|
||||||
|
}
|
||||||
@@ -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()
|
||||||
@@ -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()
|
||||||
Reference in New Issue
Block a user