kaos-ml-core 0.1.0a1__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 (75) hide show
  1. kaos_ml_core-0.1.0a1/.github/CODEOWNERS +16 -0
  2. kaos_ml_core-0.1.0a1/.github/ISSUE_TEMPLATE/bug.yml +59 -0
  3. kaos_ml_core-0.1.0a1/.github/ISSUE_TEMPLATE/config.yml +5 -0
  4. kaos_ml_core-0.1.0a1/.github/ISSUE_TEMPLATE/feature.yml +26 -0
  5. kaos_ml_core-0.1.0a1/.github/PULL_REQUEST_TEMPLATE.md +23 -0
  6. kaos_ml_core-0.1.0a1/.github/dependabot.yml +56 -0
  7. kaos_ml_core-0.1.0a1/.github/workflows/ci.yml +270 -0
  8. kaos_ml_core-0.1.0a1/.github/workflows/release.yml +241 -0
  9. kaos_ml_core-0.1.0a1/.github/workflows/security.yml +113 -0
  10. kaos_ml_core-0.1.0a1/.gitignore +44 -0
  11. kaos_ml_core-0.1.0a1/.pre-commit-config.yaml +76 -0
  12. kaos_ml_core-0.1.0a1/CHANGELOG.md +158 -0
  13. kaos_ml_core-0.1.0a1/Cargo.lock +133 -0
  14. kaos_ml_core-0.1.0a1/Cargo.toml +44 -0
  15. kaos_ml_core-0.1.0a1/LICENSE +201 -0
  16. kaos_ml_core-0.1.0a1/NOTICE +8 -0
  17. kaos_ml_core-0.1.0a1/PKG-INFO +401 -0
  18. kaos_ml_core-0.1.0a1/README.md +355 -0
  19. kaos_ml_core-0.1.0a1/SECURITY.md +58 -0
  20. kaos_ml_core-0.1.0a1/deny.toml +58 -0
  21. kaos_ml_core-0.1.0a1/pyproject.toml +171 -0
  22. kaos_ml_core-0.1.0a1/python/kaos_ml_core/__init__.py +96 -0
  23. kaos_ml_core-0.1.0a1/python/kaos_ml_core/__main__.py +6 -0
  24. kaos_ml_core-0.1.0a1/python/kaos_ml_core/_rust/__init__.pyi +12 -0
  25. kaos_ml_core-0.1.0a1/python/kaos_ml_core/aggregate.py +267 -0
  26. kaos_ml_core-0.1.0a1/python/kaos_ml_core/cli.py +56 -0
  27. kaos_ml_core-0.1.0a1/python/kaos_ml_core/cluster.py +140 -0
  28. kaos_ml_core-0.1.0a1/python/kaos_ml_core/corpus.py +820 -0
  29. kaos_ml_core-0.1.0a1/python/kaos_ml_core/errors.py +45 -0
  30. kaos_ml_core-0.1.0a1/python/kaos_ml_core/features.py +96 -0
  31. kaos_ml_core-0.1.0a1/python/kaos_ml_core/index.py +498 -0
  32. kaos_ml_core-0.1.0a1/python/kaos_ml_core/label.py +123 -0
  33. kaos_ml_core-0.1.0a1/python/kaos_ml_core/metrics.py +389 -0
  34. kaos_ml_core-0.1.0a1/python/kaos_ml_core/pipeline.py +486 -0
  35. kaos_ml_core-0.1.0a1/python/kaos_ml_core/predict.py +135 -0
  36. kaos_ml_core-0.1.0a1/python/kaos_ml_core/py.typed +0 -0
  37. kaos_ml_core-0.1.0a1/python/kaos_ml_core/serve.py +20 -0
  38. kaos_ml_core-0.1.0a1/python/kaos_ml_core/settings.py +53 -0
  39. kaos_ml_core-0.1.0a1/python/kaos_ml_core/split.py +170 -0
  40. kaos_ml_core-0.1.0a1/python/kaos_ml_core/threshold.py +228 -0
  41. kaos_ml_core-0.1.0a1/python/kaos_ml_core/tools.py +1163 -0
  42. kaos_ml_core-0.1.0a1/python/kaos_ml_core/train.py +158 -0
  43. kaos_ml_core-0.1.0a1/rust/bindings/mod.rs +7 -0
  44. kaos_ml_core-0.1.0a1/rust/bindings/version.rs +15 -0
  45. kaos_ml_core-0.1.0a1/rust/core/mod.rs +8 -0
  46. kaos_ml_core-0.1.0a1/rust/core/version.rs +18 -0
  47. kaos_ml_core-0.1.0a1/rust/lib.rs +47 -0
  48. kaos_ml_core-0.1.0a1/tests/__init__.py +0 -0
  49. kaos_ml_core-0.1.0a1/tests/benchmarks/__init__.py +0 -0
  50. kaos_ml_core-0.1.0a1/tests/benchmarks/test_corpus_benchmarks.py +129 -0
  51. kaos_ml_core-0.1.0a1/tests/fixtures/__init__.py +0 -0
  52. kaos_ml_core-0.1.0a1/tests/fixtures/usc_corpus.py +252 -0
  53. kaos_ml_core-0.1.0a1/tests/integration/__init__.py +0 -0
  54. kaos_ml_core-0.1.0a1/tests/integration/_usc_helpers.py +314 -0
  55. kaos_ml_core-0.1.0a1/tests/integration/test_corpus_index_persistence.py +187 -0
  56. kaos_ml_core-0.1.0a1/tests/integration/test_usc_cold_start_endtoend.py +169 -0
  57. kaos_ml_core-0.1.0a1/tests/integration/test_usc_harder_pair.py +168 -0
  58. kaos_ml_core-0.1.0a1/tests/integration/test_usc_llm_label_quality.py +145 -0
  59. kaos_ml_core-0.1.0a1/tests/integration/test_usc_pipeline_integrity.py +114 -0
  60. kaos_ml_core-0.1.0a1/tests/integration/test_v0_vertical_slice.py +132 -0
  61. kaos_ml_core-0.1.0a1/tests/unit/__init__.py +0 -0
  62. kaos_ml_core-0.1.0a1/tests/unit/test_aggregate.py +180 -0
  63. kaos_ml_core-0.1.0a1/tests/unit/test_cluster.py +125 -0
  64. kaos_ml_core-0.1.0a1/tests/unit/test_corpus.py +774 -0
  65. kaos_ml_core-0.1.0a1/tests/unit/test_corpus_levels.py +111 -0
  66. kaos_ml_core-0.1.0a1/tests/unit/test_features.py +100 -0
  67. kaos_ml_core-0.1.0a1/tests/unit/test_index.py +218 -0
  68. kaos_ml_core-0.1.0a1/tests/unit/test_metrics.py +207 -0
  69. kaos_ml_core-0.1.0a1/tests/unit/test_pipeline.py +160 -0
  70. kaos_ml_core-0.1.0a1/tests/unit/test_predict.py +158 -0
  71. kaos_ml_core-0.1.0a1/tests/unit/test_rust_smoke.py +54 -0
  72. kaos_ml_core-0.1.0a1/tests/unit/test_split.py +86 -0
  73. kaos_ml_core-0.1.0a1/tests/unit/test_threshold.py +136 -0
  74. kaos_ml_core-0.1.0a1/tests/unit/test_tools.py +158 -0
  75. kaos_ml_core-0.1.0a1/tests/unit/test_train.py +121 -0
@@ -0,0 +1,16 @@
1
+ # Default owner for everything in this repo
2
+ * @mjbommar
3
+
4
+ # Critical paths get explicit ownership for clarity
5
+ /.github/ @mjbommar
6
+ /pyproject.toml @mjbommar
7
+ /Cargo.toml @mjbommar
8
+ /Cargo.lock @mjbommar
9
+ /LICENSE @mjbommar
10
+ /NOTICE @mjbommar
11
+ /CHANGELOG.md @mjbommar
12
+ /SECURITY.md @mjbommar
13
+ /deny.toml @mjbommar
14
+
15
+ # Rust core / bindings — version-coupled with the Python wheel
16
+ /rust/ @mjbommar
@@ -0,0 +1,59 @@
1
+ name: Bug report
2
+ description: Report a defect in kaos-ml-core
3
+ title: "[bug] "
4
+ labels: ["type:bug", "needs-triage"]
5
+ body:
6
+ - type: markdown
7
+ attributes:
8
+ value: |
9
+ Thanks for taking the time to file a bug report. Please fill out the sections below.
10
+
11
+ - type: textarea
12
+ id: what-happened
13
+ attributes:
14
+ label: What happened?
15
+ description: A clear description of the bug. Include any error messages or stack traces.
16
+ placeholder: When I call X with Y, Z happens instead of W.
17
+ validations:
18
+ required: true
19
+
20
+ - type: textarea
21
+ id: reproduce
22
+ attributes:
23
+ label: How to reproduce
24
+ description: Minimal code or commands that reproduce the bug.
25
+ render: python
26
+ validations:
27
+ required: true
28
+
29
+ - type: input
30
+ id: version
31
+ attributes:
32
+ label: kaos-ml-core version
33
+ description: Output of `python -c "import kaos_ml_core; print(kaos_ml_core.__version__)"`
34
+ placeholder: e.g. 0.1.0a1
35
+ validations:
36
+ required: true
37
+
38
+ - type: input
39
+ id: python-version
40
+ attributes:
41
+ label: Python version
42
+ description: Output of `python --version`
43
+ placeholder: e.g. 3.13.1
44
+ validations:
45
+ required: true
46
+
47
+ - type: input
48
+ id: os
49
+ attributes:
50
+ label: Operating system + architecture
51
+ placeholder: e.g. Ubuntu 24.04 x86_64, macOS 14 arm64, Windows 11 x86_64
52
+ validations:
53
+ required: true
54
+
55
+ - type: textarea
56
+ id: extra
57
+ attributes:
58
+ label: Additional context
59
+ description: Anything else that might help. For Rust-side issues, include the wheel platform tag (e.g. `manylinux_2_28_x86_64`).
@@ -0,0 +1,5 @@
1
+ blank_issues_enabled: false
2
+ contact_links:
3
+ - name: Security vulnerability
4
+ url: https://github.com/273v/kaos-ml-core/security/advisories/new
5
+ about: Report a security issue privately via GitHub Security Advisories. Do not file a public issue.
@@ -0,0 +1,26 @@
1
+ name: Feature request
2
+ description: Suggest a new capability or improvement for kaos-ml-core
3
+ title: "[feat] "
4
+ labels: ["type:feat", "needs-triage"]
5
+ body:
6
+ - type: textarea
7
+ id: problem
8
+ attributes:
9
+ label: What problem does this solve?
10
+ description: Describe the use case, not the implementation.
11
+ placeholder: I'm trying to do X and the current API forces me to Y.
12
+ validations:
13
+ required: true
14
+
15
+ - type: textarea
16
+ id: proposal
17
+ attributes:
18
+ label: Proposed solution
19
+ description: Optional. If you already have an API or implementation in mind, sketch it here.
20
+ render: python
21
+
22
+ - type: textarea
23
+ id: alternatives
24
+ attributes:
25
+ label: Alternatives considered
26
+ description: What workarounds did you try, and why aren't they enough?
@@ -0,0 +1,23 @@
1
+ ## Summary
2
+
3
+ <!-- One-paragraph description of what this PR does and why it's needed. -->
4
+
5
+ ## Type of change
6
+
7
+ - [ ] Bug fix (non-breaking change which fixes an issue)
8
+ - [ ] New feature (non-breaking change which adds functionality)
9
+ - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
10
+ - [ ] Documentation only
11
+
12
+ ## Checklist
13
+
14
+ - [ ] Commits are signed off (`git commit -s`) — DCO required
15
+ - [ ] Tests added/updated for any behavior change
16
+ - [ ] **Rust** — `cargo fmt --check`, `cargo clippy --no-default-features --all-targets -- -D warnings`, `cargo test --no-default-features --lib`
17
+ - [ ] **Python** — `uv run ruff format --check python/kaos_ml_core tests`, `uv run ruff check python/kaos_ml_core tests`, `uv run ty check python/kaos_ml_core tests`, `uv run pytest -m "not live and not network and not slow" tests/`
18
+ - [ ] **Build** — `uv run maturin develop --release` succeeds
19
+ - [ ] `CHANGELOG.md` updated under `[Unreleased]` if user-visible
20
+
21
+ ## Related issues
22
+
23
+ <!-- "Closes #123" or "Refs #123" -->
@@ -0,0 +1,56 @@
1
+ version: 2
2
+ updates:
3
+ # ────────────── GitHub Actions ──────────────
4
+ - package-ecosystem: github-actions
5
+ directory: /
6
+ schedule:
7
+ interval: monthly
8
+ day: monday
9
+ time: "06:00"
10
+ timezone: Etc/UTC
11
+ groups:
12
+ actions:
13
+ patterns: ["*"]
14
+ labels: ["type:deps", "ci"]
15
+ commit-message:
16
+ prefix: "ci(deps)"
17
+
18
+ # ────────────── Python (uv-managed via pyproject.toml) ──────────────
19
+ - package-ecosystem: pip
20
+ directory: /
21
+ schedule:
22
+ interval: monthly
23
+ day: monday
24
+ time: "06:00"
25
+ timezone: Etc/UTC
26
+ groups:
27
+ python:
28
+ patterns: ["*"]
29
+ update-types: ["minor", "patch"]
30
+ python-major:
31
+ patterns: ["*"]
32
+ update-types: ["major"]
33
+ open-pull-requests-limit: 5
34
+ labels: ["type:deps"]
35
+ commit-message:
36
+ prefix: "deps"
37
+
38
+ # ────────────── Rust (cargo) ──────────────
39
+ - package-ecosystem: cargo
40
+ directory: /
41
+ schedule:
42
+ interval: monthly
43
+ day: monday
44
+ time: "06:00"
45
+ timezone: Etc/UTC
46
+ groups:
47
+ rust:
48
+ patterns: ["*"]
49
+ update-types: ["minor", "patch"]
50
+ rust-major:
51
+ patterns: ["*"]
52
+ update-types: ["major"]
53
+ open-pull-requests-limit: 5
54
+ labels: ["type:deps", "rust"]
55
+ commit-message:
56
+ prefix: "deps(rust)"
@@ -0,0 +1,270 @@
1
+ name: CI
2
+
3
+ on:
4
+ pull_request:
5
+ branches: [main]
6
+ push:
7
+ branches: [main]
8
+
9
+ permissions:
10
+ contents: read
11
+
12
+ concurrency:
13
+ group: ci-${{ github.workflow }}-${{ github.ref }}
14
+ cancel-in-progress: ${{ github.event_name == 'pull_request' }}
15
+
16
+ jobs:
17
+ # ────────────── lint (Python + Rust) ──────────────
18
+ lint:
19
+ name: Lint
20
+ runs-on: ubuntu-latest
21
+ steps:
22
+ - name: Checkout
23
+ uses: actions/checkout@v6
24
+
25
+ - name: Set up Rust toolchain
26
+ uses: dtolnay/rust-toolchain@stable
27
+ with:
28
+ components: rustfmt, clippy
29
+
30
+ - name: Cargo fmt
31
+ run: cargo fmt --check
32
+
33
+ - name: Cargo clippy (no PyO3 features)
34
+ run: cargo clippy --no-default-features --all-targets -- -D warnings
35
+
36
+ - name: Set up uv
37
+ uses: astral-sh/setup-uv@v7
38
+ with:
39
+ enable-cache: true
40
+
41
+ - name: Install Python 3.13
42
+ run: uv python install 3.13
43
+
44
+ - name: Install dependencies (transformers + mcp extras for ty resolution)
45
+ # ty static-analyzes the pipeline.py / tools.py imports of
46
+ # kaos_nlp_transformers.models and kaos_mcp; install both extras
47
+ # so the symbols resolve. The runtime tests don't need this — the
48
+ # imports are gated by try/except — but the type checker is strict.
49
+ run: uv sync --group dev --extra transformers --extra mcp --python 3.13
50
+
51
+ - name: Ruff format check
52
+ run: uv run ruff format --check python/kaos_ml_core tests
53
+
54
+ - name: Ruff lint
55
+ run: uv run ruff check python/kaos_ml_core tests
56
+
57
+ - name: Type check (ty)
58
+ run: uv run ty check python/kaos_ml_core tests
59
+
60
+ # ────────────── pre-commit ──────────────
61
+ pre-commit:
62
+ name: Pre-commit hooks
63
+ runs-on: ubuntu-latest
64
+ steps:
65
+ - name: Checkout
66
+ uses: actions/checkout@v6
67
+
68
+ - name: Set up Rust toolchain
69
+ uses: dtolnay/rust-toolchain@stable
70
+
71
+ - name: Set up uv
72
+ uses: astral-sh/setup-uv@v7
73
+ with:
74
+ enable-cache: true
75
+
76
+ - name: Install Python 3.13
77
+ run: uv python install 3.13
78
+
79
+ - name: Install dependencies (transformers + mcp for ty resolution)
80
+ run: uv sync --group dev --extra transformers --extra mcp --python 3.13
81
+
82
+ - name: Run pre-commit
83
+ run: uvx pre-commit run --all-files --show-diff-on-failure
84
+
85
+ # ────────────── Rust unit tests (pure Rust core) ──────────────
86
+ rust-test:
87
+ name: Rust tests (no PyO3)
88
+ runs-on: ubuntu-latest
89
+ steps:
90
+ - name: Checkout
91
+ uses: actions/checkout@v6
92
+
93
+ - name: Set up Rust toolchain
94
+ uses: dtolnay/rust-toolchain@stable
95
+
96
+ - name: Cargo test (--no-default-features)
97
+ run: cargo test --no-default-features --lib
98
+
99
+ # ────────────── Python tests (Python × maturin develop) ──────────────
100
+ test:
101
+ name: Test (Python ${{ matrix.python-version }})
102
+ runs-on: ubuntu-latest
103
+ strategy:
104
+ fail-fast: false
105
+ matrix:
106
+ include:
107
+ - python-version: "3.13"
108
+ experimental: false
109
+ - python-version: "3.14"
110
+ experimental: false
111
+ - python-version: "3.14t"
112
+ experimental: true
113
+ - python-version: "3.15"
114
+ experimental: true
115
+ continue-on-error: ${{ matrix.experimental }}
116
+ steps:
117
+ - name: Checkout
118
+ uses: actions/checkout@v6
119
+
120
+ - name: Set up Rust toolchain
121
+ uses: dtolnay/rust-toolchain@stable
122
+
123
+ - name: Set up uv
124
+ uses: astral-sh/setup-uv@v7
125
+ with:
126
+ enable-cache: true
127
+
128
+ - name: Install Python ${{ matrix.python-version }}
129
+ run: uv python install --preview ${{ matrix.python-version }}
130
+
131
+ - name: Install dependencies
132
+ run: uv sync --group dev --python ${{ matrix.python-version }}
133
+
134
+ - name: Build PyO3 extension (maturin develop --release)
135
+ run: uv run maturin develop --release
136
+
137
+ - name: Run tests with coverage
138
+ run: |
139
+ uv run pytest \
140
+ -m "not live and not network and not slow" \
141
+ --cov=kaos_ml_core \
142
+ --cov-branch \
143
+ --cov-report=term-missing \
144
+ --cov-report=xml:coverage.xml \
145
+ tests/
146
+
147
+ - name: Upload coverage report
148
+ if: always() && !matrix.experimental
149
+ uses: actions/upload-artifact@v7
150
+ with:
151
+ name: coverage-${{ matrix.python-version }}
152
+ path: coverage.xml
153
+ retention-days: 14
154
+
155
+ # ────────────── min-deps ──────────────
156
+ min-deps:
157
+ name: Test against minimum dependencies
158
+ runs-on: ubuntu-latest
159
+ steps:
160
+ - name: Checkout
161
+ uses: actions/checkout@v6
162
+
163
+ - name: Set up Rust toolchain
164
+ uses: dtolnay/rust-toolchain@stable
165
+
166
+ - name: Set up uv
167
+ uses: astral-sh/setup-uv@v7
168
+
169
+ - name: Install Python 3.13
170
+ run: uv python install 3.13
171
+
172
+ - name: Install with lowest-direct resolution
173
+ run: uv sync --group dev --resolution=lowest-direct --python 3.13
174
+
175
+ - name: Build PyO3 extension
176
+ run: uv run maturin develop --release
177
+
178
+ - name: Run tests
179
+ run: |
180
+ uv run pytest \
181
+ -m "not live and not network and not slow" \
182
+ --no-cov \
183
+ -q \
184
+ tests/
185
+
186
+ # ────────────── build + wheel smoke test ──────────────
187
+ build:
188
+ name: Build distribution + smoke test
189
+ runs-on: ubuntu-latest
190
+ needs: [lint, test, rust-test]
191
+ steps:
192
+ - name: Checkout
193
+ uses: actions/checkout@v6
194
+
195
+ - name: Set up Rust toolchain
196
+ uses: dtolnay/rust-toolchain@stable
197
+
198
+ - name: Set up uv
199
+ uses: astral-sh/setup-uv@v7
200
+ with:
201
+ enable-cache: true
202
+
203
+ - name: Install Python 3.13
204
+ run: uv python install 3.13
205
+
206
+ - name: Build wheel + sdist
207
+ run: uv build
208
+
209
+ - name: Verify metadata (twine check)
210
+ run: uvx --from twine twine check --strict dist/*
211
+
212
+ - name: Smoke-test the built wheel in a clean venv
213
+ run: |
214
+ uv venv --python 3.13 /tmp/smoke
215
+ # Install with [mcp] so register_ml_tools is reachable; the
216
+ # actual ML-pipeline smoke (embed + train + predict) lives in
217
+ # the integration tests, not in this fast-CI smoke.
218
+ uv pip install --python /tmp/smoke/bin/python "dist/kaos_ml_core-0.1.0a1-cp313-abi3-linux_x86_64.whl[mcp]"
219
+ /tmp/smoke/bin/python -c "
220
+ import kaos_ml_core
221
+ from kaos_ml_core import (
222
+ Corpus, KaosMLCoreSettings, Metrics, Pipeline, PipelineError,
223
+ SplitResult, ThresholdResult, aggregate_predictions, evaluate,
224
+ stratified_split, tune_threshold, wilson_score_interval,
225
+ )
226
+ assert kaos_ml_core.__version__, 'version missing from wheel'
227
+ assert len(kaos_ml_core.__all__) >= 22, f'unexpected public surface: {kaos_ml_core.__all__}'
228
+
229
+ # Hard-rule enforcement primitives are reachable.
230
+ lo, hi = wilson_score_interval(80, 100, confidence=0.95)
231
+ assert 0.7 < lo < 0.72 and 0.86 < hi < 0.87
232
+
233
+ # Four granularity levels supported.
234
+ from kaos_content.model.blocks import Heading, Paragraph
235
+ from kaos_content.model.document import ContentDocument
236
+ from kaos_content.model.inlines import Text
237
+ from kaos_content.model.metadata import DocumentMetadata, SourceRef
238
+ doc = ContentDocument(
239
+ metadata=DocumentMetadata(source=SourceRef(uri='smoke://1')),
240
+ body=(
241
+ Heading(depth=1, children=(Text(value='Indemnification'),)),
242
+ Paragraph(children=(Text(value='The Seller indemnifies Buyer.'),)),
243
+ Paragraph(children=(Text(value='Cap is 10 percent.'),)),
244
+ ),
245
+ )
246
+ assert len(Corpus.from_documents([doc], level='paragraph')) == 2
247
+ assert len(Corpus.from_documents([doc], level='section')) == 1
248
+ assert len(Corpus.from_documents([doc], level='document')) == 1
249
+
250
+ # MCP tool surface registers 11 tools.
251
+ from kaos_core import KaosRuntime
252
+ from kaos_ml_core.tools import register_ml_tools
253
+ rt = KaosRuntime()
254
+ assert register_ml_tools(rt) == 11
255
+
256
+ # Settings + Rust extension reachable.
257
+ assert KaosMLCoreSettings().default_threshold == 0.5
258
+ from kaos_ml_core._rust import version as rust_version_fn
259
+ assert rust_version_fn() == kaos_ml_core.rust_version
260
+ print(f'kaos-ml-core {kaos_ml_core.__version__}: smoke OK ({len(kaos_ml_core.__all__)} symbols, 11 MCP tools)')
261
+ "
262
+ # Exercise the CLI entrypoint.
263
+ /tmp/smoke/bin/kaos-ml info --json
264
+
265
+ - name: Upload distribution artifacts
266
+ uses: actions/upload-artifact@v7
267
+ with:
268
+ name: dist-${{ github.sha }}
269
+ path: dist/
270
+ retention-days: 7
@@ -0,0 +1,241 @@
1
+ name: Release
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - "v*"
7
+ # Manual fallback so a failed publish (e.g. transient PyPI 5xx) can be
8
+ # retried without re-tagging.
9
+ workflow_dispatch:
10
+
11
+ permissions:
12
+ contents: read
13
+
14
+ concurrency:
15
+ group: release-${{ github.ref }}
16
+ cancel-in-progress: false
17
+
18
+ jobs:
19
+ # ────────────── Pre-publish QA + sdist ──────────────
20
+ # One job that gates everything else: verifies version sync, runs the
21
+ # full QA gauntlet, builds + verifies the sdist (the format-agnostic
22
+ # source artifact). Wheel-matrix jobs depend on this; if the source
23
+ # tree is broken we never compile 8 wheels for nothing.
24
+ sdist:
25
+ name: Build sdist + pre-publish QA
26
+ runs-on: ubuntu-latest
27
+ outputs:
28
+ version: ${{ steps.version.outputs.version }}
29
+ steps:
30
+ - name: Checkout
31
+ uses: actions/checkout@v6
32
+ with:
33
+ fetch-depth: 0
34
+
35
+ - name: Set up Rust toolchain
36
+ uses: dtolnay/rust-toolchain@stable
37
+ with:
38
+ components: rustfmt, clippy
39
+
40
+ - name: Set up uv
41
+ uses: astral-sh/setup-uv@v7
42
+ with:
43
+ enable-cache: true
44
+
45
+ - name: Install Python 3.13
46
+ run: uv python install 3.13
47
+
48
+ - name: Install dependencies (transformers + mcp for ty resolution)
49
+ run: uv sync --group dev --extra transformers --extra mcp --python 3.13
50
+
51
+ - name: Verify Cargo.toml version matches tag
52
+ id: version
53
+ if: startsWith(github.ref, 'refs/tags/v')
54
+ run: |
55
+ # Cargo SemVer "0.1.0-alpha.1" maps to PEP 440 "0.1.0a1".
56
+ CARGO_VERSION=$(awk -F\" '/^version = "/{print $2; exit}' Cargo.toml)
57
+ # Normalize Cargo SemVer "X.Y.Z-alpha.N" -> PEP 440 "X.Y.ZaN" etc.
58
+ PEP440_VERSION=$(echo "$CARGO_VERSION" \
59
+ | sed -E 's/-alpha\.([0-9]+)$/a\1/' \
60
+ | sed -E 's/-beta\.([0-9]+)$/b\1/' \
61
+ | sed -E 's/-rc\.([0-9]+)$/rc\1/')
62
+ TAG=${GITHUB_REF_NAME#v}
63
+ if [ "$PEP440_VERSION" != "$TAG" ]; then
64
+ echo "::error::Tag '$TAG' does not match Cargo.toml-derived PEP 440 version '$PEP440_VERSION' (Cargo SemVer '$CARGO_VERSION')"
65
+ exit 1
66
+ fi
67
+ echo "version=$PEP440_VERSION" >> "$GITHUB_OUTPUT"
68
+ echo "kaos-ml-core release: tag=$TAG, cargo=$CARGO_VERSION, pep440=$PEP440_VERSION"
69
+
70
+ - name: Pre-publish QA — Rust
71
+ run: |
72
+ cargo fmt --check
73
+ cargo clippy --no-default-features --all-targets -- -D warnings
74
+ cargo test --no-default-features --lib
75
+
76
+ - name: Pre-publish QA — Python (build extension first)
77
+ run: |
78
+ uv run maturin develop --release
79
+ uv run ruff format --check python/kaos_ml_core tests
80
+ uv run ruff check python/kaos_ml_core tests
81
+ uv run ty check python/kaos_ml_core tests
82
+ uv run pytest -m "not live and not network and not slow" --no-cov tests/
83
+
84
+ - name: Build sdist
85
+ run: uv run maturin sdist --out dist
86
+
87
+ - name: Verify sdist metadata
88
+ run: uvx --from twine twine check --strict dist/*.tar.gz
89
+
90
+ - name: Upload sdist
91
+ uses: actions/upload-artifact@v7
92
+ with:
93
+ name: sdist
94
+ path: dist/*.tar.gz
95
+ retention-days: 30
96
+
97
+ # ────────────── Wheel matrix ──────────────
98
+ # 8 wheels per release, per D017 (docs/oss/30-rust-packaging/wheel-matrix.md):
99
+ # - Linux x86_64 manylinux + musllinux
100
+ # - Linux aarch64 manylinux + musllinux
101
+ # - macOS arm64
102
+ # - Windows x86_64
103
+ # - Windows arm64
104
+ # macOS x86_64 deliberately skipped (Apple ended Intel sales in 2023).
105
+ wheels:
106
+ name: ${{ matrix.target }} ${{ matrix.linux-tag && '(' || '' }}${{ matrix.linux-tag }}${{ matrix.linux-tag && ')' || '' }}
107
+ needs: sdist
108
+ strategy:
109
+ fail-fast: false
110
+ matrix:
111
+ include:
112
+ - os: ubuntu-latest
113
+ target: x86_64-unknown-linux-gnu
114
+ linux-tag: manylinux_2_28
115
+ manylinux: "2_28"
116
+ - os: ubuntu-latest
117
+ target: x86_64-unknown-linux-musl
118
+ linux-tag: musllinux_1_2
119
+ manylinux: musllinux_1_2
120
+ - os: ubuntu-24.04-arm
121
+ target: aarch64-unknown-linux-gnu
122
+ linux-tag: manylinux_2_28
123
+ manylinux: "2_28"
124
+ - os: ubuntu-24.04-arm
125
+ target: aarch64-unknown-linux-musl
126
+ linux-tag: musllinux_1_2
127
+ manylinux: musllinux_1_2
128
+ - os: macos-14
129
+ target: aarch64-apple-darwin
130
+ linux-tag: ""
131
+ manylinux: ""
132
+ - os: windows-latest
133
+ target: x86_64-pc-windows-msvc
134
+ linux-tag: ""
135
+ manylinux: ""
136
+ - os: windows-11-arm
137
+ target: aarch64-pc-windows-msvc
138
+ linux-tag: ""
139
+ manylinux: ""
140
+ runs-on: ${{ matrix.os }}
141
+ steps:
142
+ - name: Checkout
143
+ uses: actions/checkout@v6
144
+
145
+ - name: Set up Python (host)
146
+ uses: actions/setup-python@v6
147
+ with:
148
+ python-version: "3.13"
149
+
150
+ - name: Build wheel via PyO3/maturin-action
151
+ uses: PyO3/maturin-action@v1
152
+ with:
153
+ target: ${{ matrix.target }}
154
+ # Empty for macOS/Windows; "2_28" or "musllinux_1_2" for Linux.
155
+ manylinux: ${{ matrix.manylinux }}
156
+ args: --release --strip --out dist
157
+ # Don't restore from cache — release builds must be reproducible
158
+ # from a clean state (per docs/oss/30-rust-packaging/wheel-matrix.md).
159
+ rust-toolchain: stable
160
+ sccache: "true"
161
+
162
+ - name: Upload wheel
163
+ uses: actions/upload-artifact@v7
164
+ with:
165
+ name: wheels-${{ matrix.target }}-${{ matrix.linux-tag || matrix.os }}
166
+ path: dist/*.whl
167
+ retention-days: 30
168
+
169
+ # ────────────── Publish to PyPI via OIDC ──────────────
170
+ publish-pypi:
171
+ name: Publish to PyPI
172
+ needs: [sdist, wheels]
173
+ if: startsWith(github.ref, 'refs/tags/v')
174
+ runs-on: ubuntu-latest
175
+ environment:
176
+ name: pypi
177
+ url: https://pypi.org/p/kaos-ml-core
178
+ permissions:
179
+ id-token: write # OIDC for Trusted Publishing
180
+ steps:
181
+ - name: Download sdist
182
+ uses: actions/download-artifact@v8
183
+ with:
184
+ name: sdist
185
+ path: dist/
186
+
187
+ - name: Download all wheels
188
+ uses: actions/download-artifact@v8
189
+ with:
190
+ pattern: wheels-*
191
+ path: dist/
192
+ merge-multiple: true
193
+
194
+ - name: Show artifact set
195
+ run: ls -la dist/
196
+
197
+ - name: Publish to PyPI
198
+ uses: pypa/gh-action-pypi-publish@release/v1
199
+ with:
200
+ attestations: true
201
+ skip-existing: false
202
+
203
+ # ────────────── GitHub Release ──────────────
204
+ github-release:
205
+ name: Create GitHub Release
206
+ needs: [sdist, wheels]
207
+ if: startsWith(github.ref, 'refs/tags/v')
208
+ runs-on: ubuntu-latest
209
+ permissions:
210
+ contents: write
211
+ steps:
212
+ - name: Checkout
213
+ uses: actions/checkout@v6
214
+
215
+ - name: Download sdist
216
+ uses: actions/download-artifact@v8
217
+ with:
218
+ name: sdist
219
+ path: dist/
220
+
221
+ - name: Download all wheels
222
+ uses: actions/download-artifact@v8
223
+ with:
224
+ pattern: wheels-*
225
+ path: dist/
226
+ merge-multiple: true
227
+
228
+ - name: Create GitHub Release
229
+ env:
230
+ GH_TOKEN: ${{ github.token }}
231
+ run: |
232
+ VERSION=${GITHUB_REF_NAME#v}
233
+ PRERELEASE_FLAG=""
234
+ if [[ "$VERSION" == *a* || "$VERSION" == *b* || "$VERSION" == *rc* ]]; then
235
+ PRERELEASE_FLAG="--prerelease"
236
+ fi
237
+ gh release create "$GITHUB_REF_NAME" \
238
+ --title "kaos-ml-core $VERSION" \
239
+ --notes-from-tag \
240
+ $PRERELEASE_FLAG \
241
+ dist/*