From 679425d0d32b9e8310cfb61f7ed678d858dbf22f Mon Sep 17 00:00:00 2001 From: Pigbibi <20649888+Pigbibi@users.noreply.github.com> Date: Fri, 6 Nov 2026 04:07:23 +0800 Subject: [PATCH 1/3] feat: Pin UES plain-DCA previews and verify installed contracts Co-Authored-By: Codex --- docs/runtime-target-manifest.md | 11 +-- pyproject.toml | 2 +- qsl.toml | 2 +- tests/test_plain_dca_dependency.py | 114 +++++++++++++++++++++++++++++ uv.lock | 6 +- 5 files changed, 125 insertions(+), 10 deletions(-) create mode 100644 tests/test_plain_dca_dependency.py diff --git a/docs/runtime-target-manifest.md b/docs/runtime-target-manifest.md index 7175aff7..53937dd1 100644 --- a/docs/runtime-target-manifest.md +++ b/docs/runtime-target-manifest.md @@ -215,10 +215,11 @@ Kelly scaling, catch-up, anchor acceleration or synthetic fill. All four preview flags remain enforced. The adapter neither claims periods nor reserves cash, so it makes no exactly-once or multi-process order-execution claim. -The current locked UES package does not supply `plain_dca`. Until a separately -reviewed compatible pin is adopted, a valid binding still fails with -`plain_dca_api_unavailable`. This patch does not change shared dependency pins or -other strategy bindings. It also does not authenticate the readback source or -credentials: deployed PAPER account/state/schedule isolation, authentic safety +The locked UES package supplies `plain_dca`. The dependency adoption tests check +the installed VCS revision against all three source declarations and exercise +both baseline families through the real preview adapter with synthetic facts. +A missing or incompatible installation still fails with +`plain_dca_api_unavailable`. Installing the package does not authenticate the +readback source or credentials: deployed PAPER account/state/schedule isolation, authentic safety readback, durable fencing/reconciliation, setup decisions and Phase 2 execution remain separate prerequisites. Unit fixtures cannot prove those runtime facts. diff --git a/pyproject.toml b/pyproject.toml index 5632359b..e09b7eb1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -19,7 +19,7 @@ dependencies = [ "google-auth", "longport==3.0.23", "quant-platform-kit @ git+https://github.com/QuantStrategyLab/QuantPlatformKit.git@350dd38ece0952beef096893a7dcf8ae3871609a", - "us-equity-strategies @ git+https://github.com/QuantStrategyLab/UsEquityStrategies.git@c16c81bdf21824615f7280554559adc6c721917c", + "us-equity-strategies @ git+https://github.com/QuantStrategyLab/UsEquityStrategies.git@1d087fa424972d5d5ab02c4650ce9f039cb6711f", "hk-equity-strategies @ git+https://github.com/QuantStrategyLab/HkEquityStrategies.git@fe0c32e09d454ca4388c3372bf3874097b1bbaf0", ] diff --git a/qsl.toml b/qsl.toml index 7cced307..9f5aafc4 100644 --- a/qsl.toml +++ b/qsl.toml @@ -6,7 +6,7 @@ allow_legacy = false [qsl.requires] quant_platform_kit = "350dd38ece0952beef096893a7dcf8ae3871609a" -us_equity_strategies = "8412d8338879f335ef8830678c2733e02e53e7c7" +us_equity_strategies = "1d087fa424972d5d5ab02c4650ce9f039cb6711f" hk_equity_strategies = "cc3045689ae9d76eb97b9e1aa3b8fb6288ee1bcc" [qsl.compat] diff --git a/tests/test_plain_dca_dependency.py b/tests/test_plain_dca_dependency.py new file mode 100644 index 00000000..9a10c927 --- /dev/null +++ b/tests/test_plain_dca_dependency.py @@ -0,0 +1,114 @@ +"""Exercise the installed UES package with synthetic facts, never a broker.""" +from datetime import date, datetime, time, timedelta +from decimal import Decimal as D +from importlib import metadata +import json +from pathlib import Path +import tomllib +from zoneinfo import ZoneInfo + +import pytest + + +def test_installed_ues_matches_all_source_declarations(): + root = Path(__file__).resolve().parents[1] + lock = tomllib.loads((root / "uv.lock").read_text()) + package, = [p for p in lock["package"] if p["name"] == "us-equity-strategies"] + revision = package["source"]["git"].rsplit("#", 1)[1] + project = tomllib.loads((root / "pyproject.toml").read_text()) + requirement, = [d for d in project["project"]["dependencies"] + if d.startswith("us-equity-strategies @")] + assert requirement.endswith("@" + revision) + assert tomllib.loads((root / "qsl.toml").read_text())["qsl"]["requires"]["us_equity_strategies"] == revision + installed = json.loads(metadata.distribution("us-equity-strategies").read_text("direct_url.json")) + assert installed["vcs_info"]["commit_id"] == revision + + +@pytest.fixture(params=[("nasdaq100_buy_and_hold", "QQQ"), + ("sp500_buy_and_hold", "SPY")]) +def installed_dca_case(request): + from us_equity_strategies import buy_and_hold as p1, plain_dca as api + + profile, symbol = request.param + zone = ZoneInfo("America/New_York") + now = datetime(2026, 11, 3, 11, tzinfo=zone) + fresh = dict(observed_at=now, valid_until=now + timedelta(minutes=1)) + instrument = p1.InstrumentBinding(symbol, symbol, "fake-contract", "XNAS", "USD", + D("1"), D("1"), True) + binding = p1.PlanBinding(profile, instrument, "fake-paper-account", "fake-mandate", + "fake-release", "fake-owner", "paper") + mandate = p1.Mandate(binding, now-timedelta(days=1), now+timedelta(days=1), + D("100"), D("10000"), "CAPITAL_PRESERVATION", True) + plan = api.DcaPlan(mandate, "fake-plan", 1, api.ScheduleSpec(anchor=3), + D("100"), D("100"), D("200")) + start, end = date(2026, 1, 1), date(2027, 2, 1) + days = (start + timedelta(days=i) for i in range((end-start).days+1)) + sessions = tuple(api.ExchangeSession(day, datetime.combine(day, time(9, 30), zone), + datetime.combine(day, time(16), zone)) + for day in days if day.weekday() < 5) + calendar = api.ExchangeCalendar("fake-calendar", "XNAS", "America/New_York", start, + end, now-timedelta(days=1), now+timedelta(days=1), + True, sessions, zone) + period = api.PeriodFacts(binding, "fake-plan", 1, "2026-11", **fresh, records=(), + funded_carry=D("0"), carry_verified=True, + year_new_headroom=D("1000"), lifetime_new_headroom=D("1000"), + year_spend_headroom=D("1000"), lifetime_spend_headroom=D("1000")) + facts = p1.PortfolioFacts(binding, **fresh, reconciled=True, exclusive_ownership=True, + unrelated_exposure=False, holdings_adopted=True, + held_quantity=D("0"), settled_cash_after_reservations=D("1000"), + account_risk_capital=D("20000"), risk_headroom=D("1000"), + risk_approved=True, principal_spent_and_reserved=D("0"), + contribution_ref="fake-contribution", allowance_revision=1) + quote = p1.Quote(instrument, **fresh, mark_price=D("70"), limit_price=D("70"), fee_buffer=D("0")) + capabilities = p1.Capabilities(binding, verified=True, fractional_verified=False) + return dict(plan=plan, calendar=calendar, period=period, facts=facts, quote=quote, + capabilities=capabilities, now=now) + + +def test_installed_api_preserves_final_tranche_and_preview_only(installed_dca_case): + from us_equity_strategies.plain_dca import PeriodPreview, evaluate_dca_period + + result = evaluate_dca_period(**installed_dca_case) + assert isinstance(result, PeriodPreview) + assert result.status == "DUE" + assert result.new_tranche == D("100") # Already approved; never apply the tier twice. + assert result.period_key == "2026-11" + assert result.no_order is True and result.no_execute is True + assert result.preview_only is True and result.live_ready is False + assert result.decision.budgets == () + assert evaluate_dca_period(**installed_dca_case) == result + + +def test_adapter_consumes_installed_api_and_rejects_sg(installed_dca_case): + from application.plain_dca_paper_adapter import PlainDcaPaperError, consume_plain_dca_preview + from application.runtime_target_manifest import load_runtime_target_manifest + from us_equity_strategies.plain_dca import evaluate_dca_period + + service, = [t.service for t in load_runtime_target_manifest().targets if t.id == "paper"] + now = installed_dca_case["now"] + readback = dict(observed_at=now, valid_until=now+timedelta(minutes=1), + target_id="paper", environment="longbridge-paper", + live_enabled=False, kelly_enabled=False, stop_loss_enabled=False, + protected_env={ + "CLOUD_RUN_SERVICE": service, "RUNTIME_TARGET_ENABLED": "false", + "LONGBRIDGE_DRY_RUN_ONLY": "false", + "LONGBRIDGE_PHYSICAL_ACCOUNT_ID": "fake-paper-account", + "RUNTIME_TARGET_JSON": json.dumps(dict( + platform_id="longbridge", service_name=service, + execution_environment="paper", execution_mode="live", dry_run_only=False, + account_scope="PAPER", account_selector=["PAPER"], deployment_selector="PAPER")), + }) + assert consume_plain_dca_preview(read_binding=lambda: readback, **installed_dca_case) == evaluate_dca_period(**installed_dca_case) + with pytest.raises(PlainDcaPaperError, match="paper_target_environment_required"): + consume_plain_dca_preview(read_binding=lambda: {**readback, "environment": "longbridge-sg"}, + **installed_dca_case) + + +def test_installed_api_rejects_missing_facts(installed_dca_case): + from us_equity_strategies.plain_dca import evaluate_dca_period + + result = evaluate_dca_period(**{**installed_dca_case, "facts": None}) + assert result.status == "BLOCKED" + assert result.decision.positions == result.decision.budgets == () + assert result.no_order and result.no_execute and result.preview_only + assert result.live_ready is False diff --git a/uv.lock b/uv.lock index 15b314d8..a57ef62b 100644 --- a/uv.lock +++ b/uv.lock @@ -1,5 +1,5 @@ version = 1 -revision = 5 +revision = 3 requires-python = ">=3.11" resolution-markers = [ "python_full_version >= '3.14' and sys_platform == 'win32'", @@ -730,7 +730,7 @@ requires-dist = [ { name = "quant-platform-kit", git = "https://github.com/QuantStrategyLab/QuantPlatformKit.git?rev=350dd38ece0952beef096893a7dcf8ae3871609a" }, { name = "requests" }, { name = "ruff", marker = "extra == 'test'" }, - { name = "us-equity-strategies", git = "https://github.com/QuantStrategyLab/UsEquityStrategies.git?rev=c16c81bdf21824615f7280554559adc6c721917c" }, + { name = "us-equity-strategies", git = "https://github.com/QuantStrategyLab/UsEquityStrategies.git?rev=1d087fa424972d5d5ab02c4650ce9f039cb6711f" }, ] provides-extras = ["test"] @@ -1354,7 +1354,7 @@ wheels = [ [[package]] name = "us-equity-strategies" version = "0.7.60" -source = { git = "https://github.com/QuantStrategyLab/UsEquityStrategies.git?rev=c16c81bdf21824615f7280554559adc6c721917c#c16c81bdf21824615f7280554559adc6c721917c" } +source = { git = "https://github.com/QuantStrategyLab/UsEquityStrategies.git?rev=1d087fa424972d5d5ab02c4650ce9f039cb6711f#1d087fa424972d5d5ab02c4650ce9f039cb6711f" } dependencies = [ { name = "pandas" }, { name = "pytz" }, From 52c6bc40bcb31c8388d9db0246d70255f93a5989 Mon Sep 17 00:00:00 2001 From: Pigbibi <20649888+Pigbibi@users.noreply.github.com> Date: Fri, 6 Nov 2026 04:08:36 +0800 Subject: [PATCH 2/3] test: Match the repository lint conventions Co-Authored-By: Codex --- tests/test_plain_dca_dependency.py | 61 ++++++++++++++++-------------- 1 file changed, 33 insertions(+), 28 deletions(-) diff --git a/tests/test_plain_dca_dependency.py b/tests/test_plain_dca_dependency.py index 9a10c927..0073fcfa 100644 --- a/tests/test_plain_dca_dependency.py +++ b/tests/test_plain_dca_dependency.py @@ -1,10 +1,10 @@ """Exercise the installed UES package with synthetic facts, never a broker.""" +import json +import tomllib from datetime import date, datetime, time, timedelta from decimal import Decimal as D from importlib import metadata -import json from pathlib import Path -import tomllib from zoneinfo import ZoneInfo import pytest @@ -27,20 +27,21 @@ def test_installed_ues_matches_all_source_declarations(): @pytest.fixture(params=[("nasdaq100_buy_and_hold", "QQQ"), ("sp500_buy_and_hold", "SPY")]) def installed_dca_case(request): - from us_equity_strategies import buy_and_hold as p1, plain_dca as api + from us_equity_strategies import buy_and_hold as p1 + from us_equity_strategies import plain_dca as api profile, symbol = request.param zone = ZoneInfo("America/New_York") now = datetime(2026, 11, 3, 11, tzinfo=zone) - fresh = dict(observed_at=now, valid_until=now + timedelta(minutes=1)) + fresh = {"observed_at": now, "valid_until": now + timedelta(minutes=1)} instrument = p1.InstrumentBinding(symbol, symbol, "fake-contract", "XNAS", "USD", - D("1"), D("1"), True) + D(1), D(1), True) binding = p1.PlanBinding(profile, instrument, "fake-paper-account", "fake-mandate", "fake-release", "fake-owner", "paper") mandate = p1.Mandate(binding, now-timedelta(days=1), now+timedelta(days=1), - D("100"), D("10000"), "CAPITAL_PRESERVATION", True) + D(100), D(10000), "CAPITAL_PRESERVATION", True) plan = api.DcaPlan(mandate, "fake-plan", 1, api.ScheduleSpec(anchor=3), - D("100"), D("100"), D("200")) + D(100), D(100), D(200)) start, end = date(2026, 1, 1), date(2027, 2, 1) days = (start + timedelta(days=i) for i in range((end-start).days+1)) sessions = tuple(api.ExchangeSession(day, datetime.combine(day, time(9, 30), zone), @@ -50,19 +51,19 @@ def installed_dca_case(request): end, now-timedelta(days=1), now+timedelta(days=1), True, sessions, zone) period = api.PeriodFacts(binding, "fake-plan", 1, "2026-11", **fresh, records=(), - funded_carry=D("0"), carry_verified=True, - year_new_headroom=D("1000"), lifetime_new_headroom=D("1000"), - year_spend_headroom=D("1000"), lifetime_spend_headroom=D("1000")) + funded_carry=D(0), carry_verified=True, + year_new_headroom=D(1000), lifetime_new_headroom=D(1000), + year_spend_headroom=D(1000), lifetime_spend_headroom=D(1000)) facts = p1.PortfolioFacts(binding, **fresh, reconciled=True, exclusive_ownership=True, unrelated_exposure=False, holdings_adopted=True, - held_quantity=D("0"), settled_cash_after_reservations=D("1000"), - account_risk_capital=D("20000"), risk_headroom=D("1000"), - risk_approved=True, principal_spent_and_reserved=D("0"), + held_quantity=D(0), settled_cash_after_reservations=D(1000), + account_risk_capital=D(20000), risk_headroom=D(1000), + risk_approved=True, principal_spent_and_reserved=D(0), contribution_ref="fake-contribution", allowance_revision=1) - quote = p1.Quote(instrument, **fresh, mark_price=D("70"), limit_price=D("70"), fee_buffer=D("0")) + quote = p1.Quote(instrument, **fresh, mark_price=D(70), limit_price=D(70), fee_buffer=D(0)) capabilities = p1.Capabilities(binding, verified=True, fractional_verified=False) - return dict(plan=plan, calendar=calendar, period=period, facts=facts, quote=quote, - capabilities=capabilities, now=now) + return {"plan": plan, "calendar": calendar, "period": period, "facts": facts, "quote": quote, + "capabilities": capabilities, "now": now} def test_installed_api_preserves_final_tranche_and_preview_only(installed_dca_case): @@ -71,7 +72,7 @@ def test_installed_api_preserves_final_tranche_and_preview_only(installed_dca_ca result = evaluate_dca_period(**installed_dca_case) assert isinstance(result, PeriodPreview) assert result.status == "DUE" - assert result.new_tranche == D("100") # Already approved; never apply the tier twice. + assert result.new_tranche == D(100) # Already approved; never apply the tier twice. assert result.period_key == "2026-11" assert result.no_order is True and result.no_execute is True assert result.preview_only is True and result.live_ready is False @@ -80,24 +81,28 @@ def test_installed_api_preserves_final_tranche_and_preview_only(installed_dca_ca def test_adapter_consumes_installed_api_and_rejects_sg(installed_dca_case): - from application.plain_dca_paper_adapter import PlainDcaPaperError, consume_plain_dca_preview - from application.runtime_target_manifest import load_runtime_target_manifest from us_equity_strategies.plain_dca import evaluate_dca_period + from application.plain_dca_paper_adapter import ( + PlainDcaPaperError, + consume_plain_dca_preview, + ) + from application.runtime_target_manifest import load_runtime_target_manifest + service, = [t.service for t in load_runtime_target_manifest().targets if t.id == "paper"] now = installed_dca_case["now"] - readback = dict(observed_at=now, valid_until=now+timedelta(minutes=1), - target_id="paper", environment="longbridge-paper", - live_enabled=False, kelly_enabled=False, stop_loss_enabled=False, - protected_env={ + readback = {"observed_at": now, "valid_until": now+timedelta(minutes=1), + "target_id": "paper", "environment": "longbridge-paper", + "live_enabled": False, "kelly_enabled": False, "stop_loss_enabled": False, + "protected_env": { "CLOUD_RUN_SERVICE": service, "RUNTIME_TARGET_ENABLED": "false", "LONGBRIDGE_DRY_RUN_ONLY": "false", "LONGBRIDGE_PHYSICAL_ACCOUNT_ID": "fake-paper-account", - "RUNTIME_TARGET_JSON": json.dumps(dict( - platform_id="longbridge", service_name=service, - execution_environment="paper", execution_mode="live", dry_run_only=False, - account_scope="PAPER", account_selector=["PAPER"], deployment_selector="PAPER")), - }) + "RUNTIME_TARGET_JSON": json.dumps({ + "platform_id": "longbridge", "service_name": service, + "execution_environment": "paper", "execution_mode": "live", "dry_run_only": False, + "account_scope": "PAPER", "account_selector": ["PAPER"], "deployment_selector": "PAPER"}), + }} assert consume_plain_dca_preview(read_binding=lambda: readback, **installed_dca_case) == evaluate_dca_period(**installed_dca_case) with pytest.raises(PlainDcaPaperError, match="paper_target_environment_required"): consume_plain_dca_preview(read_binding=lambda: {**readback, "environment": "longbridge-sg"}, From 96b2ff4238720832601dce4d8c048d0b5369a63e Mon Sep 17 00:00:00 2001 From: Pigbibi <20649888+Pigbibi@users.noreply.github.com> Date: Fri, 6 Nov 2026 04:15:52 +0800 Subject: [PATCH 3/3] test: Preserve V7 approval when adopting the plain-DCA pin Co-Authored-By: Codex --- docs/runtime-target-manifest.md | 5 +++++ tests/test_ues_revision.py | 2 +- tests/test_v7_paper_application.py | 17 +++++++++++++++++ 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/docs/runtime-target-manifest.md b/docs/runtime-target-manifest.md index 53937dd1..7165ef78 100644 --- a/docs/runtime-target-manifest.md +++ b/docs/runtime-target-manifest.md @@ -223,3 +223,8 @@ A missing or incompatible installation still fails with readback source or credentials: deployed PAPER account/state/schedule isolation, authentic safety readback, durable fencing/reconciliation, setup decisions and Phase 2 execution remain separate prerequisites. Unit fixtures cannot prove those runtime facts. + +The existing V7 PAPER approval remains bound to its original UES revision. +The plain-DCA dependency adoption does not renew or broaden that approval: +V7 loaded-version admission rejects the new installed revision. No V7 approval +constant, approved candidate or protected application binding is changed. diff --git a/tests/test_ues_revision.py b/tests/test_ues_revision.py index 58035bd4..e2f4d573 100644 --- a/tests/test_ues_revision.py +++ b/tests/test_ues_revision.py @@ -7,7 +7,7 @@ import pytest ROOT = Path(__file__).resolve().parents[1] -PIN = "c16c81bdf21824615f7280554559adc6c721917c" +PIN = "1d087fa424972d5d5ab02c4650ce9f039cb6711f" OTHER = "a" * 40 diff --git a/tests/test_v7_paper_application.py b/tests/test_v7_paper_application.py index 9002b13d..aebf700b 100644 --- a/tests/test_v7_paper_application.py +++ b/tests/test_v7_paper_application.py @@ -413,6 +413,13 @@ def _loaded_v7_readback(monkeypatch): def test_loaded_version_readback_uses_process_identity_and_stays_paused(monkeypatch) -> None: + from application import v7_paper_application + + original = v7_paper_application._installed_revision + monkeypatch.setattr( + v7_paper_application, "_installed_revision", + lambda name: V7_APPROVED_UES_REVISION if name == "us-equity-strategies" else original(name), + ) readback = _loaded_v7_readback(monkeypatch) assert readback["activation_state"] == "applied_paused" assert readback["runtime_target_enabled"] is False @@ -422,6 +429,16 @@ def test_loaded_version_readback_uses_process_identity_and_stays_paused(monkeypa assert readback["runtime_loaded_receipt"]["schema_version"] == "runtime_loaded_receipt.v1" +def test_plain_dca_installed_pin_does_not_renew_v7_approval(monkeypatch) -> None: + from application import v7_paper_application + + # Exercise the real installed package: M03 adoption cannot alter V7 authority. + assert v7_paper_application._installed_revision("us-equity-strategies") == "1d087fa424972d5d5ab02c4650ce9f039cb6711f" + assert V7_APPROVED_UES_REVISION == "c16c81bdf21824615f7280554559adc6c721917c" + with pytest.raises(V7PaperApplicationError, match="loaded UES revision"): + _loaded_v7_readback(monkeypatch) + + @pytest.mark.parametrize("observed_revision", [ "8412d8338879f335ef8830678c2733e02e53e7c7", "a" * 40, "", None, ])