unalloc 0.2.2__tar.gz → 0.2.3__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.
- {unalloc-0.2.2 → unalloc-0.2.3}/CHANGELOG.md +10 -0
- {unalloc-0.2.2 → unalloc-0.2.3}/PKG-INFO +3 -3
- {unalloc-0.2.2 → unalloc-0.2.3}/README.md +2 -2
- {unalloc-0.2.2 → unalloc-0.2.3}/pyproject.toml +1 -1
- {unalloc-0.2.2 → unalloc-0.2.3}/src/unalloc/__init__.py +1 -1
- {unalloc-0.2.2 → unalloc-0.2.3}/tests/test_paper_numbers.py +50 -0
- {unalloc-0.2.2 → unalloc-0.2.3}/.gitignore +0 -0
- {unalloc-0.2.2 → unalloc-0.2.3}/LICENSE +0 -0
- {unalloc-0.2.2 → unalloc-0.2.3}/src/unalloc/cli.py +0 -0
- {unalloc-0.2.2 → unalloc-0.2.3}/src/unalloc/core/__init__.py +0 -0
- {unalloc-0.2.2 → unalloc-0.2.3}/src/unalloc/core/attribute.py +0 -0
- {unalloc-0.2.2 → unalloc-0.2.3}/src/unalloc/core/models.py +0 -0
- {unalloc-0.2.2 → unalloc-0.2.3}/src/unalloc/core/normalize.py +0 -0
- {unalloc-0.2.2 → unalloc-0.2.3}/src/unalloc/core/reconcile.py +0 -0
- {unalloc-0.2.2 → unalloc-0.2.3}/src/unalloc/fixtures/anthropic_cost_report.json +0 -0
- {unalloc-0.2.2 → unalloc-0.2.3}/src/unalloc/fixtures/litellm_spend.json +0 -0
- {unalloc-0.2.2 → unalloc-0.2.3}/src/unalloc/fixtures/openai_costs.json +0 -0
- {unalloc-0.2.2 → unalloc-0.2.3}/src/unalloc/fixtures/opencost_allocation.json +0 -0
- {unalloc-0.2.2 → unalloc-0.2.3}/src/unalloc/render/__init__.py +0 -0
- {unalloc-0.2.2 → unalloc-0.2.3}/src/unalloc/render/table.py +0 -0
- {unalloc-0.2.2 → unalloc-0.2.3}/src/unalloc/sources/__init__.py +0 -0
- {unalloc-0.2.2 → unalloc-0.2.3}/src/unalloc/sources/anthropic.py +0 -0
- {unalloc-0.2.2 → unalloc-0.2.3}/src/unalloc/sources/base.py +0 -0
- {unalloc-0.2.2 → unalloc-0.2.3}/src/unalloc/sources/litellm.py +0 -0
- {unalloc-0.2.2 → unalloc-0.2.3}/src/unalloc/sources/openai.py +0 -0
- {unalloc-0.2.2 → unalloc-0.2.3}/src/unalloc/sources/opencost.py +0 -0
- {unalloc-0.2.2 → unalloc-0.2.3}/tests/test_attribute.py +0 -0
- {unalloc-0.2.2 → unalloc-0.2.3}/tests/test_cli.py +0 -0
- {unalloc-0.2.2 → unalloc-0.2.3}/tests/test_docs_build.py +0 -0
- {unalloc-0.2.2 → unalloc-0.2.3}/tests/test_fetch.py +0 -0
- {unalloc-0.2.2 → unalloc-0.2.3}/tests/test_normalize.py +0 -0
- {unalloc-0.2.2 → unalloc-0.2.3}/tests/test_paper_lint.py +0 -0
- {unalloc-0.2.2 → unalloc-0.2.3}/tests/test_reconcile.py +0 -0
- {unalloc-0.2.2 → unalloc-0.2.3}/tests/test_sources.py +0 -0
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.2.3 — 2026-09-21
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
- Figure 9's within-run spread is drawn as its own vertical bar rather than an error bar hung off the whole-run point. The old form had to clip whenever the whole-run share fell outside the window quartiles, which it does at three of the eight plotted points — the whole-run share is weighted by each window's traffic, so it need not lie inside the quartiles of its own windows.
|
|
7
|
+
- §9 no longer presents the window statistics as a bootstrap confidence interval or as a bound on uncertainty. Consecutive windows of one run are not independent observations, so the paragraph now reports median, interquartile range and sign as descriptive statistics of that run, and the cross-reference matches what the figure actually draws. `bootstrap_ci` is renamed `resample_range`, and the metrics key `divergence_mean_ci95` becomes `divergence_mean_resample_range`.
|
|
8
|
+
- arXiv kit refreshed against the built PDF: 14 pages, AI-use disclosure on page 13, and the concept DOI in the Comments field. The standalone abstract gained the synthetic-scenario qualification and the session-initial arrival-rate clarification that the paper's abstract already carried.
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- `tests/test_paper_numbers.py` also checks the submission kit: the page, figure and table counts against the committed PDF, the concept DOI in both the kit and the paper, and the standalone abstract's length and scope wording.
|
|
12
|
+
|
|
3
13
|
## 0.2.2 — 2026-09-21
|
|
4
14
|
|
|
5
15
|
### Fixed
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: unalloc
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.3
|
|
4
4
|
Summary: Find the AI spend nobody owns. Joins OpenCost allocation data with LLM provider bills and reports what's unattributed.
|
|
5
5
|
Project-URL: Homepage, https://github.com/timurista/unalloc
|
|
6
6
|
Project-URL: Issues, https://github.com/timurista/unalloc/issues
|
|
@@ -261,14 +261,14 @@ ruff check . && pytest
|
|
|
261
261
|
|
|
262
262
|
If you use unalloc or its case studies, please cite the archived release. GitHub's "Cite this repository" button produces the same entry from [`CITATION.cff`](https://github.com/timurista/unalloc/blob/main/CITATION.cff).
|
|
263
263
|
|
|
264
|
-
- **All versions:** [doi:10.5281/zenodo.22761012](https://doi.org/10.5281/zenodo.22761012), which always resolves to the latest release — currently 0.2.
|
|
264
|
+
- **All versions:** [doi:10.5281/zenodo.22761012](https://doi.org/10.5281/zenodo.22761012), which always resolves to the latest release — currently 0.2.3, the code the paper describes
|
|
265
265
|
- **Version 0.2.1:** [doi:10.5281/zenodo.22761013](https://doi.org/10.5281/zenodo.22761013)
|
|
266
266
|
|
|
267
267
|
```bibtex
|
|
268
268
|
@software{urista_unalloc_2026,
|
|
269
269
|
author = {Urista, Timothy},
|
|
270
270
|
title = {unalloc: find the AI spend nobody owns},
|
|
271
|
-
version = {0.2.
|
|
271
|
+
version = {0.2.3},
|
|
272
272
|
year = {2026},
|
|
273
273
|
doi = {10.5281/zenodo.22761012},
|
|
274
274
|
url = {https://github.com/timurista/unalloc}
|
|
@@ -219,14 +219,14 @@ ruff check . && pytest
|
|
|
219
219
|
|
|
220
220
|
If you use unalloc or its case studies, please cite the archived release. GitHub's "Cite this repository" button produces the same entry from [`CITATION.cff`](https://github.com/timurista/unalloc/blob/main/CITATION.cff).
|
|
221
221
|
|
|
222
|
-
- **All versions:** [doi:10.5281/zenodo.22761012](https://doi.org/10.5281/zenodo.22761012), which always resolves to the latest release — currently 0.2.
|
|
222
|
+
- **All versions:** [doi:10.5281/zenodo.22761012](https://doi.org/10.5281/zenodo.22761012), which always resolves to the latest release — currently 0.2.3, the code the paper describes
|
|
223
223
|
- **Version 0.2.1:** [doi:10.5281/zenodo.22761013](https://doi.org/10.5281/zenodo.22761013)
|
|
224
224
|
|
|
225
225
|
```bibtex
|
|
226
226
|
@software{urista_unalloc_2026,
|
|
227
227
|
author = {Urista, Timothy},
|
|
228
228
|
title = {unalloc: find the AI spend nobody owns},
|
|
229
|
-
version = {0.2.
|
|
229
|
+
version = {0.2.3},
|
|
230
230
|
year = {2026},
|
|
231
231
|
doi = {10.5281/zenodo.22761012},
|
|
232
232
|
url = {https://github.com/timurista/unalloc}
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "unalloc"
|
|
7
|
-
version = "0.2.
|
|
7
|
+
version = "0.2.3"
|
|
8
8
|
description = "Find the AI spend nobody owns. Joins OpenCost allocation data with LLM provider bills and reports what's unattributed."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.11"
|
|
@@ -110,3 +110,53 @@ def test_configured_rate_is_distinguished_from_completed_traffic(rows):
|
|
|
110
110
|
assert "session-initial" in text
|
|
111
111
|
done = [run["requests"] / run["wall_s"] for _, run in rows]
|
|
112
112
|
assert f"{min(done):.1f} to {max(done):.1f} completed requests per second" in text
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
# --- the arXiv submission kit must describe the PDF that is actually committed ---
|
|
116
|
+
|
|
117
|
+
PDF = ROOT / "paper" / "unalloc-case-studies.pdf"
|
|
118
|
+
KIT = ROOT / "paper" / "arxiv" / "SUBMISSION.md"
|
|
119
|
+
ABSTRACT = ROOT / "paper" / "arxiv" / "abstract.txt"
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def _pdf_pages(path: Path) -> int:
|
|
123
|
+
"""Page count from the PDF's page tree, without a PDF library."""
|
|
124
|
+
blob = path.read_bytes()
|
|
125
|
+
counts = re.findall(rb"/Type\s*/Pages[^>]*?/Count\s+(\d+)", blob)
|
|
126
|
+
assert counts, "no page tree found in the PDF"
|
|
127
|
+
return max(int(c) for c in counts)
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
@pytest.mark.skipif(not PDF.exists() or not KIT.exists(), reason="paper artifacts not present")
|
|
131
|
+
def test_submission_comments_match_the_built_pdf():
|
|
132
|
+
kit = KIT.read_text()
|
|
133
|
+
pages = _pdf_pages(PDF)
|
|
134
|
+
assert f"| Comments | {pages} pages," in kit, (
|
|
135
|
+
f"SUBMISSION.md Comments claims a different length; the PDF has {pages} pages"
|
|
136
|
+
)
|
|
137
|
+
source = SOURCE.read_text()
|
|
138
|
+
figures = source.count("#figure(image(")
|
|
139
|
+
tables = len(re.findall(r"^#figure\($", source, re.MULTILINE))
|
|
140
|
+
assert f"{pages} pages, {figures} figures, {tables} tables" in kit
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
@pytest.mark.skipif(not KIT.exists(), reason="submission kit not present")
|
|
144
|
+
def test_submission_kit_cites_the_concept_doi():
|
|
145
|
+
"""A version DOI goes stale on the next release; the concept DOI does not."""
|
|
146
|
+
kit = KIT.read_text()
|
|
147
|
+
concept = "10.5281/zenodo.22761012"
|
|
148
|
+
assert f"Software: doi:{concept}" in kit
|
|
149
|
+
assert concept in SOURCE.read_text(), "the paper itself should cite the same DOI"
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
@pytest.mark.skipif(not ABSTRACT.exists(), reason="abstract not present")
|
|
153
|
+
def test_standalone_abstract_carries_the_same_qualifications_as_the_paper():
|
|
154
|
+
text = ABSTRACT.read_text().strip()
|
|
155
|
+
assert len(text) <= 1920, f"arXiv caps the abstract at 1920 characters; this is {len(text)}"
|
|
156
|
+
# The two scope corrections must survive in the copy that readers see first.
|
|
157
|
+
assert "constructed multi-pod deployment scenario" in text
|
|
158
|
+
assert "synthetic OpenCost allocations" in text
|
|
159
|
+
assert "session-initial" in text
|
|
160
|
+
assert "completed requests per second" in text
|
|
161
|
+
# The bare claim the review flagged must not come back.
|
|
162
|
+
assert "97-99% from 2 to 16 requests per second" not in text
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|