seqpro 0.11.0__tar.gz → 0.12.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 (106) hide show
  1. seqpro-0.12.0/.github/workflows/bump.yaml +94 -0
  2. seqpro-0.12.0/.github/workflows/merge.yaml +50 -0
  3. {seqpro-0.11.0 → seqpro-0.12.0}/.github/workflows/publish.yaml +52 -11
  4. seqpro-0.12.0/.github/workflows/release-pipeline.yaml +101 -0
  5. seqpro-0.12.0/.github/workflows/release.yaml +71 -0
  6. {seqpro-0.11.0 → seqpro-0.12.0}/CHANGELOG.md +56 -0
  7. {seqpro-0.11.0 → seqpro-0.12.0}/CLAUDE.md +4 -0
  8. seqpro-0.12.0/Cargo.lock +1497 -0
  9. {seqpro-0.11.0 → seqpro-0.12.0}/Cargo.toml +9 -1
  10. {seqpro-0.11.0 → seqpro-0.12.0}/PKG-INFO +1 -1
  11. seqpro-0.12.0/benches/kshuffle.rs +30 -0
  12. seqpro-0.12.0/docs/superpowers/plans/2026-05-20-kshuffle-optimization.md +1102 -0
  13. seqpro-0.12.0/docs/superpowers/plans/2026-05-20-kshuffle-pooled-buffers-and-k2-fast-path.md +852 -0
  14. seqpro-0.12.0/docs/superpowers/plans/2026-05-20-kshuffle-wilson-single-pass.md +368 -0
  15. seqpro-0.12.0/docs/superpowers/plans/2026-05-20-release-pipeline.md +760 -0
  16. seqpro-0.12.0/docs/superpowers/plans/2026-05-28-translate-lut-validation.md +793 -0
  17. seqpro-0.12.0/docs/superpowers/specs/2026-05-20-kshuffle-optimization-design.md +161 -0
  18. seqpro-0.12.0/docs/superpowers/specs/2026-05-20-kshuffle-pooled-buffers-and-k2-fast-path-design.md +174 -0
  19. seqpro-0.12.0/docs/superpowers/specs/2026-05-20-kshuffle-wilson-single-pass-design.md +65 -0
  20. seqpro-0.12.0/docs/superpowers/specs/2026-05-20-release-pipeline-design.md +167 -0
  21. seqpro-0.12.0/docs/superpowers/specs/2026-05-28-translate-lut-and-validation-design.md +149 -0
  22. {seqpro-0.11.0 → seqpro-0.12.0}/pixi.lock +9548 -7470
  23. {seqpro-0.11.0 → seqpro-0.12.0}/pixi.toml +11 -0
  24. {seqpro-0.11.0 → seqpro-0.12.0}/pyproject.toml +1 -1
  25. {seqpro-0.11.0 → seqpro-0.12.0}/python/seqpro/_analyzers.py +9 -4
  26. {seqpro-0.11.0 → seqpro-0.12.0}/python/seqpro/_coords.py +5 -3
  27. seqpro-0.12.0/python/seqpro/_encoders.py +322 -0
  28. {seqpro-0.11.0 → seqpro-0.12.0}/python/seqpro/_modifiers.py +8 -2
  29. {seqpro-0.11.0 → seqpro-0.12.0}/python/seqpro/_numba.py +57 -1
  30. {seqpro-0.11.0 → seqpro-0.12.0}/python/seqpro/_utils.py +3 -1
  31. {seqpro-0.11.0 → seqpro-0.12.0}/python/seqpro/alphabets/_alphabets.py +213 -92
  32. seqpro-0.12.0/skills/seqpro/SKILL.md +157 -0
  33. seqpro-0.12.0/src/kmer_encode.rs +88 -0
  34. seqpro-0.12.0/src/kshuffle.rs +630 -0
  35. seqpro-0.11.0/src/kshuffle.rs → seqpro-0.12.0/src/kshuffle_ref.rs +3 -36
  36. {seqpro-0.11.0 → seqpro-0.12.0}/src/lib.rs +8 -1
  37. seqpro-0.12.0/tests/_shape_fixtures.py +222 -0
  38. seqpro-0.12.0/tests/bench_translate_lut.py +60 -0
  39. seqpro-0.12.0/tests/conftest.py +0 -0
  40. seqpro-0.12.0/tests/test_encoders.py +44 -0
  41. seqpro-0.12.0/tests/test_ohe.py +185 -0
  42. seqpro-0.12.0/tests/test_shape_matrix.py +440 -0
  43. {seqpro-0.11.0 → seqpro-0.12.0}/tests/test_tokenize.py +61 -0
  44. seqpro-0.12.0/tests/test_translate.py +449 -0
  45. seqpro-0.11.0/.github/workflows/bump.yaml +0 -49
  46. seqpro-0.11.0/.github/workflows/merge.yaml +0 -32
  47. seqpro-0.11.0/.github/workflows/release.yaml +0 -49
  48. seqpro-0.11.0/Cargo.lock +0 -598
  49. seqpro-0.11.0/python/seqpro/_encoders.py +0 -209
  50. seqpro-0.11.0/tests/test_ohe.py +0 -79
  51. seqpro-0.11.0/tests/test_translate.py +0 -167
  52. {seqpro-0.11.0 → seqpro-0.12.0}/.claude/skills/zensical-setup/.skillfish.json +0 -0
  53. {seqpro-0.11.0 → seqpro-0.12.0}/.claude/skills/zensical-setup/SKILL.md +0 -0
  54. {seqpro-0.11.0 → seqpro-0.12.0}/.gitattributes +0 -0
  55. {seqpro-0.11.0 → seqpro-0.12.0}/.github/workflows/docs.yml +0 -0
  56. {seqpro-0.11.0 → seqpro-0.12.0}/.github/workflows/lint.yaml +0 -0
  57. {seqpro-0.11.0 → seqpro-0.12.0}/.github/workflows/test.yaml +0 -0
  58. {seqpro-0.11.0 → seqpro-0.12.0}/.gitignore +0 -0
  59. {seqpro-0.11.0 → seqpro-0.12.0}/.pre-commit-config.yaml +0 -0
  60. {seqpro-0.11.0 → seqpro-0.12.0}/LICENSE +0 -0
  61. {seqpro-0.11.0 → seqpro-0.12.0}/README.md +0 -0
  62. {seqpro-0.11.0 → seqpro-0.12.0}/docs/api/alphabets.md +0 -0
  63. {seqpro-0.11.0 → seqpro-0.12.0}/docs/api/bed.md +0 -0
  64. {seqpro-0.11.0 → seqpro-0.12.0}/docs/api/gtf.md +0 -0
  65. {seqpro-0.11.0 → seqpro-0.12.0}/docs/api/index.md +0 -0
  66. {seqpro-0.11.0 → seqpro-0.12.0}/docs/api/ragged.md +0 -0
  67. {seqpro-0.11.0 → seqpro-0.12.0}/docs/api/types.md +0 -0
  68. {seqpro-0.11.0 → seqpro-0.12.0}/docs/index.md +0 -0
  69. {seqpro-0.11.0 → seqpro-0.12.0}/docs/ragged.md +0 -0
  70. {seqpro-0.11.0 → seqpro-0.12.0}/docs/superpowers/plans/2026-05-04-ragged-record-array.md +0 -0
  71. {seqpro-0.11.0 → seqpro-0.12.0}/docs/superpowers/plans/2026-05-05-documentation-site.md +0 -0
  72. {seqpro-0.11.0 → seqpro-0.12.0}/docs/superpowers/plans/2026-05-05-narwhals-coord-schema.md +0 -0
  73. {seqpro-0.11.0 → seqpro-0.12.0}/docs/superpowers/plans/2026-05-05-ragged-zip-and-record-introspection.md +0 -0
  74. {seqpro-0.11.0 → seqpro-0.12.0}/docs/superpowers/specs/2026-05-04-ragged-record-array-design.md +0 -0
  75. {seqpro-0.11.0 → seqpro-0.12.0}/docs/superpowers/specs/2026-05-05-documentation-site-design.md +0 -0
  76. {seqpro-0.11.0 → seqpro-0.12.0}/docs/superpowers/specs/2026-05-05-narwhals-coord-schema-design.md +0 -0
  77. {seqpro-0.11.0 → seqpro-0.12.0}/docs/superpowers/specs/2026-05-05-ragged-zip-and-record-introspection-design.md +0 -0
  78. {seqpro-0.11.0 → seqpro-0.12.0}/meta.yaml +0 -0
  79. {seqpro-0.11.0 → seqpro-0.12.0}/python/seqpro/__init__.py +0 -0
  80. {seqpro-0.11.0 → seqpro-0.12.0}/python/seqpro/_cleaners.py +0 -0
  81. {seqpro-0.11.0 → seqpro-0.12.0}/python/seqpro/_types.py +0 -0
  82. {seqpro-0.11.0 → seqpro-0.12.0}/python/seqpro/alphabets/__init__.py +0 -0
  83. {seqpro-0.11.0 → seqpro-0.12.0}/python/seqpro/bed.py +0 -0
  84. {seqpro-0.11.0 → seqpro-0.12.0}/python/seqpro/experimental/_experimental.py +0 -0
  85. {seqpro-0.11.0 → seqpro-0.12.0}/python/seqpro/experimental/_visualizers.py +0 -0
  86. {seqpro-0.11.0 → seqpro-0.12.0}/python/seqpro/gtf.py +0 -0
  87. {seqpro-0.11.0 → seqpro-0.12.0}/python/seqpro/py.typed +0 -0
  88. {seqpro-0.11.0 → seqpro-0.12.0}/python/seqpro/rag/__init__.py +0 -0
  89. {seqpro-0.11.0 → seqpro-0.12.0}/python/seqpro/rag/_array.py +0 -0
  90. {seqpro-0.11.0 → seqpro-0.12.0}/python/seqpro/rag/_gufuncs.py +0 -0
  91. {seqpro-0.11.0 → seqpro-0.12.0}/python/seqpro/rag/_types.py +0 -0
  92. {seqpro-0.11.0 → seqpro-0.12.0}/python/seqpro/rag/_utils.py +0 -0
  93. {seqpro-0.11.0 → seqpro-0.12.0}/python/seqpro/transforms/__init__.py +0 -0
  94. {seqpro-0.11.0 → seqpro-0.12.0}/python/seqpro/transforms/augmentation.py +0 -0
  95. {seqpro-0.11.0 → seqpro-0.12.0}/python/seqpro/transforms/tmm.py +0 -0
  96. {seqpro-0.11.0 → seqpro-0.12.0}/python/seqpro/xr/__init__.py +0 -0
  97. {seqpro-0.11.0 → seqpro-0.12.0}/tests/bed/test_pyranges.py +0 -0
  98. {seqpro-0.11.0 → seqpro-0.12.0}/tests/bed/test_read.py +0 -0
  99. {seqpro-0.11.0 → seqpro-0.12.0}/tests/bed/test_sort.py +0 -0
  100. {seqpro-0.11.0 → seqpro-0.12.0}/tests/bed/test_with_length.py +0 -0
  101. {seqpro-0.11.0 → seqpro-0.12.0}/tests/test_analyzers.py +0 -0
  102. {seqpro-0.11.0 → seqpro-0.12.0}/tests/test_coords.py +0 -0
  103. {seqpro-0.11.0 → seqpro-0.12.0}/tests/test_modifiers.py +0 -0
  104. {seqpro-0.11.0 → seqpro-0.12.0}/tests/test_ragged.py +0 -0
  105. {seqpro-0.11.0 → seqpro-0.12.0}/tests/test_transforms.py +0 -0
  106. {seqpro-0.11.0 → seqpro-0.12.0}/zensical.toml +0 -0
@@ -0,0 +1,94 @@
1
+ name: Bump version
2
+
3
+ on:
4
+ workflow_call:
5
+ inputs:
6
+ increment:
7
+ description: "Force a specific bump (auto|PATCH|MINOR|MAJOR)"
8
+ type: string
9
+ required: false
10
+ default: "auto"
11
+ dry_run:
12
+ description: "Compute the bump but do not commit/push"
13
+ type: boolean
14
+ required: false
15
+ default: false
16
+ outputs:
17
+ tag:
18
+ description: "The version string after the bump (or projected version in dry-run)"
19
+ value: ${{ jobs.bump.outputs.tag }}
20
+ workflow_dispatch:
21
+ inputs:
22
+ increment:
23
+ description: "Force a specific bump"
24
+ type: choice
25
+ required: false
26
+ default: "auto"
27
+ options: ["auto", "PATCH", "MINOR", "MAJOR"]
28
+ dry_run:
29
+ description: "Compute the bump but do not commit/push"
30
+ type: boolean
31
+ required: false
32
+ default: false
33
+
34
+ jobs:
35
+ bump:
36
+ runs-on: ubuntu-latest
37
+ outputs:
38
+ tag: ${{ steps.emit.outputs.tag }}
39
+ steps:
40
+ - uses: actions/checkout@v4
41
+ with:
42
+ fetch-depth: 0
43
+ token: "${{ secrets.GH_TOKEN }}"
44
+
45
+ - name: Install commitizen
46
+ run: pip install commitizen --quiet
47
+
48
+ - name: Detect partial bump
49
+ id: detect
50
+ run: |
51
+ PROJECT_VERSION=$(cz version --project)
52
+ LATEST_TAG=$(git tag --sort=-version:refname | grep -E '^[0-9]+\.[0-9]+\.[0-9]+$' | head -1)
53
+ if [ -n "$LATEST_TAG" ] && [ "$LATEST_TAG" != "$PROJECT_VERSION" ]; then
54
+ echo "partial=true" >> $GITHUB_OUTPUT
55
+ echo "tag=$LATEST_TAG" >> $GITHUB_OUTPUT
56
+ else
57
+ echo "partial=false" >> $GITHUB_OUTPUT
58
+ fi
59
+
60
+ - name: Bump version (real)
61
+ if: steps.detect.outputs.partial != 'true' && inputs.dry_run == false
62
+ uses: commitizen-tools/commitizen-action@master
63
+ with:
64
+ github_token: ${{ secrets.GH_TOKEN }}
65
+ increment: ${{ inputs.increment != 'auto' && inputs.increment || '' }}
66
+
67
+ - name: Bump version (dry-run)
68
+ if: steps.detect.outputs.partial != 'true' && inputs.dry_run == true
69
+ run: |
70
+ ARGS="--dry-run --yes"
71
+ if [ "${{ inputs.increment }}" != "auto" ]; then
72
+ ARGS="$ARGS --increment ${{ inputs.increment }}"
73
+ fi
74
+ cz bump $ARGS
75
+
76
+ - name: Fix partial bump (tag exists on remote, update files only)
77
+ if: steps.detect.outputs.partial == 'true' && inputs.dry_run == false
78
+ run: |
79
+ git config user.name "github-actions[bot]"
80
+ git config user.email "github-actions[bot]@users.noreply.github.com"
81
+ NEW_VERSION="${{ steps.detect.outputs.tag }}"
82
+ cz bump --files-only --yes
83
+ BUMPED_VERSION=$(cz version --project)
84
+ git add pyproject.toml CHANGELOG.md
85
+ git commit -m "bump: version $NEW_VERSION"
86
+ git push origin main
87
+ git push origin "$BUMPED_VERSION"
88
+
89
+ - name: Emit resulting tag
90
+ id: emit
91
+ run: |
92
+ TAG=$(cz version --project)
93
+ echo "tag=$TAG" >> $GITHUB_OUTPUT
94
+ echo "Resolved tag: $TAG"
@@ -0,0 +1,50 @@
1
+ name: Merge main -> stable
2
+
3
+ on:
4
+ workflow_call:
5
+ inputs:
6
+ dry_run:
7
+ description: 'Compute the rebase but do not push'
8
+ type: boolean
9
+ required: false
10
+ default: false
11
+ workflow_dispatch:
12
+ inputs:
13
+ dry_run:
14
+ description: 'Compute the rebase but do not push'
15
+ type: boolean
16
+ required: false
17
+ default: false
18
+
19
+ jobs:
20
+ merge:
21
+ environment: pypi
22
+ permissions:
23
+ id-token: write
24
+ runs-on: ubuntu-latest
25
+ steps:
26
+ - name: Check out
27
+ uses: actions/checkout@v4
28
+ with:
29
+ ref: stable
30
+ fetch-depth: 0
31
+ token: "${{ secrets.GH_TOKEN }}"
32
+ - name: Config git
33
+ run: |
34
+ git config --global user.name "${GITHUB_ACTOR}"
35
+ git config --global user.email "${GITHUB_ACTOR}@users.noreply.github.com"
36
+ - name: Rebase stable onto main
37
+ run: git rebase origin/main
38
+ - name: Push to stable
39
+ if: inputs.dry_run == false
40
+ run: git push origin stable
41
+ - name: Dry-run summary (skipped push)
42
+ if: inputs.dry_run == true
43
+ run: |
44
+ {
45
+ echo "## Dry-run: would push the following to stable"
46
+ echo
47
+ echo '```'
48
+ git log --oneline origin/stable..HEAD
49
+ echo '```'
50
+ } >> "$GITHUB_STEP_SUMMARY"
@@ -1,22 +1,48 @@
1
- # This file is autogenerated by maturin v1.13.1
2
- # To update, run
1
+ # This file was autogenerated by maturin v1.13.1 and has been hand-modified
2
+ # to support workflow_call from release-pipeline.yaml.
3
+ #
4
+ # To regenerate, run:
3
5
  #
4
6
  # maturin generate-ci -o .github/workflows/publish.yaml github
5
7
  #
8
+ # Regenerating will overwrite the trigger block and the per-job `if:`
9
+ # conditions below. Re-apply the workflow_call inputs (`dry_run`), delete
10
+ # the `on.workflow_run` block, remove all `if: ${{ github.event_name ... }}`
11
+ # guards, and wrap the `uv publish` step with the dry_run gate before
12
+ # committing.
6
13
  name: Publish
7
14
 
8
15
  on:
9
- workflow_run:
10
- workflows: [Create release]
11
- types: [completed]
16
+ workflow_call:
17
+ inputs:
18
+ dry_run:
19
+ description: 'Build wheels but skip uv publish'
20
+ type: boolean
21
+ required: false
22
+ default: false
23
+ tag:
24
+ description: 'Tag to check out and build wheels from (defaults to caller ref)'
25
+ type: string
26
+ required: false
27
+ default: ''
12
28
  workflow_dispatch:
29
+ inputs:
30
+ dry_run:
31
+ description: 'Build wheels but skip uv publish'
32
+ type: boolean
33
+ required: false
34
+ default: false
35
+ tag:
36
+ description: 'Tag to check out and build wheels from (defaults to current ref)'
37
+ type: string
38
+ required: false
39
+ default: ''
13
40
 
14
41
  permissions:
15
42
  contents: read
16
43
 
17
44
  jobs:
18
45
  linux:
19
- if: ${{ github.event_name == 'workflow_dispatch' || github.event.workflow_run.conclusion == 'success' }}
20
46
  runs-on: ${{ matrix.platform.runner }}
21
47
  strategy:
22
48
  matrix:
@@ -35,6 +61,8 @@ jobs:
35
61
  target: ppc64le
36
62
  steps:
37
63
  - uses: actions/checkout@v6
64
+ with:
65
+ ref: ${{ inputs.tag }}
38
66
  - uses: actions/setup-python@v6
39
67
  with:
40
68
  python-version: '3.10'
@@ -59,7 +87,6 @@ jobs:
59
87
  path: dist
60
88
 
61
89
  musllinux:
62
- if: ${{ github.event_name == 'workflow_dispatch' || github.event.workflow_run.conclusion == 'success' }}
63
90
  runs-on: ${{ matrix.platform.runner }}
64
91
  strategy:
65
92
  matrix:
@@ -74,6 +101,8 @@ jobs:
74
101
  target: armv7
75
102
  steps:
76
103
  - uses: actions/checkout@v6
104
+ with:
105
+ ref: ${{ inputs.tag }}
77
106
  - uses: actions/setup-python@v6
78
107
  with:
79
108
  python-version: '3.10'
@@ -98,7 +127,6 @@ jobs:
98
127
  path: dist
99
128
 
100
129
  windows:
101
- if: ${{ github.event_name == 'workflow_dispatch' || github.event.workflow_run.conclusion == 'success' }}
102
130
  runs-on: ${{ matrix.platform.runner }}
103
131
  strategy:
104
132
  matrix:
@@ -114,6 +142,8 @@ jobs:
114
142
  python_arch: arm64
115
143
  steps:
116
144
  - uses: actions/checkout@v6
145
+ with:
146
+ ref: ${{ inputs.tag }}
117
147
  - uses: actions/setup-python@v6
118
148
  with:
119
149
  python-version: '3.13'
@@ -141,7 +171,6 @@ jobs:
141
171
  path: dist
142
172
 
143
173
  macos:
144
- if: ${{ github.event_name == 'workflow_dispatch' || github.event.workflow_run.conclusion == 'success' }}
145
174
  runs-on: ${{ matrix.platform.runner }}
146
175
  strategy:
147
176
  matrix:
@@ -152,6 +181,8 @@ jobs:
152
181
  target: aarch64
153
182
  steps:
154
183
  - uses: actions/checkout@v6
184
+ with:
185
+ ref: ${{ inputs.tag }}
155
186
  - uses: actions/setup-python@v6
156
187
  with:
157
188
  python-version: '3.10'
@@ -177,10 +208,11 @@ jobs:
177
208
  path: dist
178
209
 
179
210
  sdist:
180
- if: ${{ github.event_name == 'workflow_dispatch' || github.event.workflow_run.conclusion == 'success' }}
181
211
  runs-on: ubuntu-latest
182
212
  steps:
183
213
  - uses: actions/checkout@v6
214
+ with:
215
+ ref: ${{ inputs.tag }}
184
216
  - name: Build sdist
185
217
  uses: PyO3/maturin-action@v1
186
218
  with:
@@ -196,7 +228,6 @@ jobs:
196
228
  environment: pypi
197
229
  name: Release
198
230
  runs-on: ubuntu-latest
199
- if: ${{ github.event_name == 'workflow_dispatch' || github.event.workflow_run.conclusion == 'success' }}
200
231
  needs: [linux, musllinux, windows, macos, sdist]
201
232
  permissions:
202
233
  # Use to sign the release artifacts
@@ -214,4 +245,14 @@ jobs:
214
245
  - name: Install uv
215
246
  uses: astral-sh/setup-uv@v7
216
247
  - name: Publish to PyPI
248
+ if: inputs.dry_run == false
217
249
  run: uv publish 'wheels-*/*'
250
+
251
+ - name: Dry-run summary (skipped uv publish)
252
+ if: inputs.dry_run == true
253
+ run: |
254
+ {
255
+ echo "## Dry-run: would have published the following wheels"
256
+ echo
257
+ ls -1 wheels-*/* | sed 's/^/- /'
258
+ } >> "$GITHUB_STEP_SUMMARY"
@@ -0,0 +1,101 @@
1
+ name: Release pipeline
2
+
3
+ on:
4
+ workflow_dispatch:
5
+ inputs:
6
+ increment:
7
+ description: "Force a specific bump (auto = let commitizen decide)"
8
+ type: choice
9
+ required: false
10
+ default: "auto"
11
+ options: ["auto", "PATCH", "MINOR", "MAJOR"]
12
+ skip_bump:
13
+ description: "Skip bump; release/publish/merge an existing tag instead"
14
+ type: boolean
15
+ required: false
16
+ default: false
17
+ tag:
18
+ description: "Existing tag to release (required when skip_bump=true)"
19
+ type: string
20
+ required: false
21
+ default: ""
22
+ dry_run:
23
+ description: "Run end-to-end without external side effects"
24
+ type: boolean
25
+ required: false
26
+ default: false
27
+
28
+ permissions:
29
+ contents: write
30
+ id-token: write
31
+ attestations: write
32
+
33
+ jobs:
34
+ resolve:
35
+ runs-on: ubuntu-latest
36
+ outputs:
37
+ tag: ${{ steps.out.outputs.tag }}
38
+ steps:
39
+ - uses: actions/checkout@v4
40
+ with:
41
+ fetch-depth: 0
42
+ - name: Validate inputs
43
+ id: out
44
+ run: |
45
+ if [ "${{ inputs.skip_bump }}" = "true" ]; then
46
+ TAG="${{ inputs.tag }}"
47
+ if [ -z "$TAG" ]; then
48
+ echo "::error::skip_bump=true requires a tag input"
49
+ exit 1
50
+ fi
51
+ if ! echo "$TAG" | grep -Eq '^[0-9]+\.[0-9]+\.[0-9]+$'; then
52
+ echo "::error::tag '$TAG' does not match X.Y.Z"
53
+ exit 1
54
+ fi
55
+ git fetch --tags --quiet
56
+ if ! git rev-parse --verify --quiet "refs/tags/$TAG" >/dev/null; then
57
+ echo "::error::tag '$TAG' does not exist on the remote"
58
+ exit 1
59
+ fi
60
+ echo "tag=$TAG" >> "$GITHUB_OUTPUT"
61
+ else
62
+ echo "tag=" >> "$GITHUB_OUTPUT"
63
+ fi
64
+
65
+ bump:
66
+ needs: resolve
67
+ if: inputs.skip_bump == false
68
+ uses: ./.github/workflows/bump.yaml
69
+ secrets: inherit
70
+ with:
71
+ increment: ${{ inputs.increment }}
72
+ dry_run: ${{ inputs.dry_run }}
73
+
74
+ release:
75
+ needs: [resolve, bump]
76
+ if: |
77
+ always() &&
78
+ needs.resolve.result == 'success' &&
79
+ (needs.bump.result == 'success' || needs.bump.result == 'skipped')
80
+ uses: ./.github/workflows/release.yaml
81
+ secrets: inherit
82
+ with:
83
+ tag: ${{ needs.bump.outputs.tag || needs.resolve.outputs.tag }}
84
+ dry_run: ${{ inputs.dry_run }}
85
+
86
+ publish:
87
+ needs: [resolve, bump, release]
88
+ if: always() && needs.release.result == 'success'
89
+ uses: ./.github/workflows/publish.yaml
90
+ secrets: inherit
91
+ with:
92
+ dry_run: ${{ inputs.dry_run }}
93
+ tag: ${{ needs.bump.outputs.tag || needs.resolve.outputs.tag }}
94
+
95
+ merge:
96
+ needs: publish
97
+ if: always() && needs.publish.result == 'success'
98
+ uses: ./.github/workflows/merge.yaml
99
+ secrets: inherit
100
+ with:
101
+ dry_run: ${{ inputs.dry_run }}
@@ -0,0 +1,71 @@
1
+ name: Create release
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - '[0-9]+.[0-9]+.[0-9]+'
7
+ workflow_dispatch:
8
+ inputs:
9
+ tag:
10
+ description: 'Tag to release (e.g. 0.10.0)'
11
+ required: true
12
+ workflow_call:
13
+ inputs:
14
+ tag:
15
+ description: 'Tag to release'
16
+ type: string
17
+ required: true
18
+ dry_run:
19
+ description: 'Build the release body but do not create a GH release'
20
+ type: boolean
21
+ required: false
22
+ default: false
23
+
24
+ jobs:
25
+ release:
26
+ runs-on: ubuntu-latest
27
+ permissions:
28
+ contents: write
29
+ steps:
30
+ - uses: actions/checkout@v4
31
+ with:
32
+ fetch-depth: 0
33
+
34
+ - name: Resolve tag
35
+ id: tag
36
+ run: |
37
+ case "${{ github.event_name }}" in
38
+ push) echo "tag=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT ;;
39
+ workflow_dispatch) echo "tag=${{ inputs.tag }}" >> $GITHUB_OUTPUT ;;
40
+ workflow_call) echo "tag=${{ inputs.tag }}" >> $GITHUB_OUTPUT ;;
41
+ esac
42
+
43
+ - name: Extract changelog section
44
+ run: |
45
+ TAG="${{ steps.tag.outputs.tag }}"
46
+ awk -v tag="$TAG" '
47
+ $0 ~ "^## " tag " " { flag=1; next }
48
+ flag && /^## / { exit }
49
+ flag { print }
50
+ ' CHANGELOG.md > body.md
51
+
52
+ - name: Dry-run summary
53
+ if: github.event_name == 'workflow_call' && inputs.dry_run == true
54
+ run: |
55
+ {
56
+ echo "## Dry-run: release ${{ steps.tag.outputs.tag }}"
57
+ echo
58
+ echo "Would create a GitHub Release with the following body:"
59
+ echo
60
+ echo '```markdown'
61
+ cat body.md
62
+ echo '```'
63
+ } >> "$GITHUB_STEP_SUMMARY"
64
+
65
+ - name: Create GitHub release
66
+ if: ${{ !(github.event_name == 'workflow_call' && inputs.dry_run == true) }}
67
+ uses: softprops/action-gh-release@v3
68
+ with:
69
+ tag_name: ${{ steps.tag.outputs.tag }}
70
+ body_path: body.md
71
+ token: ${{ secrets.GH_TOKEN }}
@@ -1,3 +1,59 @@
1
+ ## 0.12.0 (2026-05-29)
2
+
3
+ ### Feat
4
+
5
+ - **translate**: validate OHE inputs are one-hot
6
+ - **translate**: add validate flag for nucleotide input checking
7
+
8
+ ### Fix
9
+
10
+ - **ci**: merge runs when publish succeeded after a transitive skip
11
+ - **ci**: allow publish to run when bump was skipped
12
+ - **ci**: publish.yaml checks out the bumped tag, not the dispatch SHA
13
+
14
+ ### Refactor
15
+
16
+ - **translate**: gate LUT build with predicate, drop exception control-flow
17
+ - **translate**: single source of truth for codon LUT index
18
+
19
+ ### Perf
20
+
21
+ - **translate**: route Ragged path through codon LUT
22
+ - **translate**: O(1) LUT codon→AA lookup — 179× speedup on bench
23
+
24
+ ## 0.11.1 (2026-05-21)
25
+
26
+ ### Feat
27
+
28
+ - **ci**: add release-pipeline.yaml orchestrator
29
+ - add on_path flag to Vertex and path stack to ShuffleBuffers
30
+ - specialize k=2 path to skip LUT and codes lookup
31
+ - add ShuffleBuffers with sparse-reset LUT
32
+ - add KmerIndex trait with DirectLut and HashLut impls
33
+ - add kmer_encode module with rolling integer encoder
34
+ - ragged support for ohe, decode_ohe, tokenize, decode_tokens
35
+
36
+ ### Fix
37
+
38
+ - **ci**: grant orchestrator permissions required by called workflows
39
+ - **ci**: make merge.yaml workflow_call-able, drop workflow_run
40
+ - **ci**: make publish.yaml workflow_call-able, drop workflow_run
41
+ - **ci**: make release.yaml workflow_call-able with dry_run
42
+ - **ci**: make bump.yaml workflow_call-able with increment and dry_run
43
+ - derive per-row seeds so batches get independent shuffles
44
+ - support arbitrary leading/trailing dims across public functions
45
+ - types
46
+
47
+ ### Refactor
48
+
49
+ - pool LUT and reuse buffers via ShuffleBuffers
50
+ - rewrite k_shuffle1 with KmerIndex strategy + u32 Vertex
51
+
52
+ ### Perf
53
+
54
+ - replace two-pass Wilson with single-pass loop-erased random walk
55
+ - add criterion benchmark for k_shuffle
56
+
1
57
  ## 0.11.0 (2026-05-07)
2
58
 
3
59
  ### Feat
@@ -72,3 +72,7 @@ Only `kshuffle.rs` is compiled. It's exposed as `seqpro._k_shuffle` (called by `
72
72
  - Axis arguments (`length_axis`, `ohe_axis`) are always integers referring to the NumPy axis index; negative indexing is supported.
73
73
  - The `transforms/` module wraps functional ops into callable objects with `__call__` for use in data pipelines.
74
74
  - Conventional commits are enforced — use `feat:`, `fix:`, `ci:`, `bump:`, `refactor:`, `docs:`, etc. prefixes.
75
+
76
+ ## Skills
77
+
78
+ This repo ships an installable skill at `skills/seqpro/SKILL.md` (skills.sh layout) describing how to use seqpro. **Any PR that adds a new public feature, changes a public signature, or makes a breaking change MUST update `skills/seqpro/SKILL.md` in the same PR.** Doc-only edits and internal refactors do not require updates unless they change conventions documented in the skill. Reviewers should reject feature/breaking PRs that don't touch the skill.