Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions config/runtime_targets.manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
{
"id": "soxl_soxx_trend_income",
"label": "SOXL/SOXX trend income",
"service": "interactive-brokers-quant-live-u00000001-service",
"service": "ibkr-quant-live-demo01-service",
"region": "us-central1",
"account_group": "live-u00000001",
"strategy_profile": "soxl_soxx_trend_income",
Expand All @@ -19,7 +19,7 @@
{
"id": "tqqq_growth_income",
"label": "TQQQ growth income",
"service": "interactive-brokers-quant-live-u00000002-service",
"service": "ibkr-quant-live-demo02-service",
"region": "us-central1",
"account_group": "live-u00000002",
"strategy_profile": "tqqq_growth_income",
Expand All @@ -32,7 +32,7 @@
{
"id": "global_etf_rotation",
"label": "Global ETF rotation",
"service": "interactive-brokers-quant-live-u00000003-service",
"service": "ibkr-quant-live-demo03-service",
"region": "us-central1",
"account_group": "live-u00000003",
"strategy_profile": "global_etf_rotation",
Expand All @@ -45,7 +45,7 @@
{
"id": "russell_top50_leader_rotation",
"label": "Russell top-50 leader rotation",
"service": "interactive-brokers-quant-live-u00000004-service",
"service": "ibkr-quant-live-demo04-service",
"region": "us-central1",
"account_group": "live-u00000004",
"strategy_profile": "russell_top50_leader_rotation",
Expand Down
56 changes: 52 additions & 4 deletions docs/runtime-target-manifest.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,10 @@

| id | service | account_group | execution_mode | include_lifecycle | include_reconciliation |
| --- | --- | --- | --- | --- | --- |
| `soxl_soxx_trend_income` | `interactive-brokers-quant-live-u00000001-service` | `live-u00000001` | `live` | true | true |
| `tqqq_growth_income` | `interactive-brokers-quant-live-u00000002-service` | `live-u00000002` | `live` | true | true |
| `global_etf_rotation` | `interactive-brokers-quant-live-u00000003-service` | `live-u00000003` | `live` | true | true |
| `russell_top50_leader_rotation` | `interactive-brokers-quant-live-u00000004-service` | `live-u00000004` | `live` | true | true |
| `soxl_soxx_trend_income` | `ibkr-quant-live-demo01-service` | `live-u00000001` | `live` | true | true |
| `tqqq_growth_income` | `ibkr-quant-live-demo02-service` | `live-u00000002` | `live` | true | true |
| `global_etf_rotation` | `ibkr-quant-live-demo03-service` | `live-u00000003` | `live` | true | true |
| `russell_top50_leader_rotation` | `ibkr-quant-live-demo04-service` | `live-u00000004` | `live` | true | true |
| `us_combo_shadow` | `interactive-brokers-us-combo-shadow-service` | `us-combo-shadow` | `shadow` | false | false |

示例中五个目标的 `enabled` 均为 `false`。这表示公开清单的安全默认值,**不**覆盖 Environment / Cloud Run 里现有的启停状态,也不授权交易。
Expand Down Expand Up @@ -98,3 +98,51 @@ Unclassified or missing dates remain `null`. These are local execution records,
not a broker open-order count or authorization to clear a claim. The diagnostic
reads bounded objects without connecting to the broker and emits no account,
order, object URI, marker key or financial values.

## Short service names and staged migration

The four synthetic live examples use `ibkr-quant-live-demoNN-service`, with no
account identifier in the service name. Each is 30 characters; a 13-character
`cand-01234567` tag gives a combined length of 43, within the shared
`cloud-run-tags/v1` budget of 46. Production candidates use a private, unique
opaque slot instead of `demoNN`; resolve the exact old-to-new mapping from the
approved protected inventory. The examples are not that mapping. The shadow
example is outside this migration.

Set the same approved short name in every applicable protected inventory field:
`service`, `service_name` and `runtime_target.service_name`. The existing sync-plan
builder rejects a mismatch and runs the shared tag preflight. Do not add an
implicit long-to-short fallback: missing, duplicate, ambiguous or mismatched
bindings must stop preparation. Keep account selectors, strategy profiles,
execution modes and risk settings unchanged when preparing a candidate inventory.
The public manifest cannot change a deployed target or the protected inventory.

Cloud Run does not rename an existing service in place. A later approved operation
must create a replacement and explicitly migrate consumers. Before requesting
that operation, prepare and review the following against a fresh source readback:

1. Bind the exact old/new service pair, project, region and source revision; verify
the destination is absent or belongs to this same approved migration. An
unknown destination owner or service collision blocks the operation.
2. Revalidate the runtime-target fingerprint, execution claims, continuity and
strategy-release bindings. A changed `service_name` changes target identity;
carrying the old fingerprint, release admission or continuity receipt forward
without revalidation is not valid. Do not reset, duplicate or fabricate order
markers or opening state.
3. Inventory Scheduler URLs and OIDC audiences, health probes, reconciliation,
account-facts consumers, notification producers, runtime-setting selectors and
rollback references. Prepare coordinated updates so both services cannot
execute the same account concurrently. Do not enable a Scheduler job or
execution on the replacement as part of source preparation.
4. Obtain separate owner authorization bound to the destination and reviewed
revision before any deployment, traffic, protected configuration, IAM, Secret
or Scheduler mutation. Use the established guarded workflow and require its
dry-run and before/after readbacks; this document adds no workflow or bypass.
5. Keep the existing service and its evidence until the approved migration has
verified consumer adoption and rollback. An interrupted or uncertain migration
requires reconciliation and a fresh readback before another attempt; never
infer success from a short name or a green offline test.

The source-only short-name change leaves all five example targets disabled.
It does not deploy, change traffic, switch execution mode, approve continuity,
qualify PAPER sessions or enable live trading, Kelly or stop-loss controls.
25 changes: 20 additions & 5 deletions tests/test_runtime_target_manifest.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,25 +20,25 @@
EXPECTED_LIVE_TARGETS = {
"soxl_soxx_trend_income": {
"label": "SOXL/SOXX trend income",
"service": "interactive-brokers-quant-live-u00000001-service",
"service": "ibkr-quant-live-demo01-service",
"account_group": "live-u00000001",
"strategy_profile": "soxl_soxx_trend_income",
},
"tqqq_growth_income": {
"label": "TQQQ growth income",
"service": "interactive-brokers-quant-live-u00000002-service",
"service": "ibkr-quant-live-demo02-service",
"account_group": "live-u00000002",
"strategy_profile": "tqqq_growth_income",
},
"global_etf_rotation": {
"label": "Global ETF rotation",
"service": "interactive-brokers-quant-live-u00000003-service",
"service": "ibkr-quant-live-demo03-service",
"account_group": "live-u00000003",
"strategy_profile": "global_etf_rotation",
},
"russell_top50_leader_rotation": {
"label": "Russell top-50 leader rotation",
"service": "interactive-brokers-quant-live-u00000004-service",
"service": "ibkr-quant-live-demo04-service",
"account_group": "live-u00000004",
"strategy_profile": "russell_top50_leader_rotation",
},
Expand All @@ -53,7 +53,7 @@ def _valid_payload() -> dict:
{
"id": "soxl_soxx_trend_income",
"label": "SOXL/SOXX trend income",
"service": "interactive-brokers-quant-live-u00000001-service",
"service": "ibkr-quant-live-demo01-service",
"region": "us-central1",
"account_group": "live-u00000001",
"strategy_profile": "soxl_soxx_trend_income",
Expand Down Expand Up @@ -287,3 +287,18 @@ def test_validate_script_accepts_checked_in_manifest(tmp_path, capsys):
encoding="utf-8",
)
assert module.main(["--path", str(bad)]) == 1


@pytest.mark.parametrize("target_id", EXPECTED_LIVE_TARGETS)
def test_live_example_service_preserves_full_candidate_tag(target_id):
from scripts.cloud_run_tag_policy import allocate_tag

target = next(t for t in load_runtime_target_manifest().targets if t.id == target_id)
preferred = "cand-01234567"
allocation = allocate_tag(
target.service, preferred, existing_tags=[], operation_id="fake-rename-check"
)
assert allocation.status == "ALLOCATED"
assert allocation.tag == preferred
assert len(target.service) + len(preferred) <= 46
assert target.enabled is False
8 changes: 4 additions & 4 deletions tests/test_runtime_target_matrix.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,19 +19,19 @@
EXPECTED_RECONCILIATION = [
{
"profile": "soxl_soxx_trend_income",
"service": "interactive-brokers-quant-live-u00000001-service",
"service": "ibkr-quant-live-demo01-service",
},
{
"profile": "tqqq_growth_income",
"service": "interactive-brokers-quant-live-u00000002-service",
"service": "ibkr-quant-live-demo02-service",
},
{
"profile": "global_etf_rotation",
"service": "interactive-brokers-quant-live-u00000003-service",
"service": "ibkr-quant-live-demo03-service",
},
{
"profile": "russell_top50_leader_rotation",
"service": "interactive-brokers-quant-live-u00000004-service",
"service": "ibkr-quant-live-demo04-service",
},
]

Expand Down
Loading