feat: preserve Quant OS target-package vertical slice
This commit is contained in:
@@ -11,10 +11,57 @@ sys.path.insert(0, str(ROOT))
|
||||
sys.path.insert(0, str(ROOT / "src"))
|
||||
|
||||
from platforms import joinquant_strategy, qmt_builtin_strategy
|
||||
from quant60.target_package import seal_target_package
|
||||
from tools.bundle_platforms import bundle_all, effective_platform_config
|
||||
from tools.capability_probe import probe_capabilities
|
||||
|
||||
|
||||
def target_package():
|
||||
return seal_target_package(
|
||||
{
|
||||
"schema_version": "1.0",
|
||||
"package_type": "TargetPackageV1",
|
||||
"package_id": "TP-20260724-bundle",
|
||||
"decision_id": "D-20260724-bundle",
|
||||
"release": "quant60-research-candidate-v1",
|
||||
"evidence_class": "synthetic-research",
|
||||
"model_id": "deterministic-ridge-alpha-5",
|
||||
"signal_as_of": "2026-07-24T15:00:00+08:00",
|
||||
"next_session": "2026-07-27",
|
||||
"model_sha256": "1" * 64,
|
||||
"data_sha256": "2" * 64,
|
||||
"feature_sha256": "3" * 64,
|
||||
"risk_sha256": "4" * 64,
|
||||
"cost_sha256": "5" * 64,
|
||||
"optimizer_sha256": "6" * 64,
|
||||
"config_sha256": "7" * 64,
|
||||
"source_sha256": "8" * 64,
|
||||
"target_weights": {
|
||||
"000001.XSHE": 0.30,
|
||||
"600000.XSHG": 0.20,
|
||||
},
|
||||
"universe": {
|
||||
"000001.XSHE": {
|
||||
"state": "openable",
|
||||
"reasons": ["ELIGIBLE"],
|
||||
},
|
||||
"600000.XSHG": {
|
||||
"state": "openable",
|
||||
"reasons": ["ELIGIBLE"],
|
||||
},
|
||||
},
|
||||
"constraints": {
|
||||
"constraint_state": "FEASIBLE",
|
||||
"long_only": True,
|
||||
"max_single_weight": 0.40,
|
||||
"max_gross_weight": 0.80,
|
||||
"max_one_way_turnover": 0.50,
|
||||
"actual_gross_weight": 0.50,
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
class BundleTest(unittest.TestCase):
|
||||
def test_source_wrappers_match_canonical_baseline_config(self):
|
||||
baseline = json.loads(
|
||||
@@ -66,6 +113,35 @@ class BundleTest(unittest.TestCase):
|
||||
(ROOT / "configs/baseline.json").read_bytes()
|
||||
).hexdigest(),
|
||||
)
|
||||
self.assertEqual(
|
||||
stored["decision_mode"],
|
||||
"portable_momentum_smoke",
|
||||
)
|
||||
self.assertEqual(stored["target_package_count"], 0)
|
||||
self.assertIsNone(stored["target_package_tape_sha256"])
|
||||
self.assertEqual(
|
||||
stored["joinquant_observation"]["prefix"],
|
||||
"QUANT60_JOINQUANT_EVIDENCE_V1 ",
|
||||
)
|
||||
self.assertTrue(
|
||||
stored["joinquant_observation"]["fail_soft"]
|
||||
)
|
||||
self.assertEqual(
|
||||
stored["joinquant_observation"]["target_price_source"],
|
||||
"CURRENT_DATA_DAY_OPEN",
|
||||
)
|
||||
self.assertEqual(
|
||||
stored["joinquant_observation"]["eod_chunk_encoding"],
|
||||
"base64-canonical-json",
|
||||
)
|
||||
self.assertEqual(
|
||||
stored["joinquant_observation"]["eod_chunk_characters"],
|
||||
1800,
|
||||
)
|
||||
self.assertIn(
|
||||
"EOD_STATUS",
|
||||
stored["joinquant_observation"]["events"],
|
||||
)
|
||||
|
||||
def test_committed_dist_is_byte_for_byte_fresh(self):
|
||||
with tempfile.TemporaryDirectory() as temp:
|
||||
@@ -112,6 +188,65 @@ class BundleTest(unittest.TestCase):
|
||||
)
|
||||
self.assertTrue(all(value >= 0 for value in quantities.values()))
|
||||
|
||||
def test_target_package_bundle_is_explicit_pinned_and_no_fallback(self):
|
||||
with tempfile.TemporaryDirectory() as temp:
|
||||
root = Path(temp)
|
||||
package_path = root / "target_package.json"
|
||||
package = target_package()
|
||||
package_path.write_text(
|
||||
json.dumps(package, ensure_ascii=False),
|
||||
encoding="utf-8",
|
||||
)
|
||||
output = root / "bundle"
|
||||
manifest = bundle_all(ROOT, output, package_path)
|
||||
self.assertEqual(manifest["decision_mode"], "target_package")
|
||||
self.assertEqual(manifest["target_package_count"], 1)
|
||||
self.assertEqual(
|
||||
manifest["target_package_ids"],
|
||||
[package["package_id"]],
|
||||
)
|
||||
self.assertEqual(
|
||||
manifest["target_package_sha256"],
|
||||
[package["package_sha256"]],
|
||||
)
|
||||
self.assertNotIn(
|
||||
str(root),
|
||||
json.dumps(manifest, ensure_ascii=False),
|
||||
)
|
||||
for filename in (
|
||||
"joinquant_strategy.py",
|
||||
"qmt_builtin_strategy.py",
|
||||
):
|
||||
source = (output / filename).read_text(encoding="utf-8")
|
||||
self.assertIn(
|
||||
"'decision_mode': 'target_package'",
|
||||
source,
|
||||
)
|
||||
self.assertNotIn("TARGET_PACKAGES = []", source)
|
||||
self.assertIn(package["package_sha256"], source)
|
||||
self.assertIn("build_target_weight_plan", source)
|
||||
joinquant_source = (
|
||||
output / "joinquant_strategy.py"
|
||||
).read_text(encoding="utf-8")
|
||||
self.assertIn(
|
||||
"QUANT60_JOINQUANT_EVIDENCE_V1 ",
|
||||
joinquant_source,
|
||||
)
|
||||
self.assertIn("CURRENT_DATA_DAY_OPEN", joinquant_source)
|
||||
self.assertIn("day_open", joinquant_source)
|
||||
self.assertNotIn("CURRENT_DATA_LAST_PRICE", joinquant_source)
|
||||
for event in manifest["joinquant_observation"]["events"]:
|
||||
self.assertIn(event, joinquant_source)
|
||||
|
||||
tampered = dict(package)
|
||||
tampered["release"] = "tampered"
|
||||
package_path.write_text(
|
||||
json.dumps(tampered),
|
||||
encoding="utf-8",
|
||||
)
|
||||
with self.assertRaisesRegex(ValueError, "hash mismatch"):
|
||||
bundle_all(ROOT, root / "tampered", package_path)
|
||||
|
||||
|
||||
class CapabilityProbeTest(unittest.TestCase):
|
||||
def test_shallow_probe_does_not_claim_external_verification(self):
|
||||
|
||||
@@ -0,0 +1,687 @@
|
||||
import base64
|
||||
import copy
|
||||
import contextlib
|
||||
import datetime
|
||||
import io
|
||||
import json
|
||||
import sys
|
||||
import types
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
from types import SimpleNamespace
|
||||
from unittest import mock
|
||||
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
sys.path.insert(0, str(ROOT))
|
||||
sys.path.insert(0, str(ROOT / "src"))
|
||||
|
||||
from platforms import joinquant_strategy, qmt_builtin_strategy
|
||||
from platforms.fake_joinquant_harness import (
|
||||
FakeJoinQuantHarness,
|
||||
FakePosition,
|
||||
)
|
||||
from platforms.fake_qmt_harness import FakeQmtContext, FakeQmtHarness
|
||||
from quant60 import portable_core
|
||||
from quant60.portable_core import target_package_tape_sha256
|
||||
from quant60.target_package import seal_target_package
|
||||
|
||||
|
||||
def _package(
|
||||
signal_as_of="2026-07-17T15:00:00+08:00",
|
||||
next_session="2026-07-20",
|
||||
package_id="TP-20260717-A",
|
||||
decision_id="D-20260717-A",
|
||||
):
|
||||
return seal_target_package(
|
||||
{
|
||||
"schema_version": "1.0",
|
||||
"package_type": "TargetPackageV1",
|
||||
"package_id": package_id,
|
||||
"decision_id": decision_id,
|
||||
"release": "quant60-baseline-60-v1",
|
||||
"evidence_class": "provider-snapshot-local",
|
||||
"model_id": "ridge-alpha-v1",
|
||||
"signal_as_of": signal_as_of,
|
||||
"next_session": next_session,
|
||||
"model_sha256": "1" * 64,
|
||||
"data_sha256": "2" * 64,
|
||||
"feature_sha256": "3" * 64,
|
||||
"risk_sha256": "4" * 64,
|
||||
"cost_sha256": "5" * 64,
|
||||
"optimizer_sha256": "6" * 64,
|
||||
"config_sha256": "7" * 64,
|
||||
"source_sha256": "8" * 64,
|
||||
"target_weights": {
|
||||
"000001.XSHE": 0.30,
|
||||
"600000.XSHG": 0.0,
|
||||
},
|
||||
"universe": {
|
||||
"000001.XSHE": {
|
||||
"state": "openable",
|
||||
"reasons": ["ELIGIBLE"],
|
||||
},
|
||||
"600000.XSHG": {
|
||||
"state": "sell_only",
|
||||
"reasons": ["RISK_REDUCTION"],
|
||||
},
|
||||
},
|
||||
"constraints": {
|
||||
"constraint_state": "FEASIBLE",
|
||||
"long_only": True,
|
||||
"max_single_weight": 0.40,
|
||||
"max_gross_weight": 0.80,
|
||||
"max_one_way_turnover": 0.80,
|
||||
"actual_gross_weight": 0.30,
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
def _jq_histories():
|
||||
return {
|
||||
"000001.XSHE": [
|
||||
10.0 + 0.1 * index for index in range(21)
|
||||
],
|
||||
"600000.XSHG": [
|
||||
15.0 - 0.02 * index for index in range(21)
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
def _qmt_histories():
|
||||
return {
|
||||
symbol.replace(".XSHE", ".SZ").replace(".XSHG", ".SH"): values
|
||||
for symbol, values in _jq_histories().items()
|
||||
}
|
||||
|
||||
|
||||
def _target_config(base, packages):
|
||||
config = dict(base)
|
||||
config.update(
|
||||
{
|
||||
"decision_mode": "target_package",
|
||||
"target_package_count": len(packages),
|
||||
"target_package_tape_sha256": target_package_tape_sha256(
|
||||
packages
|
||||
),
|
||||
"universe_mode": "fixed",
|
||||
"universe": sorted(
|
||||
{
|
||||
symbol
|
||||
for package in packages
|
||||
for symbol in package["universe"]
|
||||
}
|
||||
),
|
||||
}
|
||||
)
|
||||
return config
|
||||
|
||||
|
||||
def _evidence_records(output):
|
||||
prefix = joinquant_strategy.EVIDENCE_PREFIX
|
||||
records = []
|
||||
for line in output.getvalue().splitlines():
|
||||
if not line.startswith(prefix):
|
||||
continue
|
||||
encoded = line[len(prefix) :]
|
||||
record = json.loads(encoded)
|
||||
canonical = json.dumps(
|
||||
record,
|
||||
ensure_ascii=True,
|
||||
sort_keys=True,
|
||||
separators=(",", ":"),
|
||||
allow_nan=False,
|
||||
)
|
||||
if canonical != encoded:
|
||||
raise AssertionError("JoinQuant evidence is not canonical JSON")
|
||||
records.append(record)
|
||||
return records
|
||||
|
||||
|
||||
class PlatformTargetPackageExecutionTest(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.jq_config = joinquant_strategy.CONFIG
|
||||
self.jq_packages = joinquant_strategy.TARGET_PACKAGES
|
||||
self.qmt_config = qmt_builtin_strategy.CONFIG
|
||||
self.qmt_packages = qmt_builtin_strategy.TARGET_PACKAGES
|
||||
|
||||
def tearDown(self):
|
||||
joinquant_strategy.CONFIG = self.jq_config
|
||||
joinquant_strategy.TARGET_PACKAGES = self.jq_packages
|
||||
qmt_builtin_strategy.CONFIG = self.qmt_config
|
||||
qmt_builtin_strategy.TARGET_PACKAGES = self.qmt_packages
|
||||
|
||||
def _install_package(self, package):
|
||||
self._install_packages([package])
|
||||
|
||||
def _install_packages(self, packages):
|
||||
packages = copy.deepcopy(packages)
|
||||
joinquant_strategy.TARGET_PACKAGES = copy.deepcopy(packages)
|
||||
joinquant_strategy.CONFIG = _target_config(
|
||||
self.jq_config,
|
||||
packages,
|
||||
)
|
||||
qmt_builtin_strategy.TARGET_PACKAGES = copy.deepcopy(packages)
|
||||
qmt_config = _target_config(self.qmt_config, packages)
|
||||
qmt_config["universe"] = [
|
||||
symbol.replace(".XSHE", ".SZ").replace(".XSHG", ".SH")
|
||||
for symbol in qmt_config["universe"]
|
||||
]
|
||||
qmt_builtin_strategy.CONFIG = qmt_config
|
||||
|
||||
def test_same_package_binds_same_weights_orders_and_lineage(self):
|
||||
package = _package()
|
||||
self._install_package(package)
|
||||
jq = FakeJoinQuantHarness(
|
||||
_jq_histories(),
|
||||
positions={
|
||||
"600000.XSHG": FakePosition(
|
||||
total_amount=1050,
|
||||
closeable_amount=200,
|
||||
)
|
||||
},
|
||||
)
|
||||
jq.initialize(joinquant_strategy)
|
||||
jq_plan = jq.run_scheduled()
|
||||
|
||||
qmt_position = SimpleNamespace(
|
||||
stock_code="600000.SH",
|
||||
volume=1050,
|
||||
can_use_volume=200,
|
||||
)
|
||||
context = FakeQmtContext(
|
||||
_qmt_histories(),
|
||||
positions=[qmt_position],
|
||||
bar_time=datetime.datetime(2026, 7, 17, 15, 0),
|
||||
)
|
||||
qmt = FakeQmtHarness(context)
|
||||
qmt_plan = qmt.run(qmt_builtin_strategy)
|
||||
|
||||
self.assertIsNotNone(jq_plan)
|
||||
self.assertIsNotNone(qmt_plan)
|
||||
for field in (
|
||||
"weights",
|
||||
"targets",
|
||||
"orders",
|
||||
"lineage",
|
||||
"universe",
|
||||
):
|
||||
self.assertEqual(jq_plan[field], qmt_plan[field])
|
||||
self.assertEqual(
|
||||
jq_plan["lineage"],
|
||||
{
|
||||
"package_id": package["package_id"],
|
||||
"package_sha256": package["package_sha256"],
|
||||
"decision_id": package["decision_id"],
|
||||
"signal_as_of": package["signal_as_of"],
|
||||
"next_session": package["next_session"],
|
||||
"release": package["release"],
|
||||
"model_id": package["model_id"],
|
||||
},
|
||||
)
|
||||
self.assertEqual(
|
||||
jq_plan["execution_contract"],
|
||||
{
|
||||
"signal_price_source": "CURRENT_DATA_DAY_OPEN",
|
||||
"submit_trigger": "DECLARED_NEXT_SESSION_OPEN_CALLBACK",
|
||||
"declared_next_session": package["next_session"],
|
||||
"real_platform_observed": False,
|
||||
},
|
||||
)
|
||||
self.assertEqual(
|
||||
qmt_plan["execution_contract"],
|
||||
{
|
||||
"signal_price_source": "COMPLETED_DAILY_CLOSE",
|
||||
"submit_trigger": "NEXT_BAR_FIRST_TICK",
|
||||
"quick_trade": 0,
|
||||
"declared_next_session": package["next_session"],
|
||||
"real_platform_observed": False,
|
||||
},
|
||||
)
|
||||
self.assertEqual(jq_plan["orders"]["600000.XSHG"], -200)
|
||||
self.assertEqual(dict(jq.orders)["600000.XSHG"], 850)
|
||||
self.assertEqual(qmt_plan["orders"]["600000.XSHG"], -200)
|
||||
sell_order = [
|
||||
order
|
||||
for order in qmt.orders
|
||||
if order["order_code"] == "600000.SH"
|
||||
][0]
|
||||
self.assertEqual(sell_order["volume"], 200)
|
||||
self.assertEqual(sell_order["quick_trade"], 0)
|
||||
self.assertTrue(
|
||||
all(
|
||||
int(quantity) % 100 == 0
|
||||
for quantity in jq_plan["targets"].values()
|
||||
)
|
||||
)
|
||||
|
||||
def test_missing_exact_clock_is_noop_without_momentum_fallback(self):
|
||||
package = _package(
|
||||
signal_as_of="2026-07-10T15:00:00+08:00",
|
||||
next_session="2026-07-13",
|
||||
)
|
||||
self._install_package(package)
|
||||
jq = FakeJoinQuantHarness(_jq_histories())
|
||||
jq.initialize(joinquant_strategy)
|
||||
self.assertIsNone(jq.run_scheduled())
|
||||
self.assertEqual(jq.orders, [])
|
||||
self.assertIsNone(jq.last_index_request)
|
||||
self.assertIsNone(jq.last_extras_request)
|
||||
self.assertIsNone(jq.last_history_request)
|
||||
|
||||
context = FakeQmtContext(
|
||||
_qmt_histories(),
|
||||
bar_time=datetime.datetime(2026, 7, 17, 15, 0),
|
||||
)
|
||||
qmt = FakeQmtHarness(context)
|
||||
self.assertIsNone(qmt.run(qmt_builtin_strategy))
|
||||
self.assertEqual(qmt.orders, [])
|
||||
self.assertIsNone(context.last_sector_request)
|
||||
self.assertIsNone(context.last_market_request)
|
||||
|
||||
def test_tampered_package_fails_closed_during_initialization(self):
|
||||
package = _package()
|
||||
tampered = copy.deepcopy(package)
|
||||
tampered["target_weights"]["000001.XSHE"] = 0.25
|
||||
tampered["constraints"]["actual_gross_weight"] = 0.25
|
||||
self._install_package(tampered)
|
||||
|
||||
jq = FakeJoinQuantHarness(_jq_histories())
|
||||
with self.assertRaises(ValueError):
|
||||
jq.initialize(joinquant_strategy)
|
||||
self.assertEqual(jq.orders, [])
|
||||
|
||||
context = FakeQmtContext(_qmt_histories())
|
||||
qmt = FakeQmtHarness(context)
|
||||
with self.assertRaises(ValueError):
|
||||
qmt.run(qmt_builtin_strategy)
|
||||
self.assertEqual(qmt.orders, [])
|
||||
|
||||
def test_duplicate_package_id_fails_closed_during_initialization(self):
|
||||
first = _package()
|
||||
second = _package(
|
||||
signal_as_of="2026-07-24T15:00:00+08:00",
|
||||
next_session="2026-07-27",
|
||||
package_id=first["package_id"],
|
||||
decision_id="D-20260724-B",
|
||||
)
|
||||
self._install_packages([first, second])
|
||||
|
||||
jq = FakeJoinQuantHarness(_jq_histories())
|
||||
with self.assertRaisesRegex(ValueError, "duplicate"):
|
||||
jq.initialize(joinquant_strategy)
|
||||
|
||||
context = FakeQmtContext(_qmt_histories())
|
||||
qmt = FakeQmtHarness(context)
|
||||
with self.assertRaisesRegex(
|
||||
qmt_builtin_strategy.UnsupportedStrategyPeriod,
|
||||
"duplicate",
|
||||
):
|
||||
qmt.run(qmt_builtin_strategy)
|
||||
|
||||
def test_joinquant_emits_canonical_observation_stream_and_fail_soft_eod(self):
|
||||
package = _package()
|
||||
self._install_package(package)
|
||||
jq = FakeJoinQuantHarness(
|
||||
_jq_histories(),
|
||||
positions={
|
||||
"600000.XSHG": FakePosition(
|
||||
total_amount=1050,
|
||||
closeable_amount=200,
|
||||
)
|
||||
},
|
||||
)
|
||||
output = io.StringIO()
|
||||
with contextlib.redirect_stdout(output):
|
||||
jq.initialize(joinquant_strategy)
|
||||
plan = jq.run_scheduled()
|
||||
joinquant_strategy.after_trading_end(jq.context)
|
||||
self.assertIsNotNone(plan)
|
||||
|
||||
records = _evidence_records(output)
|
||||
events = [record["event"] for record in records]
|
||||
for event in (
|
||||
"INIT",
|
||||
"TARGET_PACKAGE_HIT",
|
||||
"PLATFORM_BINDING_INPUT",
|
||||
"TARGET_PACKAGE_PLAN",
|
||||
"ORDER_REQUEST",
|
||||
"ORDER_RETURN",
|
||||
"EOD_STATUS",
|
||||
):
|
||||
self.assertIn(event, events)
|
||||
self.assertEqual(
|
||||
[record["sequence"] for record in records],
|
||||
list(range(1, len(records) + 1)),
|
||||
)
|
||||
|
||||
binding = [
|
||||
record["payload"]
|
||||
for record in records
|
||||
if record["event"] == "PLATFORM_BINDING_INPUT"
|
||||
][0]
|
||||
self.assertEqual(binding["equity"], 1_000_000.0)
|
||||
self.assertEqual(binding["current"], {"600000.XSHG": 1050})
|
||||
self.assertEqual(binding["sellable"], {"600000.XSHG": 200})
|
||||
self.assertEqual(
|
||||
binding["price_source"],
|
||||
"CURRENT_DATA_DAY_OPEN",
|
||||
)
|
||||
self.assertEqual(
|
||||
binding["lineage"]["package_sha256"],
|
||||
package["package_sha256"],
|
||||
)
|
||||
|
||||
plan_record = [
|
||||
record["payload"]
|
||||
for record in records
|
||||
if record["event"] == "TARGET_PACKAGE_PLAN"
|
||||
][0]
|
||||
self.assertEqual(plan_record["weights"], package["target_weights"])
|
||||
self.assertEqual(plan_record["orders"], plan["orders"])
|
||||
|
||||
eod_records = [
|
||||
record
|
||||
for record in records
|
||||
if record["event"] == "EOD_STATUS"
|
||||
]
|
||||
self.assertTrue(eod_records)
|
||||
chunk_count = eod_records[0]["chunk_count"]
|
||||
self.assertEqual(len(eod_records), chunk_count)
|
||||
self.assertEqual(
|
||||
[record["chunk_index"] for record in eod_records],
|
||||
list(range(1, chunk_count + 1)),
|
||||
)
|
||||
self.assertTrue(
|
||||
all(
|
||||
record["chunk_count"] == chunk_count
|
||||
for record in eod_records
|
||||
)
|
||||
)
|
||||
self.assertTrue(
|
||||
all(
|
||||
record["payload"]["chunk_encoding"]
|
||||
== "base64-canonical-json"
|
||||
for record in eod_records
|
||||
)
|
||||
)
|
||||
encoded = "".join(
|
||||
record["payload"]["content"]
|
||||
for record in eod_records
|
||||
)
|
||||
self.assertTrue(
|
||||
all(
|
||||
record["payload"]["encoded_length"] == len(encoded)
|
||||
for record in eod_records
|
||||
)
|
||||
)
|
||||
for record in eod_records:
|
||||
line = joinquant_strategy.EVIDENCE_PREFIX + json.dumps(
|
||||
record,
|
||||
ensure_ascii=True,
|
||||
sort_keys=True,
|
||||
separators=(",", ":"),
|
||||
allow_nan=False,
|
||||
)
|
||||
self.assertLess(len(line.encode("utf-8")), 3 * 1024)
|
||||
canonical = base64.b64decode(
|
||||
encoded.encode("ascii"),
|
||||
validate=True,
|
||||
)
|
||||
eod = json.loads(canonical.decode("ascii"))
|
||||
self.assertEqual(
|
||||
base64.b64encode(
|
||||
json.dumps(
|
||||
eod,
|
||||
ensure_ascii=True,
|
||||
sort_keys=True,
|
||||
separators=(",", ":"),
|
||||
allow_nan=False,
|
||||
).encode("ascii")
|
||||
).decode("ascii"),
|
||||
encoded,
|
||||
)
|
||||
self.assertFalse(eod["orders_api"]["available"])
|
||||
self.assertFalse(eod["trades_api"]["available"])
|
||||
self.assertTrue(eod["portfolio"]["available"])
|
||||
self.assertEqual(
|
||||
eod["last_plan"]["lineage"]["package_id"],
|
||||
package["package_id"],
|
||||
)
|
||||
|
||||
def test_joinquant_target_package_binds_day_open_not_last_price(self):
|
||||
package = _package()
|
||||
self._install_package(package)
|
||||
jq = FakeJoinQuantHarness(_jq_histories())
|
||||
jq.current_data["000001.XSHE"].day_open = 20.0
|
||||
jq.current_data["000001.XSHE"].last_price = 999.0
|
||||
output = io.StringIO()
|
||||
with contextlib.redirect_stdout(output):
|
||||
jq.initialize(joinquant_strategy)
|
||||
plan = jq.run_scheduled()
|
||||
|
||||
self.assertIsNotNone(plan)
|
||||
self.assertEqual(plan["targets"]["000001.XSHE"], 15_000)
|
||||
self.assertEqual(jq.orders, [("000001.XSHE", 15_000)])
|
||||
binding = [
|
||||
record["payload"]
|
||||
for record in _evidence_records(output)
|
||||
if record["event"] == "PLATFORM_BINDING_INPUT"
|
||||
][0]
|
||||
self.assertEqual(binding["price_source"], "CURRENT_DATA_DAY_OPEN")
|
||||
self.assertEqual(binding["prices"]["000001.XSHE"], 20.0)
|
||||
self.assertIsNone(jq.last_history_request)
|
||||
|
||||
def test_joinquant_missing_day_open_fails_closed_without_fallback(self):
|
||||
package = _package()
|
||||
self._install_package(package)
|
||||
jq = FakeJoinQuantHarness(_jq_histories())
|
||||
del jq.current_data["000001.XSHE"].day_open
|
||||
output = io.StringIO()
|
||||
with contextlib.redirect_stdout(output):
|
||||
jq.initialize(joinquant_strategy)
|
||||
with self.assertRaisesRegex(
|
||||
joinquant_strategy.PriceHistoryUnavailable,
|
||||
"day_open",
|
||||
):
|
||||
jq.run_scheduled()
|
||||
|
||||
self.assertEqual(jq.orders, [])
|
||||
self.assertIsNone(jq.last_index_request)
|
||||
self.assertIsNone(jq.last_extras_request)
|
||||
self.assertIsNone(jq.last_history_request)
|
||||
events = [
|
||||
record["event"] for record in _evidence_records(output)
|
||||
]
|
||||
self.assertIn("TARGET_PACKAGE_HIT", events)
|
||||
self.assertNotIn("PLATFORM_BINDING_INPUT", events)
|
||||
self.assertNotIn("TARGET_PACKAGE_PLAN", events)
|
||||
self.assertNotIn("ORDER_REQUEST", events)
|
||||
|
||||
def test_joinquant_noop_eod_clears_prior_session_evidence(self):
|
||||
package = _package()
|
||||
self._install_package(package)
|
||||
jq = FakeJoinQuantHarness(
|
||||
_jq_histories(),
|
||||
positions={
|
||||
"600000.XSHG": FakePosition(
|
||||
total_amount=1050,
|
||||
closeable_amount=200,
|
||||
)
|
||||
},
|
||||
)
|
||||
jq.current_data["000001.XSHE"].paused = True
|
||||
|
||||
def eod_payload(output):
|
||||
chunks = [
|
||||
record
|
||||
for record in _evidence_records(output)
|
||||
if record["event"] == "EOD_STATUS"
|
||||
]
|
||||
self.assertTrue(chunks)
|
||||
self.assertEqual(
|
||||
[record["chunk_index"] for record in chunks],
|
||||
list(range(1, chunks[0]["chunk_count"] + 1)),
|
||||
)
|
||||
encoded = "".join(
|
||||
record["payload"]["content"] for record in chunks
|
||||
)
|
||||
return json.loads(
|
||||
base64.b64decode(
|
||||
encoded.encode("ascii"),
|
||||
validate=True,
|
||||
).decode("ascii")
|
||||
)
|
||||
|
||||
hit_output = io.StringIO()
|
||||
with contextlib.redirect_stdout(hit_output):
|
||||
jq.initialize(joinquant_strategy)
|
||||
self.assertIsNotNone(jq.run_scheduled())
|
||||
joinquant_strategy.after_trading_end(jq.context)
|
||||
hit_eod = eod_payload(hit_output)
|
||||
self.assertIsNotNone(hit_eod["last_plan"])
|
||||
self.assertTrue(hit_eod["order_returns"])
|
||||
self.assertTrue(hit_eod["skipped_orders"])
|
||||
orders_after_hit = list(jq.orders)
|
||||
self.assertTrue(orders_after_hit)
|
||||
|
||||
for unused_day in range(2):
|
||||
del unused_day
|
||||
jq.advance_session()
|
||||
noop_output = io.StringIO()
|
||||
with contextlib.redirect_stdout(noop_output):
|
||||
self.assertIsNone(jq.run_scheduled())
|
||||
joinquant_strategy.after_trading_end(jq.context)
|
||||
noop_records = _evidence_records(noop_output)
|
||||
self.assertIn(
|
||||
"TARGET_PACKAGE_NOOP",
|
||||
[record["event"] for record in noop_records],
|
||||
)
|
||||
noop_eod = eod_payload(noop_output)
|
||||
self.assertIsNone(noop_eod["last_plan"])
|
||||
self.assertEqual(noop_eod["order_returns"], [])
|
||||
self.assertEqual(noop_eod["skipped_orders"], [])
|
||||
self.assertEqual(jq.orders, orders_after_hit)
|
||||
|
||||
def test_joinquant_hostile_any_still_runs_final_three_day_tape(self):
|
||||
bundled = types.ModuleType("hostile_joinquant_bundle")
|
||||
source = (
|
||||
ROOT / "dist/target-package/joinquant_strategy.py"
|
||||
).read_bytes()
|
||||
exec(
|
||||
compile(
|
||||
source,
|
||||
"dist/target-package/joinquant_strategy.py",
|
||||
"exec",
|
||||
),
|
||||
bundled.__dict__,
|
||||
)
|
||||
package = copy.deepcopy(bundled.TARGET_PACKAGES[0])
|
||||
histories = {
|
||||
symbol: [10.0] * 21 for symbol in package["universe"]
|
||||
}
|
||||
hostile_any = lambda values: True
|
||||
|
||||
def run_three_days(module):
|
||||
jq = FakeJoinQuantHarness(histories)
|
||||
jq.context.current_dt = datetime.datetime(
|
||||
2024,
|
||||
3,
|
||||
11,
|
||||
9,
|
||||
30,
|
||||
)
|
||||
jq.context.previous_date = datetime.date(2024, 3, 8)
|
||||
daily_orders = []
|
||||
output = io.StringIO()
|
||||
with contextlib.redirect_stdout(output):
|
||||
jq.initialize(module)
|
||||
for day in range(3):
|
||||
before = len(jq.orders)
|
||||
jq.run_scheduled()
|
||||
daily_orders.append(len(jq.orders) - before)
|
||||
if day < 2:
|
||||
jq.advance_session()
|
||||
self.assertEqual(daily_orders, [0, 4, 0])
|
||||
|
||||
with self.subTest(artifact="source-wrapper"):
|
||||
self._install_package(package)
|
||||
with (
|
||||
mock.patch.object(
|
||||
portable_core,
|
||||
"any",
|
||||
hostile_any,
|
||||
create=True,
|
||||
),
|
||||
mock.patch.object(
|
||||
joinquant_strategy,
|
||||
"any",
|
||||
hostile_any,
|
||||
create=True,
|
||||
),
|
||||
):
|
||||
run_three_days(joinquant_strategy)
|
||||
|
||||
with self.subTest(artifact="final-target-bundle"):
|
||||
bundled.any = hostile_any
|
||||
self.assertEqual(
|
||||
bundled.TARGET_PACKAGES[0]["package_sha256"],
|
||||
package["package_sha256"],
|
||||
)
|
||||
run_three_days(bundled)
|
||||
|
||||
def test_joinquant_emits_noop_and_skipped_order(self):
|
||||
missing = _package(
|
||||
signal_as_of="2026-07-10T15:00:00+08:00",
|
||||
next_session="2026-07-13",
|
||||
)
|
||||
self._install_package(missing)
|
||||
jq = FakeJoinQuantHarness(_jq_histories())
|
||||
output = io.StringIO()
|
||||
with contextlib.redirect_stdout(output):
|
||||
jq.initialize(joinquant_strategy)
|
||||
self.assertIsNone(jq.run_scheduled())
|
||||
events = [
|
||||
record["event"] for record in _evidence_records(output)
|
||||
]
|
||||
self.assertIn("TARGET_PACKAGE_NOOP", events)
|
||||
self.assertNotIn("TARGET_PACKAGE_PLAN", events)
|
||||
self.assertNotIn("ORDER_REQUEST", events)
|
||||
|
||||
package = _package()
|
||||
self._install_package(package)
|
||||
jq = FakeJoinQuantHarness(_jq_histories())
|
||||
jq.current_data["000001.XSHE"].paused = True
|
||||
output = io.StringIO()
|
||||
with contextlib.redirect_stdout(output):
|
||||
jq.initialize(joinquant_strategy)
|
||||
plan = jq.run_scheduled()
|
||||
self.assertIsNotNone(plan)
|
||||
records = _evidence_records(output)
|
||||
skipped = [
|
||||
record["payload"]
|
||||
for record in records
|
||||
if record["event"] == "SKIPPED_ORDER"
|
||||
]
|
||||
self.assertEqual(len(skipped), 1)
|
||||
self.assertEqual(skipped[0]["skip"]["reason"], "paused")
|
||||
self.assertEqual(jq.orders, [])
|
||||
|
||||
def test_joinquant_observation_failure_does_not_change_order_path(self):
|
||||
package = _package()
|
||||
self._install_package(package)
|
||||
jq = FakeJoinQuantHarness(_jq_histories())
|
||||
with mock.patch("builtins.print", side_effect=RuntimeError("log down")):
|
||||
jq.initialize(joinquant_strategy)
|
||||
plan = jq.run_scheduled()
|
||||
joinquant_strategy.after_trading_end(jq.context)
|
||||
self.assertIsNotNone(plan)
|
||||
self.assertEqual(
|
||||
sorted(jq.orders),
|
||||
[("000001.XSHE", 25000)],
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,228 @@
|
||||
import copy
|
||||
import unittest
|
||||
|
||||
from quant60.baseline_pipeline import (
|
||||
AlphaForecastInput,
|
||||
BaselinePipelineError,
|
||||
BaselinePipelinePolicy,
|
||||
CostForecastInput,
|
||||
FIVE_LAYER_ORDER,
|
||||
RiskForecastInput,
|
||||
SecurityStateInput,
|
||||
build_baseline_pipeline,
|
||||
verify_layer_trace,
|
||||
)
|
||||
from quant60.optimizer import PortfolioConstraints
|
||||
from quant60.universe import UniverseState
|
||||
|
||||
|
||||
SYMBOLS = (
|
||||
"600000.XSHG",
|
||||
"000001.XSHE",
|
||||
"000333.XSHE",
|
||||
)
|
||||
|
||||
|
||||
def inputs(*, first_variance=0.03, first_cost_bps=8.0):
|
||||
alpha = [
|
||||
AlphaForecastInput(
|
||||
SYMBOLS[0],
|
||||
expected_excess_return=0.030,
|
||||
model_version="ridge-frozen-fixture-v1",
|
||||
feature_version="transparent-price-v1",
|
||||
),
|
||||
AlphaForecastInput(
|
||||
SYMBOLS[1],
|
||||
expected_excess_return=0.020,
|
||||
model_version="ridge-frozen-fixture-v1",
|
||||
feature_version="transparent-price-v1",
|
||||
),
|
||||
AlphaForecastInput(
|
||||
SYMBOLS[2],
|
||||
expected_excess_return=0.010,
|
||||
model_version="ridge-frozen-fixture-v1",
|
||||
feature_version="transparent-price-v1",
|
||||
),
|
||||
]
|
||||
risk = [
|
||||
RiskForecastInput(
|
||||
SYMBOLS[0],
|
||||
first_variance,
|
||||
"diagonal-risk-fixture-v1",
|
||||
),
|
||||
RiskForecastInput(SYMBOLS[1], 0.03, "diagonal-risk-fixture-v1"),
|
||||
RiskForecastInput(SYMBOLS[2], 0.03, "diagonal-risk-fixture-v1"),
|
||||
]
|
||||
cost = [
|
||||
CostForecastInput(
|
||||
SYMBOLS[0],
|
||||
first_cost_bps,
|
||||
1.0,
|
||||
"dated-cost-fixture-v1",
|
||||
),
|
||||
CostForecastInput(SYMBOLS[1], 8.0, 1.0, "dated-cost-fixture-v1"),
|
||||
CostForecastInput(SYMBOLS[2], 8.0, 1.0, "dated-cost-fixture-v1"),
|
||||
]
|
||||
securities = [
|
||||
SecurityStateInput(
|
||||
SYMBOLS[0],
|
||||
UniverseState.OPENABLE,
|
||||
"bank",
|
||||
10.0,
|
||||
),
|
||||
SecurityStateInput(
|
||||
SYMBOLS[1],
|
||||
UniverseState.OPENABLE,
|
||||
"bank",
|
||||
20.0,
|
||||
),
|
||||
SecurityStateInput(
|
||||
SYMBOLS[2],
|
||||
UniverseState.OPENABLE,
|
||||
"consumer",
|
||||
50.0,
|
||||
),
|
||||
]
|
||||
return alpha, risk, cost, securities
|
||||
|
||||
|
||||
def policy():
|
||||
return BaselinePipelinePolicy(
|
||||
constraints=PortfolioConstraints(
|
||||
gross_target=0.80,
|
||||
single_name_cap=0.80,
|
||||
industry_cap=0.80,
|
||||
one_way_turnover_cap=0.80,
|
||||
risk_aversion=1.0,
|
||||
cost_aversion=1.0,
|
||||
turnover_aversion=0.0,
|
||||
),
|
||||
cash_buffer=0.10,
|
||||
)
|
||||
|
||||
|
||||
class BaselinePipelineTests(unittest.TestCase):
|
||||
def test_canonical_path_emits_exact_five_layer_hash_chain(self):
|
||||
alpha, risk, cost, securities = inputs()
|
||||
result = build_baseline_pipeline(
|
||||
alpha=alpha,
|
||||
risk=risk,
|
||||
cost=cost,
|
||||
securities=securities,
|
||||
equity=1_000_000,
|
||||
policy=policy(),
|
||||
)
|
||||
self.assertEqual(
|
||||
tuple(event["layer"] for event in result.layer_trace),
|
||||
FIVE_LAYER_ORDER,
|
||||
)
|
||||
self.assertTrue(result.risk_decision.approved)
|
||||
self.assertTrue(result.order_deltas)
|
||||
verify_layer_trace(result.layer_trace, result.layer_payloads)
|
||||
|
||||
def test_risk_and_cost_are_causal_inputs_to_portfolio(self):
|
||||
alpha, risk, cost, securities = inputs()
|
||||
base = build_baseline_pipeline(
|
||||
alpha=alpha,
|
||||
risk=risk,
|
||||
cost=cost,
|
||||
securities=securities,
|
||||
equity=1_000_000,
|
||||
policy=policy(),
|
||||
)
|
||||
alpha, risk, cost, securities = inputs(first_variance=0.30)
|
||||
high_risk = build_baseline_pipeline(
|
||||
alpha=alpha,
|
||||
risk=risk,
|
||||
cost=cost,
|
||||
securities=securities,
|
||||
equity=1_000_000,
|
||||
policy=policy(),
|
||||
)
|
||||
alpha, risk, cost, securities = inputs(first_cost_bps=250.0)
|
||||
high_cost = build_baseline_pipeline(
|
||||
alpha=alpha,
|
||||
risk=risk,
|
||||
cost=cost,
|
||||
securities=securities,
|
||||
equity=1_000_000,
|
||||
policy=policy(),
|
||||
)
|
||||
symbol = SYMBOLS[0]
|
||||
self.assertLess(
|
||||
high_risk.solution.weights[symbol],
|
||||
base.solution.weights[symbol],
|
||||
)
|
||||
self.assertLess(
|
||||
high_cost.solution.weights[symbol],
|
||||
base.solution.weights[symbol],
|
||||
)
|
||||
self.assertNotEqual(
|
||||
base.layer_trace[2]["event_sha256"],
|
||||
high_risk.layer_trace[2]["event_sha256"],
|
||||
)
|
||||
self.assertNotEqual(
|
||||
base.layer_trace[2]["event_sha256"],
|
||||
high_cost.layer_trace[2]["event_sha256"],
|
||||
)
|
||||
|
||||
def test_missing_layer_input_fails_closed(self):
|
||||
alpha, risk, cost, securities = inputs()
|
||||
with self.assertRaisesRegex(
|
||||
BaselinePipelineError,
|
||||
"symbol sets must match exactly",
|
||||
):
|
||||
build_baseline_pipeline(
|
||||
alpha=alpha,
|
||||
risk=risk[:-1],
|
||||
cost=cost,
|
||||
securities=securities,
|
||||
equity=1_000_000,
|
||||
policy=policy(),
|
||||
)
|
||||
|
||||
def test_smoke_model_cannot_claim_baseline_candidate(self):
|
||||
alpha, risk, cost, securities = inputs()
|
||||
alpha = [
|
||||
AlphaForecastInput(
|
||||
item.symbol,
|
||||
item.expected_excess_return,
|
||||
"portable-momentum-v1",
|
||||
item.feature_version,
|
||||
)
|
||||
for item in alpha
|
||||
]
|
||||
with self.assertRaisesRegex(
|
||||
BaselinePipelineError,
|
||||
"platform smoke strategy",
|
||||
):
|
||||
build_baseline_pipeline(
|
||||
alpha=alpha,
|
||||
risk=risk,
|
||||
cost=cost,
|
||||
securities=securities,
|
||||
equity=1_000_000,
|
||||
policy=policy(),
|
||||
)
|
||||
|
||||
def test_layer_trace_tampering_is_rejected(self):
|
||||
alpha, risk, cost, securities = inputs()
|
||||
result = build_baseline_pipeline(
|
||||
alpha=alpha,
|
||||
risk=risk,
|
||||
cost=cost,
|
||||
securities=securities,
|
||||
equity=1_000_000,
|
||||
policy=policy(),
|
||||
)
|
||||
trace = copy.deepcopy(list(result.layer_trace))
|
||||
trace[2]["output_sha256"] = "0" * 64
|
||||
with self.assertRaisesRegex(
|
||||
BaselinePipelineError,
|
||||
"output hash mismatch",
|
||||
):
|
||||
verify_layer_trace(trace, result.layer_payloads)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,134 @@
|
||||
import json
|
||||
import subprocess
|
||||
import sys
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
|
||||
from quant60.ledger import canonical_json
|
||||
from quant60.release_reachability import LAYERS
|
||||
|
||||
|
||||
PROJECT = Path(__file__).resolve().parents[1]
|
||||
sys.path.insert(0, str(PROJECT))
|
||||
|
||||
from tools.build_release_reachability import ( # noqa: E402
|
||||
DEFAULT_OUTPUT,
|
||||
JOINQUANT_TARGET_PACKAGE_OBSERVED_AT,
|
||||
JOINQUANT_TARGET_PACKAGE_RUN_ID,
|
||||
JOINQUANT_TARGET_PACKAGE_RUN_PATH,
|
||||
PLATFORM_ENTRYPOINTS,
|
||||
RELEASE_ID,
|
||||
build_manifest,
|
||||
)
|
||||
|
||||
|
||||
class BuildReleaseReachabilityTests(unittest.TestCase):
|
||||
def test_checked_in_manifest_exactly_matches_generator(self):
|
||||
expected = build_manifest(repository_root=PROJECT)
|
||||
observed = json.loads(DEFAULT_OUTPUT.read_text(encoding="utf-8"))
|
||||
self.assertEqual(observed, expected)
|
||||
self.assertEqual(
|
||||
DEFAULT_OUTPUT.read_bytes(),
|
||||
(canonical_json(expected) + "\n").encode("utf-8"),
|
||||
)
|
||||
|
||||
def test_only_execution_has_real_joinquant_observation(self):
|
||||
manifest = build_manifest(repository_root=PROJECT)
|
||||
self.assertEqual(manifest["release_id"], RELEASE_ID)
|
||||
for layer in LAYERS:
|
||||
claims = manifest["layers"][layer]
|
||||
for declaration in PLATFORM_ENTRYPOINTS.values():
|
||||
claim = claims[declaration["capability"]]
|
||||
self.assertTrue(claim["status"])
|
||||
self.assertEqual(len(claim["artifacts"]), 1)
|
||||
artifact = claim["artifacts"][0]
|
||||
self.assertIn("targetpackagev1", artifact["artifact_id"])
|
||||
self.assertEqual(artifact["path"], declaration["path"])
|
||||
self.assertEqual(artifact["platform"], declaration["platform"])
|
||||
observed = claims["real_platform_observed"]
|
||||
if layer != "execution":
|
||||
self.assertEqual(
|
||||
observed,
|
||||
{"status": False, "artifacts": []},
|
||||
)
|
||||
continue
|
||||
self.assertTrue(observed["status"])
|
||||
self.assertEqual(len(observed["artifacts"]), 1)
|
||||
artifact = observed["artifacts"][0]
|
||||
self.assertEqual(artifact["kind"], "platform_run")
|
||||
self.assertEqual(artifact["platform"], "joinquant")
|
||||
self.assertEqual(
|
||||
artifact["path"],
|
||||
JOINQUANT_TARGET_PACKAGE_RUN_PATH,
|
||||
)
|
||||
self.assertEqual(
|
||||
artifact["observed_at"],
|
||||
JOINQUANT_TARGET_PACKAGE_OBSERVED_AT,
|
||||
)
|
||||
self.assertEqual(
|
||||
artifact["run_id"],
|
||||
JOINQUANT_TARGET_PACKAGE_RUN_ID,
|
||||
)
|
||||
self.assertFalse(
|
||||
manifest["summary"]["all_layers_real_platform_observed"]
|
||||
)
|
||||
|
||||
def test_tracked_joinquant_run_preserves_conservative_boundary(self):
|
||||
run = json.loads(
|
||||
(PROJECT / JOINQUANT_TARGET_PACKAGE_RUN_PATH).read_text(
|
||||
encoding="utf-8"
|
||||
)
|
||||
)
|
||||
self.assertEqual(run["run_id"], JOINQUANT_TARGET_PACKAGE_RUN_ID)
|
||||
self.assertEqual(run["observed_at"], JOINQUANT_TARGET_PACKAGE_OBSERVED_AT)
|
||||
self.assertEqual(
|
||||
run["platform_evidence_class"],
|
||||
"real_platform_runtime",
|
||||
)
|
||||
self.assertEqual(
|
||||
run["input_evidence_class"],
|
||||
"synthetic-research",
|
||||
)
|
||||
self.assertFalse(run["performance_claim"])
|
||||
self.assertEqual(
|
||||
run["target_package"]["evidence_class"],
|
||||
"synthetic-research",
|
||||
)
|
||||
self.assertEqual(run["counts"], {
|
||||
"orders": 3,
|
||||
"fills": 3,
|
||||
"skipped_orders": 0,
|
||||
})
|
||||
boundary = run["claim_boundary"]
|
||||
self.assertEqual(
|
||||
boundary["real_platform_observed_layers"],
|
||||
["execution"],
|
||||
)
|
||||
self.assertFalse(boundary["upstream_layers_real_platform_observed"])
|
||||
self.assertFalse(boundary["qmt_peer_observed"])
|
||||
self.assertFalse(boundary["same_input_cross_engine_parity_observed"])
|
||||
self.assertFalse(boundary["all_five_layers_real_platform_observed"])
|
||||
self.assertFalse(boundary["g9_passed"])
|
||||
self.assertFalse(boundary["baseline_60_passed"])
|
||||
self.assertFalse(boundary["investment_value_claim"])
|
||||
|
||||
def test_check_mode_verifies_current_file(self):
|
||||
completed = subprocess.run(
|
||||
[
|
||||
sys.executable,
|
||||
str(PROJECT / "tools/build_release_reachability.py"),
|
||||
"--check",
|
||||
],
|
||||
cwd=PROJECT,
|
||||
check=False,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
)
|
||||
self.assertEqual(completed.returncode, 0, completed.stderr)
|
||||
result = json.loads(completed.stdout)
|
||||
self.assertTrue(result["ok"])
|
||||
self.assertTrue(result["checked"])
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -19,6 +19,22 @@ class ResearchExperimentTests(unittest.TestCase):
|
||||
self.assertGreater(first["report"]["fold_count"], 0)
|
||||
self.assertFalse(first["report"]["investment_value_claim"])
|
||||
self.assertTrue(first["targets"])
|
||||
self.assertLess(
|
||||
first["report"]["final_training_max_label_exit"],
|
||||
first["report"]["target_date"],
|
||||
)
|
||||
self.assertEqual(
|
||||
first["target_package"]["model_sha256"],
|
||||
first["model_bundle"]["bundle_sha256"],
|
||||
)
|
||||
self.assertEqual(
|
||||
[item["layer"] for item in first["pipeline"]["layer_trace"]],
|
||||
["universe", "alpha", "portfolio", "risk", "execution"],
|
||||
)
|
||||
self.assertEqual(
|
||||
first["target_package"]["target_weights"],
|
||||
first["pipeline"]["weights"],
|
||||
)
|
||||
|
||||
with tempfile.TemporaryDirectory() as left_dir, tempfile.TemporaryDirectory() as right_dir:
|
||||
left = write_research_artifacts(first, left_dir)
|
||||
|
||||
@@ -0,0 +1,191 @@
|
||||
import copy
|
||||
import hashlib
|
||||
import json
|
||||
import tempfile
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
|
||||
from quant60.features import TrainOnlyFeaturePreprocessor
|
||||
from quant60.ledger import canonical_json
|
||||
from quant60.model_bundle import (
|
||||
ModelBundleIntegrityError,
|
||||
create_model_bundle,
|
||||
load_verified_model_bundle,
|
||||
model_bundle_sha256,
|
||||
verify_model_bundle,
|
||||
write_model_bundle,
|
||||
)
|
||||
from quant60.research import DeterministicRidge
|
||||
|
||||
|
||||
HASHES = {
|
||||
"data_sha256": hashlib.sha256(b"training-data").hexdigest(),
|
||||
"source_sha256": hashlib.sha256(b"source-tree").hexdigest(),
|
||||
"config_sha256": hashlib.sha256(b"training-config").hexdigest(),
|
||||
}
|
||||
|
||||
|
||||
class ModelBundleTests(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.training_rows = [
|
||||
{"momentum": -0.2, "volatility": 0.10},
|
||||
{"momentum": -0.1, "volatility": None},
|
||||
{"momentum": 0.0, "volatility": 0.20},
|
||||
{"momentum": 0.1, "volatility": 0.25},
|
||||
{"momentum": 0.2, "volatility": 0.30},
|
||||
]
|
||||
self.processor = TrainOnlyFeaturePreprocessor(
|
||||
winsor_fraction=0.1
|
||||
).fit(self.training_rows)
|
||||
transformed = self.processor.transform(self.training_rows)
|
||||
matrix = [
|
||||
[row[name] for name in self.processor.output_names]
|
||||
for row in transformed
|
||||
]
|
||||
self.model = DeterministicRidge(alpha=0.5).fit(
|
||||
matrix,
|
||||
[-0.03, -0.01, 0.0, 0.02, 0.04],
|
||||
)
|
||||
self.bundle = create_model_bundle(
|
||||
self.processor,
|
||||
self.model,
|
||||
trained_through="2024-12-31",
|
||||
label_name="t_plus_1_open_to_t_plus_6_open_excess",
|
||||
horizon_trading_days=5,
|
||||
**HASHES,
|
||||
)
|
||||
|
||||
def test_freezes_preprocessor_model_label_and_lineage(self):
|
||||
verified = verify_model_bundle(self.bundle)
|
||||
self.assertEqual(
|
||||
verified.feature_order,
|
||||
tuple(sorted(self.training_rows[0])),
|
||||
)
|
||||
self.assertEqual(
|
||||
verified.output_feature_order,
|
||||
self.processor.output_names,
|
||||
)
|
||||
self.assertEqual(
|
||||
verified.coefficients,
|
||||
self.model.coef_,
|
||||
)
|
||||
self.assertEqual(verified.intercept, self.model.intercept_)
|
||||
self.assertEqual(verified.trained_through.isoformat(), "2024-12-31")
|
||||
self.assertEqual(verified.horizon_trading_days, 5)
|
||||
self.assertEqual(verified.data_sha256, HASHES["data_sha256"])
|
||||
|
||||
def test_write_read_and_prediction_replay_are_deterministic(self):
|
||||
replay_rows = [
|
||||
{"volatility": None, "momentum": 0.07},
|
||||
{"momentum": -100.0, "volatility": 100.0},
|
||||
]
|
||||
transformed = self.processor.transform(replay_rows)
|
||||
matrix = [
|
||||
[row[name] for name in self.processor.output_names]
|
||||
for row in transformed
|
||||
]
|
||||
expected = self.model.predict(matrix)
|
||||
|
||||
with tempfile.TemporaryDirectory() as directory:
|
||||
left = write_model_bundle(
|
||||
self.bundle,
|
||||
Path(directory) / "left.json",
|
||||
)
|
||||
right = write_model_bundle(
|
||||
copy.deepcopy(self.bundle),
|
||||
Path(directory) / "right.json",
|
||||
)
|
||||
self.assertEqual(left.read_bytes(), right.read_bytes())
|
||||
loaded = load_verified_model_bundle(
|
||||
left,
|
||||
expected_bundle_sha256=self.bundle["bundle_sha256"],
|
||||
**{
|
||||
f"expected_{key}": value
|
||||
for key, value in HASHES.items()
|
||||
},
|
||||
)
|
||||
self.assertEqual(loaded.predict(replay_rows), expected)
|
||||
independently_loaded = load_verified_model_bundle(right)
|
||||
self.assertEqual(
|
||||
loaded.prediction_bytes(replay_rows),
|
||||
independently_loaded.prediction_bytes(replay_rows),
|
||||
)
|
||||
self.assertEqual(loaded.canonical_bytes, left.read_bytes())
|
||||
|
||||
def test_content_tampering_fails_closed(self):
|
||||
with tempfile.TemporaryDirectory() as directory:
|
||||
path = write_model_bundle(
|
||||
self.bundle,
|
||||
Path(directory) / "bundle.json",
|
||||
)
|
||||
tampered = json.loads(path.read_text(encoding="utf-8"))
|
||||
tampered["model"]["coefficients"][0] += 0.01
|
||||
path.write_text(
|
||||
canonical_json(tampered) + "\n",
|
||||
encoding="utf-8",
|
||||
)
|
||||
with self.assertRaisesRegex(
|
||||
ModelBundleIntegrityError,
|
||||
"SHA-256 mismatch",
|
||||
):
|
||||
load_verified_model_bundle(path)
|
||||
|
||||
def test_resealed_semantic_tampering_fails_closed(self):
|
||||
tampered = copy.deepcopy(self.bundle)
|
||||
tampered["preprocessor"]["output_feature_order"] = list(
|
||||
reversed(tampered["preprocessor"]["output_feature_order"])
|
||||
)
|
||||
tampered["bundle_sha256"] = model_bundle_sha256(tampered)
|
||||
with self.assertRaisesRegex(
|
||||
ModelBundleIntegrityError,
|
||||
"output_feature_order is inconsistent",
|
||||
):
|
||||
verify_model_bundle(tampered)
|
||||
|
||||
def test_expected_identity_rejects_a_valid_but_wrong_bundle(self):
|
||||
with self.assertRaisesRegex(
|
||||
ModelBundleIntegrityError,
|
||||
"data_sha256 does not match expected identity",
|
||||
):
|
||||
verify_model_bundle(
|
||||
self.bundle,
|
||||
expected_data_sha256="f" * 64,
|
||||
)
|
||||
|
||||
def test_placeholder_lineage_hash_is_rejected(self):
|
||||
with self.assertRaisesRegex(
|
||||
ModelBundleIntegrityError,
|
||||
"all-zero placeholder",
|
||||
):
|
||||
create_model_bundle(
|
||||
self.processor,
|
||||
self.model,
|
||||
trained_through="2024-12-31",
|
||||
label_name="label",
|
||||
horizon_trading_days=5,
|
||||
data_sha256="0" * 64,
|
||||
source_sha256=HASHES["source_sha256"],
|
||||
config_sha256=HASHES["config_sha256"],
|
||||
)
|
||||
|
||||
def test_unfitted_components_and_non_finite_state_are_rejected(self):
|
||||
with self.assertRaisesRegex(ValueError, "preprocessor is not fitted"):
|
||||
create_model_bundle(
|
||||
TrainOnlyFeaturePreprocessor(),
|
||||
self.model,
|
||||
trained_through="2024-12-31",
|
||||
label_name="label",
|
||||
horizon_trading_days=5,
|
||||
**HASHES,
|
||||
)
|
||||
tampered = copy.deepcopy(self.bundle)
|
||||
tampered["model"]["intercept"] = float("nan")
|
||||
with self.assertRaisesRegex(
|
||||
ModelBundleIntegrityError,
|
||||
"canonical JSON",
|
||||
):
|
||||
verify_model_bundle(tampered)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -1,16 +1,99 @@
|
||||
import ast
|
||||
import copy
|
||||
import hashlib
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
|
||||
from quant60.ledger import canonical_json
|
||||
from quant60.portable_core import (
|
||||
TargetPackageLookupMiss,
|
||||
_any_true,
|
||||
build_rebalance_plan,
|
||||
build_target_weight_plan,
|
||||
capped_target_weights,
|
||||
lookup_target_package_exact,
|
||||
momentum_score,
|
||||
normalize_symbol,
|
||||
order_deltas,
|
||||
target_package_tape_sha256,
|
||||
target_quantities,
|
||||
verify_target_package,
|
||||
)
|
||||
from quant60.target_package import seal_target_package
|
||||
|
||||
|
||||
def sealed_target_package(
|
||||
package_id="TP-20260724-A",
|
||||
decision_id="D-20260724-A",
|
||||
signal_as_of="2026-07-24T15:00:00+08:00",
|
||||
next_session="2026-07-27",
|
||||
):
|
||||
return seal_target_package(
|
||||
{
|
||||
"schema_version": "1.0",
|
||||
"package_type": "TargetPackageV1",
|
||||
"package_id": package_id,
|
||||
"decision_id": decision_id,
|
||||
"release": "quant60-baseline-60-v1",
|
||||
"evidence_class": "provider-snapshot-local",
|
||||
"model_id": "alpha158-lightgbm-v1",
|
||||
"signal_as_of": signal_as_of,
|
||||
"next_session": next_session,
|
||||
"model_sha256": "1" * 64,
|
||||
"data_sha256": "2" * 64,
|
||||
"feature_sha256": "3" * 64,
|
||||
"risk_sha256": "4" * 64,
|
||||
"cost_sha256": "5" * 64,
|
||||
"optimizer_sha256": "6" * 64,
|
||||
"config_sha256": "7" * 64,
|
||||
"source_sha256": "8" * 64,
|
||||
"target_weights": {
|
||||
"000001.XSHE": 0.30,
|
||||
"600000.XSHG": 0.20,
|
||||
},
|
||||
"universe": {
|
||||
"000001.XSHE": {
|
||||
"state": "openable",
|
||||
"reasons": ["ELIGIBLE"],
|
||||
},
|
||||
"600000.XSHG": {
|
||||
"state": "hold_only",
|
||||
"reasons": ["LIQUIDITY_BELOW_FLOOR"],
|
||||
},
|
||||
},
|
||||
"constraints": {
|
||||
"constraint_state": "FEASIBLE",
|
||||
"long_only": True,
|
||||
"max_single_weight": 0.40,
|
||||
"max_gross_weight": 0.80,
|
||||
"max_one_way_turnover": 0.20,
|
||||
"actual_gross_weight": 0.50,
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
class PortableCoreTests(unittest.TestCase):
|
||||
def test_private_any_true_preserves_builtin_semantics(self):
|
||||
for values in (
|
||||
[],
|
||||
[False, 0, None, ""],
|
||||
[False, 0, "truthy"],
|
||||
[1],
|
||||
):
|
||||
with self.subTest(values=values):
|
||||
self.assertEqual(_any_true(iter(values)), any(values))
|
||||
|
||||
visited = []
|
||||
|
||||
def values():
|
||||
for value in (False, True, "must-not-be-read"):
|
||||
visited.append(value)
|
||||
yield value
|
||||
|
||||
self.assertTrue(_any_true(values()))
|
||||
self.assertEqual(visited, [False, True])
|
||||
|
||||
def test_symbol_round_trip(self):
|
||||
inputs = [
|
||||
("600000.XSHG", "600000.SH", "SH600000"),
|
||||
@@ -166,6 +249,255 @@ class PortableCoreTests(unittest.TestCase):
|
||||
build_rebalance_plan(**arguments),
|
||||
)
|
||||
|
||||
def test_target_weight_plan_is_causal_and_preserves_lineage(self):
|
||||
common = {
|
||||
"prices": {
|
||||
"600000.SH": 10.0,
|
||||
"000001.SZ": 10.0,
|
||||
},
|
||||
"current": {},
|
||||
"sellable": {},
|
||||
"equity": 100_000,
|
||||
"cash_buffer": 0.02,
|
||||
"lot_size": 100,
|
||||
"decision_id": "D-20260724-A",
|
||||
"package_sha256": "a" * 64,
|
||||
}
|
||||
first = build_target_weight_plan(
|
||||
{
|
||||
"600000.XSHG": 0.60,
|
||||
"000001.XSHE": 0.20,
|
||||
},
|
||||
**common
|
||||
)
|
||||
second = build_target_weight_plan(
|
||||
{
|
||||
"600000.XSHG": 0.20,
|
||||
"000001.XSHE": 0.60,
|
||||
},
|
||||
**common
|
||||
)
|
||||
self.assertNotEqual(first["targets"], second["targets"])
|
||||
self.assertNotEqual(first["orders"], second["orders"])
|
||||
self.assertEqual(first["decision_id"], "D-20260724-A")
|
||||
self.assertEqual(first["package_sha256"], "a" * 64)
|
||||
self.assertNotIn("scores", first)
|
||||
|
||||
def test_target_weight_plan_rejects_alias_duplicates_and_bad_weights(self):
|
||||
common = {
|
||||
"prices": {"600000.XSHG": 10.0},
|
||||
"current": {},
|
||||
"sellable": {},
|
||||
"equity": 100_000,
|
||||
}
|
||||
with self.assertRaisesRegex(ValueError, "duplicate normalized"):
|
||||
build_target_weight_plan(
|
||||
{
|
||||
"600000.SH": 0.20,
|
||||
"600000.XSHG": 0.20,
|
||||
},
|
||||
**common
|
||||
)
|
||||
for weights in (
|
||||
{"600000.XSHG": -0.1},
|
||||
{"600000.XSHG": float("nan")},
|
||||
{"600000.XSHG": 1.01},
|
||||
):
|
||||
with self.subTest(weights=weights):
|
||||
with self.assertRaises(ValueError):
|
||||
build_target_weight_plan(weights, **common)
|
||||
with self.assertRaisesRegex(ValueError, "gross"):
|
||||
build_target_weight_plan(
|
||||
{
|
||||
"600000.XSHG": 0.60,
|
||||
"000001.XSHE": 0.50,
|
||||
},
|
||||
prices={
|
||||
"600000.XSHG": 10.0,
|
||||
"000001.XSHE": 10.0,
|
||||
},
|
||||
current={},
|
||||
sellable={},
|
||||
equity=100_000,
|
||||
)
|
||||
|
||||
def test_target_weight_plan_respects_t1_and_odd_lot_liquidation(self):
|
||||
t1_limited = build_target_weight_plan(
|
||||
{},
|
||||
{"600000.XSHG": 10.0},
|
||||
{"600000.XSHG": 1050},
|
||||
{"600000.XSHG": 250},
|
||||
equity=100_000,
|
||||
)
|
||||
self.assertEqual(t1_limited["weights"], {"600000.XSHG": 0.0})
|
||||
self.assertEqual(t1_limited["targets"], {"600000.XSHG": 0})
|
||||
self.assertEqual(t1_limited["orders"], {"600000.XSHG": -200})
|
||||
|
||||
complete = build_target_weight_plan(
|
||||
{},
|
||||
{"600000.XSHG": 10.0},
|
||||
{"600000.XSHG": 1050},
|
||||
{"600000.XSHG": 1050},
|
||||
equity=100_000,
|
||||
)
|
||||
self.assertEqual(complete["orders"], {"600000.XSHG": -1050})
|
||||
|
||||
unsellable = build_target_weight_plan(
|
||||
{},
|
||||
{"600000.XSHG": 10.0},
|
||||
{"600000.XSHG": 1050},
|
||||
{},
|
||||
equity=100_000,
|
||||
)
|
||||
self.assertEqual(unsellable["orders"], {})
|
||||
|
||||
def test_target_weight_plan_requires_exact_managed_price_coverage(self):
|
||||
with self.assertRaisesRegex(KeyError, "missing"):
|
||||
build_target_weight_plan(
|
||||
{"600000.XSHG": 0.20},
|
||||
{"600000.XSHG": 10.0},
|
||||
{"000001.XSHE": 100},
|
||||
{"000001.XSHE": 100},
|
||||
equity=100_000,
|
||||
)
|
||||
with self.assertRaisesRegex(ValueError, "unmanaged"):
|
||||
build_target_weight_plan(
|
||||
{"600000.XSHG": 0.20},
|
||||
{
|
||||
"600000.XSHG": 10.0,
|
||||
"000001.XSHE": 10.0,
|
||||
},
|
||||
{},
|
||||
{},
|
||||
equity=100_000,
|
||||
)
|
||||
|
||||
def test_portable_target_package_verifier_matches_local_seal(self):
|
||||
package = sealed_target_package()
|
||||
self.assertEqual(verify_target_package(package), package)
|
||||
self.assertEqual(
|
||||
verify_target_package(
|
||||
package,
|
||||
expected_signal_as_of=package["signal_as_of"],
|
||||
expected_next_session=package["next_session"],
|
||||
expected_decision_id=package["decision_id"],
|
||||
expected_package_sha256=package["package_sha256"],
|
||||
),
|
||||
package,
|
||||
)
|
||||
|
||||
tampered = copy.deepcopy(package)
|
||||
tampered["target_weights"]["000001.XSHE"] = 0.29
|
||||
tampered["constraints"]["actual_gross_weight"] = 0.49
|
||||
with self.assertRaisesRegex(ValueError, "hash mismatch"):
|
||||
verify_target_package(tampered)
|
||||
|
||||
quantity_injected = copy.deepcopy(package)
|
||||
quantity_injected["target_quantity"] = 100
|
||||
with self.assertRaisesRegex(ValueError, "quantities do not belong"):
|
||||
verify_target_package(quantity_injected)
|
||||
|
||||
noncanonical = copy.deepcopy(package)
|
||||
noncanonical["target_weights"]["000001.SZ"] = noncanonical[
|
||||
"target_weights"
|
||||
].pop("000001.XSHE")
|
||||
with self.assertRaisesRegex(ValueError, "must be canonical"):
|
||||
verify_target_package(noncanonical)
|
||||
|
||||
def test_target_package_tape_is_pinned_and_exact_only(self):
|
||||
first = sealed_target_package()
|
||||
second = sealed_target_package(
|
||||
package_id="TP-20260731-B",
|
||||
decision_id="D-20260731-B",
|
||||
signal_as_of="2026-07-31T15:00:00+08:00",
|
||||
next_session="2026-08-03",
|
||||
)
|
||||
packages = [first, second]
|
||||
tape_hash = target_package_tape_sha256(packages)
|
||||
self.assertEqual(
|
||||
tape_hash,
|
||||
hashlib.sha256(
|
||||
canonical_json(packages).encode("utf-8")
|
||||
).hexdigest(),
|
||||
)
|
||||
found = lookup_target_package_exact(
|
||||
packages,
|
||||
signal_as_of=second["signal_as_of"],
|
||||
next_session=second["next_session"],
|
||||
decision_id=second["decision_id"],
|
||||
expected_tape_sha256=tape_hash,
|
||||
expected_count=2,
|
||||
)
|
||||
self.assertEqual(found, second)
|
||||
found["release"] = "mutated"
|
||||
self.assertEqual(packages[1]["release"], second["release"])
|
||||
|
||||
with self.assertRaises(TargetPackageLookupMiss):
|
||||
lookup_target_package_exact(
|
||||
packages,
|
||||
signal_as_of="2026-07-30T15:00:00+08:00",
|
||||
next_session="2026-07-31",
|
||||
expected_tape_sha256=tape_hash,
|
||||
expected_count=2,
|
||||
)
|
||||
with self.assertRaisesRegex(ValueError, "decision_id mismatch"):
|
||||
lookup_target_package_exact(
|
||||
packages,
|
||||
signal_as_of=first["signal_as_of"],
|
||||
next_session=first["next_session"],
|
||||
decision_id="D-WRONG",
|
||||
)
|
||||
with self.assertRaisesRegex(ValueError, "count mismatch"):
|
||||
lookup_target_package_exact(
|
||||
packages[:1],
|
||||
signal_as_of=first["signal_as_of"],
|
||||
next_session=first["next_session"],
|
||||
expected_count=2,
|
||||
)
|
||||
with self.assertRaisesRegex(ValueError, "digest mismatch"):
|
||||
lookup_target_package_exact(
|
||||
packages[:1],
|
||||
signal_as_of=first["signal_as_of"],
|
||||
next_session=first["next_session"],
|
||||
expected_tape_sha256=tape_hash,
|
||||
)
|
||||
|
||||
def test_target_package_tape_rejects_duplicates_and_unmatched_tamper(self):
|
||||
first = sealed_target_package()
|
||||
duplicate_clock = sealed_target_package(
|
||||
package_id="TP-20260724-B",
|
||||
decision_id="D-20260724-B",
|
||||
)
|
||||
with self.assertRaisesRegex(ValueError, "duplicate target package clock"):
|
||||
lookup_target_package_exact(
|
||||
[first, duplicate_clock],
|
||||
signal_as_of=first["signal_as_of"],
|
||||
next_session=first["next_session"],
|
||||
)
|
||||
|
||||
later = sealed_target_package(
|
||||
package_id="TP-20260731-B",
|
||||
decision_id="D-20260731-B",
|
||||
signal_as_of="2026-07-31T15:00:00+08:00",
|
||||
next_session="2026-08-03",
|
||||
)
|
||||
later["release"] = "tampered"
|
||||
with self.assertRaisesRegex(ValueError, "hash mismatch"):
|
||||
lookup_target_package_exact(
|
||||
[first, later],
|
||||
signal_as_of=first["signal_as_of"],
|
||||
next_session=first["next_session"],
|
||||
)
|
||||
|
||||
def test_portable_core_parses_as_python_36(self):
|
||||
source = (
|
||||
Path(__file__).parents[1]
|
||||
/ "src"
|
||||
/ "quant60"
|
||||
/ "portable_core.py"
|
||||
).read_text(encoding="utf-8")
|
||||
ast.parse(source, feature_version=(3, 6))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import importlib.util
|
||||
import hashlib
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
@@ -112,10 +113,191 @@ class PublicStatusTests(unittest.TestCase):
|
||||
|
||||
platforms = {platform["name"]: platform for platform in payload["platforms"]}
|
||||
self.assertEqual(platforms["JoinQuant hosted bundle"]["status"], "real_runtime")
|
||||
self.assertIn(
|
||||
"3",
|
||||
platforms["JoinQuant hosted bundle"]["claim"],
|
||||
)
|
||||
self.assertIn(
|
||||
"execution",
|
||||
platforms["JoinQuant hosted bundle"]["limitations"][0],
|
||||
)
|
||||
self.assertEqual(platforms["QMT built-in bundle"]["status"], "implemented")
|
||||
self.assertFalse(platforms["XtTrader read-only shadow"]["liveReady"])
|
||||
self.assertIn("fake", platforms["XtTrader read-only shadow"]["claim"].lower())
|
||||
|
||||
def test_candidate_records_only_real_joinquant_execution_observation(self):
|
||||
payload = _read_payload()
|
||||
candidate = payload["candidateBoundary"]
|
||||
self.assertEqual(candidate["decisionMode"], "target_package")
|
||||
self.assertEqual(candidate["localEvidenceClass"], "synthetic_research")
|
||||
self.assertTrue(candidate["realJoinQuantObserved"])
|
||||
self.assertFalse(candidate["realQmtObserved"])
|
||||
self.assertEqual(
|
||||
candidate["realPlatformObservedLayers"],
|
||||
["execution"],
|
||||
)
|
||||
self.assertFalse(candidate["allFiveLayersRealPlatformObserved"])
|
||||
run = candidate["joinQuantTargetPackageRun"]
|
||||
self.assertEqual(
|
||||
run["runId"],
|
||||
"2457a7c39a276e09e0fabf99e28978e1",
|
||||
)
|
||||
self.assertEqual(run["evidenceClass"], "synthetic-research")
|
||||
self.assertEqual(run["observedLayers"], ["execution"])
|
||||
self.assertEqual((run["orders"], run["fills"]), (3, 3))
|
||||
self.assertFalse(run["allFiveLayersObserved"])
|
||||
self.assertFalse(run["qmtPeerObserved"])
|
||||
self.assertFalse(run["g9Passed"])
|
||||
self.assertFalse(run["baseline60Passed"])
|
||||
self.assertFalse(run["investmentValueClaim"])
|
||||
self.assertFalse(candidate["joinQuantTargetPackageCountsAsBaseline"])
|
||||
self.assertFalse(candidate["joinQuantTargetPackageCountsAsG9"])
|
||||
self.assertEqual(
|
||||
candidate["historicalJoinQuantMode"], "portable_momentum_smoke"
|
||||
)
|
||||
self.assertFalse(candidate["historicalJoinQuantCountsAsBaseline"])
|
||||
self.assertTrue(payload["summary"]["candidateRealPlatformObserved"])
|
||||
self.assertEqual(
|
||||
payload["summary"]["candidateRealPlatformObservationScope"],
|
||||
"target_package_execution_consumer_only",
|
||||
)
|
||||
self.assertFalse(
|
||||
payload["summary"]["allFiveLayersRealPlatformObserved"]
|
||||
)
|
||||
reachability = candidate["reachability"]
|
||||
self.assertEqual(
|
||||
reachability["releaseId"], "quant60-research-candidate-v1"
|
||||
)
|
||||
self.assertTrue(
|
||||
reachability["summary"]["all_layers_implemented"]
|
||||
)
|
||||
self.assertTrue(
|
||||
reachability["summary"]["all_layers_local_entrypoint_reachable"]
|
||||
)
|
||||
self.assertFalse(
|
||||
reachability["summary"]["all_layers_real_platform_observed"]
|
||||
)
|
||||
self.assertEqual(
|
||||
reachability["realPlatformsObserved"],
|
||||
["joinquant"],
|
||||
)
|
||||
self.assertEqual(
|
||||
reachability["realPlatformObservedLayers"],
|
||||
["execution"],
|
||||
)
|
||||
evidence = {item["id"]: item for item in payload["evidence"]}
|
||||
self.assertEqual(
|
||||
evidence["release-reachability"]["path"],
|
||||
"releases/quant60-research-candidate-v1/reachability.json",
|
||||
)
|
||||
self.assertEqual(
|
||||
evidence["joinquant-target-package-run"]["path"],
|
||||
"evidence/joinquant/TP-20240311-795dcfba/"
|
||||
"2457a7c39a276e09e0fabf99e28978e1/run.json",
|
||||
)
|
||||
self.assertEqual(
|
||||
evidence["joinquant-target-package-evidence"]["path"],
|
||||
"docs/JOINQUANT_TARGET_PACKAGE_EVIDENCE_2026-07-26.md",
|
||||
)
|
||||
|
||||
gaps = payload["deliveryGaps"]
|
||||
self.assertGreaterEqual(len(gaps["internal"]), 3)
|
||||
self.assertGreaterEqual(len(gaps["externalEvidence"]), 5)
|
||||
internal = " ".join(gaps["internal"])
|
||||
self.assertIn("provider-data", internal)
|
||||
self.assertIn("factor_risk.py", internal)
|
||||
self.assertIn("CVXPY", internal)
|
||||
self.assertIn("TWAP/POV", internal)
|
||||
self.assertIn("synthetic-research", internal)
|
||||
self.assertIn("TargetPackageV1", internal)
|
||||
self.assertIn("real JoinQuant", internal)
|
||||
self.assertIn("real QMT", internal)
|
||||
|
||||
def test_public_builder_rejects_wrong_reachability_evidence_class(self):
|
||||
module = _load_builder()
|
||||
path = (
|
||||
PROJECT
|
||||
/ "releases"
|
||||
/ "quant60-research-candidate-v1"
|
||||
/ "reachability.json"
|
||||
)
|
||||
manifest = json.loads(path.read_text(encoding="utf-8"))
|
||||
artifact = manifest["layers"]["alpha"]["jq_entrypoint_reachable"][
|
||||
"artifacts"
|
||||
][0]
|
||||
artifact["kind"] = "source"
|
||||
body = {
|
||||
key: value
|
||||
for key, value in manifest.items()
|
||||
if key != "manifest_sha256"
|
||||
}
|
||||
manifest["manifest_sha256"] = hashlib.sha256(
|
||||
json.dumps(
|
||||
body,
|
||||
ensure_ascii=False,
|
||||
sort_keys=True,
|
||||
separators=(",", ":"),
|
||||
).encode("utf-8")
|
||||
).hexdigest()
|
||||
with self.assertRaises(module.PublicStatusError):
|
||||
module._validate_reachability_manifest(PROJECT, manifest)
|
||||
|
||||
def test_public_builder_rejects_upstream_real_platform_overclaim(self):
|
||||
module = _load_builder()
|
||||
path = (
|
||||
PROJECT
|
||||
/ "releases"
|
||||
/ "quant60-research-candidate-v1"
|
||||
/ "reachability.json"
|
||||
)
|
||||
manifest = json.loads(path.read_text(encoding="utf-8"))
|
||||
artifact = dict(
|
||||
manifest["layers"]["execution"]["real_platform_observed"][
|
||||
"artifacts"
|
||||
][0]
|
||||
)
|
||||
artifact["artifact_id"] = "alpha-real-platform-overclaim"
|
||||
manifest["layers"]["alpha"]["real_platform_observed"] = {
|
||||
"status": True,
|
||||
"artifacts": [artifact],
|
||||
}
|
||||
body = {
|
||||
key: value
|
||||
for key, value in manifest.items()
|
||||
if key != "manifest_sha256"
|
||||
}
|
||||
manifest["manifest_sha256"] = hashlib.sha256(
|
||||
json.dumps(
|
||||
body,
|
||||
ensure_ascii=False,
|
||||
sort_keys=True,
|
||||
separators=(",", ":"),
|
||||
).encode("utf-8")
|
||||
).hexdigest()
|
||||
with self.assertRaisesRegex(
|
||||
module.PublicStatusError,
|
||||
"only JoinQuant execution",
|
||||
):
|
||||
module._validate_reachability_manifest(PROJECT, manifest)
|
||||
|
||||
def test_public_builder_rejects_target_package_performance_claim(self):
|
||||
module = _load_builder()
|
||||
path = (
|
||||
PROJECT
|
||||
/ "evidence"
|
||||
/ "joinquant"
|
||||
/ "TP-20240311-795dcfba"
|
||||
/ "2457a7c39a276e09e0fabf99e28978e1"
|
||||
/ "run.json"
|
||||
)
|
||||
run = json.loads(path.read_text(encoding="utf-8"))
|
||||
run["performance_claim"] = True
|
||||
with self.assertRaisesRegex(
|
||||
module.PublicStatusError,
|
||||
"evidence classes are unsafe",
|
||||
):
|
||||
module._validate_joinquant_target_package_run(PROJECT, run)
|
||||
|
||||
def test_freshness_uses_daily_bars_not_the_later_trade_calendar(self):
|
||||
payload = _read_payload()
|
||||
freshness = {item["id"]: item for item in payload["freshness"]}
|
||||
@@ -124,6 +306,19 @@ class PublicStatusTests(unittest.TestCase):
|
||||
freshness["joinquant-hosted-market-window"]["marketDataThrough"],
|
||||
"2024-12-31",
|
||||
)
|
||||
target_package = freshness[
|
||||
"joinquant-target-package-execution-smoke"
|
||||
]
|
||||
self.assertEqual(target_package["marketDataFrom"], "2024-03-11")
|
||||
self.assertEqual(target_package["marketDataThrough"], "2024-03-13")
|
||||
self.assertEqual(
|
||||
target_package["observedAt"],
|
||||
"2026-07-26T08:50:15Z",
|
||||
)
|
||||
self.assertFalse(target_package["productionReady"])
|
||||
self.assertFalse(target_package["investmentValueClaim"])
|
||||
self.assertIn("execution", target_package["semantics"])
|
||||
self.assertIn("G9", target_package["semantics"])
|
||||
|
||||
tushare = freshness["tushare-daily-market-data"]
|
||||
self.assertEqual(tushare["completedPartitions"], 35)
|
||||
|
||||
@@ -0,0 +1,405 @@
|
||||
import copy
|
||||
import hashlib
|
||||
import json
|
||||
import tempfile
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
|
||||
from quant60.ledger import canonical_json
|
||||
from quant60.release_reachability import (
|
||||
CAPABILITIES,
|
||||
LAYERS,
|
||||
ReleaseReachabilityError,
|
||||
build_evidence_artifact,
|
||||
build_release_reachability,
|
||||
load_verified_release_reachability,
|
||||
release_reachability_sha256,
|
||||
seal_release_reachability,
|
||||
validate_release_reachability,
|
||||
write_release_reachability,
|
||||
)
|
||||
|
||||
|
||||
GENERATED_AT = "2026-07-26T12:00:00Z"
|
||||
|
||||
|
||||
class ReleaseReachabilityTests(unittest.TestCase):
|
||||
def setUp(self):
|
||||
temporary = tempfile.TemporaryDirectory()
|
||||
self.addCleanup(temporary.cleanup)
|
||||
self.root = Path(temporary.name)
|
||||
for directory in ("src", "tests", "tools", "platforms", "evidence"):
|
||||
(self.root / directory).mkdir()
|
||||
for layer in LAYERS:
|
||||
(self.root / "src" / f"{layer}.py").write_text(
|
||||
f"LAYER = {layer!r}\n",
|
||||
encoding="utf-8",
|
||||
)
|
||||
(self.root / "tests" / f"test_{layer}.py").write_text(
|
||||
f"def test_{layer}():\n assert True\n",
|
||||
encoding="utf-8",
|
||||
)
|
||||
(self.root / "tools" / f"{layer}_entry.py").write_text(
|
||||
f"from src import {layer}\n",
|
||||
encoding="utf-8",
|
||||
)
|
||||
(self.root / "platforms" / "joinquant_entry.py").write_text(
|
||||
"def execute():\n return 'submitted'\n",
|
||||
encoding="utf-8",
|
||||
)
|
||||
(self.root / "platforms" / "qmt_entry.py").write_text(
|
||||
"def execute():\n return 'submitted'\n",
|
||||
encoding="utf-8",
|
||||
)
|
||||
(self.root / "evidence" / "jq-execution.json").write_text(
|
||||
canonical_json(
|
||||
{
|
||||
"platform": "joinquant",
|
||||
"layer": "execution",
|
||||
"release_id": "quant60-baseline-v1",
|
||||
"result": "passed",
|
||||
}
|
||||
)
|
||||
+ "\n",
|
||||
encoding="utf-8",
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def _false_claim():
|
||||
return {"status": False, "artifacts": []}
|
||||
|
||||
def _artifact(
|
||||
self,
|
||||
*,
|
||||
artifact_id,
|
||||
kind,
|
||||
path,
|
||||
platform,
|
||||
observed_at=None,
|
||||
run_id=None,
|
||||
):
|
||||
return build_evidence_artifact(
|
||||
artifact_id=artifact_id,
|
||||
kind=kind,
|
||||
path=path,
|
||||
platform=platform,
|
||||
repository_root=self.root,
|
||||
observed_at=observed_at,
|
||||
run_id=run_id,
|
||||
)
|
||||
|
||||
def _layers(self):
|
||||
layers = {}
|
||||
for layer in LAYERS:
|
||||
layers[layer] = {
|
||||
"implemented": {
|
||||
"status": True,
|
||||
"artifacts": [
|
||||
self._artifact(
|
||||
artifact_id=f"{layer}-source",
|
||||
kind="source",
|
||||
path=f"src/{layer}.py",
|
||||
platform="repository",
|
||||
)
|
||||
],
|
||||
},
|
||||
"unit_tested": {
|
||||
"status": True,
|
||||
"artifacts": [
|
||||
self._artifact(
|
||||
artifact_id=f"{layer}-test",
|
||||
kind="test",
|
||||
path=f"tests/test_{layer}.py",
|
||||
platform="repository",
|
||||
)
|
||||
],
|
||||
},
|
||||
"local_entrypoint_reachable": {
|
||||
"status": True,
|
||||
"artifacts": [
|
||||
self._artifact(
|
||||
artifact_id=f"{layer}-local-entry",
|
||||
kind="entrypoint",
|
||||
path=f"tools/{layer}_entry.py",
|
||||
platform="local",
|
||||
)
|
||||
],
|
||||
},
|
||||
"jq_entrypoint_reachable": self._false_claim(),
|
||||
"qmt_entrypoint_reachable": self._false_claim(),
|
||||
"real_platform_observed": self._false_claim(),
|
||||
}
|
||||
layers["execution"]["jq_entrypoint_reachable"] = {
|
||||
"status": True,
|
||||
"artifacts": [
|
||||
self._artifact(
|
||||
artifact_id="execution-jq-entry",
|
||||
kind="entrypoint",
|
||||
path="platforms/joinquant_entry.py",
|
||||
platform="joinquant",
|
||||
)
|
||||
],
|
||||
}
|
||||
layers["execution"]["real_platform_observed"] = {
|
||||
"status": True,
|
||||
"artifacts": [
|
||||
self._artifact(
|
||||
artifact_id="execution-jq-run",
|
||||
kind="platform_run",
|
||||
path="evidence/jq-execution.json",
|
||||
platform="joinquant",
|
||||
observed_at="2026-07-26T11:30:00Z",
|
||||
run_id="jq-backtest-20260726-01",
|
||||
)
|
||||
],
|
||||
}
|
||||
return layers
|
||||
|
||||
def _manifest(self):
|
||||
return build_release_reachability(
|
||||
release_id="quant60-baseline-v1",
|
||||
generated_at=GENERATED_AT,
|
||||
layers=self._layers(),
|
||||
repository_root=self.root,
|
||||
)
|
||||
|
||||
def test_build_write_load_preserves_exact_six_claims_per_layer(self):
|
||||
manifest = self._manifest()
|
||||
self.assertEqual(
|
||||
manifest["manifest_sha256"],
|
||||
release_reachability_sha256(manifest),
|
||||
)
|
||||
for layer in LAYERS:
|
||||
self.assertEqual(
|
||||
set(manifest["layers"][layer]),
|
||||
set(CAPABILITIES),
|
||||
)
|
||||
self.assertTrue(manifest["summary"]["all_layers_implemented"])
|
||||
self.assertTrue(manifest["summary"]["all_layers_unit_tested"])
|
||||
self.assertTrue(
|
||||
manifest["summary"]["all_layers_local_entrypoint_reachable"]
|
||||
)
|
||||
self.assertFalse(
|
||||
manifest["summary"]["all_layers_jq_entrypoint_reachable"]
|
||||
)
|
||||
self.assertFalse(
|
||||
manifest["summary"]["all_layers_qmt_entrypoint_reachable"]
|
||||
)
|
||||
self.assertFalse(
|
||||
manifest["summary"]["all_layers_real_platform_observed"]
|
||||
)
|
||||
|
||||
path = write_release_reachability(
|
||||
manifest,
|
||||
self.root / "reachability.json",
|
||||
repository_root=self.root,
|
||||
)
|
||||
loaded = load_verified_release_reachability(
|
||||
path,
|
||||
repository_root=self.root,
|
||||
expected_release_id="quant60-baseline-v1",
|
||||
expected_manifest_sha256=manifest["manifest_sha256"],
|
||||
)
|
||||
self.assertEqual(loaded, manifest)
|
||||
self.assertEqual(
|
||||
path.read_bytes(),
|
||||
(canonical_json(manifest) + "\n").encode("utf-8"),
|
||||
)
|
||||
|
||||
def test_manifest_and_artifact_tampering_both_fail_closed(self):
|
||||
manifest = self._manifest()
|
||||
status_tamper = copy.deepcopy(manifest)
|
||||
status_tamper["layers"]["alpha"]["implemented"]["status"] = False
|
||||
with self.assertRaisesRegex(
|
||||
ReleaseReachabilityError,
|
||||
"SHA-256 mismatch",
|
||||
):
|
||||
validate_release_reachability(
|
||||
status_tamper,
|
||||
repository_root=self.root,
|
||||
)
|
||||
|
||||
path = write_release_reachability(
|
||||
manifest,
|
||||
self.root / "reachability.json",
|
||||
repository_root=self.root,
|
||||
)
|
||||
(self.root / "src" / "alpha.py").write_text(
|
||||
"LAYER = 'tampered'\n",
|
||||
encoding="utf-8",
|
||||
)
|
||||
with self.assertRaisesRegex(
|
||||
ReleaseReachabilityError,
|
||||
"artifact hash mismatch",
|
||||
):
|
||||
load_verified_release_reachability(
|
||||
path,
|
||||
repository_root=self.root,
|
||||
)
|
||||
|
||||
def test_source_hash_cannot_masquerade_as_real_platform_observation(self):
|
||||
layers = self._layers()
|
||||
source = self.root / "src" / "execution.py"
|
||||
layers["execution"]["real_platform_observed"] = {
|
||||
"status": True,
|
||||
"artifacts": [
|
||||
{
|
||||
"artifact_id": "fake-platform-run",
|
||||
"kind": "platform_run",
|
||||
"path": "src/execution.py",
|
||||
"sha256": hashlib.sha256(source.read_bytes()).hexdigest(),
|
||||
"platform": "joinquant",
|
||||
"observed_at": "2026-07-26T11:30:00Z",
|
||||
"run_id": "fake-run",
|
||||
}
|
||||
],
|
||||
}
|
||||
with self.assertRaisesRegex(
|
||||
ReleaseReachabilityError,
|
||||
"real-platform evidence must live under",
|
||||
):
|
||||
build_release_reachability(
|
||||
release_id="quant60-baseline-v1",
|
||||
generated_at=GENERATED_AT,
|
||||
layers=layers,
|
||||
repository_root=self.root,
|
||||
)
|
||||
|
||||
def test_true_status_requires_typed_evidence_and_false_forbids_it(self):
|
||||
true_without_evidence = self._layers()
|
||||
true_without_evidence["risk"]["unit_tested"] = {
|
||||
"status": True,
|
||||
"artifacts": [],
|
||||
}
|
||||
with self.assertRaisesRegex(
|
||||
ReleaseReachabilityError,
|
||||
"iff at least one evidence",
|
||||
):
|
||||
build_release_reachability(
|
||||
release_id="quant60-baseline-v1",
|
||||
generated_at=GENERATED_AT,
|
||||
layers=true_without_evidence,
|
||||
repository_root=self.root,
|
||||
)
|
||||
|
||||
wrong_evidence_type = self._layers()
|
||||
wrong_evidence_type["risk"]["unit_tested"]["artifacts"][0].update(
|
||||
{"kind": "source", "platform": "repository"}
|
||||
)
|
||||
with self.assertRaisesRegex(
|
||||
ReleaseReachabilityError,
|
||||
"requires kind='test'",
|
||||
):
|
||||
build_release_reachability(
|
||||
release_id="quant60-baseline-v1",
|
||||
generated_at=GENERATED_AT,
|
||||
layers=wrong_evidence_type,
|
||||
repository_root=self.root,
|
||||
)
|
||||
|
||||
def test_real_observation_requires_corresponding_platform_entrypoint(self):
|
||||
layers = self._layers()
|
||||
layers["execution"]["jq_entrypoint_reachable"] = self._false_claim()
|
||||
with self.assertRaisesRegex(
|
||||
ReleaseReachabilityError,
|
||||
"requires jq_entrypoint_reachable",
|
||||
):
|
||||
build_release_reachability(
|
||||
release_id="quant60-baseline-v1",
|
||||
generated_at=GENERATED_AT,
|
||||
layers=layers,
|
||||
repository_root=self.root,
|
||||
)
|
||||
|
||||
def test_path_hash_id_and_clock_validation_are_strict(self):
|
||||
cases = []
|
||||
|
||||
absolute = self._layers()
|
||||
absolute["alpha"]["implemented"]["artifacts"][0]["path"] = str(
|
||||
self.root / "src" / "alpha.py"
|
||||
)
|
||||
cases.append((absolute, "repository-relative path"))
|
||||
|
||||
traversal = self._layers()
|
||||
traversal["alpha"]["implemented"]["artifacts"][0]["path"] = (
|
||||
"src/../tests/test_alpha.py"
|
||||
)
|
||||
cases.append((traversal, "normalized repository-relative path"))
|
||||
|
||||
placeholder = self._layers()
|
||||
placeholder["alpha"]["implemented"]["artifacts"][0]["sha256"] = (
|
||||
"0" * 64
|
||||
)
|
||||
cases.append((placeholder, "all-zero placeholder"))
|
||||
|
||||
duplicate = self._layers()
|
||||
duplicate["alpha"]["implemented"]["artifacts"][0]["artifact_id"] = (
|
||||
duplicate["universe"]["implemented"]["artifacts"][0]["artifact_id"]
|
||||
)
|
||||
cases.append((duplicate, "reused across claims"))
|
||||
|
||||
future_run = self._layers()
|
||||
future_run["execution"]["real_platform_observed"]["artifacts"][0][
|
||||
"observed_at"
|
||||
] = "2026-07-26T12:00:01Z"
|
||||
cases.append((future_run, "cannot be after generated_at"))
|
||||
|
||||
for layers, message in cases:
|
||||
with self.subTest(message=message):
|
||||
with self.assertRaisesRegex(
|
||||
ReleaseReachabilityError,
|
||||
message,
|
||||
):
|
||||
build_release_reachability(
|
||||
release_id="quant60-baseline-v1",
|
||||
generated_at=GENERATED_AT,
|
||||
layers=layers,
|
||||
repository_root=self.root,
|
||||
)
|
||||
|
||||
def test_strict_loader_rejects_duplicate_json_keys(self):
|
||||
path = self.root / "duplicate.json"
|
||||
path.write_text(
|
||||
'{"schema_version":"1.0","schema_version":"1.0"}',
|
||||
encoding="utf-8",
|
||||
)
|
||||
with self.assertRaisesRegex(
|
||||
ReleaseReachabilityError,
|
||||
"duplicate JSON key",
|
||||
):
|
||||
load_verified_release_reachability(
|
||||
path,
|
||||
repository_root=self.root,
|
||||
)
|
||||
|
||||
def test_resealed_derived_summary_tamper_is_rejected(self):
|
||||
manifest = self._manifest()
|
||||
manifest["summary"]["all_layers_qmt_entrypoint_reachable"] = True
|
||||
manifest["manifest_sha256"] = release_reachability_sha256(manifest)
|
||||
with self.assertRaisesRegex(
|
||||
ReleaseReachabilityError,
|
||||
"summary is not the exact derived",
|
||||
):
|
||||
validate_release_reachability(
|
||||
manifest,
|
||||
repository_root=self.root,
|
||||
)
|
||||
|
||||
def test_seal_rejects_prepopulated_derived_fields(self):
|
||||
body = {
|
||||
"schema_version": "1.0",
|
||||
"artifact_type": "quant60-release-reachability",
|
||||
"release_id": "quant60-baseline-v1",
|
||||
"generated_at": GENERATED_AT,
|
||||
"layers": self._layers(),
|
||||
"summary": {},
|
||||
}
|
||||
with self.assertRaisesRegex(
|
||||
ReleaseReachabilityError,
|
||||
"derived summary",
|
||||
):
|
||||
seal_release_reachability(body, repository_root=self.root)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,314 @@
|
||||
import copy
|
||||
import json
|
||||
import tempfile
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
|
||||
from quant60.target_package import (
|
||||
DuplicateTargetDecisionError,
|
||||
SHA256_FIELDS,
|
||||
TargetPackageError,
|
||||
TargetPackageNotFoundError,
|
||||
TargetPackageTape,
|
||||
TargetPackageV1,
|
||||
load_target_package_tape,
|
||||
seal_target_package,
|
||||
target_package_sha256,
|
||||
validate_target_package,
|
||||
)
|
||||
|
||||
|
||||
def package_body(
|
||||
*,
|
||||
package_id: str = "TP-20260724-A",
|
||||
decision_id: str = "D-20260724-A",
|
||||
signal_as_of: str = "2026-07-24T15:00:00+08:00",
|
||||
next_session: str = "2026-07-27",
|
||||
release: str = "quant60-baseline-60-v1",
|
||||
model_id: str = "alpha158-lightgbm-v1",
|
||||
) -> dict:
|
||||
return {
|
||||
"schema_version": "1.0",
|
||||
"package_type": "TargetPackageV1",
|
||||
"package_id": package_id,
|
||||
"decision_id": decision_id,
|
||||
"release": release,
|
||||
"evidence_class": "provider-snapshot-local",
|
||||
"model_id": model_id,
|
||||
"signal_as_of": signal_as_of,
|
||||
"next_session": next_session,
|
||||
"model_sha256": "1" * 64,
|
||||
"data_sha256": "2" * 64,
|
||||
"feature_sha256": "3" * 64,
|
||||
"risk_sha256": "4" * 64,
|
||||
"cost_sha256": "5" * 64,
|
||||
"optimizer_sha256": "6" * 64,
|
||||
"config_sha256": "7" * 64,
|
||||
"source_sha256": "8" * 64,
|
||||
"target_weights": {
|
||||
"000001.XSHE": 0.30,
|
||||
"600000.XSHG": 0.20,
|
||||
},
|
||||
"universe": {
|
||||
"000001.XSHE": {
|
||||
"state": "openable",
|
||||
"reasons": ["ELIGIBLE"],
|
||||
},
|
||||
"600000.XSHG": {
|
||||
"state": "hold_only",
|
||||
"reasons": ["LIQUIDITY_BELOW_FLOOR"],
|
||||
},
|
||||
},
|
||||
"constraints": {
|
||||
"constraint_state": "FEASIBLE",
|
||||
"long_only": True,
|
||||
"max_single_weight": 0.40,
|
||||
"max_gross_weight": 0.80,
|
||||
"max_one_way_turnover": 0.20,
|
||||
"actual_gross_weight": 0.50,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def sealed_package(**overrides) -> dict:
|
||||
return seal_target_package(package_body(**overrides))
|
||||
|
||||
|
||||
class TargetPackageTests(unittest.TestCase):
|
||||
def test_valid_package_is_deterministic_and_quantity_free(self):
|
||||
package = sealed_package()
|
||||
self.assertEqual(
|
||||
package["package_sha256"],
|
||||
target_package_sha256(package),
|
||||
)
|
||||
self.assertEqual(len(package["package_sha256"]), 64)
|
||||
self.assertNotIn("quantity", json.dumps(package))
|
||||
self.assertEqual(validate_target_package(package), package)
|
||||
wrapped = TargetPackageV1.from_dict(package)
|
||||
self.assertEqual(wrapped.package_id, package["package_id"])
|
||||
self.assertEqual(wrapped.as_dict(), package)
|
||||
|
||||
def test_tamper_is_rejected(self):
|
||||
package = sealed_package()
|
||||
package["target_weights"]["000001.XSHE"] = 0.25
|
||||
package["constraints"]["actual_gross_weight"] = 0.45
|
||||
with self.assertRaisesRegex(TargetPackageError, "hash mismatch"):
|
||||
validate_target_package(package)
|
||||
|
||||
def test_every_layer_hash_is_required_and_strict(self):
|
||||
package = sealed_package()
|
||||
for field in SHA256_FIELDS:
|
||||
with self.subTest(field=field):
|
||||
missing = copy.deepcopy(package)
|
||||
missing.pop(field)
|
||||
with self.assertRaises(TargetPackageError):
|
||||
validate_target_package(missing)
|
||||
malformed = copy.deepcopy(package)
|
||||
malformed[field] = "A" * 64
|
||||
with self.assertRaises(TargetPackageError):
|
||||
validate_target_package(malformed)
|
||||
placeholder = copy.deepcopy(package)
|
||||
placeholder[field] = "0" * 64
|
||||
placeholder["package_sha256"] = target_package_sha256(
|
||||
placeholder
|
||||
)
|
||||
with self.assertRaisesRegex(
|
||||
TargetPackageError,
|
||||
"all-zero placeholder",
|
||||
):
|
||||
validate_target_package(placeholder)
|
||||
|
||||
def test_portable_momentum_cannot_masquerade_as_baseline(self):
|
||||
body = package_body(model_id="portable-momentum-v1")
|
||||
with self.assertRaisesRegex(TargetPackageError, "cannot claim"):
|
||||
seal_target_package(body)
|
||||
|
||||
smoke = package_body(
|
||||
release="platform-smoke-v1",
|
||||
model_id="portable-momentum-v1",
|
||||
)
|
||||
self.assertEqual(
|
||||
seal_target_package(smoke)["model_id"],
|
||||
"portable-momentum-v1",
|
||||
)
|
||||
|
||||
def test_quantities_are_forbidden_at_any_depth(self):
|
||||
for mutation in (
|
||||
lambda body: body.update({"target_quantity": 100}),
|
||||
lambda body: body["constraints"].update({"quantity": 100}),
|
||||
lambda body: body["universe"]["000001.XSHE"].update(
|
||||
{"sellable_quantity": 100}
|
||||
),
|
||||
):
|
||||
with self.subTest(mutation=mutation):
|
||||
body = package_body()
|
||||
mutation(body)
|
||||
with self.assertRaisesRegex(
|
||||
TargetPackageError,
|
||||
"do not belong",
|
||||
):
|
||||
seal_target_package(body)
|
||||
|
||||
def test_clock_must_be_canonical_close_and_future_weekday(self):
|
||||
cases = (
|
||||
("2026-07-24T14:59:59+08:00", "2026-07-27"),
|
||||
("2026-07-24T07:00:00+00:00", "2026-07-27"),
|
||||
("2026-07-24T15:00:00.000000+08:00", "2026-07-27"),
|
||||
("2026-07-24T15:00:00+08:00", "2026-07-24"),
|
||||
("2026-07-24T15:00:00+08:00", "2026-07-25"),
|
||||
)
|
||||
for signal_as_of, next_session in cases:
|
||||
with self.subTest(
|
||||
signal_as_of=signal_as_of,
|
||||
next_session=next_session,
|
||||
):
|
||||
with self.assertRaises(TargetPackageError):
|
||||
seal_target_package(
|
||||
package_body(
|
||||
signal_as_of=signal_as_of,
|
||||
next_session=next_session,
|
||||
)
|
||||
)
|
||||
|
||||
def test_symbols_weights_and_gross_fail_closed(self):
|
||||
noncanonical = package_body()
|
||||
noncanonical["target_weights"] = {
|
||||
"000001.SZ": 0.30,
|
||||
"600000.XSHG": 0.20,
|
||||
}
|
||||
with self.assertRaisesRegex(TargetPackageError, "canonical"):
|
||||
seal_target_package(noncanonical)
|
||||
|
||||
missing_universe = package_body()
|
||||
missing_universe["universe"].pop("000001.XSHE")
|
||||
with self.assertRaisesRegex(TargetPackageError, "absent from universe"):
|
||||
seal_target_package(missing_universe)
|
||||
|
||||
bad_gross = package_body()
|
||||
bad_gross["constraints"]["actual_gross_weight"] = 0.49
|
||||
with self.assertRaisesRegex(TargetPackageError, "does not equal"):
|
||||
seal_target_package(bad_gross)
|
||||
|
||||
gross_breach = package_body()
|
||||
gross_breach["constraints"]["max_gross_weight"] = 0.49
|
||||
with self.assertRaisesRegex(TargetPackageError, "max_gross"):
|
||||
seal_target_package(gross_breach)
|
||||
|
||||
single_breach = package_body()
|
||||
single_breach["constraints"]["max_single_weight"] = 0.25
|
||||
with self.assertRaisesRegex(TargetPackageError, "max_single"):
|
||||
seal_target_package(single_breach)
|
||||
|
||||
excluded = package_body()
|
||||
excluded["universe"]["000001.XSHE"] = {
|
||||
"state": "excluded",
|
||||
"reasons": ["NOT_PIT_INDEX_MEMBER"],
|
||||
}
|
||||
with self.assertRaisesRegex(TargetPackageError, "excluded"):
|
||||
seal_target_package(excluded)
|
||||
|
||||
def test_tape_supports_multiple_decisions_with_exact_lookup(self):
|
||||
first = sealed_package()
|
||||
second = sealed_package(
|
||||
package_id="TP-20260731-B",
|
||||
decision_id="D-20260731-B",
|
||||
signal_as_of="2026-07-31T15:00:00+08:00",
|
||||
next_session="2026-08-03",
|
||||
)
|
||||
tape = TargetPackageTape([second, first])
|
||||
self.assertEqual(len(tape), 2)
|
||||
found = tape.lookup_exact(
|
||||
signal_as_of=first["signal_as_of"],
|
||||
next_session=first["next_session"],
|
||||
)
|
||||
self.assertEqual(found["decision_id"], first["decision_id"])
|
||||
found["release"] = "mutated"
|
||||
self.assertEqual(
|
||||
tape.lookup_exact(
|
||||
signal_as_of=first["signal_as_of"],
|
||||
next_session=first["next_session"],
|
||||
)["release"],
|
||||
first["release"],
|
||||
)
|
||||
with self.assertRaises(TargetPackageNotFoundError):
|
||||
tape.lookup_exact(
|
||||
signal_as_of="2026-07-30T15:00:00+08:00",
|
||||
next_session="2026-07-31",
|
||||
)
|
||||
with self.assertRaises(TargetPackageNotFoundError):
|
||||
tape.lookup_exact(
|
||||
signal_as_of=first["signal_as_of"],
|
||||
next_session=first["next_session"],
|
||||
decision_id="D-wrong",
|
||||
)
|
||||
|
||||
def test_duplicate_decision_identity_is_rejected(self):
|
||||
first = sealed_package()
|
||||
duplicate_id = sealed_package(
|
||||
package_id="TP-20260731-B",
|
||||
decision_id=first["decision_id"],
|
||||
signal_as_of="2026-07-31T15:00:00+08:00",
|
||||
next_session="2026-08-03",
|
||||
)
|
||||
with self.assertRaises(DuplicateTargetDecisionError):
|
||||
TargetPackageTape([first, duplicate_id])
|
||||
|
||||
duplicate_clock = sealed_package(
|
||||
package_id="TP-20260724-B",
|
||||
decision_id="D-20260724-B",
|
||||
)
|
||||
with self.assertRaises(DuplicateTargetDecisionError):
|
||||
TargetPackageTape([first, duplicate_clock])
|
||||
|
||||
def test_json_and_jsonl_tapes_load_multiple_decisions(self):
|
||||
packages = [
|
||||
sealed_package(),
|
||||
sealed_package(
|
||||
package_id="TP-20260731-B",
|
||||
decision_id="D-20260731-B",
|
||||
signal_as_of="2026-07-31T15:00:00+08:00",
|
||||
next_session="2026-08-03",
|
||||
),
|
||||
]
|
||||
with tempfile.TemporaryDirectory() as directory:
|
||||
root = Path(directory)
|
||||
json_path = root / "tape.json"
|
||||
json_path.write_text(
|
||||
json.dumps({"packages": packages}),
|
||||
encoding="utf-8",
|
||||
)
|
||||
jsonl_path = root / "tape.jsonl"
|
||||
jsonl_path.write_text(
|
||||
"".join(json.dumps(item) + "\n" for item in packages),
|
||||
encoding="utf-8",
|
||||
)
|
||||
self.assertEqual(len(load_target_package_tape(json_path)), 2)
|
||||
self.assertEqual(len(load_target_package_tape(jsonl_path)), 2)
|
||||
|
||||
def test_single_package_loads_and_strict_json_rejects_ambiguity(self):
|
||||
with tempfile.TemporaryDirectory() as directory:
|
||||
root = Path(directory)
|
||||
single = root / "single.json"
|
||||
single.write_text(
|
||||
json.dumps(sealed_package()),
|
||||
encoding="utf-8",
|
||||
)
|
||||
self.assertEqual(len(load_target_package_tape(single)), 1)
|
||||
|
||||
duplicate = root / "duplicate.json"
|
||||
duplicate.write_text(
|
||||
'{"package_type":"TargetPackageV1",'
|
||||
'"package_type":"TargetPackageV1"}',
|
||||
encoding="utf-8",
|
||||
)
|
||||
with self.assertRaisesRegex(TargetPackageError, "duplicate JSON key"):
|
||||
load_target_package_tape(duplicate)
|
||||
|
||||
non_finite = root / "nan.json"
|
||||
non_finite.write_text("[NaN]", encoding="utf-8")
|
||||
with self.assertRaisesRegex(TargetPackageError, "non-finite"):
|
||||
load_target_package_tape(non_finite)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user