Skip to content

Commit db4ed71

Browse files
authored
Declare crypto artifact contract
1 parent 514ddd9 commit db4ed71

9 files changed

Lines changed: 62 additions & 3 deletions

docs/crypto_cross_platform_strategy_spec.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,18 @@ A crypto runtime adapter must declare at least:
4444
- `available_inputs`
4545
- `available_capabilities`
4646
- `portfolio_input_name` when the strategy needs `ctx.portfolio`
47+
- `artifact_contract` when the strategy consumes upstream artifacts
48+
49+
`crypto_leader_rotation` currently declares an explicit artifact contract:
50+
51+
- `requires_snapshot_artifacts = true`
52+
- `requires_snapshot_manifest_path = true`
53+
- `snapshot_contract_version = crypto_leader_rotation.live_pool.v1`
54+
- `config_source_policy = none`
55+
56+
The strategy package owns this declaration. Downstream platforms may decide how
57+
to fetch the artifact, but they should not infer artifact requirements from
58+
profile-name branches.
4759

4860
## Allowed and forbidden boundaries
4961

docs/crypto_cross_platform_strategy_spec.zh-CN.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,16 @@
4444
- `available_inputs`
4545
- `available_capabilities`
4646
- 当策略需要 `ctx.portfolio` 时的 `portfolio_input_name`
47+
- 当策略依赖上游 artifact 时的 `artifact_contract`
48+
49+
`crypto_leader_rotation` 当前显式声明的 artifact contract 是:
50+
51+
- `requires_snapshot_artifacts = true`
52+
- `requires_snapshot_manifest_path = true`
53+
- `snapshot_contract_version = crypto_leader_rotation.live_pool.v1`
54+
- `config_source_policy = none`
55+
56+
策略包负责声明这些需求。下游平台可以决定从 Firestore、GCS、本地文件或状态里取 artifact,但不能再靠 profile 名称分支来猜这条策略需要什么 artifact。
4757

4858
## 允许和禁止
4959

docs/crypto_portability_checklist.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ Use this before enabling a crypto profile on any downstream platform.
55
- [ ] `required_inputs` only use canonical crypto input names
66
- [ ] `target_mode` is explicitly declared
77
- [ ] every compatible platform has a runtime adapter
8+
- [ ] upstream artifact needs are declared through `artifact_contract`, not platform profile branches
89
- [ ] strategy code does not branch on platform names
910
- [ ] strategy code does not read exchange env vars
1011
- [ ] downstream runtime builds canonical inputs, not exchange-shaped names

docs/crypto_portability_checklist.zh-CN.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
- [ ] `required_inputs` 只使用 canonical 加密输入名
66
- [ ] `target_mode` 已显式声明
77
- [ ] 每个兼容平台都有对应 runtime adapter
8+
- [ ] 上游 artifact 需求通过 `artifact_contract` 声明,而不是下游平台 profile 分支
89
- [ ] 策略代码没有平台分支
910
- [ ] 策略代码没有直接读取交易所环境变量
1011
- [ ] 下游 runtime 传给策略的是 canonical 输入,而不是交易所专属名字

docs/crypto_strategy_template.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ At minimum, a new profile should touch these places:
2020
3. add a unified entrypoint in `src/crypto_strategies/entrypoints/__init__.py`
2121
4. add a runtime adapter in `src/crypto_strategies/runtime_adapters.py`
2222
5. add catalog and entrypoint tests
23-
6. if the profile becomes live, add platform status and portability checks downstream
23+
6. if the profile consumes upstream artifacts, add an explicit `StrategyArtifactContract`
24+
7. if the profile becomes live, add platform status and portability checks downstream
2425

2526
## StrategyDefinition
2627

@@ -59,9 +60,13 @@ A new runtime adapter must declare at least:
5960

6061
- `available_inputs`
6162
- `portfolio_input_name` when the strategy reads `ctx.portfolio`
63+
- `artifact_contract` when the strategy needs upstream artifacts
6264

6365
If a platform does not support the profile yet, do not add it to `supported_platforms`.
6466

67+
The artifact contract belongs in this strategy package. Platform repositories
68+
should consume it and map it to their own env/filesystem/runtime source rules.
69+
6570
## Forbidden shortcuts
6671

6772
Do not:
@@ -84,6 +89,7 @@ Do not:
8489
- [ ] `StrategyManifest` matches the catalog definition
8590
- [ ] entrypoint reads only canonical inputs
8691
- [ ] runtime adapter added for every compatible platform
92+
- [ ] artifact contract added when upstream artifacts are required
8793
- [ ] strategy code has no platform branch or env reads
8894
- [ ] catalog, entrypoint, and governance tests were updated
8995
- [ ] downstream platform status script or adapter smoke was updated when rollout changed

docs/crypto_strategy_template.zh-CN.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@
2020
3.`src/crypto_strategies/entrypoints/__init__.py` 里加统一 entrypoint
2121
4.`src/crypto_strategies/runtime_adapters.py` 里加 runtime adapter
2222
5. 补 catalog 和 entrypoint 测试
23-
6. 如果要变成 live,再去下游平台补状态和 portability 检查
23+
6. 如果策略消费上游 artifact,补显式 `StrategyArtifactContract`
24+
7. 如果要变成 live,再去下游平台补状态和 portability 检查
2425

2526
## StrategyDefinition 必填项
2627

@@ -59,9 +60,12 @@ entrypoint 必须做到:
5960

6061
- `available_inputs`
6162
- 如果策略会读 `ctx.portfolio`,则声明 `portfolio_input_name`
63+
- 如果策略依赖上游 artifact,则声明 `artifact_contract`
6264

6365
如果某个平台还不支持这条策略,就不要先把它写进 `supported_platforms`
6466

67+
artifact contract 属于策略包。平台仓库只负责把它映射到自己的环境变量、文件、Firestore/GCS 或 runtime 状态来源,不能靠 profile 名称分支来猜策略需要什么 artifact。
68+
6569
## 禁止的偷懒方式
6670

6771
不要:
@@ -84,6 +88,7 @@ entrypoint 必须做到:
8488
- [ ] `StrategyManifest` 和 catalog 定义一致
8589
- [ ] entrypoint 只读取 canonical 输入
8690
- [ ] 每个兼容平台都补了 runtime adapter
91+
- [ ] 需要上游 artifact 时已新增 artifact contract
8792
- [ ] 策略代码里没有平台分支和环境变量读取
8893
- [ ] catalog、entrypoint、governance 测试已更新
8994
- [ ] 如果 rollout 变了,下游平台的状态脚本或 adapter smoke 也已更新

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
44

55
[project]
66
name = "crypto-strategies"
7-
version = "0.4.3"
7+
version = "0.4.4"
88
description = "Shared crypto strategy catalog and implementations"
99
readme = "README.md"
1010
requires-python = ">=3.11"

src/crypto_strategies/runtime_adapters.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
from quant_platform_kit.common.strategies import resolve_catalog_profile
44
from quant_platform_kit.strategy_contracts import (
5+
StrategyArtifactContract,
56
StrategyRuntimeAdapter,
67
validate_strategy_runtime_adapter,
78
)
@@ -23,12 +24,22 @@
2324
)
2425

2526

27+
CRYPTO_LEADER_ROTATION_ARTIFACT_CONTRACT = StrategyArtifactContract(
28+
requires_snapshot_artifacts=True,
29+
requires_snapshot_manifest_path=True,
30+
requires_strategy_config_path=False,
31+
snapshot_contract_version="crypto_leader_rotation.live_pool.v1",
32+
config_source_policy="none",
33+
)
34+
35+
2636
PLATFORM_RUNTIME_ADAPTERS: dict[str, dict[str, StrategyRuntimeAdapter]] = {
2737
BINANCE_PLATFORM: {
2838
"crypto_leader_rotation": StrategyRuntimeAdapter(
2939
status_icon="🪙",
3040
available_inputs=CRYPTO_CANONICAL_REQUIRED_INPUTS,
3141
portfolio_input_name="portfolio_snapshot",
42+
artifact_contract=CRYPTO_LEADER_ROTATION_ARTIFACT_CONTRACT,
3243
),
3344
}
3445
}
@@ -55,6 +66,7 @@ def get_platform_runtime_adapter(profile: str | None, *, platform_id: str) -> St
5566
__all__ = [
5667
"BINANCE_PLATFORM",
5768
"CRYPTO_CANONICAL_REQUIRED_INPUTS",
69+
"CRYPTO_LEADER_ROTATION_ARTIFACT_CONTRACT",
5870
"PLATFORM_RUNTIME_ADAPTERS",
5971
"get_platform_runtime_adapter",
6072
"resolve_canonical_profile",

tests/test_contract_governance.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,11 @@
1414
from crypto_strategies.runtime_adapters import (
1515
BINANCE_PLATFORM,
1616
CRYPTO_CANONICAL_REQUIRED_INPUTS,
17+
CRYPTO_LEADER_ROTATION_ARTIFACT_CONTRACT,
1718
PLATFORM_RUNTIME_ADAPTERS,
1819
get_platform_runtime_adapter,
1920
)
21+
from quant_platform_kit.strategy_contracts import resolve_strategy_artifact_contract
2022

2123

2224
ALLOWED_TARGET_MODES = frozenset({"weight", "value"})
@@ -56,6 +58,16 @@ def test_every_compatible_platform_has_runtime_adapter_coverage(self) -> None:
5658
elif definition.target_mode != PLATFORM_NATIVE_TARGET_MODES[platform_id]:
5759
self.assertTrue(adapter.portfolio_input_name)
5860

61+
def test_live_profiles_declare_explicit_artifact_contract(self) -> None:
62+
adapter = get_platform_runtime_adapter("crypto_leader_rotation", platform_id=BINANCE_PLATFORM)
63+
contract = resolve_strategy_artifact_contract(adapter)
64+
65+
self.assertEqual(contract, CRYPTO_LEADER_ROTATION_ARTIFACT_CONTRACT)
66+
self.assertTrue(contract.requires_snapshot_artifacts)
67+
self.assertTrue(contract.requires_snapshot_manifest_path)
68+
self.assertEqual(contract.snapshot_contract_version, "crypto_leader_rotation.live_pool.v1")
69+
self.assertEqual(contract.config_source_policy, "none")
70+
5971
def test_runtime_adapter_map_matches_catalog_compatibility(self) -> None:
6072
compatibility_map = {
6173
profile: frozenset(definition.supported_platforms)

0 commit comments

Comments
 (0)