class1 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.
- class1-0.1.0/PKG-INFO +135 -0
- class1-0.1.0/README.md +119 -0
- class1-0.1.0/blue_book/actuals.py +126 -0
- class1-0.1.0/blue_book/actuals_history.py +503 -0
- class1-0.1.0/blue_book/allocation.py +31 -0
- class1-0.1.0/blue_book/calibration_data.py +544 -0
- class1-0.1.0/blue_book/estimate_store.py +101 -0
- class1-0.1.0/blue_book/focus.py +143 -0
- class1-0.1.0/blue_book/footprint_actuals.py +93 -0
- class1-0.1.0/blue_book/ingest.py +61 -0
- class1-0.1.0/blue_book/ingest_core.py +184 -0
- class1-0.1.0/blue_book/mine.py +171 -0
- class1-0.1.0/blue_book/opendata.py +180 -0
- class1-0.1.0/blue_book/otel_receiver.py +260 -0
- class1-0.1.0/blue_book/search_first.py +28 -0
- class1-0.1.0/blue_book/usage_openai.py +57 -0
- class1-0.1.0/class1.egg-info/PKG-INFO +135 -0
- class1-0.1.0/class1.egg-info/SOURCES.txt +175 -0
- class1-0.1.0/class1.egg-info/dependency_links.txt +1 -0
- class1-0.1.0/class1.egg-info/entry_points.txt +2 -0
- class1-0.1.0/class1.egg-info/requires.txt +10 -0
- class1-0.1.0/class1.egg-info/top_level.txt +4 -0
- class1-0.1.0/cost_engine/__init__.py +97 -0
- class1-0.1.0/cost_engine/aliases.py +53 -0
- class1-0.1.0/cost_engine/autopoiesis.py +109 -0
- class1-0.1.0/cost_engine/basis.py +118 -0
- class1-0.1.0/cost_engine/basis_of_estimate.py +65 -0
- class1-0.1.0/cost_engine/budget.py +101 -0
- class1-0.1.0/cost_engine/calibration.py +136 -0
- class1-0.1.0/cost_engine/calibrator.py +91 -0
- class1-0.1.0/cost_engine/capability.py +130 -0
- class1-0.1.0/cost_engine/capability_data.py +43 -0
- class1-0.1.0/cost_engine/capex.py +90 -0
- class1-0.1.0/cost_engine/classification.py +45 -0
- class1-0.1.0/cost_engine/cloud_cost.py +78 -0
- class1-0.1.0/cost_engine/commitment.py +41 -0
- class1-0.1.0/cost_engine/contingency.py +26 -0
- class1-0.1.0/cost_engine/distributions.py +28 -0
- class1-0.1.0/cost_engine/energy.py +92 -0
- class1-0.1.0/cost_engine/escalation.py +40 -0
- class1-0.1.0/cost_engine/estimate_decay.py +38 -0
- class1-0.1.0/cost_engine/evidence.py +217 -0
- class1-0.1.0/cost_engine/grades_real.py +123 -0
- class1-0.1.0/cost_engine/mcp_overhead.py +80 -0
- class1-0.1.0/cost_engine/monte_carlo.py +107 -0
- class1-0.1.0/cost_engine/prices.py +89 -0
- class1-0.1.0/cost_engine/pricing_loader.py +35 -0
- class1-0.1.0/cost_engine/recommend.py +65 -0
- class1-0.1.0/cost_engine/report.py +69 -0
- class1-0.1.0/cost_engine/scenario.py +106 -0
- class1-0.1.0/cost_engine/self_cost.py +27 -0
- class1-0.1.0/cost_engine/structured_price.py +162 -0
- class1-0.1.0/pyproject.toml +36 -0
- class1-0.1.0/setup.cfg +4 -0
- class1-0.1.0/snapshots/__init__.py +0 -0
- class1-0.1.0/snapshots/actuals_index.json +738 -0
- class1-0.1.0/snapshots/actuarial_table_real.json +2132 -0
- class1-0.1.0/snapshots/autobuild_runs.json +176 -0
- class1-0.1.0/snapshots/capability.json +280 -0
- class1-0.1.0/snapshots/cloud_price_index.json +219694 -0
- class1-0.1.0/snapshots/estimates.json +54 -0
- class1-0.1.0/snapshots/footprint_basis.json +33 -0
- class1-0.1.0/snapshots/grid_intensity.json +31 -0
- class1-0.1.0/snapshots/price_index.json +45810 -0
- class1-0.1.0/snapshots/pricing.json +49088 -0
- class1-0.1.0/snapshots/pricing_structure.json +10193 -0
- class1-0.1.0/snapshots/spec_sheet.json +419463 -0
- class1-0.1.0/snapshots/water_basis.json +17 -0
- class1-0.1.0/takeoff/__init__.py +14 -0
- class1-0.1.0/takeoff/estimate_pr.py +423 -0
- class1-0.1.0/takeoff/license.py +91 -0
- class1-0.1.0/takeoff/pilot.py +68 -0
- class1-0.1.0/takeoff/policy.py +96 -0
- class1-0.1.0/takeoff/post_pr.py +67 -0
- class1-0.1.0/takeoff/scan.py +354 -0
- class1-0.1.0/takeoff/scan_treesitter.py +173 -0
- class1-0.1.0/takeoff/translate.py +92 -0
- class1-0.1.0/tests/test_actuals.py +51 -0
- class1-0.1.0/tests/test_actuals_history.py +191 -0
- class1-0.1.0/tests/test_actuarial.py +52 -0
- class1-0.1.0/tests/test_aliases.py +31 -0
- class1-0.1.0/tests/test_allocation.py +27 -0
- class1-0.1.0/tests/test_analyze.py +61 -0
- class1-0.1.0/tests/test_analyze_trends.py +12 -0
- class1-0.1.0/tests/test_api_sources.py +125 -0
- class1-0.1.0/tests/test_autobuild_agents.py +254 -0
- class1-0.1.0/tests/test_autobuild_loop.py +348 -0
- class1-0.1.0/tests/test_autobuild_robustness.py +23 -0
- class1-0.1.0/tests/test_autopoiesis.py +139 -0
- class1-0.1.0/tests/test_basis.py +105 -0
- class1-0.1.0/tests/test_basis_of_estimate.py +49 -0
- class1-0.1.0/tests/test_budget.py +200 -0
- class1-0.1.0/tests/test_calibration.py +25 -0
- class1-0.1.0/tests/test_calibration_data.py +366 -0
- class1-0.1.0/tests/test_calibrator.py +58 -0
- class1-0.1.0/tests/test_capability_data.py +27 -0
- class1-0.1.0/tests/test_capability_ingest.py +44 -0
- class1-0.1.0/tests/test_capability_tail.py +58 -0
- class1-0.1.0/tests/test_capex.py +44 -0
- class1-0.1.0/tests/test_classification.py +31 -0
- class1-0.1.0/tests/test_cloud_cost.py +29 -0
- class1-0.1.0/tests/test_cloud_prices.py +53 -0
- class1-0.1.0/tests/test_code_harvest.py +71 -0
- class1-0.1.0/tests/test_commitment.py +29 -0
- class1-0.1.0/tests/test_contingency.py +34 -0
- class1-0.1.0/tests/test_distributions.py +117 -0
- class1-0.1.0/tests/test_drift.py +147 -0
- class1-0.1.0/tests/test_driver.py +232 -0
- class1-0.1.0/tests/test_effort.py +23 -0
- class1-0.1.0/tests/test_energy.py +55 -0
- class1-0.1.0/tests/test_escalation.py +46 -0
- class1-0.1.0/tests/test_estimate_decay.py +26 -0
- class1-0.1.0/tests/test_estimate_pr.py +72 -0
- class1-0.1.0/tests/test_estimate_pr_grade_join.py +22 -0
- class1-0.1.0/tests/test_estimate_store.py +35 -0
- class1-0.1.0/tests/test_evidence.py +291 -0
- class1-0.1.0/tests/test_evidence_signed.py +27 -0
- class1-0.1.0/tests/test_focus.py +114 -0
- class1-0.1.0/tests/test_footprint_actuals.py +47 -0
- class1-0.1.0/tests/test_footprint_carbon.py +40 -0
- class1-0.1.0/tests/test_footprint_materials.py +35 -0
- class1-0.1.0/tests/test_footprint_mc.py +50 -0
- class1-0.1.0/tests/test_footprint_water.py +43 -0
- class1-0.1.0/tests/test_github_action_api.py +87 -0
- class1-0.1.0/tests/test_governor.py +177 -0
- class1-0.1.0/tests/test_grades_real.py +90 -0
- class1-0.1.0/tests/test_harvest_recommend.py +50 -0
- class1-0.1.0/tests/test_health.py +335 -0
- class1-0.1.0/tests/test_health_fix_tasks.py +26 -0
- class1-0.1.0/tests/test_history_parsers.py +136 -0
- class1-0.1.0/tests/test_ingest_core.py +62 -0
- class1-0.1.0/tests/test_jobs.py +240 -0
- class1-0.1.0/tests/test_js_engine_parity.py +93 -0
- class1-0.1.0/tests/test_license.py +136 -0
- class1-0.1.0/tests/test_lock.py +155 -0
- class1-0.1.0/tests/test_lock_stale.py +108 -0
- class1-0.1.0/tests/test_mcp_overhead.py +42 -0
- class1-0.1.0/tests/test_metering.py +171 -0
- class1-0.1.0/tests/test_metering_usage_records.py +105 -0
- class1-0.1.0/tests/test_mine.py +256 -0
- class1-0.1.0/tests/test_model_swap_delta.py +39 -0
- class1-0.1.0/tests/test_monte_carlo.py +126 -0
- class1-0.1.0/tests/test_opendata.py +34 -0
- class1-0.1.0/tests/test_organism.py +101 -0
- class1-0.1.0/tests/test_otel_receiver.py +114 -0
- class1-0.1.0/tests/test_pilot.py +21 -0
- class1-0.1.0/tests/test_planner.py +323 -0
- class1-0.1.0/tests/test_planner_tuple_provider.py +18 -0
- class1-0.1.0/tests/test_policy_gate.py +232 -0
- class1-0.1.0/tests/test_post_pr.py +23 -0
- class1-0.1.0/tests/test_preflight.py +42 -0
- class1-0.1.0/tests/test_price_history.py +41 -0
- class1-0.1.0/tests/test_prices.py +48 -0
- class1-0.1.0/tests/test_prices_medallion.py +306 -0
- class1-0.1.0/tests/test_provider_local.py +38 -0
- class1-0.1.0/tests/test_provider_usage.py +57 -0
- class1-0.1.0/tests/test_recommend.py +55 -0
- class1-0.1.0/tests/test_report_boe.py +21 -0
- class1-0.1.0/tests/test_resilience.py +222 -0
- class1-0.1.0/tests/test_roadmap.py +184 -0
- class1-0.1.0/tests/test_router.py +56 -0
- class1-0.1.0/tests/test_scan.py +141 -0
- class1-0.1.0/tests/test_scan_bare_imports.py +40 -0
- class1-0.1.0/tests/test_scan_gemini_langchain.py +110 -0
- class1-0.1.0/tests/test_scan_inferred_model.py +54 -0
- class1-0.1.0/tests/test_scan_treesitter.py +49 -0
- class1-0.1.0/tests/test_scenario.py +190 -0
- class1-0.1.0/tests/test_scout.py +179 -0
- class1-0.1.0/tests/test_self_calibrate.py +192 -0
- class1-0.1.0/tests/test_self_calibrate_measured.py +97 -0
- class1-0.1.0/tests/test_self_cost.py +19 -0
- class1-0.1.0/tests/test_source_catalogs.py +44 -0
- class1-0.1.0/tests/test_spec_sheet.py +81 -0
- class1-0.1.0/tests/test_structured_price.py +98 -0
- class1-0.1.0/tests/test_translate.py +122 -0
- class1-0.1.0/tests/test_usage_openai.py +40 -0
- class1-0.1.0/tests/test_variance_waterfall.py +34 -0
class1-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: class1
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Monthly LLM cost-risk estimation and project controls for AI systems
|
|
5
|
+
Requires-Python: >=3.11
|
|
6
|
+
Description-Content-Type: text/markdown
|
|
7
|
+
Requires-Dist: numpy>=1.26.0
|
|
8
|
+
Requires-Dist: pandas>=2.0.0
|
|
9
|
+
Requires-Dist: openai>=1.0.0
|
|
10
|
+
Requires-Dist: PyJWT>=2.8.0
|
|
11
|
+
Requires-Dist: cryptography>=42.0.0
|
|
12
|
+
Provides-Extra: dev
|
|
13
|
+
Requires-Dist: pytest~=8.3.0; extra == "dev"
|
|
14
|
+
Requires-Dist: mypy; extra == "dev"
|
|
15
|
+
Requires-Dist: ruff; extra == "dev"
|
|
16
|
+
|
|
17
|
+
# Class1 (Internal name: abc7d) — Project controls and cost-risk estimation for AI systems
|
|
18
|
+
|
|
19
|
+
Class1 is a high-performance cost-engineering tool for LLM-based systems. Unlike typical observability tools that look backward at historical spend, Class1 focuses on **estimation**: providing a risk-adjusted forecast of a code change's monthly cost delta **in the pull request, before merge**, with a declared AACE estimate class and a calibration loop.
|
|
20
|
+
|
|
21
|
+
Cost engineering, not dashboards.
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## How it works
|
|
26
|
+
|
|
27
|
+
When a developer submits a PR, the Class1 GitHub Action:
|
|
28
|
+
1. **Scans the diff** to identify added, modified, or removed LLM callsites (Python AST + TS/JS tree-sitter).
|
|
29
|
+
2. **Translates code changes** (model swaps, token changes, tool changes) into baseline vs. head scenarios.
|
|
30
|
+
3. **Runs a Monte Carlo simulation** using Common Random Numbers (CRN) to estimate the monthly cost delta.
|
|
31
|
+
4. **Applies a budget policy** to automatically warn or block the PR if the P90 tail risk exceeds your threshold.
|
|
32
|
+
5. **Posts a detailed cost-risk report** directly to the PR comments.
|
|
33
|
+
|
|
34
|
+
```
|
|
35
|
+
ABC7D · AI cost-risk report
|
|
36
|
+
=========================================
|
|
37
|
+
Expected Monthly Delta: +$124.50
|
|
38
|
+
P50 (Median) Delta: +$112.00
|
|
39
|
+
P90 (Tail Risk) Delta: +$210.00
|
|
40
|
+
P95 Delta: +$245.00
|
|
41
|
+
|
|
42
|
+
Estimate Class: Class 4 (Study)
|
|
43
|
+
Accuracy Range: -30% / +50%
|
|
44
|
+
|
|
45
|
+
Recommendation:
|
|
46
|
+
Optimal model selected for the workload. Under-spec models (e.g. gpt-4o-mini)
|
|
47
|
+
would result in lower unit cost but higher overall cost due to retries (+14%).
|
|
48
|
+
|
|
49
|
+
Verdict: PASS
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## Getting Started: GitHub Action Setup
|
|
55
|
+
|
|
56
|
+
Add the Class1 check to your repository in three simple steps:
|
|
57
|
+
|
|
58
|
+
### 1. Create a budget policy
|
|
59
|
+
Add a `.class1.json` file at the root of your repository:
|
|
60
|
+
```json
|
|
61
|
+
{
|
|
62
|
+
"fail_pr_if": {
|
|
63
|
+
"delta_p90_usd": 500.0,
|
|
64
|
+
"warn_at_fraction": 0.8
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
*If a PR's estimated monthly P90 cost increase exceeds $500, the GitHub status check will fail, blocking the merge.*
|
|
69
|
+
|
|
70
|
+
### 2. Configure the GitHub Actions workflow
|
|
71
|
+
Create `.github/workflows/class1.yml`:
|
|
72
|
+
```yaml
|
|
73
|
+
name: Class1 Cost-Risk Guard
|
|
74
|
+
|
|
75
|
+
on:
|
|
76
|
+
pull_request:
|
|
77
|
+
branches: [ main ]
|
|
78
|
+
|
|
79
|
+
jobs:
|
|
80
|
+
estimate:
|
|
81
|
+
runs-on: ubuntu-latest
|
|
82
|
+
steps:
|
|
83
|
+
- name: Checkout Code
|
|
84
|
+
uses: actions/checkout@v4
|
|
85
|
+
with:
|
|
86
|
+
fetch-depth: 0 # Required to scan history and base ref diffs
|
|
87
|
+
|
|
88
|
+
- name: Run Class1 Guard
|
|
89
|
+
uses: class1-dev/class1@v1
|
|
90
|
+
with:
|
|
91
|
+
license_key: ${{ secrets.CLASS1_LICENSE_KEY }}
|
|
92
|
+
github_token: ${{ secrets.GITHUB_TOKEN }}
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### 3. Add your License Key (Premium features)
|
|
96
|
+
To unlock blocking budget gates, custom price overrides, and data persistence for post-merge calibration, get a license key from [https://class1.dev](https://class1.dev) and add it as a Repository Secret named `CLASS1_LICENSE_KEY`.
|
|
97
|
+
|
|
98
|
+
*Class1 remains completely **free and advisory** (posting comments without blocking) for open-source repositories and individual developers.*
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
## Architecture & Subsystems (For Developers)
|
|
103
|
+
|
|
104
|
+
If you are developing or hosting Class1 yourself, the project is structured as follows:
|
|
105
|
+
|
|
106
|
+
1. **`cost_engine/`** — Pure cost-risk math (no GitHub/UI/DB).
|
|
107
|
+
- Monte Carlo simulation with systemic risk factors (`monte_carlo.py`, `distributions.py`).
|
|
108
|
+
- Forward escalation forecast decomposed into price, volume, and structure (`escalation.py`).
|
|
109
|
+
- Contingency and sensitivity tornado analysis (`contingency.py`).
|
|
110
|
+
- Estimate classification based on AACE standards (`classification.py`).
|
|
111
|
+
- Ecological footprint delta tracking (carbon, water, materials) (`footprint/`).
|
|
112
|
+
2. **`blue_book/`** — The historical ledger database.
|
|
113
|
+
- Per-provider token usage normalization and deduplicated cost calculation.
|
|
114
|
+
- Spec sheet and historical capability indexing (`model_capability`).
|
|
115
|
+
- MEDALLION pipeline (`bronze -> silver -> gold`) for ingestion.
|
|
116
|
+
3. **`takeoff/`** — The product integration surface.
|
|
117
|
+
- Python stdlib AST diff scanner and TS/JS tree-sitter scanner.
|
|
118
|
+
- Translation layers to transform code changes into Scenario models.
|
|
119
|
+
- CLI tool (`python -m takeoff.estimate_pr`) and GitHub Action harness.
|
|
120
|
+
|
|
121
|
+
### Local Development Commands
|
|
122
|
+
Run tests constantly using the project's Makefile wrapper:
|
|
123
|
+
```bash
|
|
124
|
+
make test # Run full test suite (~870 tests, 2.5s)
|
|
125
|
+
make demo # Execute end-to-end local PR estimation demo
|
|
126
|
+
make up # Spin up local throwaway Postgres instance (docker-free)
|
|
127
|
+
make down # Tear down local Postgres instance
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
132
|
+
## License
|
|
133
|
+
|
|
134
|
+
Class1 is licensed under the Business Source License 1.1 (BSL) — see [LICENSE](file:///Users/owner/Desktop/abc7d/LICENSE) for details. The project relies on price and capability dataset snapshots under their respective open-source licenses.
|
|
135
|
+
|
class1-0.1.0/README.md
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
# Class1 (Internal name: abc7d) — Project controls and cost-risk estimation for AI systems
|
|
2
|
+
|
|
3
|
+
Class1 is a high-performance cost-engineering tool for LLM-based systems. Unlike typical observability tools that look backward at historical spend, Class1 focuses on **estimation**: providing a risk-adjusted forecast of a code change's monthly cost delta **in the pull request, before merge**, with a declared AACE estimate class and a calibration loop.
|
|
4
|
+
|
|
5
|
+
Cost engineering, not dashboards.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## How it works
|
|
10
|
+
|
|
11
|
+
When a developer submits a PR, the Class1 GitHub Action:
|
|
12
|
+
1. **Scans the diff** to identify added, modified, or removed LLM callsites (Python AST + TS/JS tree-sitter).
|
|
13
|
+
2. **Translates code changes** (model swaps, token changes, tool changes) into baseline vs. head scenarios.
|
|
14
|
+
3. **Runs a Monte Carlo simulation** using Common Random Numbers (CRN) to estimate the monthly cost delta.
|
|
15
|
+
4. **Applies a budget policy** to automatically warn or block the PR if the P90 tail risk exceeds your threshold.
|
|
16
|
+
5. **Posts a detailed cost-risk report** directly to the PR comments.
|
|
17
|
+
|
|
18
|
+
```
|
|
19
|
+
ABC7D · AI cost-risk report
|
|
20
|
+
=========================================
|
|
21
|
+
Expected Monthly Delta: +$124.50
|
|
22
|
+
P50 (Median) Delta: +$112.00
|
|
23
|
+
P90 (Tail Risk) Delta: +$210.00
|
|
24
|
+
P95 Delta: +$245.00
|
|
25
|
+
|
|
26
|
+
Estimate Class: Class 4 (Study)
|
|
27
|
+
Accuracy Range: -30% / +50%
|
|
28
|
+
|
|
29
|
+
Recommendation:
|
|
30
|
+
Optimal model selected for the workload. Under-spec models (e.g. gpt-4o-mini)
|
|
31
|
+
would result in lower unit cost but higher overall cost due to retries (+14%).
|
|
32
|
+
|
|
33
|
+
Verdict: PASS
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## Getting Started: GitHub Action Setup
|
|
39
|
+
|
|
40
|
+
Add the Class1 check to your repository in three simple steps:
|
|
41
|
+
|
|
42
|
+
### 1. Create a budget policy
|
|
43
|
+
Add a `.class1.json` file at the root of your repository:
|
|
44
|
+
```json
|
|
45
|
+
{
|
|
46
|
+
"fail_pr_if": {
|
|
47
|
+
"delta_p90_usd": 500.0,
|
|
48
|
+
"warn_at_fraction": 0.8
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
*If a PR's estimated monthly P90 cost increase exceeds $500, the GitHub status check will fail, blocking the merge.*
|
|
53
|
+
|
|
54
|
+
### 2. Configure the GitHub Actions workflow
|
|
55
|
+
Create `.github/workflows/class1.yml`:
|
|
56
|
+
```yaml
|
|
57
|
+
name: Class1 Cost-Risk Guard
|
|
58
|
+
|
|
59
|
+
on:
|
|
60
|
+
pull_request:
|
|
61
|
+
branches: [ main ]
|
|
62
|
+
|
|
63
|
+
jobs:
|
|
64
|
+
estimate:
|
|
65
|
+
runs-on: ubuntu-latest
|
|
66
|
+
steps:
|
|
67
|
+
- name: Checkout Code
|
|
68
|
+
uses: actions/checkout@v4
|
|
69
|
+
with:
|
|
70
|
+
fetch-depth: 0 # Required to scan history and base ref diffs
|
|
71
|
+
|
|
72
|
+
- name: Run Class1 Guard
|
|
73
|
+
uses: class1-dev/class1@v1
|
|
74
|
+
with:
|
|
75
|
+
license_key: ${{ secrets.CLASS1_LICENSE_KEY }}
|
|
76
|
+
github_token: ${{ secrets.GITHUB_TOKEN }}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### 3. Add your License Key (Premium features)
|
|
80
|
+
To unlock blocking budget gates, custom price overrides, and data persistence for post-merge calibration, get a license key from [https://class1.dev](https://class1.dev) and add it as a Repository Secret named `CLASS1_LICENSE_KEY`.
|
|
81
|
+
|
|
82
|
+
*Class1 remains completely **free and advisory** (posting comments without blocking) for open-source repositories and individual developers.*
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
## Architecture & Subsystems (For Developers)
|
|
87
|
+
|
|
88
|
+
If you are developing or hosting Class1 yourself, the project is structured as follows:
|
|
89
|
+
|
|
90
|
+
1. **`cost_engine/`** — Pure cost-risk math (no GitHub/UI/DB).
|
|
91
|
+
- Monte Carlo simulation with systemic risk factors (`monte_carlo.py`, `distributions.py`).
|
|
92
|
+
- Forward escalation forecast decomposed into price, volume, and structure (`escalation.py`).
|
|
93
|
+
- Contingency and sensitivity tornado analysis (`contingency.py`).
|
|
94
|
+
- Estimate classification based on AACE standards (`classification.py`).
|
|
95
|
+
- Ecological footprint delta tracking (carbon, water, materials) (`footprint/`).
|
|
96
|
+
2. **`blue_book/`** — The historical ledger database.
|
|
97
|
+
- Per-provider token usage normalization and deduplicated cost calculation.
|
|
98
|
+
- Spec sheet and historical capability indexing (`model_capability`).
|
|
99
|
+
- MEDALLION pipeline (`bronze -> silver -> gold`) for ingestion.
|
|
100
|
+
3. **`takeoff/`** — The product integration surface.
|
|
101
|
+
- Python stdlib AST diff scanner and TS/JS tree-sitter scanner.
|
|
102
|
+
- Translation layers to transform code changes into Scenario models.
|
|
103
|
+
- CLI tool (`python -m takeoff.estimate_pr`) and GitHub Action harness.
|
|
104
|
+
|
|
105
|
+
### Local Development Commands
|
|
106
|
+
Run tests constantly using the project's Makefile wrapper:
|
|
107
|
+
```bash
|
|
108
|
+
make test # Run full test suite (~870 tests, 2.5s)
|
|
109
|
+
make demo # Execute end-to-end local PR estimation demo
|
|
110
|
+
make up # Spin up local throwaway Postgres instance (docker-free)
|
|
111
|
+
make down # Tear down local Postgres instance
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## License
|
|
117
|
+
|
|
118
|
+
Class1 is licensed under the Business Source License 1.1 (BSL) — see [LICENSE](file:///Users/owner/Desktop/abc7d/LICENSE) for details. The project relies on price and capability dataset snapshots under their respective open-source licenses.
|
|
119
|
+
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
"""FinOps actuals — FOCUS-IN + close the calibration loop.
|
|
2
|
+
|
|
3
|
+
The FinOps-canonical source of ACTUAL spend is a FOCUS dataset (FinOps Open Cost & Usage
|
|
4
|
+
Specification): a cloud/billing export, a FinOps platform (Vantage / CloudZero / Finout) export,
|
|
5
|
+
or the provider usage/costs API mapped to FOCUS. blue_book already EXPORTS FOCUS (focus.py); this is
|
|
6
|
+
the inverse — read a FOCUS dataset, aggregate the FinOps `EffectiveCost` per workload/month into the
|
|
7
|
+
monthly ACTUAL, and feed it (paired with the prior ESTIMATE) into the ActuarialTable so the estimate
|
|
8
|
+
class rises from 5 (a guess) toward validated. Pure/offline: the REAL FOCUS rows are the user's data.
|
|
9
|
+
"""
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
import csv
|
|
13
|
+
from pathlib import Path
|
|
14
|
+
|
|
15
|
+
from cost_engine.calibration import ActuarialTable # NOTE: layer violation — blue_book imports cost_engine. Tracked as tech debt.
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def read_focus_csv(path: str | Path) -> list[dict]:
|
|
19
|
+
"""Read a FOCUS-format CSV (as exported by focus.export_to_csv or any FinOps tool / cloud billing).
|
|
20
|
+
Uses utf-8-SIG: real exports (verified on Microsoft's Azure EA FOCUS sample) carry a UTF-8 BOM that
|
|
21
|
+
would otherwise corrupt the first column name (\\ufeffBilledCost)."""
|
|
22
|
+
with Path(path).open(newline="", encoding="utf-8-sig") as f:
|
|
23
|
+
return list(csv.DictReader(f))
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def monthly_actual(focus_rows: list[dict], workflow: str | None = None, month: str | None = None,
|
|
27
|
+
cost_col: str = "EffectiveCost", tag_col: str = "x_workflow_name") -> float:
|
|
28
|
+
"""The ACTUAL monthly spend = sum of FinOps EffectiveCost over FOCUS rows. Optionally scope to a
|
|
29
|
+
workload (the `tag_col` column == `workflow` — x_workflow_name for our LLM exports, or ServiceName/
|
|
30
|
+
ResourceId for cloud FOCUS) and/or a month (YYYY-MM prefix of ChargePeriodStart). EffectiveCost is
|
|
31
|
+
the post-discount FinOps cost — the right number to validate an estimate against."""
|
|
32
|
+
total = 0.0
|
|
33
|
+
for r in focus_rows:
|
|
34
|
+
if workflow is not None and (r.get(tag_col) or "") != workflow:
|
|
35
|
+
continue
|
|
36
|
+
if month is not None and not str(r.get("ChargePeriodStart", "")).startswith(month):
|
|
37
|
+
continue
|
|
38
|
+
try:
|
|
39
|
+
total += float(r.get(cost_col) or 0.0)
|
|
40
|
+
except (TypeError, ValueError):
|
|
41
|
+
continue
|
|
42
|
+
return total
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def record_actual(table: ActuarialTable, workflow: str, estimate: dict, focus_rows: list[dict], *,
|
|
46
|
+
month: str | None = None, dominant_driver: str = "output length",
|
|
47
|
+
tag_col: str = "x_workflow_name") -> float:
|
|
48
|
+
"""Close the loop: pair the prior ESTIMATE for `workflow` with its ACTUAL spend (from the FOCUS
|
|
49
|
+
dataset) -> ActuarialTable. n_actuals rises -> estimate_class rises (the flywheel). Returns the
|
|
50
|
+
actual. This is the one step that turns a Class-5 guess into a validated estimate."""
|
|
51
|
+
actual = monthly_actual(focus_rows, workflow=workflow, month=month, tag_col=tag_col)
|
|
52
|
+
table.add(workflow, estimate, actual, dominant_driver)
|
|
53
|
+
return actual
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def variance_waterfall(estimate: dict, actual: float, driver_elasticities: dict[str, float] | None = None) -> dict[str, float]:
|
|
57
|
+
"""Isolate the cost variance (Actual - Expected) into a waterfall of risk drivers.
|
|
58
|
+
|
|
59
|
+
If actual exceeds expected, the variance is distributed proportionally
|
|
60
|
+
across the drivers based on their simulated elasticities. This bridges
|
|
61
|
+
the gap between 'we missed the budget' and 'here is exactly why'.
|
|
62
|
+
"""
|
|
63
|
+
driver_elasticities = driver_elasticities or {}
|
|
64
|
+
expected = float(estimate.get("expected", 0.0))
|
|
65
|
+
total_variance = actual - expected
|
|
66
|
+
|
|
67
|
+
waterfall = {}
|
|
68
|
+
if total_variance == 0 or not driver_elasticities:
|
|
69
|
+
waterfall["unexplained"] = total_variance
|
|
70
|
+
return waterfall
|
|
71
|
+
|
|
72
|
+
total_elasticity = sum(driver_elasticities.values())
|
|
73
|
+
if total_elasticity == 0:
|
|
74
|
+
waterfall["unexplained"] = total_variance
|
|
75
|
+
return waterfall
|
|
76
|
+
|
|
77
|
+
explained = 0.0
|
|
78
|
+
for driver, elasticity in driver_elasticities.items():
|
|
79
|
+
# Using abs(elasticity) in case negative correlation exists but we allocate magnitude
|
|
80
|
+
weight = abs(elasticity) / sum(abs(v) for v in driver_elasticities.values())
|
|
81
|
+
impact = total_variance * weight
|
|
82
|
+
waterfall[driver] = impact
|
|
83
|
+
explained += impact
|
|
84
|
+
|
|
85
|
+
remainder = total_variance - explained
|
|
86
|
+
if abs(remainder) > 0.01:
|
|
87
|
+
waterfall["remainder"] = remainder
|
|
88
|
+
|
|
89
|
+
return waterfall
|
|
90
|
+
|
|
91
|
+
def _main(argv=None) -> int:
|
|
92
|
+
"""CLI: record a real ACTUAL (from a FOCUS export) against a stored ESTIMATE -> persist the loop.
|
|
93
|
+
|
|
94
|
+
python -m blue_book.actuals --focus bill.csv --workflow support_agent \\
|
|
95
|
+
--estimate '{"expected":18,"p50":16,"p90":30}' [--month 2026-06]
|
|
96
|
+
"""
|
|
97
|
+
import argparse
|
|
98
|
+
import json
|
|
99
|
+
|
|
100
|
+
from cost_engine.calibration import ActuarialTable, load_table, save_table # NOTE: layer violation — blue_book imports cost_engine. Tracked as tech debt.
|
|
101
|
+
|
|
102
|
+
ap = argparse.ArgumentParser(description="Close the calibration loop: a FOCUS actual vs a prior estimate.")
|
|
103
|
+
ap.add_argument("--focus", required=True, help="FOCUS CSV (FinOps export / cloud billing / provider-usage->FOCUS)")
|
|
104
|
+
ap.add_argument("--workflow", required=True, help="x_workflow_name to scope the actual to")
|
|
105
|
+
ap.add_argument("--estimate", required=True, help="JSON (file path or inline) with expected/p50/p90")
|
|
106
|
+
ap.add_argument("--month", default=None, help="YYYY-MM to scope the actual (default: all)")
|
|
107
|
+
ap.add_argument("--table", default="snapshots/actuarial_table.json", help="persisted ActuarialTable")
|
|
108
|
+
ap.add_argument("--driver", default="output length")
|
|
109
|
+
ap.add_argument("--scope-col", default="x_workflow_name",
|
|
110
|
+
help="FOCUS column to scope by (x_workflow_name for LLM; ServiceName/ResourceId for cloud)")
|
|
111
|
+
a = ap.parse_args(argv)
|
|
112
|
+
|
|
113
|
+
est = json.loads(Path(a.estimate).read_text()) if Path(a.estimate).exists() else json.loads(a.estimate)
|
|
114
|
+
table = load_table(a.table) if Path(a.table).exists() else ActuarialTable()
|
|
115
|
+
actual = record_actual(table, a.workflow, est, read_focus_csv(a.focus),
|
|
116
|
+
month=a.month, dominant_driver=a.driver, tag_col=a.scope_col)
|
|
117
|
+
save_table(table, a.table)
|
|
118
|
+
cls = table.estimate_class(a.workflow)
|
|
119
|
+
print(f"actual ${actual:,.2f} recorded for '{a.workflow}' (month={a.month or 'all'}) -> "
|
|
120
|
+
f"n_actuals={table.n_actuals(a.workflow)}, class={cls.label}, "
|
|
121
|
+
f"verdict={table._scoped(a.workflow)[-1].verdict}")
|
|
122
|
+
return 0
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
if __name__ == "__main__":
|
|
126
|
+
raise SystemExit(_main())
|