Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
12 changes: 12 additions & 0 deletions compat/bundles/2026.07.1.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
name = "2026.07.1"
description = "Phase-2 QSL compatibility bundle (strict transition warning convergence)"
created_at = "2026-07-03"

[repos]
QuantPlatformKit = "7032cde4547e7ec59af15df8935d142461a77051"
UsEquityStrategies = "9f0e5e2deca8a9c16d711eb4772f08a7901da101"
HkEquityStrategies = "00dd0e5b62a6fa65bd9262e15c083468e8b8c191"
CnEquityStrategies = "c6d680d6d2690fe6ff77872355719751c021f9a0"
CryptoStrategies = "c0203b66746efb63e79f4d4bc9a65758c342817e"
QuantStrategyPlugins = "1f3a27b8fd83d71b583f4f5160a748e95fbefaa1"
MarketSignalSources = "bda8ab10b80a646e4b579ef4c0d5dfe90776e908"
39 changes: 25 additions & 14 deletions docs/qsl_compat_upgrade.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
# QSL Compatibility & Upgrade Checklist (Central Manifest Phase-1)
# QSL Compatibility & Upgrade Checklist (Central Manifest)

This repository carries the first version of the QSL central compatibility manifest.
This repository defines the QSL central compatibility manifest and its upgrade policy.

## 文件结构

- `compat/bundles/*.toml`
- 每个 bundle 用 Calendar Version 命名(当前:`2026.07.0`)。
- 每个 bundle 用 Calendar Version 命名(当前:`2026.07.1`)。
- 记录 QSL 管控的固定内部仓库提交。
- `compat/repo-tiers.toml`
- 记录仓库层级(`core/strategy-lib/pipeline/runtime/ops`)与升级 ring 规则。
Expand All @@ -26,8 +26,8 @@ This repository carries the first version of the QSL central compatibility manif

```toml
[qsl]
bundle = "2026.07.0" # 选择要对齐的 central bundle
compat = "2026.07.0" # 兼容检查入口(与 bundle 相同)
bundle = "2026.07.1" # 选择要对齐的 central bundle
compat = "2026.07.1" # 兼容检查入口(与 bundle 相同)
tier = "ops/tooling"
upgrade_ring = "ring_e"
allow_legacy = false # 需要临时兼容时可先放开
Expand All @@ -43,15 +43,26 @@ python scripts/check_qsl_compat.py --repo-root . --non-strict
python scripts/render_qsl_dependency_graph.py --repo-root . --format md
```

说明:默认脚本会输出错误并以非零退出码返回;`--non-strict` 仅用于本地快速预览。
说明:
- 默认脚本执行严格模式:`forbidden short/invalid`、`bundle pin mismatch`、`@main` 均为 issue(非零退出)。
- 阶段过渡仓可设置 `enforce_bundle = false`(建议限时):
- `forbidden short/invalid` 与 `bundle pin mismatch` 降级为 warning。
- `forbidden ref 'main'` 始终为 issue,不降级。
- `--non-strict` 仅用于本地快速预览,不作为发布门禁依据。

## 当前中心兼容基线

- Bundle: `2026.07.0`
- QPK: `0063af3b4a974650ea58a7d3f26dd1b94f65d3e8`
- UsEquityStrategies: `46887bc3f5454d5b59623b1f5efb7c65912c6b8b`
- HkEquityStrategies: `61993bf261aeccf64b5a75428b9405f4e1d1d682`
- CnEquityStrategies: `ffbdf7303179ba6e7f9d3e28c21202f77e04762c`
- CryptoStrategies: `8039ddddde7634ad3615496c9b79d2918996938c`
- QuantStrategyPlugins: `6c10aef8989f52d82571e676092b14d315401989`
- MarketSignalSources: `ea8771b6b65f356e7edc4a2b08cd621186726646`
- Bundle: `2026.07.1`
- QPK: `7032cde4547e7ec59af15df8935d142461a77051`
- UsEquityStrategies: `9f0e5e2deca8a9c16d711eb4772f08a7901da101`
- HkEquityStrategies: `00dd0e5b62a6fa65bd9262e15c083468e8b8c191`
- CnEquityStrategies: `c6d680d6d2690fe6ff77872355719751c021f9a0`
- CryptoStrategies: `c0203b66746efb63e79f4d4bc9a65758c342817e`
- QuantStrategyPlugins: `1f3a27b8fd83d71b583f4f5160a748e95fbefaa1`
- MarketSignalSources: `bda8ab10b80a646e4b579ef4c0d5dfe90776e908`

## Phase-2 Transition Warning 收敛路径

1. 发现 phase-1 之后的 drift/main 问题先通过 `--non-strict` 定位;提交修复前确保日志可回放。
2. 过渡仓可短期开启 `enforce_bundle = false`,仅将 drift / short SHA 降级为 warning。
3. 版本发布前将仓库切回 `enforce_bundle = true`,并清零 transition warning。
104 changes: 104 additions & 0 deletions python/tests/test_qsl_compat_checker.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
from __future__ import annotations

import importlib.util
import sys
import tempfile
import unittest
from pathlib import Path

ROOT = Path(__file__).resolve().parents[2]
MODULE_PATH = ROOT / "scripts" / "check_qsl_compat.py"
MODULE_SPEC = importlib.util.spec_from_file_location("check_qsl_compat", MODULE_PATH)
check_qsl_compat = importlib.util.module_from_spec(MODULE_SPEC)
assert MODULE_SPEC.loader is not None
sys.modules[MODULE_SPEC.name] = check_qsl_compat
MODULE_SPEC.loader.exec_module(check_qsl_compat)


class QSLCompatCheckerTest(unittest.TestCase):
def _make_repo_root(self, qsl_toml: str, pyproject: str) -> Path:
root = Path(tempfile.mkdtemp())
(root / "qsl.toml").write_text(qsl_toml, encoding="utf-8")
(root / "pyproject.toml").write_text(pyproject, encoding="utf-8")
return root

def _write_bundle(self, compat_root: Path, bundle_name: str, repos: dict[str, str]) -> None:
bundle_path = compat_root / "compat" / "bundles" / f"{bundle_name}.toml"
bundle_path.parent.mkdir(parents=True, exist_ok=True)
block = [f'name = "{bundle_name}"', "[repos]"]
for repo, ref in repos.items():
block.append(f'{repo} = "{ref}"')
bundle_path.write_text("\n".join(block) + "\n", encoding="utf-8")

def test_root_compat_bundle_and_ring_schema(self):
with tempfile.TemporaryDirectory() as workspace:
compat_root = Path(workspace)
self._write_bundle(
compat_root,
"2026.07.1",
{"QuantPlatformKit": "7032cde4547e7ec59af15df8935d142461a77051"},
)
repo_root = self._make_repo_root(
qsl_toml=(
"tier = \"ops/tooling\"\n"
"ring = \"ring_e\"\n"
"[compat]\n"
'bundle = "2026.07.1"\n'
),
pyproject=(
"dependencies = [\n"
' "quant-platform-kit @ git+https://github.com/QuantStrategyLab/QuantPlatformKit.git@7032cde4547e7ec59af15df8935d142461a77051"\n'
"]\n"
),
)

ok, issues, warnings, notes = check_qsl_compat._check(repo_root=repo_root, compat_root=compat_root)

self.assertTrue(ok)
self.assertEqual(issues, [])
self.assertEqual(warnings, [])
self.assertIn("bundle=2026.07.1", notes)
self.assertIn("upgrade_ring=ring_e", notes)

def test_not_enforced_bundle_reports_warning_for_short_sha_and_mismatch_but_main_stays_issue(self):
with tempfile.TemporaryDirectory() as workspace:
compat_root = Path(workspace)
self._write_bundle(
compat_root,
"2026.07.1",
{
"QuantPlatformKit": "7032cde4547e7ec59af15df8935d142461a77051",
"UsEquityStrategies": "9f0e5e2deca8a9c16d711eb4772f08a7901da101",
},
)
repo_root = self._make_repo_root(
qsl_toml=(
"tier = \"ops/tooling\"\n"
"ring = \"ring_e\"\n"
"[compat]\n"
'bundle = "2026.07.1"\n'
"enforce_bundle = false\n"
),
pyproject=(
"dependencies = [\n"
' "quant-platform-kit @ git+https://github.com/QuantStrategyLab/QuantPlatformKit.git@abc123"\n'
' "quant-platform-kit @ git+https://github.com/QuantStrategyLab/QuantPlatformKit.git@'
'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"\n'
' "us-equity-strategies @ https://github.com/QuantStrategyLab/UsEquityStrategies.git?rev=main"\n'
"]\n"
),
)

ok, issues, warnings, notes = check_qsl_compat._check(repo_root=repo_root, compat_root=compat_root)

self.assertFalse(ok)
self.assertEqual(len(issues), 1)
self.assertIn("forbidden ref 'main'", issues[0])
self.assertEqual(len(warnings), 2)
self.assertTrue(any("forbidden short/invalid ref 'abc123'" in warning for warning in warnings))
self.assertTrue(any("bundle pin mismatch for QuantPlatformKit" in warning for warning in warnings))
self.assertEqual(notes[0], "qsl=" + str(repo_root / "qsl.toml"))


if __name__ == "__main__":
unittest.main()
Loading