unalloc 0.2.0__tar.gz → 0.2.1__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.0 → unalloc-0.2.1}/CHANGELOG.md +11 -0
- {unalloc-0.2.0 → unalloc-0.2.1}/PKG-INFO +2 -1
- {unalloc-0.2.0 → unalloc-0.2.1}/README.md +1 -0
- {unalloc-0.2.0 → unalloc-0.2.1}/pyproject.toml +1 -1
- {unalloc-0.2.0 → unalloc-0.2.1}/src/unalloc/__init__.py +1 -1
- unalloc-0.2.1/tests/test_paper_lint.py +30 -0
- {unalloc-0.2.0 → unalloc-0.2.1}/.gitignore +0 -0
- {unalloc-0.2.0 → unalloc-0.2.1}/LICENSE +0 -0
- {unalloc-0.2.0 → unalloc-0.2.1}/src/unalloc/cli.py +0 -0
- {unalloc-0.2.0 → unalloc-0.2.1}/src/unalloc/core/__init__.py +0 -0
- {unalloc-0.2.0 → unalloc-0.2.1}/src/unalloc/core/attribute.py +0 -0
- {unalloc-0.2.0 → unalloc-0.2.1}/src/unalloc/core/models.py +0 -0
- {unalloc-0.2.0 → unalloc-0.2.1}/src/unalloc/core/normalize.py +0 -0
- {unalloc-0.2.0 → unalloc-0.2.1}/src/unalloc/core/reconcile.py +0 -0
- {unalloc-0.2.0 → unalloc-0.2.1}/src/unalloc/fixtures/anthropic_cost_report.json +0 -0
- {unalloc-0.2.0 → unalloc-0.2.1}/src/unalloc/fixtures/litellm_spend.json +0 -0
- {unalloc-0.2.0 → unalloc-0.2.1}/src/unalloc/fixtures/openai_costs.json +0 -0
- {unalloc-0.2.0 → unalloc-0.2.1}/src/unalloc/fixtures/opencost_allocation.json +0 -0
- {unalloc-0.2.0 → unalloc-0.2.1}/src/unalloc/render/__init__.py +0 -0
- {unalloc-0.2.0 → unalloc-0.2.1}/src/unalloc/render/table.py +0 -0
- {unalloc-0.2.0 → unalloc-0.2.1}/src/unalloc/sources/__init__.py +0 -0
- {unalloc-0.2.0 → unalloc-0.2.1}/src/unalloc/sources/anthropic.py +0 -0
- {unalloc-0.2.0 → unalloc-0.2.1}/src/unalloc/sources/base.py +0 -0
- {unalloc-0.2.0 → unalloc-0.2.1}/src/unalloc/sources/litellm.py +0 -0
- {unalloc-0.2.0 → unalloc-0.2.1}/src/unalloc/sources/openai.py +0 -0
- {unalloc-0.2.0 → unalloc-0.2.1}/src/unalloc/sources/opencost.py +0 -0
- {unalloc-0.2.0 → unalloc-0.2.1}/tests/test_attribute.py +0 -0
- {unalloc-0.2.0 → unalloc-0.2.1}/tests/test_cli.py +0 -0
- {unalloc-0.2.0 → unalloc-0.2.1}/tests/test_fetch.py +0 -0
- {unalloc-0.2.0 → unalloc-0.2.1}/tests/test_normalize.py +0 -0
- {unalloc-0.2.0 → unalloc-0.2.1}/tests/test_reconcile.py +0 -0
- {unalloc-0.2.0 → unalloc-0.2.1}/tests/test_sources.py +0 -0
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.2.1 — 2026-09-14
|
|
4
|
+
|
|
5
|
+
### Changed
|
|
6
|
+
- Paper prepared for arXiv: abstract leads with the attribution failures at the seams between ledgers and the H100 result; metering results are framed as disagreement between rules rather than over-charging, since none is a ground truth; new Related Work section (JouleShare, LLMVisor, PrefixShield, Cost-Governed RAG and others); defect catalogue moved to Appendix A; use of AI tools disclosed.
|
|
7
|
+
- `paper/build.py` fails on Typst that compiles but renders wrong (`~`, `;` after a citation, unescaped dollar amounts).
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
- `case_studies/gpu_validation`: benchmark client, fake server, remote setup script, analysis and evidence renderer for validating the metering results with real vLLM on a GPU, plus a DigitalOcean runbook. First run: H100, vLLM 0.29.0, Qwen2.5-7B-Instruct, 6,241 requests, 0 errors.
|
|
11
|
+
- Blog addendum with the verified GPU specs, results and bring-up/teardown evidence.
|
|
12
|
+
- Paper §9, "Validation on a datacenter GPU", with the H100 results table and figure; abstract, methodology table and limitations updated to match.
|
|
13
|
+
|
|
3
14
|
## 0.2.0 — 2026-09-13
|
|
4
15
|
|
|
5
16
|
Validated against five inference case studies; see `paper/unalloc-case-studies.pdf`.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: unalloc
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.1
|
|
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
|
|
@@ -198,6 +198,7 @@ Five studies push real (or realistically simulated) inference workloads through
|
|
|
198
198
|
| [`distributed`](https://github.com/timurista/unalloc/blob/main/case_studies/distributed) | Tensor and pipeline parallel on `torch.distributed` (gloo), verified against a single-process reference | Owner label on LeaderWorkerSet leaders only: 66% unallocated; falling back to `name` "fixes" it by sending 61% to a Helm chart name |
|
|
199
199
|
| [`hybrid_e2e`](https://github.com/timurista/unalloc/blob/main/case_studies/hybrid_e2e) | The real CLI as a subprocess against live mock OpenCost / LiteLLM / OpenAI / Anthropic APIs (Postgres-backed LiteLLM in the dev container) | Enabling every source double counts $11.8K; reading only page one of the billing APIs reports 25% of spend |
|
|
200
200
|
| [`use_cases`](https://github.com/timurista/unalloc/blob/main/case_studies/use_cases) | Labeling Pareto, per-feature unit economics, self-host break-even, CI budget gate | Three label fixes take a 67%-unallocated org under 10% |
|
|
201
|
+
| [`gpu_validation`](https://github.com/timurista/unalloc/blob/main/case_studies/gpu_validation) | Real vLLM 0.29 serving Qwen2.5-7B on a DigitalOcean H100, driven with the simulator's tenants ([runbook](https://github.com/timurista/unalloc/blob/main/case_studies/gpu_validation/RUNBOOK.md), [evidence](https://github.com/timurista/unalloc/tree/main/case_studies/results/gpu_validation/evidence)) | Token metering over-charges search by 12–14 points vs time share; GPU "utilization" reads 97% at 2 req/s and 99% at 16 req/s |
|
|
201
202
|
|
|
202
203
|
```bash
|
|
203
204
|
make research # CPU torch, notebook tooling, typst
|
|
@@ -157,6 +157,7 @@ Five studies push real (or realistically simulated) inference workloads through
|
|
|
157
157
|
| [`distributed`](https://github.com/timurista/unalloc/blob/main/case_studies/distributed) | Tensor and pipeline parallel on `torch.distributed` (gloo), verified against a single-process reference | Owner label on LeaderWorkerSet leaders only: 66% unallocated; falling back to `name` "fixes" it by sending 61% to a Helm chart name |
|
|
158
158
|
| [`hybrid_e2e`](https://github.com/timurista/unalloc/blob/main/case_studies/hybrid_e2e) | The real CLI as a subprocess against live mock OpenCost / LiteLLM / OpenAI / Anthropic APIs (Postgres-backed LiteLLM in the dev container) | Enabling every source double counts $11.8K; reading only page one of the billing APIs reports 25% of spend |
|
|
159
159
|
| [`use_cases`](https://github.com/timurista/unalloc/blob/main/case_studies/use_cases) | Labeling Pareto, per-feature unit economics, self-host break-even, CI budget gate | Three label fixes take a 67%-unallocated org under 10% |
|
|
160
|
+
| [`gpu_validation`](https://github.com/timurista/unalloc/blob/main/case_studies/gpu_validation) | Real vLLM 0.29 serving Qwen2.5-7B on a DigitalOcean H100, driven with the simulator's tenants ([runbook](https://github.com/timurista/unalloc/blob/main/case_studies/gpu_validation/RUNBOOK.md), [evidence](https://github.com/timurista/unalloc/tree/main/case_studies/results/gpu_validation/evidence)) | Token metering over-charges search by 12–14 points vs time share; GPU "utilization" reads 97% at 2 req/s and 99% at 16 req/s |
|
|
160
161
|
|
|
161
162
|
```bash
|
|
162
163
|
make research # CPU torch, notebook tooling, typst
|
|
@@ -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.1"
|
|
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"
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"""The paper build refuses Typst that compiles but renders wrong."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import sys
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
ROOT = Path(__file__).resolve().parents[1]
|
|
9
|
+
sys.path.insert(0, str(ROOT))
|
|
10
|
+
|
|
11
|
+
from paper.build import SOURCE, lint_source # noqa: E402
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def test_published_paper_source_is_clean():
|
|
15
|
+
assert lint_source(SOURCE.read_text()) == []
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def test_tilde_is_flagged_in_prose_but_not_in_code():
|
|
19
|
+
assert lint_source("reads only ~25% of spend") == [
|
|
20
|
+
"line 1: `~` renders as a non-breaking space; write ≈ or 'about'"
|
|
21
|
+
]
|
|
22
|
+
assert lint_source("run `ls ~/.ssh` first") == []
|
|
23
|
+
assert lint_source("```\ncd ~/unalloc\n```") == []
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def test_semicolon_after_citation_and_bare_dollar_are_flagged():
|
|
27
|
+
assert lint_source('prefills #c("sarathi"); step latency')
|
|
28
|
+
assert lint_source("costs $5,703 per month")
|
|
29
|
+
assert lint_source("costs \\$5,703 per month") == []
|
|
30
|
+
assert lint_source("where $U > P$ holds") == []
|
|
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
|