From 3942430ce7f2fdc4c9a04c9c8b87942d15e14026 Mon Sep 17 00:00:00 2001 From: Pigbibi <20649888+Pigbibi@users.noreply.github.com> Date: Tue, 30 Jun 2026 23:07:52 +0800 Subject: [PATCH] refactor: split repo into python/ and web/ with independent CI - Move Python scripts to python/scripts/ with own pyproject.toml - Move Python tests to python/tests/ with __init__.py - Move shell tooling to python/shell/ - Keep JS web app and JS tests in web/ and tests/ - Update all path references in workflows, scripts, and tests - Add docs/ARCHITECTURE.md documenting the three-tier design - Split validate.yml into independent Python and JS jobs - Update dependabot.yml to point to /python - Update READMEs with new directory structure Co-Authored-By: Claude --- .github/dependabot.yml | 2 +- .github/workflows/codex_pr_review.yml | 2 +- .github/workflows/codex_review_gate.yml | 2 +- .../deploy-strategy-switch-console.yml | 10 +- .github/workflows/manual-strategy-switch.yml | 12 +- .github/workflows/validate.yml | 37 +++-- README.md | 13 +- README.zh-CN.md | 13 +- docs/ARCHITECTURE.md | 148 ++++++++++++++++++ pyproject.toml => python/pyproject.toml | 0 {scripts => python/scripts}/__init__.py | 0 {scripts => python/scripts}/build_config.py | 8 +- .../scripts}/build_platform_config.py | 6 +- .../scripts}/build_runtime_switch.py | 2 +- .../check_internal_dependency_matrix.py | 2 +- .../scripts}/gate_codex_app_review.py | 0 .../scripts}/inject_platform_config.py | 2 +- .../scripts}/run_codex_pr_review.py | 2 +- .../scripts}/runtime_settings.py | 2 +- .../sync_strategy_switch_page_asset.py | 2 +- .../checkout_internal_dependency_consumers.sh | 2 +- python/tests/__init__.py | 0 .../tests}/test_internal_dependency_matrix.py | 4 +- .../tests}/test_runtime_settings.py | 8 +- 24 files changed, 222 insertions(+), 57 deletions(-) create mode 100644 docs/ARCHITECTURE.md rename pyproject.toml => python/pyproject.toml (100%) rename {scripts => python/scripts}/__init__.py (100%) rename {scripts => python/scripts}/build_config.py (97%) rename {scripts => python/scripts}/build_platform_config.py (97%) rename {scripts => python/scripts}/build_runtime_switch.py (99%) rename {scripts => python/scripts}/check_internal_dependency_matrix.py (99%) rename {scripts => python/scripts}/gate_codex_app_review.py (100%) rename {scripts => python/scripts}/inject_platform_config.py (99%) rename {scripts => python/scripts}/run_codex_pr_review.py (99%) rename {scripts => python/scripts}/runtime_settings.py (99%) rename {scripts => python/scripts}/sync_strategy_switch_page_asset.py (96%) rename {scripts => python/shell}/checkout_internal_dependency_consumers.sh (97%) create mode 100644 python/tests/__init__.py rename {tests => python/tests}/test_internal_dependency_matrix.py (97%) rename {tests => python/tests}/test_runtime_settings.py (99%) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 2bbf4fc..ad9ce8a 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -1,7 +1,7 @@ version: 2 updates: - package-ecosystem: "pip" - directory: "/" + directory: "/python" schedule: interval: "weekly" open-pull-requests-limit: 5 diff --git a/.github/workflows/codex_pr_review.yml b/.github/workflows/codex_pr_review.yml index 8bc7881..5884343 100644 --- a/.github/workflows/codex_pr_review.yml +++ b/.github/workflows/codex_pr_review.yml @@ -42,7 +42,7 @@ jobs: OPENAI_MODEL: ${{ vars.OPENAI_MODEL || 'gpt-5.4-mini' }} CODEX_AUDIT_SERVICE_URL: ${{ secrets.CODEX_AUDIT_SERVICE_URL }} CODEX_AUDIT_SERVICE_AUDIENCE: ${{ vars.CODEX_AUDIT_SERVICE_AUDIENCE || 'quant-codex-audit' }} - run: python scripts/run_codex_pr_review.py + run: python python/scripts/run_codex_pr_review.py - name: Upload review diagnostics if: always() diff --git a/.github/workflows/codex_review_gate.yml b/.github/workflows/codex_review_gate.yml index 56bcf4e..9140a31 100644 --- a/.github/workflows/codex_review_gate.yml +++ b/.github/workflows/codex_review_gate.yml @@ -54,7 +54,7 @@ jobs: id: gate env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: python scripts/gate_codex_app_review.py + run: python python/scripts/gate_codex_app_review.py - name: Upload gate diagnostics if: always() diff --git a/.github/workflows/deploy-strategy-switch-console.yml b/.github/workflows/deploy-strategy-switch-console.yml index bf6b1e7..22afdfb 100644 --- a/.github/workflows/deploy-strategy-switch-console.yml +++ b/.github/workflows/deploy-strategy-switch-console.yml @@ -6,8 +6,8 @@ on: paths: - ".github/workflows/deploy-strategy-switch-console.yml" - "platform-config.json" - - "scripts/build_config.py" - - "scripts/sync_strategy_switch_page_asset.py" + - "python/scripts/build_config.py" + - "python/scripts/sync_strategy_switch_page_asset.py" - "web/strategy-switch-console/**" workflow_dispatch: inputs: @@ -54,9 +54,9 @@ jobs: - name: Build config & assets from platform-config.json run: | set -euo pipefail - python3 scripts/build_platform_config.py - python3 scripts/inject_platform_config.py - python3 scripts/sync_strategy_switch_page_asset.py + python3 python/scripts/build_platform_config.py + python3 python/scripts/inject_platform_config.py + python3 python/scripts/sync_strategy_switch_page_asset.py - name: Validate Worker assets continue-on-error: true diff --git a/.github/workflows/manual-strategy-switch.yml b/.github/workflows/manual-strategy-switch.yml index 26e25c7..088ef2b 100644 --- a/.github/workflows/manual-strategy-switch.yml +++ b/.github/workflows/manual-strategy-switch.yml @@ -212,7 +212,7 @@ jobs: id: platform run: | set -euo pipefail - repo="$(python3 scripts/runtime_settings.py repository "${PLATFORM}")" + repo="$(python3 python/scripts/runtime_settings.py repository "${PLATFORM}")" echo "repository=${repo}" >> "$GITHUB_OUTPUT" - name: Fetch existing service targets @@ -302,14 +302,14 @@ jobs: if [ -s "${EXISTING_SERVICE_TARGETS_JSON_FILE:-}" ]; then args+=(--existing-service-targets-json-file "${EXISTING_SERVICE_TARGETS_JSON_FILE}") fi - python3 scripts/build_runtime_switch.py "${args[@]}" - python3 scripts/runtime_settings.py validate "${target_file}" + python3 python/scripts/build_runtime_switch.py "${args[@]}" + python3 python/scripts/runtime_settings.py validate "${target_file}" echo "TARGET_FILE=${target_file}" >> "$GITHUB_ENV" - name: Preview assignments run: | set -euo pipefail - python3 scripts/runtime_settings.py render "${TARGET_FILE}" --format json --redact-values > "${RUNNER_TEMP}/assignments.json" + python3 python/scripts/runtime_settings.py render "${TARGET_FILE}" --format json --redact-values > "${RUNNER_TEMP}/assignments.json" python - <<'PY' "${TARGET_FILE}" "${RUNNER_TEMP}/assignments.json" >> "$GITHUB_STEP_SUMMARY" import json import sys @@ -336,7 +336,7 @@ jobs: - name: Apply GitHub variable updates if: env.APPLY_SWITCH == 'true' - run: python3 scripts/runtime_settings.py apply "${TARGET_FILE}" --yes + run: python3 python/scripts/runtime_settings.py apply "${TARGET_FILE}" --yes - name: Dispatch platform sync workflow if: env.APPLY_SWITCH == 'true' && env.TRIGGER_PLATFORM_SYNC == 'true' @@ -374,7 +374,7 @@ jobs: import urllib.request root = os.environ.get("GITHUB_WORKSPACE") or os.getcwd() - sys.path.insert(0, os.path.join(root, "scripts")) + sys.path.insert(0, os.path.join(root, "python", "scripts")) import runtime_settings base_url = os.environ["STRATEGY_SWITCH_CONSOLE_URL"].rstrip("/") diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index ae970fd..b9239a7 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -8,7 +8,7 @@ permissions: contents: read jobs: - validate: + python: runs-on: ubuntu-latest timeout-minutes: 15 steps: @@ -18,9 +18,6 @@ jobs: - uses: actions/setup-python@v6 with: python-version: "3.12" - - uses: actions/setup-node@v6 - with: - node-version: "22" - name: Check whitespace run: | set -euo pipefail @@ -31,23 +28,37 @@ jobs: git diff-tree --check --no-commit-id --root -r HEAD fi - name: Validate platform config - run: python3 scripts/build_config.py --check + run: python3 python/scripts/build_config.py --check - name: Validate runtime targets - run: python3 scripts/runtime_settings.py validate - - name: Run unit tests - run: python3 -m unittest discover -s tests -v + run: python3 python/scripts/runtime_settings.py validate + - name: Run Python unit tests + run: python3 -m unittest discover -s python/tests -v - name: Checkout internal dependency consumer repos env: GH_TOKEN: ${{ github.token }} - run: bash scripts/checkout_internal_dependency_consumers.sh --output-root .. + run: bash python/shell/checkout_internal_dependency_consumers.sh --output-root .. - name: Report internal dependency matrix - run: python3 scripts/check_internal_dependency_matrix.py --projects-root .. --json --strict --require-consumer-files + run: python3 python/scripts/check_internal_dependency_matrix.py --projects-root .. --json --strict --require-consumer-files + + js: + runs-on: ubuntu-latest + timeout-minutes: 10 + steps: + - uses: actions/checkout@v6 + with: + fetch-depth: 0 + - uses: actions/setup-node@v6 + with: + node-version: "22" + - uses: actions/setup-python@v6 + with: + python-version: "3.12" - name: Validate strategy switch web assets run: | set -euo pipefail - python3 scripts/build_config.py --check - python3 scripts/build_config.py - python3 scripts/sync_strategy_switch_page_asset.py + python3 python/scripts/build_config.py --check + python3 python/scripts/build_config.py + python3 python/scripts/sync_strategy_switch_page_asset.py git diff --exit-code -- web/strategy-switch-console/page_asset.js web/strategy-switch-console/strategy_profiles_asset.js jq empty web/strategy-switch-console/strategy-profiles.example.json node --experimental-default-type=module tests/strategy_switch_worker_validation.mjs diff --git a/README.md b/README.md index 5264b09..b9420b7 100644 --- a/README.md +++ b/README.md @@ -19,20 +19,23 @@ It supports the system but does not decide which strategy should be live. Strate ## Repository layout -- `tests/`: unit, contract, and regression tests. +- `python/`: Python tooling (scripts, tests, pyproject.toml) — validation, code generation, deployment scripts. +- `web/`: JavaScript web app (Cloudflare Workers strategy switch console). +- `schemas/`: JSON Schema files shared by both Python and JS. +- `tests/`: JavaScript unit/integration tests. - `.github/workflows/`: CI, scheduled jobs, release, or deployment workflows. -- `scripts/`: operator scripts and local helpers. +- `docs/ARCHITECTURE.md`: Detailed architecture documentation. ## Quick start ```bash -python3 scripts/runtime_settings.py validate -python3 -m unittest discover -s tests -v +python3 python/scripts/runtime_settings.py validate +python3 -m unittest discover -s python/tests -v ``` ## Manual Strategy Switch -`.github/workflows/manual-strategy-switch.yml` provides a central manual switch entrypoint. It builds a transient runtime target from workflow inputs, validates it with `scripts/runtime_settings.py`, and writes GitHub variables into the target platform repository. It currently supports `longbridge`, `ibkr`, `schwab`, and `firstrade`. +`.github/workflows/manual-strategy-switch.yml` provides a central manual switch entrypoint. It builds a transient runtime target from workflow inputs, validates it with `python/scripts/runtime_settings.py`, and writes GitHub variables into the target platform repository. It currently supports `longbridge`, `ibkr`, `schwab`, and `firstrade`. Recommended flow: diff --git a/README.zh-CN.md b/README.zh-CN.md index 55e5d5e..08b178c 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -19,20 +19,23 @@ QuantRuntimeSettings 是 QuantStrategyLab 的运行配置包。为 QuantStrategy ## 仓库结构 -- `tests/`:单元测试、契约测试和回归测试。 +- `python/`:Python 工具链(脚本、测试、pyproject.toml)— 校验、代码生成、部署工具。 +- `web/`:JavaScript Web 应用(Cloudflare Workers 策略切换控制台)。 +- `schemas/`:JSON Schema 文件,Python 和 JS 共享。 +- `tests/`:JavaScript 单元测试和集成测试。 - `.github/workflows/`:CI、定时任务、发布或部署 workflow。 -- `scripts/`:运维脚本和本地辅助工具。 +- `docs/ARCHITECTURE.md`:详细架构文档。 ## 快速开始 ```bash -python3 scripts/runtime_settings.py validate -python3 -m unittest discover -s tests -v +python3 python/scripts/runtime_settings.py validate +python3 -m unittest discover -s python/tests -v ``` ## 一键切换策略 -`.github/workflows/manual-strategy-switch.yml` 提供手动触发的中控切换入口。它会根据表单参数生成运行目标,复用 `scripts/runtime_settings.py` 校验并写入目标平台仓库的 GitHub variables。当前支持 `longbridge`、`ibkr`、`schwab`、`firstrade`。 +`.github/workflows/manual-strategy-switch.yml` 提供手动触发的中控切换入口。它会根据表单参数生成运行目标,复用 `python/scripts/runtime_settings.py` 校验并写入目标平台仓库的 GitHub variables。当前支持 `longbridge`、`ibkr`、`schwab`、`firstrade`。 推荐流程: diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md new file mode 100644 index 0000000..2845dc5 --- /dev/null +++ b/docs/ARCHITECTURE.md @@ -0,0 +1,148 @@ +# QuantRuntimeSettings Architecture + +## Overview + +QuantRuntimeSettings is a **config-driven** runtime settings package that serves as the central control plane for QuantStrategyLab deployments. It defines versioned strategy-to-platform assignments and hosts a Cloudflare Workers-based strategy switch console. + +The repository has a **three-tier architecture** built around a single source of truth: + +``` +platform-config.json (single source of truth) + | + v + Python scripts (validation, code generation, deployment tooling) + | + v + Generated assets (config.js, page_asset.js, strategy_profiles_asset.js) + | + v + Web application (Cloudflare Worker + frontend SPA) +``` + +--- + +## Directory Layout + +``` +. +├── platform-config.json # Central configuration (single source of truth) +├── internal_dependency_matrix.json # Internal git dependency pin tracking +│ +├── python/ # Python tooling (tests, CI, scripts) +│ ├── pyproject.toml # Python project definition & linter config +│ ├── scripts/ # Build & validation scripts +│ │ ├── build_config.py # Full build pipeline +│ │ ├── build_platform_config.py # Generate config.js from platform-config.json +│ │ ├── build_runtime_switch.py # Build transient runtime targets +│ │ ├── runtime_settings.py # Core validation & assignment engine +│ │ ├── check_internal_dependency_matrix.py +│ │ ├── gate_codex_app_review.py # PR merge gate +│ │ ├── inject_platform_config.py # Inject config into index.html +│ │ ├── run_codex_pr_review.py # Codex AI PR review +│ │ └── sync_strategy_switch_page_asset.py +│ ├── tests/ # Python unit tests +│ │ ├── test_runtime_settings.py +│ │ └── test_internal_dependency_matrix.py +│ └── shell/ # Shell scripts (Python ecosystem) +│ └── checkout_internal_dependency_consumers.sh +│ +├── web/ # JavaScript web application +│ └── strategy-switch-console/ # Cloudflare Workers app +│ ├── worker.js # Worker backend (OAuth, routing, KV) +│ ├── index.html # SPA shell +│ ├── app.js # Frontend JavaScript +│ ├── app.css # Frontend styles +│ ├── config.js # Generated: Platform config constants +│ ├── page_asset.js # Generated: Embedded index.html +│ ├── strategy_profiles_asset.js # Generated: Strategy catalog +│ ├── app_css.js # Generated: Embedded styles +│ ├── app_js.js # Generated: Embedded JS +│ └── wrangler.toml.example # Cloudflare Workers config template +│ +├── schemas/ # Shared JSON Schema (consumed by both) +│ └── runtime-target.schema.json # Runtime target validation schema +│ +├── tests/ # JavaScript tests +│ ├── strategy_switch_worker_validation.mjs +│ └── test_cash_financing.js +│ +├── docs/ # Documentation +├── examples/targets/ # Example runtime targets per platform +├── prompts/ # LLM prompt templates +│ +└── .github/workflows/ # CI/CD workflows + ├── validate.yml # Python + JS validation (split jobs) + ├── deploy-strategy-switch-console.yml + ├── manual-strategy-switch.yml + ├── codex_pr_review.yml + └── codex_review_gate.yml +``` + +--- + +## Tier 1: Source of Truth — `platform-config.json` + +Defines the entire runtime configuration universe: + +- **4 domains**: `us_equity`, `hk_equity`, `cn_equity`, `crypto` +- **6 platforms**: `longbridge`, `ibkr`, `schwab`, `firstrade`, `qmt`, `binance` +- **18 strategy profiles** with features: income layer, option overlay, DCA, combo +- **Platform capabilities, CSS theming, default accounts, repositories, variable scopes** + +Never hardcode platform or strategy data in frontend code — regenerate from this file. + +--- + +## Tier 2: Python Tooling (`python/`) + +The `python/` directory contains all Python code, organized as a self-contained project with its own `pyproject.toml`. + +**Key scripts:** + +| Script | Purpose | +|--------|---------| +| `build_config.py` | Full pipeline: validate config, generate strategy profiles, inject into index.html | +| `build_platform_config.py` | Generate `config.js` (ES module) from `platform-config.json` | +| `runtime_settings.py` | Core engine: validate targets, render variables, apply via `gh` CLI | +| `build_runtime_switch.py` | Build transient runtime targets for manual strategy switch | +| `inject_platform_config.py` | Inject platform config globals into `index.html` | +| `sync_strategy_switch_page_asset.py` | Embed HTML/JSON as ES module assets for Worker deployment | + +**Dependency boundary:** Python scripts consume `schemas/runtime-target.schema.json`, `platform-config.json`, and write to `web/strategy-switch-console/`. They do **not** depend on the JavaScript code. + +--- + +## Tier 3: Web Application (`web/`) + +A Cloudflare Workers-based strategy switch console. Built with vanilla JS (no framework) and deployed via Wrangler. + +**Key files:** + +| File | Role | +|------|------| +| `worker.js` | Backend: OAuth, session management, config serving, switch dispatch, KV caching | +| `index.html` | SPA shell with bilingual (zh/en) UI, platform selection, strategy configuration | +| `app.js` | Frontend form logic, i18n, summary panel | +| `config.js` (generated) | Platform config constants consumed by both frontend and worker | + +**Dependency boundary:** The web app consumes generated assets (`config.js`, `page_asset.js`) and reads `platform-config.json` indirectly via the Worker API. It does **not** depend on Python scripts at runtime. + +--- + +## CI/CD: Independent Validation + +The `validate.yml` workflow runs **two independent jobs**: + +1. **`python`** — Python tests, config validation, runtime target validation, dependency matrix checks +2. **`js`** — JS module syntax checks, Worker asset validation, SPA integration tests + +Neither job depends on the other. This ensures that a change to Python scripts doesn't need to wait for JS tests, and vice versa. + +--- + +## Change Guide + +- **Add a platform/strategy**: Edit `platform-config.json`, then run `python3 python/scripts/build_config.py` to regenerate all derived files. +- **Modify build logic**: Edit files in `python/scripts/`, run `python3 -m unittest discover -s python/tests`. +- **Modify web UI**: Edit files in `web/strategy-switch-console/`, run `node tests/strategy_switch_worker_validation.mjs`. +- **Update runner**: Run both Python and JS validation locally before committing. diff --git a/pyproject.toml b/python/pyproject.toml similarity index 100% rename from pyproject.toml rename to python/pyproject.toml diff --git a/scripts/__init__.py b/python/scripts/__init__.py similarity index 100% rename from scripts/__init__.py rename to python/scripts/__init__.py diff --git a/scripts/build_config.py b/python/scripts/build_config.py similarity index 97% rename from scripts/build_config.py rename to python/scripts/build_config.py index aacfddc..a05f3f8 100644 --- a/scripts/build_config.py +++ b/python/scripts/build_config.py @@ -2,8 +2,8 @@ """Build pipeline: platform-config.json → all derived files. Usage: - python3 scripts/build_config.py # full build - python3 scripts/build_config.py --check # only validate config + python3 python/scripts/build_config.py # full build + python3 python/scripts/build_config.py --check # only validate config Adds/modifies: web/strategy-switch-console/strategy-profiles.example.json @@ -20,7 +20,7 @@ import sys from pathlib import Path -ROOT = Path(__file__).resolve().parents[1] +ROOT = Path(__file__).resolve().parents[2] CONFIG_PATH = ROOT / "platform-config.json" STRATEGY_PROFILES_PATH = ROOT / "web" / "strategy-switch-console" / "strategy-profiles.example.json" STRATEGY_PROFILES_ASSET = ROOT / "web" / "strategy-switch-console" / "strategy_profiles_asset.js" @@ -207,7 +207,7 @@ def inject_into_index_html(config: dict) -> None: def run_sync_script() -> None: """Run the existing sync script to regenerate page_asset.js + strategy_profiles_asset.js.""" - sync_script = ROOT / "scripts" / "sync_strategy_switch_page_asset.py" + sync_script = ROOT / "python" / "scripts" / "sync_strategy_switch_page_asset.py" if sync_script.exists(): subprocess.run([sys.executable, str(sync_script)], cwd=ROOT, check=True) print(" Ran sync_strategy_switch_page_asset.py") diff --git a/scripts/build_platform_config.py b/python/scripts/build_platform_config.py similarity index 97% rename from scripts/build_platform_config.py rename to python/scripts/build_platform_config.py index 16e6efa..f9598c6 100644 --- a/scripts/build_platform_config.py +++ b/python/scripts/build_platform_config.py @@ -14,7 +14,7 @@ import json from pathlib import Path -ROOT = Path(__file__).resolve().parents[1] +ROOT = Path(__file__).resolve().parents[2] SOURCE = ROOT / "platform-config.json" TARGET = ROOT / "web" / "strategy-switch-console" / "config.js" STRATEGY_TARGET = ROOT / "web" / "strategy-switch-console" / "strategy_profiles_asset.js" @@ -151,7 +151,7 @@ def build_config_module(config: dict) -> str: # ── Generate JS module ── lines = [ - "// Generated by scripts/build_platform_config.py; single source of truth.", + "// Generated by python/scripts/build_platform_config.py; single source of truth.", f"// Source: platform-config.json", "", f"export const PLATFORM_CONFIG = {json.dumps(platform_config, indent=2, ensure_ascii=False)};", @@ -223,7 +223,7 @@ def build_strategy_profiles(config: dict) -> str: profiles.append(entry) payload = ( - "// Generated by scripts/build_platform_config.py from platform-config.json\n" + "// Generated by python/scripts/build_platform_config.py from platform-config.json\n" f"export const DEFAULT_STRATEGY_PROFILES = {json.dumps(profiles, indent=2, ensure_ascii=False)};\n" ) return payload diff --git a/scripts/build_runtime_switch.py b/python/scripts/build_runtime_switch.py similarity index 99% rename from scripts/build_runtime_switch.py rename to python/scripts/build_runtime_switch.py index d04f33d..e8c7c30 100644 --- a/scripts/build_runtime_switch.py +++ b/python/scripts/build_runtime_switch.py @@ -13,7 +13,7 @@ SCRIPT_DIR = Path(__file__).resolve().parent if str(SCRIPT_DIR) not in sys.path: sys.path.insert(0, str(SCRIPT_DIR)) -ROOT = SCRIPT_DIR.parent +ROOT = SCRIPT_DIR.parents[1] from runtime_settings import ( # noqa: E402 SUPPORTED_PLATFORMS, diff --git a/scripts/check_internal_dependency_matrix.py b/python/scripts/check_internal_dependency_matrix.py similarity index 99% rename from scripts/check_internal_dependency_matrix.py rename to python/scripts/check_internal_dependency_matrix.py index 40fb7e0..5c84be6 100644 --- a/scripts/check_internal_dependency_matrix.py +++ b/python/scripts/check_internal_dependency_matrix.py @@ -11,7 +11,7 @@ from typing import Any -ROOT = Path(__file__).resolve().parents[1] +ROOT = Path(__file__).resolve().parents[2] DEFAULT_MATRIX_PATH = ROOT / "internal_dependency_matrix.json" DEFAULT_PROJECTS_ROOT = ROOT.parent DEPENDENCY_PATTERN = re.compile( diff --git a/scripts/gate_codex_app_review.py b/python/scripts/gate_codex_app_review.py similarity index 100% rename from scripts/gate_codex_app_review.py rename to python/scripts/gate_codex_app_review.py diff --git a/scripts/inject_platform_config.py b/python/scripts/inject_platform_config.py similarity index 99% rename from scripts/inject_platform_config.py rename to python/scripts/inject_platform_config.py index 6c2f641..e444428 100644 --- a/scripts/inject_platform_config.py +++ b/python/scripts/inject_platform_config.py @@ -3,7 +3,7 @@ import json from pathlib import Path -ROOT = Path(__file__).resolve().parents[1] +ROOT = Path(__file__).resolve().parents[2] SOURCE = ROOT / "web" / "strategy-switch-console" / "index.html" CONFIG = ROOT / "platform-config.json" diff --git a/scripts/run_codex_pr_review.py b/python/scripts/run_codex_pr_review.py similarity index 99% rename from scripts/run_codex_pr_review.py rename to python/scripts/run_codex_pr_review.py index 4644655..15ad09d 100644 --- a/scripts/run_codex_pr_review.py +++ b/python/scripts/run_codex_pr_review.py @@ -25,7 +25,7 @@ # --------------------------------------------------------------------------- API_BASE = "https://api.github.com" -ROOT = Path(__file__).resolve().parents[1] +ROOT = Path(__file__).resolve().parents[2] POLICY_PATH = ROOT / ".github" / "codex_auto_merge_policy.json" PROMPT_TEMPLATE_PATH = ROOT / "prompts" / "pr_review.md" DEFAULT_SERVICE_AUDIENCE = "quant-codex-audit" diff --git a/scripts/runtime_settings.py b/python/scripts/runtime_settings.py similarity index 99% rename from scripts/runtime_settings.py rename to python/scripts/runtime_settings.py index 4e34bef..cac5f75 100644 --- a/scripts/runtime_settings.py +++ b/python/scripts/runtime_settings.py @@ -14,7 +14,7 @@ from pathlib import Path from typing import Any -ROOT = Path(__file__).resolve().parents[1] +ROOT = Path(__file__).resolve().parents[2] LOCAL_TARGETS_DIR = ROOT / "local" / "targets" EXAMPLE_TARGETS_DIR = ROOT / "examples" / "targets" LOCAL_POLICY_PATH = ROOT / "local" / "policy.json" diff --git a/scripts/sync_strategy_switch_page_asset.py b/python/scripts/sync_strategy_switch_page_asset.py similarity index 96% rename from scripts/sync_strategy_switch_page_asset.py rename to python/scripts/sync_strategy_switch_page_asset.py index ca4b28a..af4a252 100644 --- a/scripts/sync_strategy_switch_page_asset.py +++ b/python/scripts/sync_strategy_switch_page_asset.py @@ -7,7 +7,7 @@ from pathlib import Path -ROOT = Path(__file__).resolve().parents[1] +ROOT = Path(__file__).resolve().parents[2] SOURCE = ROOT / "web" / "strategy-switch-console" / "index.html" TARGET = ROOT / "web" / "strategy-switch-console" / "page_asset.js" PROFILE_SOURCE = ROOT / "web" / "strategy-switch-console" / "strategy-profiles.example.json" diff --git a/scripts/checkout_internal_dependency_consumers.sh b/python/shell/checkout_internal_dependency_consumers.sh similarity index 97% rename from scripts/checkout_internal_dependency_consumers.sh rename to python/shell/checkout_internal_dependency_consumers.sh index 4c3036c..7454fdd 100755 --- a/scripts/checkout_internal_dependency_consumers.sh +++ b/python/shell/checkout_internal_dependency_consumers.sh @@ -47,7 +47,7 @@ fi export GH_TOKEN="${GH_TOKEN:-${GITHUB_TOKEN}}" script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -repo_root="$(cd "${script_dir}/.." && pwd)" +repo_root="$(cd "${script_dir}/../.." && pwd)" matrix_file="${matrix_path}" if [ ! -f "${matrix_file}" ]; then matrix_file="${repo_root}/${matrix_path}" diff --git a/python/tests/__init__.py b/python/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/test_internal_dependency_matrix.py b/python/tests/test_internal_dependency_matrix.py similarity index 97% rename from tests/test_internal_dependency_matrix.py rename to python/tests/test_internal_dependency_matrix.py index d7bc453..eac185d 100644 --- a/tests/test_internal_dependency_matrix.py +++ b/python/tests/test_internal_dependency_matrix.py @@ -6,8 +6,8 @@ from pathlib import Path -ROOT = Path(__file__).resolve().parents[1] -MODULE_PATH = ROOT / "scripts" / "check_internal_dependency_matrix.py" +ROOT = Path(__file__).resolve().parents[2] +MODULE_PATH = ROOT / "python" / "scripts" / "check_internal_dependency_matrix.py" SPEC = importlib.util.spec_from_file_location("check_internal_dependency_matrix", MODULE_PATH) check_internal_dependency_matrix = importlib.util.module_from_spec(SPEC) assert SPEC.loader is not None diff --git a/tests/test_runtime_settings.py b/python/tests/test_runtime_settings.py similarity index 99% rename from tests/test_runtime_settings.py rename to python/tests/test_runtime_settings.py index 1a86fa2..439c4b0 100644 --- a/tests/test_runtime_settings.py +++ b/python/tests/test_runtime_settings.py @@ -10,15 +10,15 @@ from unittest.mock import patch -ROOT = Path(__file__).resolve().parents[1] -MODULE_PATH = ROOT / "scripts" / "runtime_settings.py" +ROOT = Path(__file__).resolve().parents[2] +MODULE_PATH = ROOT / "python" / "scripts" / "runtime_settings.py" SPEC = importlib.util.spec_from_file_location("runtime_settings", MODULE_PATH) runtime_settings = importlib.util.module_from_spec(SPEC) assert SPEC.loader is not None sys.modules[SPEC.name] = runtime_settings SPEC.loader.exec_module(runtime_settings) -SWITCH_MODULE_PATH = ROOT / "scripts" / "build_runtime_switch.py" +SWITCH_MODULE_PATH = ROOT / "python" / "scripts" / "build_runtime_switch.py" SWITCH_SPEC = importlib.util.spec_from_file_location("build_runtime_switch", SWITCH_MODULE_PATH) build_runtime_switch = importlib.util.module_from_spec(SWITCH_SPEC) assert SWITCH_SPEC.loader is not None @@ -263,7 +263,7 @@ def test_strategy_switch_console_deploy_workflow_syncs_bundled_profiles(self): self.assertIn("STRATEGY_SWITCH_SYNC_TOKEN", workflow) self.assertIn("CLOUDFLARE_WRANGLER_CONFIG_TOML", workflow) self.assertIn("STRATEGY_SWITCH_CONFIG_KV_NAMESPACE_ID", workflow) - self.assertIn("scripts/sync_strategy_switch_page_asset.py", workflow) + self.assertIn("python/scripts/sync_strategy_switch_page_asset.py", workflow) def test_plugin_mount_schema_version_must_be_non_empty_string(self): _, target = self.load_target("examples/targets/schwab/live.example.json")