graphmdo 0.2.0__tar.gz → 2.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (155) hide show
  1. graphmdo-2.0.0/.github/workflows/latest-dependencies.yml +26 -0
  2. graphmdo-2.0.0/.github/workflows/quality.yml +100 -0
  3. graphmdo-2.0.0/.github/workflows/security.yml +55 -0
  4. {graphmdo-0.2.0 → graphmdo-2.0.0}/.gitignore +7 -2
  5. graphmdo-2.0.0/AGENTS.md +105 -0
  6. graphmdo-2.0.0/Dockerfile +56 -0
  7. graphmdo-2.0.0/LICENSE +373 -0
  8. graphmdo-2.0.0/PKG-INFO +263 -0
  9. graphmdo-2.0.0/README.md +239 -0
  10. graphmdo-2.0.0/docker-compose.yml +70 -0
  11. graphmdo-2.0.0/docs/api/core/errors.md +3 -0
  12. graphmdo-2.0.0/docs/api/core/mda.md +3 -0
  13. graphmdo-2.0.0/docs/api/optimization/bo_library.md +28 -0
  14. graphmdo-2.0.0/docs/api/optimization/optimizer.md +24 -0
  15. graphmdo-2.0.0/docs/api/schema.md +5 -0
  16. graphmdo-2.0.0/docs/api/validation.md +7 -0
  17. {graphmdo-0.2.0 → graphmdo-2.0.0}/docs/dev-guide/contributing.md +7 -2
  18. graphmdo-2.0.0/docs/dev-guide/releasing.md +34 -0
  19. {graphmdo-0.2.0 → graphmdo-2.0.0}/docs/index.md +3 -3
  20. graphmdo-2.0.0/docs/technical-reference/architecture.md +96 -0
  21. graphmdo-2.0.0/docs/technical-reference/microservices.md +47 -0
  22. graphmdo-2.0.0/docs/technical-reference/study-schema.json +394 -0
  23. graphmdo-2.0.0/docs/technical-reference/study-schema.md +316 -0
  24. {graphmdo-0.2.0 → graphmdo-2.0.0}/docs/user-guide/installation.md +4 -2
  25. graphmdo-2.0.0/docs/user-guide/quick-start.md +127 -0
  26. graphmdo-2.0.0/docs/user-guide/running-optimization.md +151 -0
  27. {graphmdo-0.2.0 → graphmdo-2.0.0}/main.py +24 -17
  28. {graphmdo-0.2.0 → graphmdo-2.0.0}/mkdocs.yml +9 -1
  29. {graphmdo-0.2.0 → graphmdo-2.0.0}/pyproject.toml +15 -13
  30. graphmdo-2.0.0/src/mdo_framework/__init__.py +5 -0
  31. graphmdo-2.0.0/src/mdo_framework/core/__init__.py +5 -0
  32. graphmdo-2.0.0/src/mdo_framework/core/components.py +206 -0
  33. graphmdo-2.0.0/src/mdo_framework/core/components.py,cover +77 -0
  34. graphmdo-2.0.0/src/mdo_framework/core/dependencies.py +130 -0
  35. graphmdo-2.0.0/src/mdo_framework/core/errors.py +124 -0
  36. graphmdo-2.0.0/src/mdo_framework/core/evaluators.py +56 -0
  37. graphmdo-2.0.0/src/mdo_framework/core/evaluators.py,cover +42 -0
  38. graphmdo-2.0.0/src/mdo_framework/core/mda.py +166 -0
  39. {graphmdo-0.2.0 → graphmdo-2.0.0}/src/mdo_framework/core/surrogates.py +6 -0
  40. graphmdo-2.0.0/src/mdo_framework/core/surrogates.py,cover +72 -0
  41. graphmdo-2.0.0/src/mdo_framework/core/topology.py +143 -0
  42. graphmdo-2.0.0/src/mdo_framework/core/topology.py,cover +105 -0
  43. graphmdo-2.0.0/src/mdo_framework/core/translator.py +149 -0
  44. graphmdo-2.0.0/src/mdo_framework/core/translator.py,cover +70 -0
  45. graphmdo-2.0.0/src/mdo_framework/db/__init__.py +5 -0
  46. {graphmdo-0.2.0 → graphmdo-2.0.0}/src/mdo_framework/db/client.py +6 -0
  47. graphmdo-2.0.0/src/mdo_framework/db/client.py,cover +38 -0
  48. graphmdo-2.0.0/src/mdo_framework/db/graph_manager.py +550 -0
  49. graphmdo-2.0.0/src/mdo_framework/db/graph_manager.py,cover +240 -0
  50. graphmdo-2.0.0/src/mdo_framework/optimization/__init__.py +5 -0
  51. graphmdo-2.0.0/src/mdo_framework/optimization/ax_algo_lib.py +298 -0
  52. graphmdo-2.0.0/src/mdo_framework/optimization/ax_algo_lib.py,cover +216 -0
  53. graphmdo-2.0.0/src/mdo_framework/optimization/bo_library.py +440 -0
  54. graphmdo-2.0.0/src/mdo_framework/optimization/bo_types.py +646 -0
  55. graphmdo-2.0.0/src/mdo_framework/optimization/errors.py +33 -0
  56. graphmdo-2.0.0/src/mdo_framework/optimization/optimizer.py +603 -0
  57. graphmdo-2.0.0/src/mdo_framework/optimization/optimizer.py,cover +266 -0
  58. graphmdo-2.0.0/src/mdo_framework/optimization/parameter_codec.py +141 -0
  59. graphmdo-2.0.0/src/mdo_framework/optimization/random_search.py +130 -0
  60. graphmdo-2.0.0/src/mdo_framework/schema.py +569 -0
  61. graphmdo-2.0.0/src/mdo_framework/validation.py +711 -0
  62. graphmdo-2.0.0/src/services/__init__.py +5 -0
  63. graphmdo-2.0.0/src/services/errors.py +39 -0
  64. graphmdo-2.0.0/src/services/execution/__init__.py +5 -0
  65. {graphmdo-0.2.0 → graphmdo-2.0.0}/src/services/execution/main.py +65 -48
  66. graphmdo-2.0.0/src/services/execution/main.py,cover +428 -0
  67. graphmdo-2.0.0/src/services/graph/__init__.py +5 -0
  68. graphmdo-2.0.0/src/services/graph/main.py +205 -0
  69. graphmdo-2.0.0/src/services/graph/main.py,cover +115 -0
  70. graphmdo-2.0.0/src/services/optimization/__init__.py +5 -0
  71. graphmdo-2.0.0/src/services/optimization/main.py +246 -0
  72. graphmdo-2.0.0/src/services/optimization/main.py,cover +165 -0
  73. {graphmdo-0.2.0 → graphmdo-2.0.0}/tests/conftest.py +26 -3
  74. graphmdo-2.0.0/tests/e2e/conftest.py +174 -0
  75. graphmdo-2.0.0/tests/e2e/test_budget.py +128 -0
  76. graphmdo-2.0.0/tests/e2e/test_choices.py +142 -0
  77. graphmdo-2.0.0/tests/e2e/test_failures.py +129 -0
  78. graphmdo-2.0.0/tests/e2e/test_graph.py +155 -0
  79. graphmdo-2.0.0/tests/e2e/test_objectives.py +107 -0
  80. graphmdo-2.0.0/tests/e2e/test_reproducibility.py +32 -0
  81. graphmdo-2.0.0/tests/e2e/test_service.py +213 -0
  82. graphmdo-2.0.0/tests/fakes/__init__.py +5 -0
  83. graphmdo-2.0.0/tests/fakes/falkordb.py +279 -0
  84. graphmdo-2.0.0/tests/smoke/compose_walkthrough.py +63 -0
  85. graphmdo-2.0.0/tests/smoke/test_installed_wheel.py +49 -0
  86. graphmdo-2.0.0/tests/test_ax_algo_lib.py +509 -0
  87. graphmdo-2.0.0/tests/test_bo_library.py +940 -0
  88. graphmdo-2.0.0/tests/test_bo_types.py +692 -0
  89. graphmdo-2.0.0/tests/test_components.py +541 -0
  90. {graphmdo-0.2.0 → graphmdo-2.0.0}/tests/test_db_client.py +6 -0
  91. graphmdo-2.0.0/tests/test_dependencies.py +267 -0
  92. graphmdo-2.0.0/tests/test_deployment.py +89 -0
  93. graphmdo-2.0.0/tests/test_docs_schema.py +34 -0
  94. graphmdo-2.0.0/tests/test_errors.py +116 -0
  95. graphmdo-2.0.0/tests/test_graph_manager.py +813 -0
  96. graphmdo-2.0.0/tests/test_main.py +60 -0
  97. graphmdo-2.0.0/tests/test_mda.py +576 -0
  98. graphmdo-2.0.0/tests/test_optimization_errors.py +31 -0
  99. graphmdo-2.0.0/tests/test_optimizer.py +954 -0
  100. graphmdo-2.0.0/tests/test_parameter_codec.py +140 -0
  101. graphmdo-2.0.0/tests/test_schema.py +884 -0
  102. graphmdo-2.0.0/tests/test_services.py +2168 -0
  103. {graphmdo-0.2.0 → graphmdo-2.0.0}/tests/test_services_opt.py +6 -0
  104. {graphmdo-0.2.0 → graphmdo-2.0.0}/tests/test_surrogates.py +6 -0
  105. graphmdo-2.0.0/tests/test_tool_values.py +138 -0
  106. graphmdo-2.0.0/tests/test_topology.py +262 -0
  107. graphmdo-2.0.0/tests/test_translator.py +526 -0
  108. graphmdo-2.0.0/tests/test_validation.py +1115 -0
  109. {graphmdo-0.2.0 → graphmdo-2.0.0}/uv.lock +802 -577
  110. graphmdo-0.2.0/.github/workflows/quality.yml +0 -29
  111. graphmdo-0.2.0/.github/workflows/security.yml +0 -44
  112. graphmdo-0.2.0/AGENTS.md +0 -38
  113. graphmdo-0.2.0/Dockerfile +0 -35
  114. graphmdo-0.2.0/LICENSE +0 -21
  115. graphmdo-0.2.0/PKG-INFO +0 -143
  116. graphmdo-0.2.0/README.md +0 -122
  117. graphmdo-0.2.0/docker-compose.yml +0 -41
  118. graphmdo-0.2.0/docs/api/optimization/optimizer.md +0 -15
  119. graphmdo-0.2.0/docs/technical-reference/architecture.md +0 -45
  120. graphmdo-0.2.0/docs/technical-reference/microservices.md +0 -24
  121. graphmdo-0.2.0/docs/user-guide/quick-start.md +0 -89
  122. graphmdo-0.2.0/docs/user-guide/running-optimization.md +0 -58
  123. graphmdo-0.2.0/src/mdo_framework/__init__.py +0 -0
  124. graphmdo-0.2.0/src/mdo_framework/core/__init__.py +0 -0
  125. graphmdo-0.2.0/src/mdo_framework/core/components.py +0 -85
  126. graphmdo-0.2.0/src/mdo_framework/core/evaluators.py +0 -33
  127. graphmdo-0.2.0/src/mdo_framework/core/topology.py +0 -99
  128. graphmdo-0.2.0/src/mdo_framework/core/translator.py +0 -80
  129. graphmdo-0.2.0/src/mdo_framework/db/__init__.py +0 -0
  130. graphmdo-0.2.0/src/mdo_framework/db/graph_manager.py +0 -226
  131. graphmdo-0.2.0/src/mdo_framework/optimization/__init__.py +0 -0
  132. graphmdo-0.2.0/src/mdo_framework/optimization/optimizer.py +0 -274
  133. graphmdo-0.2.0/src/services/__init__.py +0 -0
  134. graphmdo-0.2.0/src/services/execution/__init__.py +0 -0
  135. graphmdo-0.2.0/src/services/graph/__init__.py +0 -0
  136. graphmdo-0.2.0/src/services/graph/main.py +0 -109
  137. graphmdo-0.2.0/src/services/optimization/__init__.py +0 -0
  138. graphmdo-0.2.0/src/services/optimization/main.py +0 -159
  139. graphmdo-0.2.0/tests/test_components.py +0 -171
  140. graphmdo-0.2.0/tests/test_graph_manager.py +0 -199
  141. graphmdo-0.2.0/tests/test_integration.py +0 -64
  142. graphmdo-0.2.0/tests/test_main.py +0 -47
  143. graphmdo-0.2.0/tests/test_optimizer.py +0 -209
  144. graphmdo-0.2.0/tests/test_services.py +0 -969
  145. graphmdo-0.2.0/tests/test_topology.py +0 -70
  146. graphmdo-0.2.0/tests/test_translator.py +0 -88
  147. {graphmdo-0.2.0 → graphmdo-2.0.0}/.github/workflows/docs.yml +0 -0
  148. {graphmdo-0.2.0 → graphmdo-2.0.0}/.github/workflows/pypi-publish.yml +0 -0
  149. {graphmdo-0.2.0 → graphmdo-2.0.0}/.pre-commit-config.yaml +0 -0
  150. {graphmdo-0.2.0 → graphmdo-2.0.0}/.python-version +0 -0
  151. {graphmdo-0.2.0 → graphmdo-2.0.0}/docs/api/core/components.md +0 -0
  152. {graphmdo-0.2.0 → graphmdo-2.0.0}/docs/api/core/surrogates.md +0 -0
  153. {graphmdo-0.2.0 → graphmdo-2.0.0}/docs/api/core/translator.md +0 -0
  154. {graphmdo-0.2.0 → graphmdo-2.0.0}/docs/api/db/client.md +0 -0
  155. {graphmdo-0.2.0 → graphmdo-2.0.0}/docs/api/db/graph_manager.md +0 -0
@@ -0,0 +1,26 @@
1
+ name: Latest Allowed Dependencies
2
+
3
+ on:
4
+ schedule:
5
+ - cron: "0 5 * * 0"
6
+ workflow_dispatch:
7
+
8
+ jobs:
9
+ test-latest:
10
+ runs-on: ubuntu-latest
11
+ steps:
12
+ - uses: actions/checkout@v4
13
+ - name: Install uv
14
+ uses: astral-sh/setup-uv@v5
15
+ - name: Set up Python
16
+ uses: actions/setup-python@v5
17
+ with:
18
+ python-version: "3.12"
19
+ - name: Upgrade dependency resolution
20
+ run: uv lock --upgrade
21
+ - name: Install upgraded dependencies
22
+ run: uv sync --all-extras --dev
23
+ - name: Run test suite
24
+ env:
25
+ PYTHONPATH: .
26
+ run: uv run pytest tests/
@@ -0,0 +1,100 @@
1
+ name: Quality Checks
2
+
3
+ on: [push, pull_request]
4
+
5
+ jobs:
6
+ quality:
7
+ runs-on: ubuntu-latest
8
+ steps:
9
+ - uses: actions/checkout@v4
10
+ - name: Install uv
11
+ uses: astral-sh/setup-uv@v5
12
+ - name: Set up Python
13
+ uses: actions/setup-python@v5
14
+ with:
15
+ python-version: "3.12"
16
+ - name: Install dependencies
17
+ run: uv sync --frozen --all-extras --dev
18
+ - name: Run Ruff
19
+ run: uv run ruff check .
20
+ - name: Run Tests
21
+ env:
22
+ PYTHONPATH: .
23
+ run: uv run pytest -m "not e2e" --cov=src/mdo_framework --cov=src/services --cov-report=xml tests/
24
+ - name: Upload coverage to Codecov
25
+ uses: codecov/codecov-action@v5
26
+ with:
27
+ token: ${{ secrets.CODECOV_TOKEN }}
28
+ files: ./coverage.xml
29
+ flags: unit
30
+ fail_ci_if_error: false
31
+
32
+ e2e:
33
+ name: End-to-end regression suite (real Ax + GEMSEO)
34
+ runs-on: ubuntu-latest
35
+ timeout-minutes: 15
36
+ steps:
37
+ - uses: actions/checkout@v4
38
+ - name: Install uv
39
+ uses: astral-sh/setup-uv@v5
40
+ - name: Set up Python
41
+ uses: actions/setup-python@v5
42
+ with:
43
+ python-version: "3.12"
44
+ - name: Install dependencies
45
+ run: uv sync --frozen --all-extras --dev
46
+ - name: Run end-to-end tests
47
+ env:
48
+ OMP_NUM_THREADS: "1"
49
+ PYTHONPATH: .
50
+ run: uv run pytest -m e2e --durations=10 --cov=src/mdo_framework --cov=src/services --cov-report=xml tests/
51
+ - name: Upload coverage to Codecov
52
+ uses: codecov/codecov-action@v5
53
+ with:
54
+ token: ${{ secrets.CODECOV_TOKEN }}
55
+ files: ./coverage.xml
56
+ flags: e2e
57
+ fail_ci_if_error: false
58
+
59
+ wheel-smoke:
60
+ name: Installed wheel optimization smoke test
61
+ runs-on: ubuntu-latest
62
+ steps:
63
+ - uses: actions/checkout@v4
64
+ - name: Install uv
65
+ uses: astral-sh/setup-uv@v5
66
+ - name: Set up Python
67
+ uses: actions/setup-python@v5
68
+ with:
69
+ python-version: "3.12"
70
+ - name: Build wheel
71
+ run: uv build
72
+ - name: Create clean environment
73
+ run: uv venv --python 3.12 .venv-wheel-smoke
74
+ - name: Install wheel and test runner without lockfile
75
+ run: uv pip install --python .venv-wheel-smoke dist/*.whl pytest
76
+ - name: Run installed-wheel smoke test
77
+ run: .venv-wheel-smoke/bin/python -m pytest tests/smoke/test_installed_wheel.py -q
78
+
79
+ compose-smoke:
80
+ name: Docker Compose walkthrough smoke test
81
+ runs-on: ubuntu-latest
82
+ steps:
83
+ - uses: actions/checkout@v4
84
+ - name: Start the stack and wait for healthy services
85
+ run: docker compose up -d --build --wait --wait-timeout 300
86
+ - name: Image has no dev dependencies
87
+ run: |
88
+ if docker compose exec -T graph-service python -c "import pytest"; then
89
+ echo "pytest must not be installed in the runtime image"; exit 1
90
+ fi
91
+ - name: Install uv
92
+ uses: astral-sh/setup-uv@v5
93
+ - name: Replay the documented walkthrough
94
+ run: uv run --no-project --python 3.12 --with httpx python tests/smoke/compose_walkthrough.py
95
+ - name: Service logs
96
+ if: failure()
97
+ run: docker compose logs
98
+ - name: Tear down
99
+ if: always()
100
+ run: docker compose down -v
@@ -0,0 +1,55 @@
1
+ name: Security Scan
2
+
3
+ on:
4
+ push:
5
+ branches: [ "main" ]
6
+ pull_request:
7
+ branches: [ "main" ]
8
+
9
+ env:
10
+ FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
11
+
12
+ jobs:
13
+ build:
14
+ name: Build
15
+ runs-on: ubuntu-latest
16
+ permissions:
17
+ contents: read
18
+ security-events: write
19
+ steps:
20
+ - name: Free Disk Space (Ubuntu)
21
+ uses: jlumbroso/free-disk-space@main
22
+ with:
23
+ tool-cache: false
24
+ android: true
25
+ dotnet: true
26
+ haskell: true
27
+ large-packages: true
28
+ docker-images: true
29
+ swap-storage: true
30
+
31
+ - name: Setup Docker
32
+ uses: docker/setup-buildx-action@v3
33
+
34
+ - name: Checkout code
35
+ uses: actions/checkout@v4
36
+
37
+ - name: Build an image from Dockerfile
38
+ run: |
39
+ docker build -t docker.io/my-organization/my-app:${{ github.sha }} .
40
+
41
+ - name: Scan image for vulnerabilities
42
+ uses: anchore/scan-action@v7.4.2
43
+ id: scan
44
+ with:
45
+ image: 'docker.io/my-organization/my-app:${{ github.sha }}'
46
+ fail-build: true
47
+ severity-cutoff: high
48
+ output-format: sarif
49
+ only-fixed: true
50
+
51
+ - name: Upload vulnerability report
52
+ uses: github/codeql-action/upload-sarif@v4
53
+ if: always() && steps.scan.outputs.sarif != ''
54
+ with:
55
+ sarif_file: ${{ steps.scan.outputs.sarif }}
@@ -201,12 +201,17 @@ cython_debug/
201
201
  .cursorignore
202
202
  .cursorindexingignore
203
203
 
204
+ # VS Code settings
205
+ .vscode/
206
+ .agents/
207
+
204
208
  # Marimo
205
209
  marimo/_static/
206
210
  marimo/_lsp/
207
211
  __marimo__/
208
212
 
209
- # OpenMDAO Test Artifacts
213
+ # GEMSEO Test Artifacts
210
214
  pytest*_out/
211
- *.openmdao_out
212
215
  reports/
216
+ xdsm.html
217
+ opt_history*.png
@@ -0,0 +1,105 @@
1
+ # AGENTS.md
2
+
3
+ ## Strict Coding Standards
4
+
5
+ 1. **PEP 20 (The Zen of Python)**
6
+ - Explicit is better than implicit.
7
+ - Simple is better than complex.
8
+ - Readability counts.
9
+
10
+ 2. **PEP 8 (Style Guide for Python Code)**
11
+ - Indentation: 4 spaces.
12
+ - Line Length: 88 characters.
13
+ - Naming Conventions:
14
+ - Functions/Variables: `lowercase_with_underscores`
15
+ - Classes: `CapitalizedWords`
16
+ - Constants: `ALL_CAPS_WITH_UNDERSCORES`
17
+ - Imports: Standard library, third-party, local application.
18
+ - Type Hinting: Use explicit Python 3 type hints.
19
+
20
+ 3. **Typing and Interfaces**
21
+ - Target Python 3.12+ syntax (`X | None`, `list[str]`, `dict[str, Any]`).
22
+ - Keep FastAPI request/response contracts explicit with Pydantic models.
23
+ - Prefer small, composable functions over hidden side effects.
24
+
25
+ ## Current Codebase Overview
26
+
27
+ - `main.py` is the local paraboloid demo wiring `GraphManager` -> `GraphProblemBuilder` -> `LocalEvaluator` -> `BayesianOptimizer`.
28
+ - `src/mdo_framework/schema.py` defines the typed `StudySchema` contract (`RangeVar`, `ChoiceVar`, `FixedParam`, `StateVar`, `ToolNode`, `Finding`, `ValidationReport`, `StudyValidationError`).
29
+ - `src/mdo_framework/validation.py` holds `validate_study()` (preflight against a request) and `validate_registry()` (tool registry and signature checks); `core/dependencies.py` is the shared dependency walk.
30
+ - `src/mdo_framework/db/` contains the FalkorDB integration (`client.py`, `graph_manager.py`).
31
+ - `src/mdo_framework/core/` contains schema-to-GEMSEO translation and execution helpers (`components.py`, `dependencies.py`, `errors.py`, `evaluators.py`, `mda.py`, `surrogates.py`, `topology.py`, `translator.py`).
32
+ - `src/mdo_framework/optimization/` contains the optimizer orchestration (`optimizer.py`), the backend-neutral Bayesian-optimization driver (`bo_library.py`, `bo_types.py`, `errors.py`) and its backends: Ax (`ax_algo_lib.py`) and a seeded random search (`random_search.py`).
33
+ - `src/services/graph/main.py` exposes the typed Graph Service API: `POST/PUT/DELETE` on `/variables` and `/tools`, `/connections/input`, `/connections/output`, `/schema`, `/clear`, `/health`. Conflicts return `409`, unknown nodes `404`, invalid bodies `422`.
34
+ - `src/services/execution/main.py` exposes the Execution Service API: `/evaluate`, `/health`, plus schema caching, a registry check on each loaded schema (`422` `SCHEMA_INVALID`), and pooled problem instances.
35
+ - `src/services/optimization/main.py` exposes the Optimization Service API: `/optimize` (with a `422` validation preflight), `/validate`, `/health`.
36
+ - `src/services/errors.py` registers the shared request-validation handler (`422` without echoing input) on all three services.
37
+ - `tests/` covers the core modules, services, database layer, optimizer, topology, translator, and the top-level demo entry point.
38
+ - `tests/e2e/` holds the seeded, non-mocked Ax + GEMSEO regression suite (marker `e2e`); open bugs are pinned there as strict xfails.
39
+
40
+ ## Runtime Architecture
41
+
42
+ 1. **Graph Layer**
43
+ - FalkorDB stores variables, tools, and directed data-flow edges.
44
+ - `GraphManager.get_study_schema()` returns the typed `StudySchema`, the canonical boundary exported to the rest of the system.
45
+
46
+ 2. **Translation Layer**
47
+ - `GraphProblemBuilder` builds GEMSEO problems from the `StudySchema`: one `ToolComponent` per tool (strict output contract, finite-difference Jacobians) chained in a `StrictMDAChain` (`core/mda.py`).
48
+ - Coupled tools run sequentially (Gauss-Seidel) by default; `MDASettings` selects the algorithm, and a coupled group that does not converge raises `MDANotConvergedError`.
49
+ - `TopologicalAnalyzer` resolves dependencies and extracts optimization parameters from requested outputs.
50
+
51
+ 3. **Evaluation Layer**
52
+ - Local execution uses `LocalEvaluator`.
53
+ - Remote execution uses the Execution Service, which maintains a `SchemaProvider` cache and a `ProblemPool` of initialized GEMSEO problems.
54
+
55
+ 4. **Optimization Layer**
56
+ - `BayesianOptimizer` builds the GEMSEO scenario and runs a `BaseBOLibrary` backend (`Ax_Bayesian` by default, `BO_RandomSearch`).
57
+ - `BaseBOLibrary` owns the budget (`n_init + n_steps`, plus x0 when evaluated), stopping, failure classification, the guarded start point, user-name metric bindings and constraint feasibility; backends implement only `_setup`, `_ask` and `_tell`.
58
+
59
+ 5. **Service Deployment**
60
+ - `docker-compose.yml` runs FalkorDB plus three FastAPI services.
61
+ - Default ports are 8001 (graph), 8002 (execution), and 8003 (optimization).
62
+
63
+ ## Implementation Directives
64
+
65
+ - **StudySchema Is the Source of Truth**: Flow data from FalkorDB through `get_study_schema()` into validation, topology analysis, translation, and services. Do not reintroduce untyped dict schemas.
66
+ - **Validate Before Running**: Study-level checks belong in `validate_study()` and tool-registry checks in `validate_registry()`; add new findings there with a stable error code and document them in `docs/technical-reference/study-schema.md`.
67
+ - **Keep the Published JSON Schema in Sync**: After changing `schema.py`, regenerate `docs/technical-reference/study-schema.json` with the command printed by `tests/test_docs_schema.py`.
68
+ - **Preserve Design Variable Order**: Keep FalkorDB insertion order for design variables; do not sort parameter names alphabetically before execution or optimization.
69
+ - **Use Keyword-Based Tool Invocation**: Wrapped tool functions must receive named inputs, not positional fallbacks that can scramble graph-defined ordering.
70
+ - **Raise Typed Evaluation Errors**: A point that cannot be evaluated raises an `EvaluationError` subclass from `core/errors.py` (`ToolExecutionError`, `ToolOutputError`, `MDANotConvergedError`), never a bare exception or a silently returned invalid value; services serialize them with `to_payload()`.
71
+ - **Keep Optimization State Explicit**: The library's `result` (`BORunResult`: trial records, stop reason, best trial, Pareto front) is the authoritative optimization output; avoid hidden cross-object attributes.
72
+ - **Keep Backends Thin**: Stopping, NaN handling, x0, metric naming and feasibility belong in `BaseBOLibrary`; a new backend implements only `_setup`, `_ask` and `_tell` and must pass the shared contract tests.
73
+ - **Respect Constraint Semantics**: Current optimization code uses GEMSEO/Ax convention `g(x) <= 0`; the paraboloid example encodes `c_xy = x - y`.
74
+ - **Extend Service Infrastructure, Do Not Bypass It**: Schema refresh/backoff belongs in `SchemaProvider`; reusable GEMSEO instances belong in `ProblemPool`.
75
+ - **Preserve Service Boundaries**: Cross-service calls should flow through `GRAPH_SERVICE_URL` and `EXECUTION_SERVICE_URL`, matching local and Docker Compose deployment.
76
+
77
+ ## Dependency Management
78
+
79
+ - This project uses `uv` for dependency management.
80
+ - Core runtime stack includes FalkorDB, FastAPI, GEMSEO, SMT, Ax Platform, BoTorch, pymoo, httpx, and NumPy/SciPy.
81
+ - Install project dependencies with `uv sync`.
82
+ - Install development dependencies with `uv sync --all-extras --dev`.
83
+ - Add a dependency with `uv add <package_name>`.
84
+ - Run commands in the environment with `uv run <command>`.
85
+ - **Do not use pip install manually.**
86
+
87
+ ## Development Commands
88
+
89
+ - Run the local demo: `uv run python main.py`
90
+ - Start the Graph Service: `uv run uvicorn services.graph.main:app --host 0.0.0.0 --port 8001`
91
+ - Start the Execution Service: `uv run uvicorn services.execution.main:app --host 0.0.0.0 --port 8002`
92
+ - Start the Optimization Service: `uv run uvicorn services.optimization.main:app --host 0.0.0.0 --port 8003`
93
+ - Start the full stack with containers: `docker compose up --build`
94
+
95
+ ## Validation and Docs
96
+
97
+ - Run all tests with `uv run pytest tests/`.
98
+ - Run fast unit tests with `uv run pytest -m "not e2e" tests/`.
99
+ - Run the real Ax + GEMSEO suite with `OMP_NUM_THREADS=1 uv run pytest -m e2e tests/`.
100
+ - Tests that pin an open bug are `xfail(strict=True)` with the issue number in the
101
+ reason; the PR that fixes the bug removes the marker.
102
+ - Run lint checks with `uv run ruff check .`.
103
+ - Format code with `uv run ruff format .`.
104
+ - Serve documentation locally with `uv run mkdocs serve`.
105
+ - Documentation lives under `docs/` and is built with MkDocs Material.
@@ -0,0 +1,56 @@
1
+ # Stage 1: Build stage
2
+ FROM python:3.12-slim AS builder
3
+
4
+ # Grab uv directly from astral's image
5
+ COPY --from=ghcr.io/astral-sh/uv:latest /uv /bin/
6
+
7
+ # Docker-specific uv optimizations
8
+ ENV UV_COMPILE_BYTECODE=1
9
+ ENV UV_LINK_MODE=copy
10
+
11
+ # Pass a dummy version to setuptools-scm during the docker build to prevent failures
12
+ ENV SETUPTOOLS_SCM_PRETEND_VERSION="0.0.0"
13
+
14
+ WORKDIR /app
15
+
16
+ # Copy dependency files FIRST
17
+ COPY pyproject.toml uv.lock README.md ./
18
+
19
+ # Install dependencies into a virtual environment
20
+ RUN uv sync --frozen --no-dev --no-install-project
21
+
22
+ # Copy your source code
23
+ COPY src/ src/
24
+
25
+ # Install the project itself
26
+ RUN uv sync --frozen --no-dev
27
+
28
+
29
+ # Stage 2: Final runtime stage
30
+ FROM python:3.12-slim
31
+
32
+ # Update OS packages to fix vulnerabilities
33
+ RUN apt-get update && apt-get upgrade -y && rm -rf /var/lib/apt/lists/*
34
+
35
+ # Security: Ensure uv/uvx are NOT present in the final image
36
+ RUN rm -f /usr/bin/uv /usr/bin/uvx /bin/uv /bin/uvx
37
+
38
+ WORKDIR /app
39
+
40
+ # Security: Create and use a non-root user
41
+ RUN useradd -m appuser
42
+ RUN chown appuser:appuser /app
43
+ USER appuser
44
+
45
+ # Copy the virtual environment and the source code from the builder stage
46
+ COPY --from=builder --chown=appuser:appuser /app/.venv /app/.venv
47
+ COPY --from=builder --chown=appuser:appuser /app/src /app/src
48
+
49
+ # Set environment variables to use the virtual environment
50
+ ENV PATH="/app/.venv/bin:$PATH"
51
+
52
+ # Graph, execution and optimization services (see docker-compose.yml)
53
+ EXPOSE 8001 8002 8003
54
+
55
+ # Default command
56
+ CMD ["uvicorn", "services.graph.main:app", "--host", "0.0.0.0", "--port", "8001"]