corpus-assay 0.1.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 (108) hide show
  1. corpus_assay-0.1.0/.github/workflows/ci.yml +98 -0
  2. corpus_assay-0.1.0/.github/workflows/release.yml +213 -0
  3. corpus_assay-0.1.0/.gitignore +30 -0
  4. corpus_assay-0.1.0/.python-version +1 -0
  5. corpus_assay-0.1.0/CHANGELOG.md +32 -0
  6. corpus_assay-0.1.0/CITATION.cff +23 -0
  7. corpus_assay-0.1.0/CONTRIBUTING.md +59 -0
  8. corpus_assay-0.1.0/Cargo.lock +1597 -0
  9. corpus_assay-0.1.0/Cargo.toml +45 -0
  10. corpus_assay-0.1.0/LICENSE +201 -0
  11. corpus_assay-0.1.0/Makefile +46 -0
  12. corpus_assay-0.1.0/PKG-INFO +345 -0
  13. corpus_assay-0.1.0/README.md +311 -0
  14. corpus_assay-0.1.0/SECURITY.md +18 -0
  15. corpus_assay-0.1.0/docs/architecture.md +70 -0
  16. corpus_assay-0.1.0/docs/assets/README.md +34 -0
  17. corpus_assay-0.1.0/docs/assets/favicon.svg +8 -0
  18. corpus_assay-0.1.0/docs/assets/icon-dark.svg +18 -0
  19. corpus_assay-0.1.0/docs/assets/icon-mono.svg +17 -0
  20. corpus_assay-0.1.0/docs/assets/icon.svg +17 -0
  21. corpus_assay-0.1.0/docs/assets/logo-dark.svg +19 -0
  22. corpus_assay-0.1.0/docs/assets/logo.svg +19 -0
  23. corpus_assay-0.1.0/docs/assets/make_logos.py +239 -0
  24. corpus_assay-0.1.0/docs/assets/social-preview.png +0 -0
  25. corpus_assay-0.1.0/docs/cli.md +337 -0
  26. corpus_assay-0.1.0/docs/configuration.md +135 -0
  27. corpus_assay-0.1.0/docs/experimental-spaced-seeds.md +77 -0
  28. corpus_assay-0.1.0/docs/how-it-works.md +111 -0
  29. corpus_assay-0.1.0/docs/outputs.md +106 -0
  30. corpus_assay-0.1.0/examples/config.yaml +21 -0
  31. corpus_assay-0.1.0/pyproject.toml +105 -0
  32. corpus_assay-0.1.0/python/corpus_assay/__init__.py +49 -0
  33. corpus_assay-0.1.0/python/corpus_assay/__main__.py +7 -0
  34. corpus_assay-0.1.0/python/corpus_assay/_native.pyi +49 -0
  35. corpus_assay-0.1.0/python/corpus_assay/_version.py +16 -0
  36. corpus_assay-0.1.0/python/corpus_assay/attribution.py +223 -0
  37. corpus_assay-0.1.0/python/corpus_assay/benchmark_registry.py +97 -0
  38. corpus_assay-0.1.0/python/corpus_assay/benchmark_spec.py +65 -0
  39. corpus_assay-0.1.0/python/corpus_assay/benchmarks.py +277 -0
  40. corpus_assay-0.1.0/python/corpus_assay/cli.py +1229 -0
  41. corpus_assay-0.1.0/python/corpus_assay/config.py +230 -0
  42. corpus_assay-0.1.0/python/corpus_assay/constants.py +18 -0
  43. corpus_assay-0.1.0/python/corpus_assay/formats.py +106 -0
  44. corpus_assay-0.1.0/python/corpus_assay/indexing.py +302 -0
  45. corpus_assay-0.1.0/python/corpus_assay/inspect.py +157 -0
  46. corpus_assay-0.1.0/python/corpus_assay/ngram_config.json +74 -0
  47. corpus_assay-0.1.0/python/corpus_assay/normalization.py +38 -0
  48. corpus_assay-0.1.0/python/corpus_assay/py.typed +0 -0
  49. corpus_assay-0.1.0/python/corpus_assay/reporting.py +963 -0
  50. corpus_assay-0.1.0/python/corpus_assay/scanner/__init__.py +6 -0
  51. corpus_assay-0.1.0/python/corpus_assay/scanner/fingerprint.py +69 -0
  52. corpus_assay-0.1.0/python/corpus_assay/scanner/io.py +232 -0
  53. corpus_assay-0.1.0/python/corpus_assay/scanner/layout.py +77 -0
  54. corpus_assay-0.1.0/python/corpus_assay/scanner/runner.py +115 -0
  55. corpus_assay-0.1.0/python/corpus_assay/scanner/schema.py +84 -0
  56. corpus_assay-0.1.0/python/corpus_assay/scanner/worker.py +170 -0
  57. corpus_assay-0.1.0/python/corpus_assay/schemas/__init__.py +45 -0
  58. corpus_assay-0.1.0/python/corpus_assay/schemas/doc_result.py +45 -0
  59. corpus_assay-0.1.0/python/corpus_assay/schemas/index_meta.py +34 -0
  60. corpus_assay-0.1.0/python/corpus_assay/schemas/run_manifest.py +94 -0
  61. corpus_assay-0.1.0/python/corpus_assay/schemas/scan_summary.py +35 -0
  62. corpus_assay-0.1.0/python/corpus_assay/schemas/stopgrams_meta.py +27 -0
  63. corpus_assay-0.1.0/python/corpus_assay/services/__init__.py +0 -0
  64. corpus_assay-0.1.0/python/corpus_assay/services/config_validation.py +181 -0
  65. corpus_assay-0.1.0/python/corpus_assay/services/hf_parquet.py +76 -0
  66. corpus_assay-0.1.0/python/corpus_assay/services/index_cache.py +91 -0
  67. corpus_assay-0.1.0/python/corpus_assay/services/planning.py +46 -0
  68. corpus_assay-0.1.0/python/corpus_assay/spaced_index.py +259 -0
  69. corpus_assay-0.1.0/python/corpus_assay/spaced_seeds.py +401 -0
  70. corpus_assay-0.1.0/python/corpus_assay/stopgrams.py +575 -0
  71. corpus_assay-0.1.0/python/corpus_assay/text_utils.py +141 -0
  72. corpus_assay-0.1.0/python/corpus_assay/utils.py +14 -0
  73. corpus_assay-0.1.0/src/formats.rs +117 -0
  74. corpus_assay-0.1.0/src/index.rs +259 -0
  75. corpus_assay-0.1.0/src/items_index.rs +103 -0
  76. corpus_assay-0.1.0/src/lib.rs +37 -0
  77. corpus_assay-0.1.0/src/mmap_index.rs +205 -0
  78. corpus_assay-0.1.0/src/scan.rs +787 -0
  79. corpus_assay-0.1.0/src/spaced.rs +354 -0
  80. corpus_assay-0.1.0/src/stopgrams.rs +120 -0
  81. corpus_assay-0.1.0/src/text.rs +305 -0
  82. corpus_assay-0.1.0/tests/_index_helpers.py +40 -0
  83. corpus_assay-0.1.0/tests/e2e/test_cli_offline.py +283 -0
  84. corpus_assay-0.1.0/tests/fixtures/spaced_golden.json +2586 -0
  85. corpus_assay-0.1.0/tests/test_attrib.py +128 -0
  86. corpus_assay-0.1.0/tests/test_benchmark_registry.py +58 -0
  87. corpus_assay-0.1.0/tests/test_benchmarks_config.py +417 -0
  88. corpus_assay-0.1.0/tests/test_cli.py +534 -0
  89. corpus_assay-0.1.0/tests/test_config_validation.py +209 -0
  90. corpus_assay-0.1.0/tests/test_import.py +7 -0
  91. corpus_assay-0.1.0/tests/test_indexing.py +267 -0
  92. corpus_assay-0.1.0/tests/test_integration_scan.py +95 -0
  93. corpus_assay-0.1.0/tests/test_ngram_config.py +218 -0
  94. corpus_assay-0.1.0/tests/test_ngram_override.py +161 -0
  95. corpus_assay-0.1.0/tests/test_reporting_v1.py +283 -0
  96. corpus_assay-0.1.0/tests/test_scan_item_aware.py +306 -0
  97. corpus_assay-0.1.0/tests/test_scan_jsonl.py +109 -0
  98. corpus_assay-0.1.0/tests/test_scan_stream_rust.py +148 -0
  99. corpus_assay-0.1.0/tests/test_scanner.py +404 -0
  100. corpus_assay-0.1.0/tests/test_spaced_golden.py +187 -0
  101. corpus_assay-0.1.0/tests/test_spaced_index.py +136 -0
  102. corpus_assay-0.1.0/tests/test_spaced_rust_parity.py +119 -0
  103. corpus_assay-0.1.0/tests/test_spaced_scan_integration.py +114 -0
  104. corpus_assay-0.1.0/tests/test_spaced_seeds.py +258 -0
  105. corpus_assay-0.1.0/tests/test_spaced_wiring.py +426 -0
  106. corpus_assay-0.1.0/tests/test_stopgrams.py +228 -0
  107. corpus_assay-0.1.0/tests/test_text_utils.py +65 -0
  108. corpus_assay-0.1.0/uv.lock +1820 -0
@@ -0,0 +1,98 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+
8
+ permissions:
9
+ contents: read
10
+
11
+ concurrency:
12
+ group: ${{ github.workflow }}-${{ github.ref }}
13
+ cancel-in-progress: true
14
+
15
+ jobs:
16
+ lint:
17
+ name: Lint
18
+ runs-on: ubuntu-latest
19
+ steps:
20
+ - uses: actions/checkout@v7
21
+ - uses: dtolnay/rust-toolchain@stable
22
+ with:
23
+ components: rustfmt, clippy
24
+ - uses: Swatinem/rust-cache@v2
25
+ - uses: actions/setup-python@v7
26
+ with:
27
+ python-version: "3.12"
28
+ - uses: astral-sh/setup-uv@v10.2.0
29
+ with:
30
+ enable-cache: true
31
+ - name: Install (builds the extension)
32
+ run: uv sync --locked
33
+ - run: cargo fmt --all --check
34
+ - run: cargo clippy --locked --all-targets -- -D warnings
35
+ - run: uv run --no-sync ruff check .
36
+ - run: uv run --no-sync ruff format --check .
37
+ - run: uv run --no-sync pyright
38
+
39
+ test:
40
+ name: Test (${{ matrix.os }}, Python ${{ matrix.python }})
41
+ runs-on: ${{ matrix.os }}
42
+ strategy:
43
+ fail-fast: false
44
+ matrix:
45
+ os: [ubuntu-latest, macos-14, windows-latest]
46
+ python: ["3.12", "3.13"]
47
+ steps:
48
+ - uses: actions/checkout@v7
49
+ - uses: dtolnay/rust-toolchain@stable
50
+ - uses: Swatinem/rust-cache@v2
51
+ - uses: actions/setup-python@v7
52
+ with:
53
+ python-version: ${{ matrix.python }}
54
+ - uses: astral-sh/setup-uv@v10.2.0
55
+ with:
56
+ enable-cache: true
57
+ - name: Install (builds the extension)
58
+ run: uv sync --locked --python ${{ matrix.python }}
59
+ - name: Test
60
+ run: uv run --no-sync pytest --cov=corpus_assay --cov-report=term-missing
61
+
62
+ wheel:
63
+ name: Wheel contents + offline e2e
64
+ runs-on: ubuntu-latest
65
+ steps:
66
+ - uses: actions/checkout@v7
67
+ - uses: dtolnay/rust-toolchain@stable
68
+ - uses: Swatinem/rust-cache@v2
69
+ - uses: actions/setup-python@v7
70
+ with:
71
+ python-version: "3.12"
72
+ - uses: astral-sh/setup-uv@v10.2.0
73
+ - name: Build wheel
74
+ run: uvx maturin build --release --locked --out dist
75
+ - name: Check wheel contents
76
+ run: |
77
+ python - <<'EOF'
78
+ import glob, zipfile
79
+ (wheel,) = glob.glob("dist/*.whl")
80
+ names = zipfile.ZipFile(wheel).namelist()
81
+ print("\n".join(names))
82
+ leaked = [n for n in names if n.endswith(".rs") or "Cargo." in n
83
+ or n.startswith(("target/", "tests/", "src/"))]
84
+ assert not leaked, f"unexpected files in wheel: {leaked}"
85
+ assert "corpus_assay/ngram_config.json" in names
86
+ assert "corpus_assay/py.typed" in names
87
+ native = [n for n in names
88
+ if n.startswith("corpus_assay/_native") and not n.endswith(".pyi")]
89
+ assert len(native) == 1 and ".abi3." in native[0], native
90
+ EOF
91
+ - name: Install the wheel into a clean venv
92
+ run: |
93
+ uv venv "$RUNNER_TEMP/wheel-venv" --python 3.12
94
+ uv pip install --python "$RUNNER_TEMP/wheel-venv" dist/*.whl pytest
95
+ - name: Offline e2e against the installed wheel
96
+ run: |
97
+ "$RUNNER_TEMP/wheel-venv/bin/python" -c "import corpus_assay; print(corpus_assay.__file__)"
98
+ "$RUNNER_TEMP/wheel-venv/bin/python" -m pytest tests -m e2e -p no:cacheprovider
@@ -0,0 +1,213 @@
1
+ name: Release
2
+
3
+ # Tag push (v*): build -> smoke-test -> TestPyPI -> verify -> PyPI -> GitHub Release.
4
+ # Manual run: build + smoke-test, optionally publishing to TestPyPI only.
5
+ on:
6
+ push:
7
+ tags: ["v*"]
8
+ workflow_dispatch:
9
+ inputs:
10
+ publish:
11
+ description: "Publish the built distributions to"
12
+ type: choice
13
+ options: [none, testpypi]
14
+ default: none
15
+
16
+ permissions:
17
+ contents: read
18
+
19
+ jobs:
20
+ version-check:
21
+ name: Version check
22
+ runs-on: ubuntu-latest
23
+ steps:
24
+ - uses: actions/checkout@v7
25
+ - name: Tag matches Cargo.toml and CITATION.cff versions
26
+ if: startsWith(github.ref, 'refs/tags/v')
27
+ run: |
28
+ version=$(python3 -c "import tomllib; print(tomllib.load(open('Cargo.toml', 'rb'))['package']['version'])")
29
+ if [ "v${version}" != "${GITHUB_REF_NAME}" ]; then
30
+ echo "Tag ${GITHUB_REF_NAME} does not match Cargo.toml version ${version}" >&2
31
+ exit 1
32
+ fi
33
+ # Zenodo takes the archived release's metadata from CITATION.cff.
34
+ cff_version=$(sed -n 's/^version: *"\{0,1\}\([^"]*\)"\{0,1\} *$/\1/p' CITATION.cff)
35
+ if [ "${cff_version}" != "${version}" ]; then
36
+ echo "CITATION.cff version '${cff_version}' does not match ${version}" >&2
37
+ exit 1
38
+ fi
39
+
40
+ sdist:
41
+ name: Build sdist
42
+ runs-on: ubuntu-latest
43
+ steps:
44
+ - uses: actions/checkout@v7
45
+ - uses: PyO3/maturin-action@v1
46
+ with:
47
+ command: sdist
48
+ args: --out dist
49
+ - uses: actions/upload-artifact@v7
50
+ with:
51
+ name: dist-sdist
52
+ path: dist
53
+ if-no-files-found: error
54
+
55
+ wheels:
56
+ name: Build wheel (${{ matrix.target }})
57
+ runs-on: ${{ matrix.os }}
58
+ strategy:
59
+ fail-fast: false
60
+ matrix:
61
+ include:
62
+ - os: ubuntu-latest
63
+ target: x86_64-unknown-linux-gnu
64
+ - os: ubuntu-24.04-arm
65
+ target: aarch64-unknown-linux-gnu
66
+ - os: macos-14
67
+ target: aarch64-apple-darwin
68
+ - os: macos-14
69
+ target: x86_64-apple-darwin
70
+ - os: windows-latest
71
+ target: x86_64-pc-windows-msvc
72
+ steps:
73
+ - uses: actions/checkout@v7
74
+ - uses: actions/setup-python@v7
75
+ with:
76
+ python-version: "3.12"
77
+ # abi3 (see Cargo.toml): one cp312-abi3 wheel per platform covers CPython >= 3.12.
78
+ - uses: PyO3/maturin-action@v1
79
+ with:
80
+ target: ${{ matrix.target }}
81
+ manylinux: auto
82
+ args: --release --locked --out dist
83
+ sccache: true
84
+ - uses: actions/upload-artifact@v7
85
+ with:
86
+ name: dist-${{ matrix.target }}
87
+ path: dist
88
+ if-no-files-found: error
89
+
90
+ smoke:
91
+ name: Smoke test (${{ matrix.os }}, Python ${{ matrix.python }})
92
+ needs: [wheels]
93
+ runs-on: ${{ matrix.os }}
94
+ strategy:
95
+ fail-fast: false
96
+ matrix:
97
+ os: [ubuntu-latest, ubuntu-24.04-arm, macos-14, macos-15-intel, windows-latest]
98
+ python: ["3.12", "3.13"]
99
+ steps:
100
+ - uses: actions/checkout@v7
101
+ - uses: actions/download-artifact@v8
102
+ with:
103
+ pattern: dist-*
104
+ path: dist
105
+ merge-multiple: true
106
+ - uses: actions/setup-python@v7
107
+ with:
108
+ python-version: ${{ matrix.python }}
109
+ - name: Install the built wheel
110
+ shell: bash
111
+ run: |
112
+ python -m pip install --upgrade pip
113
+ python -m pip install --no-index --no-deps --only-binary :all: --find-links dist corpus-assay
114
+ python -m pip install corpus-assay pytest
115
+ - name: Smoke
116
+ shell: bash
117
+ run: |
118
+ corpus-assay --version
119
+ python -c "import corpus_assay, corpus_assay._native as n; print(corpus_assay.__file__, n.__version__)"
120
+ - name: Test suite against the installed wheel
121
+ run: python -m pytest tests -q -p no:cacheprovider
122
+
123
+ publish-testpypi:
124
+ name: Publish to TestPyPI
125
+ needs: [version-check, sdist, smoke]
126
+ if: startsWith(github.ref, 'refs/tags/v') || inputs.publish == 'testpypi'
127
+ runs-on: ubuntu-latest
128
+ environment:
129
+ name: testpypi
130
+ url: https://test.pypi.org/p/corpus-assay
131
+ permissions:
132
+ id-token: write
133
+ steps:
134
+ - uses: actions/download-artifact@v8
135
+ with:
136
+ pattern: dist-*
137
+ path: dist
138
+ merge-multiple: true
139
+ - uses: pypa/gh-action-pypi-publish@release/v1
140
+ with:
141
+ repository-url: https://test.pypi.org/legacy/
142
+ skip-existing: true
143
+
144
+ verify-testpypi:
145
+ name: Verify TestPyPI install
146
+ needs: [publish-testpypi]
147
+ runs-on: ubuntu-latest
148
+ steps:
149
+ - uses: actions/checkout@v7
150
+ - uses: actions/setup-python@v7
151
+ with:
152
+ python-version: "3.12"
153
+ - name: Install corpus-assay from TestPyPI (dependencies from PyPI)
154
+ shell: bash
155
+ run: |
156
+ version=$(python -c "import tomllib; print(tomllib.load(open('Cargo.toml', 'rb'))['package']['version'])")
157
+ for attempt in 1 2 3 4 5 6 7 8 9 10; do
158
+ if python -m pip install --no-deps --only-binary :all: \
159
+ --index-url https://test.pypi.org/simple/ "corpus-assay==${version}"; then
160
+ break
161
+ fi
162
+ echo "TestPyPI not ready yet (attempt ${attempt}); retrying in 30s"
163
+ sleep 30
164
+ done
165
+ python -m pip show corpus-assay
166
+ # Dependencies come from PyPI; corpus-assay itself is already satisfied.
167
+ python -m pip install "corpus-assay==${version}" pytest
168
+ python -c "import corpus_assay; assert corpus_assay.__version__ == '${version}', corpus_assay.__version__"
169
+ - name: Offline e2e
170
+ run: python -m pytest tests -m e2e -q -p no:cacheprovider
171
+
172
+ publish-pypi:
173
+ name: Publish to PyPI
174
+ needs: [verify-testpypi]
175
+ if: startsWith(github.ref, 'refs/tags/v')
176
+ runs-on: ubuntu-latest
177
+ environment:
178
+ name: pypi
179
+ url: https://pypi.org/p/corpus-assay
180
+ permissions:
181
+ id-token: write
182
+ steps:
183
+ - uses: actions/download-artifact@v8
184
+ with:
185
+ pattern: dist-*
186
+ path: dist
187
+ merge-multiple: true
188
+ - uses: pypa/gh-action-pypi-publish@release/v1
189
+
190
+ github-release:
191
+ name: GitHub Release
192
+ needs: [publish-pypi]
193
+ runs-on: ubuntu-latest
194
+ permissions:
195
+ contents: write
196
+ steps:
197
+ - uses: actions/checkout@v7
198
+ - uses: actions/download-artifact@v8
199
+ with:
200
+ pattern: dist-*
201
+ path: dist
202
+ merge-multiple: true
203
+ - name: Create release with CHANGELOG notes
204
+ env:
205
+ GH_TOKEN: ${{ github.token }}
206
+ run: |
207
+ version="${GITHUB_REF_NAME#v}"
208
+ awk -v ver="$version" '
209
+ $0 ~ "^## \\[" ver "\\]" { found = 1; next }
210
+ found && /^## \[/ { exit }
211
+ found { print }
212
+ ' CHANGELOG.md > notes.md
213
+ gh release create "$GITHUB_REF_NAME" dist/* --title "corpus-assay $version" --notes-file notes.md
@@ -0,0 +1,30 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *.egg-info/
5
+ .venv/
6
+ .python-version.local
7
+
8
+ # Build outputs
9
+ /target/
10
+ /dist/
11
+ /build/
12
+ python/corpus_assay/*.so
13
+ python/corpus_assay/*.pyd
14
+ python/corpus_assay/*.dll
15
+
16
+ # Tooling caches
17
+ .pytest_cache/
18
+ .ruff_cache/
19
+ .mypy_cache/
20
+ .coverage
21
+ .coverage.*
22
+ coverage.xml
23
+ htmlcov/
24
+ .cache/
25
+
26
+ # Editors / OS
27
+ .idea/
28
+ .vscode/
29
+ *.swp
30
+ .DS_Store
@@ -0,0 +1 @@
1
+ 3.12
@@ -0,0 +1,32 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented here. The format follows
4
+ [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and the project uses
5
+ [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
+
7
+ ## [Unreleased]
8
+
9
+ ## [0.1.0] - 2026-10-03
10
+
11
+ Initial public release.
12
+
13
+ ### Added
14
+
15
+ - `build-index`: hashed word n-gram index from Hugging Face or local benchmark
16
+ splits, with per-benchmark and per-item attribution sidecars, subtraction splits,
17
+ and provenance metadata (dataset revisions, fingerprints, normalization hashes).
18
+ - `scan`, `run`, `run-hf`: multi-process Rust scanner over Parquet and JSONL
19
+ (`.gz`/`.zst`) shards, with an index-wide (`union`) or single-item (`item`) gate,
20
+ resumable per-shard outputs, and sampled per-document evidence.
21
+ - `report`: leak tables by benchmark, shard, and item (JSON, CSV, Markdown).
22
+ - `build-stopgrams-direct`: stop-grams learned from a background corpus, applied
23
+ with `--stopgrams`.
24
+ - `init-config`, `list-benchmarks`, `describe-benchmark`, `validate-config`,
25
+ `inspect-index`, `inspect-run`, `reproduce`.
26
+ - Global `--ngram-config` to override the bundled normalization config. Scans refuse
27
+ an index built with a different config unless `--allow-config-mismatch` is passed.
28
+ - Experimental: spaced-seed recall channel (`build-spaced-index`, `--spaced-seeds`).
29
+ - Prebuilt abi3 wheels for CPython 3.12+ on Linux, macOS, and Windows.
30
+
31
+ [Unreleased]: https://github.com/mrcabbage972/corpus-assay/compare/v0.1.0...HEAD
32
+ [0.1.0]: https://github.com/mrcabbage972/corpus-assay/releases/tag/v0.1.0
@@ -0,0 +1,23 @@
1
+ cff-version: 1.2.0
2
+ message: "If you use this software, please cite it as below."
3
+ type: software
4
+ title: "corpus-assay: benchmark contamination detection for LLM training corpora"
5
+ abstract: >-
6
+ Fast, auditable n-gram detection of evaluation-benchmark contamination in LLM
7
+ training corpora, with a Rust scanner and per-benchmark and per-item attribution.
8
+ authors:
9
+ - family-names: May
10
+ given-names: Victor
11
+ repository-code: "https://github.com/mrcabbage972/corpus-assay"
12
+ license: Apache-2.0
13
+ version: 0.1.0
14
+ date-released: "2026-10-03"
15
+ # Zenodo archives every GitHub Release of this repository. Each release gets its own
16
+ # version DOI, and one concept DOI covers all versions (it resolves to the latest).
17
+ # The concept DOI goes in `doi:` once Zenodo has archived the first release (v0.1.0).
18
+ keywords:
19
+ - large language models
20
+ - evaluation
21
+ - data contamination
22
+ - decontamination
23
+ - benchmarks
@@ -0,0 +1,59 @@
1
+ # Contributing to corpus-assay
2
+
3
+ Thanks for your interest! Bug reports, feature requests, and pull requests are welcome.
4
+
5
+ ## Development setup
6
+
7
+ You need [uv](https://docs.astral.sh/uv/) and a stable [Rust toolchain](https://rustup.rs).
8
+
9
+ ```bash
10
+ git clone https://github.com/mrcabbage972/corpus-assay
11
+ cd corpus-assay
12
+ make dev # uv sync + build the Rust extension in place
13
+ make check # lint (ruff, pyright, rustfmt, clippy) + tests
14
+ ```
15
+
16
+ The package lives in `python/corpus_assay/` and the Rust extension in `src/`.
17
+ `uv sync` rebuilds the extension when Rust sources change. You can also rebuild
18
+ explicitly with `make dev` (or `make release-dev` for an optimized build). Tests always
19
+ run against the built extension, so rebuild after editing Rust.
20
+
21
+ Useful targets:
22
+
23
+ | Target | What it does |
24
+ | --- | --- |
25
+ | `make test` | Full test suite |
26
+ | `make e2e` | Offline end-to-end CLI tests only (`pytest -m e2e`) |
27
+ | `make test-cov` | Tests with coverage |
28
+ | `make lint` | Checks only; never modifies files |
29
+ | `make fmt` | Apply ruff and rustfmt formatting and safe fixes |
30
+ | `make wheel` | Build a release wheel into `dist/` |
31
+
32
+ ## Pull requests
33
+
34
+ - Keep changes focused, and add or update tests for behavior changes.
35
+ - `make check` must pass. CI runs it on Linux, macOS, and Windows for Python 3.12 and 3.13.
36
+ - Update `CHANGELOG.md` under *Unreleased* for user-visible changes.
37
+ - Changing the normalization pipeline, hashing, or a binary format changes what existing
38
+ indexes mean. Call it out in the PR and the changelog.
39
+ - The spaced-seed golden vectors (`tests/fixtures/spaced_golden.json`) should only change
40
+ when spaced-seed behavior is meant to change. Regenerate them with
41
+ `uv run python tests/test_spaced_golden.py`.
42
+
43
+ ## Releasing (maintainers)
44
+
45
+ 1. Bump `version` in `Cargo.toml` (the single source of the package version), set
46
+ `version` and `date-released` in `CITATION.cff`, and date the CHANGELOG section. The
47
+ release workflow refuses a tag that doesn't match `Cargo.toml` and `CITATION.cff`.
48
+ 2. Optionally dry-run: run the *Release* workflow manually with `publish: testpypi`.
49
+ 3. Tag and push: `git tag -a vX.Y.Z -m "corpus-assay X.Y.Z" && git push origin vX.Y.Z`.
50
+ The workflow then:
51
+ 1. builds the wheels and sdist;
52
+ 2. smoke-tests them on every platform;
53
+ 3. publishes to TestPyPI and verifies the install;
54
+ 4. publishes to PyPI after approval of the `pypi` environment;
55
+ 5. creates the GitHub Release.
56
+
57
+ Zenodo's GitHub integration archives the GitHub Release and mints a DOI for that
58
+ version. The concept DOI in `CITATION.cff` and the README badge covers all versions,
59
+ so it doesn't change between releases.